diff --git a/.gitattributes b/.gitattributes index 9df1af791..afc11a7bb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,3 +11,6 @@ AppImage-Recipe.sh export-ignore # github-linguist language hints *.h linguist-language=C++ *.cpp linguist-language=C++ + +# binary files +*.ai binary diff --git a/share/macosx/keepassxc.ai b/share/macosx/keepassxc.ai new file mode 100755 index 000000000..cea3b65c0 Binary files /dev/null and b/share/macosx/keepassxc.ai differ diff --git a/share/macosx/keepassxc.icns b/share/macosx/keepassxc.icns index 02baec7d4..c5125d782 100644 Binary files a/share/macosx/keepassxc.icns and b/share/macosx/keepassxc.icns differ diff --git a/share/macosx/keepassxc.iconset/icon_128x128.png b/share/macosx/keepassxc.iconset/icon_128x128.png new file mode 100755 index 000000000..7512796d4 Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_128x128.png differ diff --git a/share/macosx/keepassxc.iconset/icon_128x128@2x.png b/share/macosx/keepassxc.iconset/icon_128x128@2x.png new file mode 100755 index 000000000..3c00e0e8c Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_128x128@2x.png differ diff --git a/share/macosx/keepassxc.iconset/icon_16x16.png b/share/macosx/keepassxc.iconset/icon_16x16.png new file mode 100755 index 000000000..ca6823954 Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_16x16.png differ diff --git a/share/macosx/keepassxc.iconset/icon_16x16@2x.png b/share/macosx/keepassxc.iconset/icon_16x16@2x.png new file mode 100755 index 000000000..47af8eb1b Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_16x16@2x.png differ diff --git a/share/macosx/keepassxc.iconset/icon_256x256.png b/share/macosx/keepassxc.iconset/icon_256x256.png new file mode 100755 index 000000000..3c00e0e8c Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_256x256.png differ diff --git a/share/macosx/keepassxc.iconset/icon_256x256@2x.png b/share/macosx/keepassxc.iconset/icon_256x256@2x.png new file mode 100755 index 000000000..1c6e2a094 Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_256x256@2x.png differ diff --git a/share/macosx/keepassxc.iconset/icon_32x32.png b/share/macosx/keepassxc.iconset/icon_32x32.png new file mode 100755 index 000000000..47af8eb1b Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_32x32.png differ diff --git a/share/macosx/keepassxc.iconset/icon_32x32@2x.png b/share/macosx/keepassxc.iconset/icon_32x32@2x.png new file mode 100755 index 000000000..63c9847c4 Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_32x32@2x.png differ diff --git a/share/macosx/keepassxc.iconset/icon_512x512.png b/share/macosx/keepassxc.iconset/icon_512x512.png new file mode 100755 index 000000000..1c6e2a094 Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_512x512.png differ diff --git a/share/macosx/keepassxc.iconset/icon_512x512@2x.png b/share/macosx/keepassxc.iconset/icon_512x512@2x.png new file mode 100755 index 000000000..68e4a3dce Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_512x512@2x.png differ diff --git a/src/gui/Application.cpp b/src/gui/Application.cpp index 15460259b..1f9543f26 100644 --- a/src/gui/Application.cpp +++ b/src/gui/Application.cpp @@ -23,6 +23,7 @@ #include "core/Bootstrap.h" #include "core/Config.h" #include "core/Global.h" +#include "gui/Icons.h" #include "gui/MainWindow.h" #include "gui/MessageBox.h" #include "gui/osutils/OSUtils.h" @@ -127,6 +128,12 @@ Application::Application(int& argc, char** argv) qWarning() << QObject::tr("The lock file could not be created. Single-instance mode disabled.").toUtf8().constData(); } + + connect(osUtils, &OSUtilsBase::interfaceThemeChanged, this, [this]() { + if (config()->get(Config::GUI_ApplicationTheme).toString() != "classic") { + applyTheme(); + } + }); } Application::~Application() @@ -174,15 +181,15 @@ void Application::applyTheme() } #endif } - + QPixmapCache::clear(); if (appTheme == "light") { - setStyle(new LightStyle); - // Workaround Qt 5.15+ bug - setPalette(style()->standardPalette()); + auto* s = new LightStyle; + setPalette(s->standardPalette()); + setStyle(s); } else if (appTheme == "dark") { - setStyle(new DarkStyle); - // Workaround Qt 5.15+ bug - setPalette(style()->standardPalette()); + auto* s = new DarkStyle; + setPalette(s->standardPalette()); + setStyle(s); m_darkTheme = true; } else { // Classic mode, don't check for dark theme on Windows diff --git a/src/gui/ApplicationSettingsWidget.cpp b/src/gui/ApplicationSettingsWidget.cpp index 182dcd052..d105b76d7 100644 --- a/src/gui/ApplicationSettingsWidget.cpp +++ b/src/gui/ApplicationSettingsWidget.cpp @@ -251,8 +251,12 @@ void ApplicationSettingsWidget::loadSettings() } m_generalUi->trayIconAppearance->clear(); +#ifdef Q_OS_MACOS + m_generalUi->trayIconAppearance->addItem(tr("Monochrome"), "monochrome"); +#else m_generalUi->trayIconAppearance->addItem(tr("Monochrome (light)"), "monochrome-light"); m_generalUi->trayIconAppearance->addItem(tr("Monochrome (dark)"), "monochrome-dark"); +#endif m_generalUi->trayIconAppearance->addItem(tr("Colorful"), "colorful"); int trayIconIndex = m_generalUi->trayIconAppearance->findData(icons()->trayIconAppearance()); if (trayIconIndex > 0) { diff --git a/src/gui/Icons.cpp b/src/gui/Icons.cpp index fb208b266..2f117b4ff 100644 --- a/src/gui/Icons.cpp +++ b/src/gui/Icons.cpp @@ -19,6 +19,8 @@ #include "Icons.h" #include +#include +#include #include #include @@ -27,8 +29,24 @@ #include "gui/MainWindow.h" #include "gui/osutils/OSUtils.h" +class AdaptiveIconEngine : public QIconEngine +{ +public: + explicit AdaptiveIconEngine(QIcon baseIcon); + void paint(QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state) override; + QPixmap pixmap(const QSize& size, QIcon::Mode mode, QIcon::State state) override; + QIconEngine* clone() const override; + +private: + QIcon m_baseIcon; +}; + Icons* Icons::m_instance(nullptr); +Icons::Icons() +{ +} + QIcon Icons::applicationIcon() { return icon("keepassxc", false); @@ -47,45 +65,102 @@ QString Icons::trayIconAppearance() const return iconAppearance; } -QIcon Icons::trayIcon() +QIcon Icons::trayIcon(QString style) { - return trayIconUnlocked(); + if (style == "unlocked") { + style.clear(); + } + if (!style.isEmpty()) { + style = "-" + style; + } + + auto iconApperance = trayIconAppearance(); + if (!iconApperance.startsWith("monochrome")) { + return icon(QString("keepassxc%1").arg(style), false); + } + + QIcon i; +#ifdef Q_OS_MACOS + if (osUtils->isStatusBarDark()) { + i = icon(QString("keepassxc-monochrome-light%1").arg(style), false); + } else { + i = icon(QString("keepassxc-monochrome-dark%1").arg(style), false); + } +#else + i = icon(QString("keepassxc-%1%2").arg(iconApperance, style), false); +#endif +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + // Set as mask to allow the operating system to recolour the tray icon. This may look weird + // if we failed to detect the status bar background colour correctly, but it is certainly + // better than a barely visible icon and even if we did guess correctly, it allows for better + // integration should the system's preferred colours not be 100% black or white. + i.setIsMask(true); +#endif + return i; } QIcon Icons::trayIconLocked() { - auto iconApperance = trayIconAppearance(); - - if (iconApperance == "monochrome-light") { - return icon("keepassxc-monochrome-light-locked", false); - } - if (iconApperance == "monochrome-dark") { - return icon("keepassxc-monochrome-dark-locked", false); - } - return icon("keepassxc-locked", false); + return trayIcon("locked"); } QIcon Icons::trayIconUnlocked() { - auto iconApperance = trayIconAppearance(); + return trayIcon("unlocked"); +} - if (iconApperance == "monochrome-light") { - return icon("keepassxc-monochrome-light", false); +AdaptiveIconEngine::AdaptiveIconEngine(QIcon baseIcon) + : QIconEngine() + , m_baseIcon(std::move(baseIcon)) +{ +} + +void AdaptiveIconEngine::paint(QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + double dpr = !kpxcApp->testAttribute(Qt::AA_UseHighDpiPixmaps) ? 1.0 : painter->device()->devicePixelRatioF(); +#else + double dpr = !kpxcApp->testAttribute(Qt::AA_UseHighDpiPixmaps) ? 1.0 : painter->device()->devicePixelRatio(); +#endif + QSize pixmapSize = rect.size() * dpr; + + painter->save(); + painter->drawPixmap(rect, m_baseIcon.pixmap(pixmapSize, mode, state)); + + if (getMainWindow()) { + QPalette palette = getMainWindow()->palette(); + painter->setCompositionMode(QPainter::CompositionMode_SourceAtop); + + if (mode == QIcon::Active) { + painter->fillRect(rect, palette.color(QPalette::Active, QPalette::ButtonText)); + } else if (mode == QIcon::Selected) { + painter->fillRect(rect, palette.color(QPalette::Active, QPalette::HighlightedText)); + } else if (mode == QIcon::Disabled) { + painter->fillRect(rect, palette.color(QPalette::Disabled, QPalette::WindowText)); + } else { + painter->fillRect(rect, palette.color(QPalette::Normal, QPalette::WindowText)); + } } - if (iconApperance == "monochrome-dark") { - return icon("keepassxc-monochrome-dark", false); - } - return icon("keepassxc", false); + painter->restore(); +} + +QPixmap AdaptiveIconEngine::pixmap(const QSize& size, QIcon::Mode mode, QIcon::State state) +{ + QImage img(size, QImage::Format_ARGB32_Premultiplied); + img.fill(0); + QPainter painter(&img); + paint(&painter, QRect(0, 0, size.width(), size.height()), mode, state); + return QPixmap::fromImage(img, Qt::NoFormatConversion); +} + +QIconEngine* AdaptiveIconEngine::clone() const +{ + return new AdaptiveIconEngine(m_baseIcon); } QIcon Icons::icon(const QString& name, bool recolor, const QColor& overrideColor) { - QIcon icon = m_iconCache.value(name); - - if (!icon.isNull() && !overrideColor.isValid()) { - return icon; - } - +#ifdef Q_OS_LINUX // Resetting the application theme name before calling QIcon::fromTheme() is required for hacky // QPA platform themes such as qt5ct, which randomly mess with the configured icon theme. // If we do not reset the theme name here, it will become empty at some point, causing @@ -94,44 +169,25 @@ QIcon Icons::icon(const QString& name, bool recolor, const QColor& overrideColor // See issue #4963: https://github.com/keepassxreboot/keepassxc/issues/4963 // and qt5ct issue #80: https://sourceforge.net/p/qt5ct/tickets/80/ QIcon::setThemeName("application"); +#endif + + QString cacheName = + QString("%1:%2:%3").arg(recolor ? "1" : "0", overrideColor.isValid() ? overrideColor.name() : "#", name); + QIcon icon = m_iconCache.value(cacheName); + + if (!icon.isNull() && !overrideColor.isValid()) { + return icon; + } icon = QIcon::fromTheme(name); - if (getMainWindow() && recolor) { - const QRect rect(0, 0, 48, 48); - QImage img = icon.pixmap(rect.width(), rect.height()).toImage(); - img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); - icon = {}; - - QPainter painter(&img); - painter.setCompositionMode(QPainter::CompositionMode_SourceAtop); - - if (!overrideColor.isValid()) { - QPalette palette = getMainWindow()->palette(); - painter.fillRect(rect, palette.color(QPalette::Normal, QPalette::WindowText)); - icon.addPixmap(QPixmap::fromImage(img), QIcon::Normal); - - painter.fillRect(rect, palette.color(QPalette::Active, QPalette::ButtonText)); - icon.addPixmap(QPixmap::fromImage(img), QIcon::Active); - - painter.fillRect(rect, palette.color(QPalette::Active, QPalette::HighlightedText)); - icon.addPixmap(QPixmap::fromImage(img), QIcon::Selected); - - painter.fillRect(rect, palette.color(QPalette::Disabled, QPalette::WindowText)); - icon.addPixmap(QPixmap::fromImage(img), QIcon::Disabled); - } else { - painter.fillRect(rect, overrideColor); - icon.addPixmap(QPixmap::fromImage(img), QIcon::Normal); - } - + if (recolor) { + icon = QIcon(new AdaptiveIconEngine(icon)); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) icon.setIsMask(true); #endif } - if (!overrideColor.isValid()) { - m_iconCache.insert(name, icon); - } - + m_iconCache.insert(cacheName, icon); return icon; } @@ -161,10 +217,6 @@ QIcon Icons::onOffIcon(const QString& name, bool recolor) return icon; } -Icons::Icons() -{ -} - Icons* Icons::instance() { if (!m_instance) { diff --git a/src/gui/Icons.h b/src/gui/Icons.h index 532f520e4..b002a241b 100644 --- a/src/gui/Icons.h +++ b/src/gui/Icons.h @@ -28,7 +28,7 @@ class Icons { public: QIcon applicationIcon(); - QIcon trayIcon(); + QIcon trayIcon(QString style = "unlocked"); QIcon trayIconLocked(); QIcon trayIconUnlocked(); QString trayIconAppearance() const; diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 728322b63..f640d8c91 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -40,6 +40,7 @@ #include "gui/Icons.h" #include "gui/MessageBox.h" #include "gui/SearchWidget.h" +#include "gui/osutils/OSUtils.h" #include "keys/CompositeKey.h" #include "keys/FileKey.h" #include "keys/PasswordKey.h" @@ -503,6 +504,8 @@ MainWindow::MainWindow() connect(m_ui->actionOnlineHelp, SIGNAL(triggered()), SLOT(openOnlineHelp())); connect(m_ui->actionKeyboardShortcuts, SIGNAL(triggered()), SLOT(openKeyboardShortcuts())); + connect(osUtils, &OSUtilsBase::statusbarThemeChanged, this, &MainWindow::updateTrayIcon); + #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // Install event filter for empty-area drag auto* eventFilter = new MainWindowEventFilter(this); @@ -599,10 +602,10 @@ MainWindow::MainWindow() } #endif - QObject::connect(qApp, SIGNAL(anotherInstanceStarted()), this, SLOT(bringToFront())); - QObject::connect(qApp, SIGNAL(applicationActivated()), this, SLOT(bringToFront())); - QObject::connect(qApp, SIGNAL(openFile(QString)), this, SLOT(openDatabase(QString))); - QObject::connect(qApp, SIGNAL(quitSignalReceived()), this, SLOT(appExit()), Qt::DirectConnection); + connect(qApp, SIGNAL(anotherInstanceStarted()), this, SLOT(bringToFront())); + connect(qApp, SIGNAL(applicationActivated()), this, SLOT(bringToFront())); + connect(qApp, SIGNAL(openFile(QString)), this, SLOT(openDatabase(QString))); + connect(qApp, SIGNAL(quitSignalReceived()), this, SLOT(appExit()), Qt::DirectConnection); restoreConfigState(); } @@ -1757,8 +1760,10 @@ void MainWindow::initViewMenu() connect(themeActions, &QActionGroup::triggered, this, [this, theme](QAction* action) { config()->set(Config::GUI_ApplicationTheme, action->data()); - if (action->data() != theme) { + if ((action->data() == "classic" || theme == "classic") && action->data() != theme) { restartApp(tr("You must restart the application to apply this setting. Would you like to restart now?")); + } else { + kpxcApp->applyTheme(); } }); 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 @@ -35,6 +35,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). */ @@ -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 +#include #include 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 +#import +#import #import #import @@ -26,17 +30,31 @@ - (id) initWithObject:(AppKit*)appkit { self = [super init]; + if (self) { m_appkit = appkit; - [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:static_cast(self) + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(didDeactivateApplicationObserver:) name:NSWorkspaceDidDeactivateApplicationNotification object:nil]; - [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:static_cast(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; } @@ -54,6 +72,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) // @@ -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(self)]; + [[NSDistributedNotificationCenter defaultCenter] removeObserver:static_cast(self)]; [static_cast(self) dealloc]; } @@ -216,6 +265,12 @@ bool AppKit::isDarkMode() return [static_cast(self) isDarkMode]; } +bool AppKit::isStatusBarDark() +{ + return [static_cast(self) isStatusBarDark]; +} + + bool AppKit::enableAccessibility() { return [static_cast(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 #include #include +#include #include #include @@ -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 +#include #include #include #include @@ -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; diff --git a/src/gui/styles/base/BaseStyle.cpp b/src/gui/styles/base/BaseStyle.cpp index 6cde175cd..54e481d7c 100644 --- a/src/gui/styles/base/BaseStyle.cpp +++ b/src/gui/styles/base/BaseStyle.cpp @@ -52,6 +52,10 @@ #include #include +#ifdef Q_OS_MACOS +#include +#endif + #include #include "gui/Icons.h" @@ -288,10 +292,16 @@ namespace Phantom #ifdef Q_OS_MACOS QColor tabBarBase(const QPalette& pal) { - return hack_isLightPalette(pal) ? QRgb(0xD1D1D1) : QRgb(0x252525); + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSBigSur) { + return hack_isLightPalette(pal) ? QRgb(0xD4D4D4) : QRgb(0x2A2A2A); + } + return hack_isLightPalette(pal) ? QRgb(0xDD1D1D1) : QRgb(0x252525); } QColor tabBarBaseInactive(const QPalette& pal) { + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSBigSur) { + return hack_isLightPalette(pal) ? QRgb(0xF5F5F5) : QRgb(0x2D2D2D); + } return hack_isLightPalette(pal) ? QRgb(0xF4F4F4) : QRgb(0x282828); } #endif @@ -4571,27 +4581,6 @@ QStyle::SubControl BaseStyle::hitTestComplexControl(ComplexControl cc, return QCommonStyle::hitTestComplexControl(cc, opt, pt, w); } -QPixmap BaseStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap& pixmap, const QStyleOption* opt) const -{ - // Default icon highlight is way too subtle - if (iconMode == QIcon::Selected) { - QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); - QPainter painter(&img); - - painter.setCompositionMode(QPainter::CompositionMode_SourceAtop); - - QColor color = - Phantom::DeriveColors::adjustLightness(opt->palette.color(QPalette::Normal, QPalette::Highlight), .25); - color.setAlphaF(0.25); - painter.fillRect(0, 0, img.width(), img.height(), color); - - painter.end(); - - return QPixmap::fromImage(img); - } - return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt); -} - int BaseStyle::styleHint(StyleHint hint, const QStyleOption* option, const QWidget* widget, diff --git a/src/gui/styles/base/BaseStyle.h b/src/gui/styles/base/BaseStyle.h index d3c20915c..e9bdcbdc8 100644 --- a/src/gui/styles/base/BaseStyle.h +++ b/src/gui/styles/base/BaseStyle.h @@ -70,7 +70,6 @@ public: const QStyleOptionComplex* opt, SubControl sc, const QWidget* widget) const override; - QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap& pixmap, const QStyleOption* opt) const override; int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, diff --git a/src/gui/styles/dark/DarkStyle.cpp b/src/gui/styles/dark/DarkStyle.cpp index 9fa03e332..b42d319af 100644 --- a/src/gui/styles/dark/DarkStyle.cpp +++ b/src/gui/styles/dark/DarkStyle.cpp @@ -114,9 +114,9 @@ void DarkStyle::polish(QWidget* widget) auto palette = widget->palette(); #if defined(Q_OS_MACOS) if (!osUtils->isDarkMode()) { - palette.setColor(QPalette::Active, QPalette::Window, QRgb(0x252525)); - palette.setColor(QPalette::Inactive, QPalette::Window, QRgb(0x282828)); - palette.setColor(QPalette::Disabled, QPalette::Window, QRgb(0x252525)); + palette.setColor(QPalette::Active, QPalette::Window, QRgb(0x2A2A2A)); + palette.setColor(QPalette::Inactive, QPalette::Window, QRgb(0x2D2D2D)); + palette.setColor(QPalette::Disabled, QPalette::Window, QRgb(0x2D2D2D)); } #elif defined(Q_OS_WIN) palette.setColor(QPalette::All, QPalette::Window, QRgb(0x2F2F30)); diff --git a/src/gui/styles/light/LightStyle.cpp b/src/gui/styles/light/LightStyle.cpp index f1f0cb997..483e1323b 100644 --- a/src/gui/styles/light/LightStyle.cpp +++ b/src/gui/styles/light/LightStyle.cpp @@ -115,9 +115,9 @@ void LightStyle::polish(QWidget* widget) auto palette = widget->palette(); #if defined(Q_OS_MACOS) if (osUtils->isDarkMode()) { - palette.setColor(QPalette::Active, QPalette::Window, QRgb(0xD1D1D1)); - palette.setColor(QPalette::Inactive, QPalette::Window, QRgb(0xF4F4F4)); - palette.setColor(QPalette::Disabled, QPalette::Window, QRgb(0xD1D1D1)); + palette.setColor(QPalette::Active, QPalette::Window, QRgb(0xD4D4D4)); + palette.setColor(QPalette::Inactive, QPalette::Window, QRgb(0xF5F5F5)); + palette.setColor(QPalette::Disabled, QPalette::Window, QRgb(0xF5F5F5)); } #elif defined(Q_OS_WIN) palette.setColor(QPalette::All, QPalette::Window, QRgb(0xFFFFFF));