Skip to content

Commit 6584221

Browse files
committed
Make startup minimized on osx finally
1 parent c0c3416 commit 6584221

3 files changed

Lines changed: 21 additions & 69 deletions

File tree

app/app_qt.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,12 @@ def update() -> None:
178178
# tray is not ready yet (common at login time on macOS before the menu bar
179179
# is available). A retry timer creates the tray once it becomes available.
180180
_start_hidden = args.start_minimized_to_tray
181-
if _start_hidden and sys.platform == "darwin":
182-
from utils.macos_activation import set_policy_accessory
183-
set_policy_accessory()
184181
if not _start_hidden:
185182
window.show()
186183

187184
if args.start_minimized_to_tray and _tray is None:
188185
def _retry_tray() -> None:
189-
if app._qt_tray is not None: # type: ignore[attr-defined]
186+
if getattr(app, "_qt_tray", None) is not None:
190187
return
191188
if QSystemTrayIcon.isSystemTrayAvailable():
192189
tray = NetNeighborTray(app.windowIcon(), window, parent=app)
@@ -199,20 +196,22 @@ def _retry_tray() -> None:
199196
if sys.platform == "darwin":
200197
# On macOS, clicking the Dock icon when the window is hidden fires
201198
# QEvent.Type.ApplicationActivate. Handle it so the window reappears.
202-
# Guard: only act if the window has been shown at least once — macOS also
203-
# sends ApplicationActivate at login (not a user action), which must not
204-
# force the window open when starting minimized.
199+
# At login macOS also sends ApplicationActivate automatically — guard
200+
# against this by only reacting once the window has been shown at least
201+
# once by a real user action (tray click, single-instance activation…).
205202
from PySide6.QtCore import QEvent, QObject
206203

207-
class _DockClickFilter(QObject):
208-
_window_shown_once: bool = not _start_hidden
204+
# True from the start for normal launches; False until user shows window
205+
# for minimized launches. Tracked via QEvent.Type.Show on the window.
206+
_window_was_shown = [not _start_hidden]
209207

208+
class _DockClickFilter(QObject):
210209
def eventFilter(self, obj: QObject, event: QEvent) -> bool:
211210
if event.type() == QEvent.Type.ApplicationActivate:
212-
if self._window_shown_once and not window.isVisible():
211+
if _window_was_shown[0] and not window.isVisible():
213212
window.bring_to_front()
214-
elif event.type() == QEvent.Type.Show and obj is window:
215-
self._window_shown_once = True
213+
elif event.type() == QEvent.Type.Show:
214+
_window_was_shown[0] = True
216215
return False
217216

218217
app._qt_dock_filter = _DockClickFilter(app)

app/ui/systray.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def __init__(self, icon: QIcon, window, parent=None) -> None:
2929
self._action_quit = self._menu.addAction(_("Quit"))
3030
self.setContextMenu(self._menu)
3131
self._sync_show_hide_label()
32+
self._menu.aboutToShow.connect(self._sync_show_hide_label)
3233
self._action_show_hide.triggered.connect(self._toggle_window)
3334
self._action_quit.triggered.connect(self._quit)
3435
self.activated.connect(self._on_activated)

app/utils/macos_activation.py

Lines changed: 9 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,68 +2,20 @@
22
# Internal version : 2.0.0 date: 2026-05-24 00:00
33
# Owner: Luc LEBOSSE all copyrights
44
# License: LGPL3
5-
"""macOS NSApplication activation-policy helpers (ctypes, no pyobjc dependency).
5+
"""macOS NSApplication activation-policy helpers — stubs only.
66
7-
Regular → Dock icon visible, app menu visible (normal windowed app).
8-
Accessory → No Dock icon, no app menu (menu-bar / tray-only app).
9-
10-
Call set_policy_regular() before showing the main window and
11-
set_policy_accessory() after hiding it to the system tray.
7+
Dynamic policy switching (Accessory ↔ Regular) was tested but found to
8+
interfere with QSystemTrayIcon availability on macOS 11 Big Sur when called
9+
before the system tray is initialised. These are no-ops until a reliable
10+
sequencing solution is found.
1211
"""
1312

1413
from __future__ import annotations
1514

16-
import sys
17-
18-
if sys.platform != "darwin":
19-
20-
def set_policy_regular() -> None:
21-
pass
22-
23-
def set_policy_accessory() -> None:
24-
pass
25-
26-
else:
27-
import ctypes
28-
import ctypes.util
29-
30-
_lib = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc") or "libobjc.dylib")
31-
_lib.objc_getClass.restype = ctypes.c_void_p
32-
_lib.objc_getClass.argtypes = [ctypes.c_char_p]
33-
_lib.sel_registerName.restype = ctypes.c_void_p
34-
_lib.sel_registerName.argtypes = [ctypes.c_char_p]
35-
36-
_POLICY_REGULAR = 0 # NSApplicationActivationPolicyRegular
37-
_POLICY_ACCESSORY = 1 # NSApplicationActivationPolicyAccessory
38-
39-
def _shared_app() -> int:
40-
# Get NSApp — set argtypes/restype for this specific call signature
41-
_lib.objc_msgSend.restype = ctypes.c_void_p
42-
_lib.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
43-
return _lib.objc_msgSend(
44-
_lib.objc_getClass(b"NSApplication"),
45-
_lib.sel_registerName(b"sharedApplication"),
46-
)
4715

48-
def _set_policy(policy: int) -> None:
49-
try:
50-
# Resolve NSApp first — _shared_app() modifies argtypes internally,
51-
# so it must be called before we set the 3-arg signature below.
52-
nsapp = _shared_app()
53-
_lib.objc_msgSend.restype = ctypes.c_void_p
54-
_lib.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_long]
55-
_lib.objc_msgSend(
56-
nsapp,
57-
_lib.sel_registerName(b"setActivationPolicy:"),
58-
ctypes.c_long(policy),
59-
)
60-
except Exception:
61-
pass
16+
def set_policy_regular() -> None:
17+
pass
6218

63-
def set_policy_regular() -> None:
64-
"""Dock icon + app menu visible (normal windowed app)."""
65-
_set_policy(_POLICY_REGULAR)
6619

67-
def set_policy_accessory() -> None:
68-
"""No Dock icon, no app menu (tray/menu-bar app)."""
69-
_set_policy(_POLICY_ACCESSORY)
20+
def set_policy_accessory() -> None:
21+
pass

0 commit comments

Comments
 (0)