diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 69ef33a80..eed3a903a 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -1368,6 +1368,16 @@ void MainWindow::trayIconTriggered(QSystemTrayIcon::ActivationReason reason) void MainWindow::processTrayIconTrigger() { +#ifdef Q_OS_MACOS + // Do not toggle the window on macOS and just show the context menu instead. + // Right click detection doesn't seem to be working anyway + // and anything else will only trigger the context menu AND + // toggle the window at the same time, which is confusing at best. + // Showing only a context menu for tray icons seems to be best + // practice on macOS anyway, so this is probably fine. + return; +#endif + if (m_trayIconTriggerReason == QSystemTrayIcon::DoubleClick) { // Always toggle window on double click toggleWindow(); @@ -1379,7 +1389,7 @@ void MainWindow::processTrayIconTrigger() // clicking the tray icon removes focus from main window. if (isHidden() || (Clock::currentMilliSecondsSinceEpoch() - m_lastFocusOutTime) <= 500) { #else - // If on Linux or macOS, check if the window has focus. + // If on Linux, check if the window has focus. if (hasFocus() || isHidden() || windowHandle()->isActive()) { #endif toggleWindow(); @@ -1394,40 +1404,39 @@ void MainWindow::show() #ifndef Q_OS_WIN m_lastShowTime = Clock::currentMilliSecondsSinceEpoch(); #endif - QMainWindow::show(); -} - -bool MainWindow::shouldHide() -{ -#ifndef Q_OS_WIN - qint64 current_time = Clock::currentMilliSecondsSinceEpoch(); - - if (current_time - m_lastShowTime < 50) { - return false; - } +#ifdef Q_OS_MACOS + // Unset minimize state to avoid weird fly-in effects + setWindowState(windowState() & ~Qt::WindowMinimized); + macUtils()->toggleForegroundApp(true); #endif - return true; + QMainWindow::show(); } void MainWindow::hide() { - if (shouldHide()) { - QMainWindow::hide(); +#ifndef Q_OS_WIN + qint64 current_time = Clock::currentMilliSecondsSinceEpoch(); + if (current_time - m_lastShowTime < 50) { + return; } +#endif + QMainWindow::hide(); +#ifdef Q_OS_MACOS + macUtils()->toggleForegroundApp(false); +#endif } void MainWindow::hideWindow() { saveWindowInformation(); - if (QGuiApplication::platformName() != "xcb") { - // In X11 the window should NOT be minimized and hidden (i.e. not - // shown) at the same time (which would happen if both minimize on - // startup and minimize to tray are set) since otherwise it causes - // problems on restore as seen on issue #1595. Hiding it is enough. - setWindowState(windowState() | Qt::WindowMinimized); - } + // Only hide if tray icon is active, otherwise window will be gone forever if (isTrayIconEnabled()) { + // On X11, the window should NOT be minimized and hidden at the same time. See issue #1595. + // On macOS, we are skipping minimization as well to avoid playing the magic lamp animation. + if (QGuiApplication::platformName() != "xcb" && QGuiApplication::platformName() != "cocoa") { + setWindowState(windowState() | Qt::WindowMinimized); + } hide(); } else { showMinimized(); diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index 9872145a7..b901ef54c 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -141,7 +141,6 @@ private: static const QString BaseWindowTitle; - bool shouldHide(); void saveWindowInformation(); bool saveLastDatabases(); void updateTrayIcon(); diff --git a/src/gui/osutils/macutils/AppKit.h b/src/gui/osutils/macutils/AppKit.h index 2bff8f5b3..a6f7b3a12 100644 --- a/src/gui/osutils/macutils/AppKit.h +++ b/src/gui/osutils/macutils/AppKit.h @@ -39,6 +39,7 @@ public: bool isDarkMode(); bool enableAccessibility(); bool enableScreenRecording(); + void toggleForegroundApp(bool foreground); signals: void lockDatabases(); diff --git a/src/gui/osutils/macutils/AppKitImpl.h b/src/gui/osutils/macutils/AppKitImpl.h index 326879766..5dadc31dd 100644 --- a/src/gui/osutils/macutils/AppKitImpl.h +++ b/src/gui/osutils/macutils/AppKitImpl.h @@ -38,5 +38,6 @@ - (void) userSwitchHandler:(NSNotification*) notification; - (bool) enableAccessibility; - (bool) enableScreenRecording; +- (void) toggleForegroundApp:(bool) foreground; @end diff --git a/src/gui/osutils/macutils/AppKitImpl.mm b/src/gui/osutils/macutils/AppKitImpl.mm index 4a93f963a..077dd71a6 100644 --- a/src/gui/osutils/macutils/AppKitImpl.mm +++ b/src/gui/osutils/macutils/AppKitImpl.mm @@ -154,6 +154,16 @@ return YES; } +- (void) toggleForegroundApp:(bool) foreground +{ + ProcessSerialNumber psn = {0, kCurrentProcess}; + if (foreground) { + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + } else { + TransformProcessType(&psn, kProcessTransformToUIElementApplication); + } +} + @end // @@ -215,3 +225,8 @@ bool AppKit::enableScreenRecording() { return [static_cast(self) enableScreenRecording]; } + +void AppKit::toggleForegroundApp(bool foreground) +{ + [static_cast(self) toggleForegroundApp:foreground]; +} diff --git a/src/gui/osutils/macutils/MacUtils.cpp b/src/gui/osutils/macutils/MacUtils.cpp index 9203d73f2..d32a15612 100644 --- a/src/gui/osutils/macutils/MacUtils.cpp +++ b/src/gui/osutils/macutils/MacUtils.cpp @@ -123,3 +123,14 @@ bool MacUtils::isCapslockEnabled() { return (CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState) & kCGEventFlagMaskAlphaShift) != 0; } + +/** + * Toggle application state between foreground app and UIElement app. + * Foreground apps have dock icons, UIElement apps do not. + * + * @param foreground whether app is foreground app + */ +void MacUtils::toggleForegroundApp(bool foreground) +{ + m_appkit->toggleForegroundApp(foreground); +} diff --git a/src/gui/osutils/macutils/MacUtils.h b/src/gui/osutils/macutils/MacUtils.h index ccabf6788..281c5438c 100644 --- a/src/gui/osutils/macutils/MacUtils.h +++ b/src/gui/osutils/macutils/MacUtils.h @@ -46,6 +46,7 @@ public: bool isHidden(); bool enableAccessibility(); bool enableScreenRecording(); + void toggleForegroundApp(bool foreground); signals: void lockDatabases();