Skip to content

Commit f500885

Browse files
MitnitskyCopilotborgmanJeremy
authored
feature(macos): show dock icon when any app window is open (flameshot-org#4628)
On macOS with LSUIElement=true, Flameshot runs as an agent app (no dock icon). This adds a dock icon that appears while any user-facing window (Settings, About, Launcher, Upload History) is visible and disappears when the last one is closed or hidden. Uses QWindow::visibilityChanged signal with a per-window dynamic property to track visibility state and a reference counter for the activation policy toggle. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: borgmanJeremy <46930769+borgmanJeremy@users.noreply.github.com>
1 parent 016b919 commit f500885

2 files changed

Lines changed: 84 additions & 8 deletions

File tree

src/core/flameshot.cpp

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,37 @@
88
#endif
99

1010
#if defined(Q_OS_MACOS)
11+
#include <QWindow>
12+
#include <objc/message.h>
13+
14+
namespace {
15+
16+
constexpr long NSApplicationActivationPolicyRegular = 0;
17+
constexpr long NSApplicationActivationPolicyAccessory = 1;
18+
19+
void setActivationPolicy(long policy)
20+
{
21+
auto sharedApp = reinterpret_cast<id (*)(id, SEL)>(objc_msgSend);
22+
auto setPolicy = reinterpret_cast<void (*)(id, SEL, long)>(objc_msgSend);
23+
id nsApp = sharedApp(reinterpret_cast<id>(objc_getClass("NSApplication")),
24+
sel_registerName("sharedApplication"));
25+
setPolicy(nsApp, sel_registerName("setActivationPolicy:"), policy);
26+
}
27+
28+
void setActivationPolicyRegular()
29+
{
30+
setActivationPolicy(NSApplicationActivationPolicyRegular);
31+
}
32+
33+
void setActivationPolicyAccessory()
34+
{
35+
setActivationPolicy(NSApplicationActivationPolicyAccessory);
36+
}
37+
38+
constexpr const char* visibleInDockProperty = "_visibleInDock";
39+
40+
} // namespace
41+
1142
#include <CoreGraphics/CoreGraphics.h>
1243
#endif
1344

@@ -227,8 +258,7 @@ void Flameshot::launcher()
227258
}
228259
m_launcherWindow->show();
229260
#if defined(Q_OS_MACOS)
230-
m_launcherWindow->activateWindow();
231-
m_launcherWindow->raise();
261+
showDockIcon(m_launcherWindow);
232262
#endif
233263
}
234264

@@ -248,8 +278,7 @@ void Flameshot::config()
248278
position.moveCenter(currentScreen->availableGeometry().center());
249279
m_configWindow->move(position.topLeft());
250280
#if defined(Q_OS_MACOS)
251-
m_configWindow->activateWindow();
252-
m_configWindow->raise();
281+
showDockIcon(m_configWindow);
253282
#endif
254283
}
255284
}
@@ -259,8 +288,7 @@ void Flameshot::info()
259288
if (m_infoWindow == nullptr) {
260289
m_infoWindow = new InfoWindow();
261290
#if defined(Q_OS_MACOS)
262-
m_infoWindow->activateWindow();
263-
m_infoWindow->raise();
291+
showDockIcon(m_infoWindow);
264292
#endif
265293
}
266294
}
@@ -286,9 +314,46 @@ void Flameshot::history()
286314
historyWidget->move(position.topLeft());
287315

288316
#if defined(Q_OS_MACOS)
289-
historyWidget->activateWindow();
290-
historyWidget->raise();
317+
showDockIcon(historyWidget);
318+
#endif
319+
}
291320
#endif
321+
322+
#if defined(Q_OS_MACOS)
323+
void Flameshot::onWindowVisibilityChanged(QWindow::Visibility newVisibility)
324+
{
325+
auto* qw = qobject_cast<QWindow*>(sender());
326+
if (!qw) {
327+
return;
328+
}
329+
330+
if (newVisibility == QWindow::Hidden) {
331+
qw->setProperty(visibleInDockProperty, false);
332+
--m_dockIconVisibleCount;
333+
if (m_dockIconVisibleCount == 0) {
334+
setActivationPolicyAccessory();
335+
}
336+
} else {
337+
bool windowTrackedInDock = qw->property(visibleInDockProperty).toBool();
338+
if (!windowTrackedInDock) {
339+
qw->setProperty(visibleInDockProperty, true);
340+
++m_dockIconVisibleCount;
341+
setActivationPolicyRegular();
342+
}
343+
}
344+
}
345+
346+
void Flameshot::showDockIcon(QWidget* w)
347+
{
348+
QWindow* qw = w->windowHandle();
349+
if (!qw) {
350+
return;
351+
}
352+
353+
connect(qw,
354+
&QWindow::visibilityChanged,
355+
this,
356+
&Flameshot::onWindowVisibilityChanged);
292357
}
293358
#endif
294359

src/core/flameshot.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
#include <QObject>
99
#include <QPointer>
1010
#include <QVersionNumber>
11+
#include <QWindow>
1112

1213
class CaptureWidget;
1314
class ConfigWindow;
1415
class InfoWindow;
1516
class CaptureLauncher;
17+
class QWidget;
1618
#ifdef ENABLE_IMGUR
1719
class UploadHistory;
1820
#endif
@@ -91,6 +93,15 @@ public slots:
9193
QPointer<CaptureLauncher> m_launcherWindow;
9294
QPointer<ConfigWindow> m_configWindow;
9395

96+
#if defined(Q_OS_MACOS)
97+
public:
98+
void showDockIcon(QWidget* window);
99+
100+
private:
101+
void onWindowVisibilityChanged(QWindow::Visibility newVisibility);
102+
int m_dockIconVisibleCount = 0;
103+
#endif
104+
94105
#if (defined(Q_OS_MACOS) || defined(Q_OS_WIN))
95106
QHotkey* m_HotkeyScreenshotCapture;
96107
#endif

0 commit comments

Comments
 (0)