Hidden-App Hook Debugging
This is an internal engineering note. It captures a specific debugging thread for contributors working on helper behavior and Dock re-promotion issues.
GhostTile originally hid apps by injecting a helper into the target process and blocking the app from promoting itself back into the Dock.
The modern rewrite now loads the helper persistently by:
- patching the managed app binary with
LC_LOAD_DYLIB @rpath/ghosthide.dylib - staging the helper at
Contents/Frameworks/ghosthide.dylib - re-signing the modified binary and bundle ad hoc
This replaces the earlier DYLD_INSERT_LIBRARIES-only launch path and allows normal app launches to keep the helper loaded.
These hooks remain in the release helper because they are useful and correspond to real promotion behavior:
-[NSApplication setActivationPolicy:]-[NSApplication activateIgnoringOtherApps:]TransformProcessType
GhostTile uses the saved original TransformProcessType only for its own explicit show and hide transitions.
These hooks were tested during debugging but are not kept in the release helper:
-[NSApplication unhide:]-[NSWindow makeKeyAndOrderFront:]applicationShouldHandleReopen:hasVisibleWindows:on Electron's app delegate-[NSRunningApplication activateWithOptions:]SetFrontProcessSetFrontProcessWithOptions
Target app:
- Legcord
- Electron version
40.6.0
Relevant Legcord app code that was inspected:
src/discord/tray.ts- tray click calls
mainWindow.show()
- tray click calls
src/discord/window.ts- app
activatehandler callsapp.show()
- app
Relevant Electron macOS code that was checked:
NativeWindowMac::Show()activateIgnoringOtherApps:YESmakeKeyAndOrderFront:nil
Browser::Show()unhide:nil
Browser::DockShow()TransformProcessType(...Foreground)activateWithOptions(...)
- Build debug helper:
GHOSTHIDE_DEBUG=1 just build-cli- Re-prepare Legcord:
./.build/release/ghosttile prepare --force /Applications/legcord.app- Launch Legcord normally:
open -a /Applications/legcord.app- Click the Dock icon through UI scripting:
osascript <<'APPLESCRIPT'
tell application "System Events"
tell process "Dock"
click UI element "Legcord" of list 1
end tell
end tell
APPLESCRIPT- Inspect:
- activation policy through
NSWorkspace.shared.runningApplications - helper log at
~/.config/ghosttile/ghosthide.log
Fresh Dock-click repro on a hidden Legcord process showed:
activateIgnoringOtherApps intercepted, flag=1 hidden=1makeKeyAndOrderFront intercepted, window=Legcord sender=nil hidden=1
What did not fire on the decisive repro:
unhideactivateWithOptionsTransformProcessTypeapplicationShouldHandleReopen:hasVisibleWindows:
Even with activateIgnoringOtherApps: and makeKeyAndOrderFront: blocked in-process, Legcord still flipped from NSApplicationActivationPolicyAccessory to NSApplicationActivationPolicyRegular.
For Electron apps like Legcord, Dock activation can still promote the process back to a regular app outside the direct in-process methods we tested.
Practical implication:
- more in-process hooks are unlikely to fully solve Dock-click re-promotion cleanly
- a future "sticky hidden" behavior should be treated as an explicit option that re-applies hidden state after activation
- do not re-add
unhide,makeKeyAndOrderFront, or delegate reopen hooks to release mode without a new confirmed repro that shows they are the decisive enforcement point
- keep the release helper minimal
- preserve debug-only logging infrastructure for future targeted investigations
- add any stronger post-activation enforcement behind a user preference instead of making it the default behavior