You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR fixes an issue on macOS where restarting Sunshine (e.g. from the system tray or Web UI) causes the system tray icon to completely disappear for the newly restarted instance.
macOS WindowServer strictly associates GUI state (including the tray icon and activation policies) with the Process ID (PID). Sunshine previously used execv() to restart itself. execv() replaces the process image but retains the exact same PID. When the new instance starts, WindowServer retains the stale state of the old process and silently refuses to initialize the new system tray icon.
execv with an artificial delay: We initially tried passing an environment variable (SUNSHINE_IS_RESTARTING) and delaying the startup of the new instance by 500ms to give the OS time to clean up. Result: Failed. Since the PID remains identical, a delay does not clear WindowServer's cache.
NSTask / fork (Fire and Forget): We tried replacing execv with an NSTask launch (which forks a new process and yields a fresh PID), then letting the original parent process exit immediately. Result: This successfully fixed the system tray icon! However, it severely broke the terminal experience. Because the parent process exited immediately, the shell (zsh/bash) reclaimed the terminal foreground. The new Sunshine instance continued running in the background, dumping logs over the user's shell prompt, and completely breaking Ctrl+C termination.
To satisfy both WindowServer (which demands a new PID) and the user's shell (which demands the original process stays alive to maintain terminal control), we implemented a Supervisor Pattern in src/platform/macos/misc.mm:
The parent process forks a child and calls execv on the new Sunshine instance. The child gets a completely fresh PID, allowing the system tray icon to initialize perfectly.
The child places itself in a new process group (setpgid(0,0)).
The parent process does not exit. Instead, it acts as a transparent supervisor, blocking on waitpid(). Because the parent stays alive, the shell never reclaims the terminal, preventing logs from interleaving with the shell prompt.
The parent catches termination signals (SIGINT, SIGTERM, SIGHUP) and forwards them directly to the child. This means Ctrl+C in the terminal gracefully kills the new instance.
eduardomozart
changed the title
fix(macos): macOS restart by keeping parent process as a supervisor
fix(macos): System tray icon disappears when restarting Sunshine
Aug 14, 2026
❌ Patch coverage is 16.00000% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 32.43%. Comparing base (0a1c365) to head (da88bce). ⚠️ Report is 1 commits behind head on master.
✅ All tests successful. No failed tests found.
ReenigneArcher
changed the title
fix(macos): System tray icon disappears when restarting Sunshine
fix(macOS): System tray icon disappears when restarting Sunshine
Aug 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR fixes an issue on macOS where restarting Sunshine (e.g. from the system tray or Web UI) causes the system tray icon to completely disappear for the newly restarted instance.
macOS WindowServer strictly associates GUI state (including the tray icon and activation policies) with the Process ID (PID). Sunshine previously used
execv()to restart itself.execv()replaces the process image but retains the exact same PID. When the new instance starts, WindowServer retains the stale state of the old process and silently refuses to initialize the new system tray icon.execvwith an artificial delay: We initially tried passing an environment variable (SUNSHINE_IS_RESTARTING) and delaying the startup of the new instance by 500ms to give the OS time to clean up. Result: Failed. Since the PID remains identical, a delay does not clear WindowServer's cache.NSTask/fork(Fire and Forget): We tried replacingexecvwith anNSTasklaunch (which forks a new process and yields a fresh PID), then letting the original parent process exit immediately. Result: This successfully fixed the system tray icon! However, it severely broke the terminal experience. Because the parent process exited immediately, the shell (zsh/bash) reclaimed the terminal foreground. The new Sunshine instance continued running in the background, dumping logs over the user's shell prompt, and completely breakingCtrl+Ctermination.To satisfy both WindowServer (which demands a new PID) and the user's shell (which demands the original process stays alive to maintain terminal control), we implemented a Supervisor Pattern in
src/platform/macos/misc.mm:forks a child and callsexecvon the new Sunshine instance. The child gets a completely fresh PID, allowing the system tray icon to initialize perfectly.setpgid(0,0)).waitpid(). Because the parent stays alive, the shell never reclaims the terminal, preventing logs from interleaving with the shell prompt.SIGINT,SIGTERM,SIGHUP) and forwards them directly to the child. This meansCtrl+Cin the terminal gracefully kills the new instance.Screenshot
Gravacao.de.Tela.2026-08-14.as.18.15.43.mov
Issues Fixed or Closed
Roadmap Issues
Type of Change
Checklist
AI Usage
See our AI usage policy.