diff options
author | Janek Bevendorff <janek@jbev.net> | 2020-12-19 02:20:24 +0300 |
---|---|---|
committer | Janek Bevendorff <janek@jbev.net> | 2021-01-07 17:22:48 +0300 |
commit | 80c1b9be6a09cee67411840ecde129bcab70ebe1 (patch) | |
tree | 9280eda76267e898830e79a871ab298bc67f91a5 /src/gui/osutils | |
parent | 37dab85df7e196c5596dd42d7fe09b95284507bd (diff) |
Improve macOS platform integration.
- Allow switching between themes without restart (except classic)
- Rework icon loading and recolouring logic to react to theme changes
- Automatically react to light/dark theme change
- Remove explicit selection of monochrome tray icon variant (selected
automatically now)
- Update theme background colours for Big Sur
- Update application icon to match Big Sur HIG
The tray icon doesn't respond perfectly to theme changes yet on Big Sur,
since we need different icons for dark and light theme and cannot simply
let the OS recolour the icon for us (we do that, too, but only as an
additional fallback). At the moment, there is no signal to listen to
that would allow this.
This patch adds a few generic methods to OSUtils for detecting and
communicating theme changes, which are only stubs for Windows and Linux at
the moment and need to be implemented in future commits.
Fixes #4933
Fixes #5349
Diffstat (limited to 'src/gui/osutils')
-rw-r--r-- | src/gui/osutils/OSUtilsBase.h | 15 | ||||
-rw-r--r-- | src/gui/osutils/macutils/AppKit.h | 3 | ||||
-rw-r--r-- | src/gui/osutils/macutils/AppKitImpl.h | 1 | ||||
-rw-r--r-- | src/gui/osutils/macutils/AppKitImpl.mm | 61 | ||||
-rw-r--r-- | src/gui/osutils/macutils/MacUtils.cpp | 14 | ||||
-rw-r--r-- | src/gui/osutils/macutils/MacUtils.h | 2 | ||||
-rw-r--r-- | src/gui/osutils/nixutils/NixUtils.cpp | 6 | ||||
-rw-r--r-- | src/gui/osutils/nixutils/NixUtils.h | 1 | ||||
-rw-r--r-- | src/gui/osutils/winutils/WinUtils.cpp | 6 | ||||
-rw-r--r-- | src/gui/osutils/winutils/WinUtils.h | 1 |
10 files changed, 107 insertions, 3 deletions
diff --git a/src/gui/osutils/OSUtilsBase.h b/src/gui/osutils/OSUtilsBase.h index 23f5b926e..5b97cd505 100644 --- a/src/gui/osutils/OSUtilsBase.h +++ b/src/gui/osutils/OSUtilsBase.h @@ -36,6 +36,11 @@ public: virtual bool isDarkMode() const = 0; /** + * @return OS task / menu bar is dark. + */ + virtual bool isStatusBarDark() const = 0; + + /** * @return KeePassXC set to launch at system startup (autostart). */ virtual bool isLaunchAtStartupEnabled() const = 0; @@ -61,6 +66,16 @@ public: signals: void globalShortcutTriggered(const QString& name); + /** + * Indicates platform UI theme change (light mode to dark mode). + */ + void interfaceThemeChanged(); + + /* + * Indicates a change in the tray / statusbar theme. + */ + void statusbarThemeChanged(); + protected: explicit OSUtilsBase(QObject* parent = nullptr); virtual ~OSUtilsBase(); diff --git a/src/gui/osutils/macutils/AppKit.h b/src/gui/osutils/macutils/AppKit.h index a6f7b3a12..9ce4c01db 100644 --- a/src/gui/osutils/macutils/AppKit.h +++ b/src/gui/osutils/macutils/AppKit.h @@ -20,6 +20,7 @@ #define KEEPASSX_APPKIT_H #include <QObject> +#include <QColor> #include <unistd.h> class AppKit : public QObject @@ -37,12 +38,14 @@ public: bool hideProcess(pid_t pid); bool isHidden(pid_t pid); bool isDarkMode(); + bool isStatusBarDark(); bool enableAccessibility(); bool enableScreenRecording(); void toggleForegroundApp(bool foreground); signals: void lockDatabases(); + void interfaceThemeChanged(); private: void* self; diff --git a/src/gui/osutils/macutils/AppKitImpl.h b/src/gui/osutils/macutils/AppKitImpl.h index 5dadc31dd..5e7a2fbae 100644 --- a/src/gui/osutils/macutils/AppKitImpl.h +++ b/src/gui/osutils/macutils/AppKitImpl.h @@ -35,6 +35,7 @@ - (bool) hideProcess:(pid_t) pid; - (bool) isHidden:(pid_t) pid; - (bool) isDarkMode; +- (bool) isStatusBarDark; - (void) userSwitchHandler:(NSNotification*) notification; - (bool) enableAccessibility; - (bool) enableScreenRecording; diff --git a/src/gui/osutils/macutils/AppKitImpl.mm b/src/gui/osutils/macutils/AppKitImpl.mm index 077dd71a6..faf061106 100644 --- a/src/gui/osutils/macutils/AppKitImpl.mm +++ b/src/gui/osutils/macutils/AppKitImpl.mm @@ -17,7 +17,11 @@ */ #import "AppKitImpl.h" +#include "AppKit.h" +#import <AppKit/NSStatusBar.h> +#import <AppKit/NSStatusItem.h> +#import <AppKit/NSStatusBarButton.h> #import <AppKit/NSWorkspace.h> #import <CoreVideo/CVPixelBuffer.h> @@ -26,17 +30,31 @@ - (id) initWithObject:(AppKit*)appkit { self = [super init]; + if (self) { m_appkit = appkit; - [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:static_cast<id>(self) + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(didDeactivateApplicationObserver:) name:NSWorkspaceDidDeactivateApplicationNotification object:nil]; - [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:static_cast<id>(self) + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(userSwitchHandler:) name:NSWorkspaceSessionDidResignActiveNotification object:nil]; + + [[NSDistributedNotificationCenter defaultCenter] addObserver:self + selector:@selector(interfaceThemeChanged:) + name:@"AppleInterfaceThemeChangedNotification" + object:nil]; + + // Unfortunately, there is no notification for a wallpaper change, which affects + // the status bar colour on macOS Big Sur, but we can at least subscribe to this. + [[NSDistributedNotificationCenter defaultCenter] addObserver:self + selector:@selector(interfaceThemeChanged:) + name:@"AppleColorPreferencesChangedNotification" + object:nil]; + } return self; } @@ -55,6 +73,18 @@ } // +// Light / dark theme toggled +// +- (void) interfaceThemeChanged:(NSNotification*) notification +{ + Q_UNUSED(notification); + if (m_appkit) { + emit m_appkit->interfaceThemeChanged(); + } +} + + +// // Get process id of frontmost application (-> keyboard input) // - (pid_t) activeProcessId @@ -108,6 +138,23 @@ && NSOrderedSame == [style caseInsensitiveCompare:@"dark"] ); } + +// +// Get global menu bar theme state +// +- (bool) isStatusBarDark +{ + if (@available(macOS 10.17, *)) { + // This is an ugly hack, but I couldn't find a way to access QTrayIcon's NSStatusItem. + NSStatusItem* dummy = [[NSStatusBar systemStatusBar] statusItemWithLength:0]; + NSString* appearance = [dummy.button.effectiveAppearance.name lowercaseString]; + [[NSStatusBar systemStatusBar] removeStatusItem:dummy]; + return [appearance containsString:@"dark"]; + } + + return [self isDarkMode]; +} + // // Notification for user switch // @@ -170,7 +217,8 @@ // ------------------------- C++ Trampolines ------------------------- // -AppKit::AppKit(QObject* parent) : QObject(parent) +AppKit::AppKit(QObject* parent) + : QObject(parent) { self = [[AppKitImpl alloc] initWithObject:this]; } @@ -178,6 +226,7 @@ AppKit::AppKit(QObject* parent) : QObject(parent) AppKit::~AppKit() { [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:static_cast<id>(self)]; + [[NSDistributedNotificationCenter defaultCenter] removeObserver:static_cast<id>(self)]; [static_cast<id>(self) dealloc]; } @@ -216,6 +265,12 @@ bool AppKit::isDarkMode() return [static_cast<id>(self) isDarkMode]; } +bool AppKit::isStatusBarDark() +{ + return [static_cast<id>(self) isStatusBarDark]; +} + + bool AppKit::enableAccessibility() { return [static_cast<id>(self) enableAccessibility]; diff --git a/src/gui/osutils/macutils/MacUtils.cpp b/src/gui/osutils/macutils/MacUtils.cpp index 73ee29627..9e85024d0 100644 --- a/src/gui/osutils/macutils/MacUtils.cpp +++ b/src/gui/osutils/macutils/MacUtils.cpp @@ -22,6 +22,7 @@ #include <QFile> #include <QSettings> #include <QStandardPaths> +#include <QTimer> #include <ApplicationServices/ApplicationServices.h> #include <CoreGraphics/CGEventSource.h> @@ -35,6 +36,14 @@ MacUtils::MacUtils(QObject* parent) , m_appkit(new AppKit()) { connect(m_appkit.data(), SIGNAL(lockDatabases()), SIGNAL(lockDatabases())); + connect(m_appkit.data(), SIGNAL(interfaceThemeChanged()), SIGNAL(interfaceThemeChanged())); + connect(m_appkit.data(), &AppKit::interfaceThemeChanged, this, [this]() { + // Emit with delay, since isStatusBarDark() still returns the old value + // if we call it too fast after a theme change. + QTimer::singleShot(100, [this]() { + emit statusbarThemeChanged(); + }); + }); } MacUtils::~MacUtils() @@ -95,6 +104,11 @@ bool MacUtils::isDarkMode() const return m_appkit->isDarkMode(); } +bool MacUtils::isStatusBarDark() const +{ + return m_appkit->isStatusBarDark(); +} + QString MacUtils::getLaunchAgentFilename() const { auto launchAgentDir = diff --git a/src/gui/osutils/macutils/MacUtils.h b/src/gui/osutils/macutils/MacUtils.h index 0a3e0f6a4..717be27db 100644 --- a/src/gui/osutils/macutils/MacUtils.h +++ b/src/gui/osutils/macutils/MacUtils.h @@ -23,6 +23,7 @@ #include "gui/osutils/OSUtilsBase.h" #include <Carbon/Carbon.h> +#include <QColor> #include <QPointer> #include <QScopedPointer> #include <qwindowdefs.h> @@ -35,6 +36,7 @@ public: static MacUtils* instance(); bool isDarkMode() const override; + bool isStatusBarDark() const override; bool isLaunchAtStartupEnabled() const override; void setLaunchAtStartup(bool enable) override; bool isCapslockEnabled() override; diff --git a/src/gui/osutils/nixutils/NixUtils.cpp b/src/gui/osutils/nixutils/NixUtils.cpp index 58a69dedc..cc9ff2c5b 100644 --- a/src/gui/osutils/nixutils/NixUtils.cpp +++ b/src/gui/osutils/nixutils/NixUtils.cpp @@ -79,6 +79,12 @@ bool NixUtils::isDarkMode() const return qApp->style()->standardPalette().color(QPalette::Window).toHsl().lightness() < 110; } +bool NixUtils::isStatusBarDark() const +{ + // TODO: implement + return isDarkMode(); +} + QString NixUtils::getAutostartDesktopFilename(bool createDirs) const { QDir autostartDir; diff --git a/src/gui/osutils/nixutils/NixUtils.h b/src/gui/osutils/nixutils/NixUtils.h index 4e0e5ca4a..bd659e210 100644 --- a/src/gui/osutils/nixutils/NixUtils.h +++ b/src/gui/osutils/nixutils/NixUtils.h @@ -30,6 +30,7 @@ public: static NixUtils* instance(); bool isDarkMode() const override; + bool isStatusBarDark() const override; bool isLaunchAtStartupEnabled() const override; void setLaunchAtStartup(bool enable) override; bool isCapslockEnabled() override; diff --git a/src/gui/osutils/winutils/WinUtils.cpp b/src/gui/osutils/winutils/WinUtils.cpp index 26c8b955b..302c3914c 100644 --- a/src/gui/osutils/winutils/WinUtils.cpp +++ b/src/gui/osutils/winutils/WinUtils.cpp @@ -87,6 +87,12 @@ bool WinUtils::isDarkMode() const return settings.value("AppsUseLightTheme", 1).toInt() == 0; } +bool WinUtils::isStatusBarDark() const +{ + // TODO: implement + return isDarkMode(); +} + bool WinUtils::isLaunchAtStartupEnabled() const { return QSettings(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run)", QSettings::NativeFormat) diff --git a/src/gui/osutils/winutils/WinUtils.h b/src/gui/osutils/winutils/WinUtils.h index d5e79f806..9e9f72684 100644 --- a/src/gui/osutils/winutils/WinUtils.h +++ b/src/gui/osutils/winutils/WinUtils.h @@ -35,6 +35,7 @@ public: static WinUtils* instance(); bool isDarkMode() const override; + bool isStatusBarDark() const override; bool isLaunchAtStartupEnabled() const override; void setLaunchAtStartup(bool enable) override; bool isCapslockEnabled() override; |