diff options
author | Janek Bevendorff <janek@jbev.net> | 2020-01-28 23:42:57 +0300 |
---|---|---|
committer | Janek Bevendorff <janek@jbev.net> | 2020-03-05 11:24:11 +0300 |
commit | 6d2ca748787c71eab3adaf2071d5738ba7c28a52 (patch) | |
tree | 031a16370418f8abf0c93950b1381dd75ab3622b /src/gui/osutils | |
parent | b9daed20558103e3c8e799f3e0575522bf823df6 (diff) |
Add OSUtils for platform-specific functionality.
Moves MacUtils into a separate sub folder and adds
WinUtils, NixUtils, and OSUtils for platform-native
code on Windows, Unix-like, and generic/all systems.
Diffstat (limited to 'src/gui/osutils')
-rw-r--r-- | src/gui/osutils/OSUtils.h | 41 | ||||
-rw-r--r-- | src/gui/osutils/OSUtilsBase.cpp | 27 | ||||
-rw-r--r-- | src/gui/osutils/OSUtilsBase.h | 40 | ||||
-rw-r--r-- | src/gui/osutils/macutils/AppKit.h | 50 | ||||
-rw-r--r-- | src/gui/osutils/macutils/AppKitImpl.h | 42 | ||||
-rw-r--r-- | src/gui/osutils/macutils/AppKitImpl.mm | 217 | ||||
-rw-r--r-- | src/gui/osutils/macutils/MacUtils.cpp | 87 | ||||
-rw-r--r-- | src/gui/osutils/macutils/MacUtils.h | 62 | ||||
-rw-r--r-- | src/gui/osutils/nixutils/NixUtils.cpp | 50 | ||||
-rw-r--r-- | src/gui/osutils/nixutils/NixUtils.h | 48 | ||||
-rw-r--r-- | src/gui/osutils/winutils/WinUtils.cpp | 85 | ||||
-rw-r--r-- | src/gui/osutils/winutils/WinUtils.h | 59 |
12 files changed, 808 insertions, 0 deletions
diff --git a/src/gui/osutils/OSUtils.h b/src/gui/osutils/OSUtils.h new file mode 100644 index 000000000..dd1bd8cd1 --- /dev/null +++ b/src/gui/osutils/OSUtils.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KEEPASSXC_OSUTILS_H +#define KEEPASSXC_OSUTILS_H + +#include "OSUtilsBase.h" +#include <QtCore> + +#if defined(Q_OS_WIN) + +#include "winutils/WinUtils.h" +#define osUtils static_cast<OSUtilsBase*>(winUtils()) + +#elif defined(Q_OS_MACOS) + +#include "macutils/MacUtils.h" +#define osUtils static_cast<OSUtilsBase*>(macUtils()) + +#elif defined(Q_OS_UNIX) + +#include "nixutils/NixUtils.h" +#define osUtils static_cast<OSUtilsBase*>(nixUtils()) + +#endif + +#endif // KEEPASSXC_OSUTILS_H diff --git a/src/gui/osutils/OSUtilsBase.cpp b/src/gui/osutils/OSUtilsBase.cpp new file mode 100644 index 000000000..143cb72c1 --- /dev/null +++ b/src/gui/osutils/OSUtilsBase.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "OSUtilsBase.h" + +OSUtilsBase::OSUtilsBase(QObject* parent) + : QObject(parent) +{ +} + +OSUtilsBase::~OSUtilsBase() +{ +} diff --git a/src/gui/osutils/OSUtilsBase.h b/src/gui/osutils/OSUtilsBase.h new file mode 100644 index 000000000..9467fca09 --- /dev/null +++ b/src/gui/osutils/OSUtilsBase.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KEEPASSXC_OSUTILSBASE_H +#define KEEPASSXC_OSUTILSBASE_H + +#include <QObject> +#include <QPointer> + +/** + * Abstract base class for generic OS-specific functionality + * which can be reasonably expected to be available on all platforms. + */ +class OSUtilsBase : public QObject +{ + Q_OBJECT + +public: + virtual bool isDarkMode() = 0; + +protected: + explicit OSUtilsBase(QObject* parent = nullptr); + virtual ~OSUtilsBase(); +}; + +#endif // KEEPASSXC_OSUTILSBASE_H diff --git a/src/gui/osutils/macutils/AppKit.h b/src/gui/osutils/macutils/AppKit.h new file mode 100644 index 000000000..2bff8f5b3 --- /dev/null +++ b/src/gui/osutils/macutils/AppKit.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Lennart Glauer <mail@lennart-glauer.de> + * Copyright (C) 2017 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KEEPASSX_APPKIT_H +#define KEEPASSX_APPKIT_H + +#include <QObject> +#include <unistd.h> + +class AppKit : public QObject +{ + Q_OBJECT + +public: + AppKit(QObject* parent = nullptr); + ~AppKit(); + + pid_t lastActiveProcessId(); + pid_t activeProcessId(); + pid_t ownProcessId(); + bool activateProcess(pid_t pid); + bool hideProcess(pid_t pid); + bool isHidden(pid_t pid); + bool isDarkMode(); + bool enableAccessibility(); + bool enableScreenRecording(); + +signals: + void lockDatabases(); + +private: + void* self; +}; + +#endif // KEEPASSX_APPKIT_H diff --git a/src/gui/osutils/macutils/AppKitImpl.h b/src/gui/osutils/macutils/AppKitImpl.h new file mode 100644 index 000000000..326879766 --- /dev/null +++ b/src/gui/osutils/macutils/AppKitImpl.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Lennart Glauer <mail@lennart-glauer.de> + * Copyright (C) 2017 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#import "AppKit.h" + +#import <Foundation/Foundation.h> +#import <AppKit/NSRunningApplication.h> + +@interface AppKitImpl : NSObject +{ + AppKit* m_appkit; +} +- (id) initWithObject:(AppKit*)appkit; + +@property (strong) NSRunningApplication *lastActiveApplication; + +- (pid_t) activeProcessId; +- (pid_t) ownProcessId; +- (bool) activateProcess:(pid_t) pid; +- (bool) hideProcess:(pid_t) pid; +- (bool) isHidden:(pid_t) pid; +- (bool) isDarkMode; +- (void) userSwitchHandler:(NSNotification*) notification; +- (bool) enableAccessibility; +- (bool) enableScreenRecording; + +@end diff --git a/src/gui/osutils/macutils/AppKitImpl.mm b/src/gui/osutils/macutils/AppKitImpl.mm new file mode 100644 index 000000000..4a93f963a --- /dev/null +++ b/src/gui/osutils/macutils/AppKitImpl.mm @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2016 Lennart Glauer <mail@lennart-glauer.de> + * Copyright (C) 2017 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#import "AppKitImpl.h" + +#import <AppKit/NSWorkspace.h> +#import <CoreVideo/CVPixelBuffer.h> + +@implementation AppKitImpl + +- (id) initWithObject:(AppKit*)appkit +{ + self = [super init]; + if (self) { + m_appkit = appkit; + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:static_cast<id>(self) + selector:@selector(didDeactivateApplicationObserver:) + name:NSWorkspaceDidDeactivateApplicationNotification + object:nil]; + + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:static_cast<id>(self) + selector:@selector(userSwitchHandler:) + name:NSWorkspaceSessionDidResignActiveNotification + object:nil]; + } + return self; +} + +// +// Update last active application property +// +- (void) didDeactivateApplicationObserver:(NSNotification*) notification +{ + NSDictionary* userInfo = notification.userInfo; + NSRunningApplication* app = userInfo[NSWorkspaceApplicationKey]; + + if (app.processIdentifier != [self ownProcessId]) { + self.lastActiveApplication = app; + } +} + +// +// Get process id of frontmost application (-> keyboard input) +// +- (pid_t) activeProcessId +{ + return [NSWorkspace sharedWorkspace].frontmostApplication.processIdentifier; +} + +// +// Get process id of own process +// +- (pid_t) ownProcessId +{ + return [NSProcessInfo processInfo].processIdentifier; +} + +// +// Activate application by process id +// +- (bool) activateProcess:(pid_t) pid +{ + NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid]; + return [app activateWithOptions:NSApplicationActivateIgnoringOtherApps]; +} + +// +// Hide application by process id +// +- (bool) hideProcess:(pid_t) pid +{ + NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid]; + return [app hide]; +} + +// +// Get application hidden state by process id +// +- (bool) isHidden:(pid_t) pid +{ + NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid]; + return [app isHidden]; +} + +// +// Get state of macOS Dark Mode color scheme +// +- (bool) isDarkMode +{ + NSDictionary* dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain]; + id style = [dict objectForKey:@"AppleInterfaceStyle"]; + return ( style && [style isKindOfClass:[NSString class]] + && NSOrderedSame == [style caseInsensitiveCompare:@"dark"] ); +} + +// +// Notification for user switch +// +- (void) userSwitchHandler:(NSNotification*) notification +{ + if ([[notification name] isEqualToString:NSWorkspaceSessionDidResignActiveNotification] && m_appkit) + { + emit m_appkit->lockDatabases(); + } +} + +// +// Check if accessibility is enabled, may show an popup asking for permissions +// +- (bool) enableAccessibility +{ + // Request accessibility permissions for Auto-Type type on behalf of the user + NSDictionary* opts = @{static_cast<id>(kAXTrustedCheckOptionPrompt): @YES}; + return AXIsProcessTrustedWithOptions(static_cast<CFDictionaryRef>(opts)); +} + +// +// Check if screen recording is enabled, may show an popup asking for permissions +// +- (bool) enableScreenRecording +{ + if (@available(macOS 10.15, *)) { + // Request screen recording permission on macOS 10.15+ + // This is necessary to get the current window title + CGDisplayStreamRef stream = CGDisplayStreamCreate(CGMainDisplayID(), 1, 1, kCVPixelFormatType_32BGRA, nil, + ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, + IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) { + Q_UNUSED(status); + Q_UNUSED(displayTime); + Q_UNUSED(frameSurface); + Q_UNUSED(updateRef); + }); + if (stream) { + CFRelease(stream); + } else { + return NO; + } + } + return YES; +} + +@end + +// +// ------------------------- C++ Trampolines ------------------------- +// + +AppKit::AppKit(QObject* parent) : QObject(parent) +{ + self = [[AppKitImpl alloc] initWithObject:this]; +} + +AppKit::~AppKit() +{ + [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:static_cast<id>(self)]; + [static_cast<id>(self) dealloc]; +} + +pid_t AppKit::lastActiveProcessId() +{ + return [static_cast<id>(self) lastActiveApplication].processIdentifier; +} + +pid_t AppKit::activeProcessId() +{ + return [static_cast<id>(self) activeProcessId]; +} + +pid_t AppKit::ownProcessId() +{ + return [static_cast<id>(self) ownProcessId]; +} + +bool AppKit::activateProcess(pid_t pid) +{ + return [static_cast<id>(self) activateProcess:pid]; +} + +bool AppKit::hideProcess(pid_t pid) +{ + return [static_cast<id>(self) hideProcess:pid]; +} + +bool AppKit::isHidden(pid_t pid) +{ + return [static_cast<id>(self) isHidden:pid]; +} + +bool AppKit::isDarkMode() +{ + return [static_cast<id>(self) isDarkMode]; +} + +bool AppKit::enableAccessibility() +{ + return [static_cast<id>(self) enableAccessibility]; +} + +bool AppKit::enableScreenRecording() +{ + return [static_cast<id>(self) enableScreenRecording]; +} diff --git a/src/gui/osutils/macutils/MacUtils.cpp b/src/gui/osutils/macutils/MacUtils.cpp new file mode 100644 index 000000000..498325868 --- /dev/null +++ b/src/gui/osutils/macutils/MacUtils.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2012 Felix Geyer <debfx@fobos.de> + * Copyright (C) 2018 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "MacUtils.h" +#include <QApplication> + +QPointer<MacUtils> MacUtils::m_instance = nullptr; + +MacUtils::MacUtils(QObject* parent) + : OSUtils(parent) + , m_appkit(new AppKit()) +{ + connect(m_appkit.data(), SIGNAL(lockDatabases()), SIGNAL(lockDatabases())); +} + +MacUtils::~MacUtils() +{ +} + +MacUtils* MacUtils::instance() +{ + if (!m_instance) { + m_instance = new MacUtils(qApp); + } + + return m_instance; +} + +WId MacUtils::activeWindow() +{ + return m_appkit->activeProcessId(); +} + +bool MacUtils::raiseWindow(WId pid) +{ + return m_appkit->activateProcess(pid); +} + +bool MacUtils::raiseOwnWindow() +{ + return m_appkit->activateProcess(m_appkit->ownProcessId()); +} + +bool MacUtils::raiseLastActiveWindow() +{ + return m_appkit->activateProcess(m_appkit->lastActiveProcessId()); +} + +bool MacUtils::hideOwnWindow() +{ + return m_appkit->hideProcess(m_appkit->ownProcessId()); +} + +bool MacUtils::isHidden() +{ + return m_appkit->isHidden(m_appkit->ownProcessId()); +} + +bool MacUtils::isDarkMode() +{ + return m_appkit->isDarkMode(); +} + +bool MacUtils::enableAccessibility() +{ + return m_appkit->enableAccessibility(); +} + +bool MacUtils::enableScreenRecording() +{ + return m_appkit->enableScreenRecording(); +} diff --git a/src/gui/osutils/macutils/MacUtils.h b/src/gui/osutils/macutils/MacUtils.h new file mode 100644 index 000000000..427c7230a --- /dev/null +++ b/src/gui/osutils/macutils/MacUtils.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012 Felix Geyer <debfx@fobos.de> + * Copyright (C) 2017 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KEEPASSXC_MACUTILS_H +#define KEEPASSXC_MACUTILS_H + +#include "gui/osutils/OSUtilsBase.h" +#include "AppKit.h" +#include <QPointer> + +class MacUtils : public OSUtils +{ + Q_OBJECT + +public: + static MacUtils* instance(); + + WId activeWindow(); + bool raiseWindow(WId pid); + bool raiseLastActiveWindow(); + bool raiseOwnWindow(); + bool hideOwnWindow(); + bool isHidden(); + bool isDarkMode() override; + bool enableAccessibility(); + bool enableScreenRecording(); + +signals: + void lockDatabases(); + +protected: + explicit MacUtils(QObject* parent = nullptr); + ~MacUtils() override; + +private: + QScopedPointer<AppKit> m_appkit; + static QPointer<MacUtils> m_instance; + + Q_DISABLE_COPY(MacUtils) +}; + +inline MacUtils* macUtils() +{ + return MacUtils::instance(); +} + +#endif // KEEPASSXC_MACUTILS_H diff --git a/src/gui/osutils/nixutils/NixUtils.cpp b/src/gui/osutils/nixutils/NixUtils.cpp new file mode 100644 index 000000000..229d6b519 --- /dev/null +++ b/src/gui/osutils/nixutils/NixUtils.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "NixUtils.h" +#include <QApplication> +#include <QColor> +#include <QPalette> +#include <QStyle> + +QPointer<NixUtils> NixUtils::m_instance = nullptr; + +NixUtils* NixUtils::instance() +{ + if (!m_instance) { + m_instance = new NixUtils(qApp); + } + + return m_instance; +} + +NixUtils::NixUtils(QObject* parent) + : OSUtilsBase(parent) +{ +} + +NixUtils::~NixUtils() +{ +} + +bool NixUtils::isDarkMode() +{ + if (!qApp || !qApp->style()) { + return false; + } + return qApp->style()->standardPalette().color(QPalette::Window).toHsl().lightness() < 110; +} diff --git a/src/gui/osutils/nixutils/NixUtils.h b/src/gui/osutils/nixutils/NixUtils.h new file mode 100644 index 000000000..bf236cdc3 --- /dev/null +++ b/src/gui/osutils/nixutils/NixUtils.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KEEPASSXC_NIXUTILS_H +#define KEEPASSXC_NIXUTILS_H + +#include "gui/osutils/OSUtilsBase.h" +#include <QPointer> + +class NixUtils : public OSUtilsBase +{ + Q_OBJECT + +public: + static NixUtils* instance(); + + bool isDarkMode() override; + +private: + explicit NixUtils(QObject* parent = nullptr); + ~NixUtils() override; + +private: + static QPointer<NixUtils> m_instance; + + Q_DISABLE_COPY(NixUtils) +}; + +inline NixUtils* nixUtils() +{ + return NixUtils::instance(); +} + +#endif // KEEPASSXC_NIXUTILS_H diff --git a/src/gui/osutils/winutils/WinUtils.cpp b/src/gui/osutils/winutils/WinUtils.cpp new file mode 100644 index 000000000..f92192f18 --- /dev/null +++ b/src/gui/osutils/winutils/WinUtils.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "WinUtils.h" +#include <QAbstractNativeEventFilter> +#include <QApplication> +#include <QSettings> + +#include <windows.h> + +QPointer<WinUtils> WinUtils::m_instance = nullptr; +QScopedPointer<WinUtils::DWMEventFilter> WinUtils::m_eventFilter; + +WinUtils* WinUtils::instance() +{ + if (!m_instance) { + m_instance = new WinUtils(qApp); + } + + return m_instance; +} + +WinUtils::WinUtils(QObject* parent) + : OSUtilsBase(parent) +{ +} + +WinUtils::~WinUtils() +{ +} + +/** + * Register event filters to handle native platform events such as theme changes. + */ +void WinUtils::registerEventFilters() +{ + if (!m_eventFilter) { + m_eventFilter.reset(new DWMEventFilter); + qApp->installNativeEventFilter(m_eventFilter.data()); + } +} + +bool WinUtils::DWMEventFilter::nativeEventFilter(const QByteArray& eventType, void* message, long*) +{ + if (eventType != "windows_generic_MSG") { + return false; + } + + auto* msg = static_cast<MSG*>(message); + if (!msg->hwnd) { + return false; + } + switch (msg->message) { + case WM_CREATE: + case WM_INITDIALOG: { + if (winUtils()->isDarkMode()) { + // TODO: indicate dark mode support for black title bar + } + break; + } + } + + return false; +} + +bool WinUtils::isDarkMode() +{ + QSettings settings(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)", + QSettings::NativeFormat); + return settings.value("AppsUseLightTheme", 1).toInt() == 0; +} diff --git a/src/gui/osutils/winutils/WinUtils.h b/src/gui/osutils/winutils/WinUtils.h new file mode 100644 index 000000000..1a95716e1 --- /dev/null +++ b/src/gui/osutils/winutils/WinUtils.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KEEPASSXC_WINUTILS_H +#define KEEPASSXC_WINUTILS_H + +#include "gui/osutils/OSUtilsBase.h" + +#include <QAbstractNativeEventFilter> +#include <QPointer> +#include <QScopedPointer> + +class WinUtils : public OSUtilsBase +{ + Q_OBJECT + +public: + static WinUtils* instance(); + static void registerEventFilters(); + + bool isDarkMode() override; + +protected: + explicit WinUtils(QObject* parent = nullptr); + ~WinUtils() override; + +private: + class DWMEventFilter : public QAbstractNativeEventFilter + { + public: + bool nativeEventFilter(const QByteArray& eventType, void* message, long*) override; + }; + + static QPointer<WinUtils> m_instance; + static QScopedPointer<DWMEventFilter> m_eventFilter; + + Q_DISABLE_COPY(WinUtils) +}; + +inline WinUtils* winUtils() +{ + return WinUtils::instance(); +} + +#endif // KEEPASSXC_WINUTILS_H |