diff --git a/GalaxyBudsClient/App.axaml.cs b/GalaxyBudsClient/App.axaml.cs
index 638d57c7..212c737f 100644
--- a/GalaxyBudsClient/App.axaml.cs
+++ b/GalaxyBudsClient/App.axaml.cs
@@ -67,13 +67,9 @@ public override void Initialize()
#if OSX
NSApplication.Init();
- NSApplication.Notifications.ObserveDidBecomeActive((_, _) =>
- {
- Dispatcher.UIThread.InvokeAsync(delegate
- {
- MainWindow.Instance.BringToFront();
- });
- });
+ // For menu bar applications (LSUIElement=true), hide the dock icon immediately at startup.
+ // The dock icon will only appear when the settings window is explicitly opened.
+ GalaxyBudsClient.Platform.OSX.AppUtils.setHideInDock(true);
#endif
AvaloniaXamlLoader.Load(this);
@@ -108,8 +104,16 @@ public override void OnFrameworkInitializationCompleted()
{
// Initialize MainWindow singleton
var mainWindow = MainWindow.Instance;
+
+#if OSX
+ // On macOS with LSUIElement=true, always start as a menu bar app (no main window attached initially)
+ // The window will be shown when the user clicks the tray icon
+ desktop.MainWindow = null;
+ mainWindow.IsVisible = false;
+#else
// Stay initially minimized: don't attach a main window
desktop.MainWindow = StartMinimized ? null : mainWindow;
+#endif
TrayManager.Init();
BatteryHistoryManager.Init();
@@ -353,4 +357,4 @@ private async void HandleOtherTouchOption(object? sender, TouchOptions e)
break;
}
}
-}
\ No newline at end of file
+}
diff --git a/GalaxyBudsClient/Info.plist b/GalaxyBudsClient/Info.plist
index 44b86169..8aeebb94 100755
--- a/GalaxyBudsClient/Info.plist
+++ b/GalaxyBudsClient/Info.plist
@@ -8,5 +8,7 @@
Galaxy Buds Manager
CFBundleDisplayName
Galaxy Buds Manager
+ LSUIElement
+
diff --git a/GalaxyBudsClient/Interface/MainWindow.axaml.cs b/GalaxyBudsClient/Interface/MainWindow.axaml.cs
index 2fed110d..be8b0ce6 100644
--- a/GalaxyBudsClient/Interface/MainWindow.axaml.cs
+++ b/GalaxyBudsClient/Interface/MainWindow.axaml.cs
@@ -59,6 +59,23 @@ private void OnLanguageUpdated()
protected override async void OnClosing(WindowClosingEventArgs e)
{
+#if OSX
+ // On macOS with LSUIElement, minimize to tray if setting is enabled
+ if (Settings.Data.MinimizeToTray && e.CloseReason is not (WindowCloseReason.OSShutdown or WindowCloseReason.ApplicationShutdown))
+ {
+ BringToTray();
+ e.Cancel = true;
+ Log.Debug("MainWindow.OnClosing: macOS menu bar app - minimized to tray");
+ base.OnClosing(e);
+ return;
+ }
+
+ // If MinimizeToTray is off, quit the app when closing the window
+ if (!Settings.Data.MinimizeToTray)
+ {
+ Log.Debug("MainWindow.OnClosing: macOS - MinimizeToTray disabled, closing app");
+ }
+#else
if (Settings.Data.MinimizeToTray && PlatformUtils.SupportsTrayIcon)
{
// check if the cause of the termination is due to shutdown or application close request
@@ -77,6 +94,7 @@ protected override async void OnClosing(WindowClosingEventArgs e)
{
Log.Debug("MainWindow.OnClosing: Now closing session");
}
+#endif
await BluetoothImpl.Instance.SendRequestAsync(MsgIds.FIND_MY_EARBUDS_STOP);
await BluetoothImpl.Instance.DisconnectAsync();
@@ -124,26 +142,32 @@ public void BringToFront()
{
Dispatcher.UIThread.InvokeAsync(() =>
{
+#if OSX
+ // On macOS, show in dock first, then make window visible
+ GalaxyBudsClient.Platform.OSX.AppUtils.setHideInDock(false);
+#endif
+
if (App.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop &&
desktop.MainWindow == null)
{
desktop.MainWindow = this;
}
- if (WindowState == WindowState.Minimized)
- {
- WindowState = WindowState.Normal;
- }
+ // Ensure window state is normal before showing
+ WindowState = WindowState.Normal;
if (PlatformUtils.IsLinux)
{
IsVisible = false; // Workaround for some Linux DMs
}
+ IsVisible = true;
+
#if OSX
- GalaxyBudsClient.Platform.OSX.AppUtils.setHideInDock(false);
+ // On macOS, re-apply theme to restore blur/transparency effects
+ // This is needed because effects don't persist when window is hidden/shown
+ (this as IStyledWindow).ApplyTheme(this);
#endif
- IsVisible = true;
Activate();
Topmost = true;
@@ -172,11 +196,22 @@ public void ToggleVisibility()
private void BringToTray()
{
#if OSX
+ // On macOS, we need to hide the window completely without minimizing to dock
+ // First hide visibility, then hide from dock
+ IsVisible = false;
+ ShowInTaskbar = false;
GalaxyBudsClient.Platform.OSX.AppUtils.setHideInDock(true);
-#endif
+
+ // Detach the main window so macOS doesn't try to show the app in dock
+ if (App.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = null;
+ }
+#else
ShowInTaskbar = false;
WindowState = WindowState.Minimized;
IsVisible = false;
+#endif
}
private void OnBluetoothError(object? sender, BluetoothException e)
@@ -195,4 +230,4 @@ private void OnBluetoothError(object? sender, BluetoothException e)
}
});
}
-}
\ No newline at end of file
+}