From a5d13e19dd7f6037e10b649c49805922ae5e0fa6 Mon Sep 17 00:00:00 2001 From: SineStriker <trueful@163.com> Date: 周五, 22 12月 2023 17:04:29 +0800 Subject: [PATCH] Prepare to remove style support again --- src/core/contexts/cocoawindowcontext.mm | 13 + qmsetup | 2 src/core/contexts/abstractwindowcontext_p.h | 11 + src/core/contexts/cocoawindowcontext_p.h | 2 CMakeLists.txt | 2 examples/mainwindow/light-style.qss | 8 src/core/contexts/win32windowcontext.cpp | 156 +++++++++++++++ src/core/style/styleagent.h | 44 ++++ src/core/style/styleagent_win.cpp | 84 ++++++++ src/core/CMakeLists.txt | 16 + examples/mainwindow/mainwindow.cpp | 18 + src/core/style/styleagent.cpp | 46 ++++ src/core/style/styleagent_mac.mm | 13 + src/core/contexts/abstractwindowcontext.cpp | 45 ++++ examples/mainwindow/CMakeLists.txt | 2 src/core/windowagentbase.h | 6 examples/mainwindow/mainwindow.h | 1 src/core/style/styleagent_p.h | 39 +++ src/core/windowagentbase.cpp | 10 + /dev/null | 11 - src/core/contexts/win32windowcontext_p.h | 2 src/CMakeLists.txt | 4 examples/mainwindow/dark-style.qss | 8 src/core/style/styleagent_linux.cpp | 13 + share/install.cmake | 4 25 files changed, 522 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 283a654..9cd6266 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,12 +8,12 @@ option(QWINDOWKIT_BUILD_STATIC "Build static libraries" OFF) option(QWINDOWKIT_BUILD_WIDGETS "Build widgets module" ON) option(QWINDOWKIT_BUILD_QUICK "Build quick module" ON) -option(QWINDOWKIT_BUILD_STYLESUPPORT "Build style support module" OFF) option(QWINDOWKIT_BUILD_EXAMPLES "Build examples" OFF) option(QWINDOWKIT_BUILD_DOCUMENTATIONS "Build documentations" OFF) option(QWINDOWKIT_INSTALL "Install library" ON) option(QWINDOWKIT_FORCE_QT_WINDOW_CONTEXT "Enable Qt Window Context anyway" OFF) +option(QWINDOWKIT_ENABLE_STYLE_AGENT "Enable building style agent" ON) # ---------------------------------- # CMake Settings diff --git a/examples/mainwindow/CMakeLists.txt b/examples/mainwindow/CMakeLists.txt index ea3c66b..c29f2b8 100644 --- a/examples/mainwindow/CMakeLists.txt +++ b/examples/mainwindow/CMakeLists.txt @@ -5,7 +5,7 @@ qwk_add_example(${PROJECT_NAME} SOURCES ${_src} mainwindow.qrc ../shared/resources/shared.qrc QT_LINKS Core Gui Widgets - LINKS QWKWidgets QWKStyleSupport WidgetFrame + LINKS QWKWidgets WidgetFrame ) set_target_properties(${PROJECT_NAME} PROPERTIES diff --git a/examples/mainwindow/dark-style.qss b/examples/mainwindow/dark-style.qss index ef77219..e3820a0 100644 --- a/examples/mainwindow/dark-style.qss +++ b/examples/mainwindow/dark-style.qss @@ -142,12 +142,12 @@ /* Window */ -MainWindow[custom-style=true] { - background-color: transparent; +MainWindow { + background-color: #1E1E1E; } -MainWindow[custom-style=false] { - background-color: #1E1E1E; +MainWindow[custom-style=true] { + background-color: transparent; } QWidget#clock-widget { diff --git a/examples/mainwindow/light-style.qss b/examples/mainwindow/light-style.qss index 6c15e62..c314c7f 100644 --- a/examples/mainwindow/light-style.qss +++ b/examples/mainwindow/light-style.qss @@ -140,12 +140,12 @@ /* Window */ -MainWindow[custom-style=true] { - background-color: transparent; +MainWindow { + background-color: #F3F3F3; } -MainWindow[custom-style=false] { - background-color: #F3F3F3; +MainWindow[custom-style=true] { + background-color: transparent; } QWidget#clock-widget { diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp index 508df7b..a394a19 100644 --- a/examples/mainwindow/mainwindow.cpp +++ b/examples/mainwindow/mainwindow.cpp @@ -10,8 +10,8 @@ #include <QtWidgets/QPushButton> #include <QtWidgets/QActionGroup> +#include <QWKCore/styleagent.h> #include <QWKWidgets/widgetwindowagent.h> -#include <QWKStyleSupport/styleagent.h> #include <widgetframe/windowbar.h> #include <widgetframe/windowbutton.h> @@ -33,8 +33,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { installWindowAgent(); - - styleAgent = new QWK::StyleAgent(this); + installStyleAgent(); auto clockWidget = new ClockWidget(); clockWidget->setObjectName(QStringLiteral("clock-widget")); @@ -139,7 +138,7 @@ #ifdef Q_OS_WIN auto dwmBlurAction = new QAction(tr("Enable DWM blur"), menuBar); dwmBlurAction->setCheckable(true); - connect(dwmBlurAction, &QAction::triggered, this, [this](bool checked){ + connect(dwmBlurAction, &QAction::triggered, this, [this](bool checked) { QWindow *w = windowHandle(); styleAgent->setWindowAttribute(w, QStringLiteral("dwm-blur"), checked); setProperty("custom-style", checked); @@ -148,7 +147,7 @@ auto acrylicAction = new QAction(tr("Enable acrylic material"), menuBar); acrylicAction->setCheckable(true); - connect(acrylicAction, &QAction::triggered, this, [this](bool checked){ + connect(acrylicAction, &QAction::triggered, this, [this](bool checked) { QWindow *w = windowHandle(); styleAgent->setWindowAttribute(w, QStringLiteral("acrylic-material"), QColor()); setProperty("custom-style", checked); @@ -157,7 +156,7 @@ auto micaAction = new QAction(tr("Enable mica"), menuBar); micaAction->setCheckable(true); - connect(micaAction, &QAction::triggered, this, [this](bool checked){ + connect(micaAction, &QAction::triggered, this, [this](bool checked) { QWindow *w = windowHandle(); styleAgent->setWindowAttribute(w, QStringLiteral("mica"), checked); setProperty("custom-style", checked); @@ -166,7 +165,7 @@ auto micaAltAction = new QAction(tr("Enable mica alt"), menuBar); micaAltAction->setCheckable(true); - connect(micaAltAction, &QAction::triggered, this, [this](bool checked){ + connect(micaAltAction, &QAction::triggered, this, [this](bool checked) { QWindow *w = windowHandle(); styleAgent->setWindowAttribute(w, QStringLiteral("mica-alt"), checked); setProperty("custom-style", checked); @@ -283,10 +282,15 @@ #endif } +void MainWindow::installStyleAgent() { + styleAgent = new QWK::StyleAgent(this); +} + void MainWindow::loadStyleSheet(Theme theme) { if (!styleSheet().isEmpty() && theme == currentTheme) return; currentTheme = theme; + if (QFile qss(theme == Dark ? QStringLiteral(":/dark-style.qss") : QStringLiteral(":/light-style.qss")); qss.open(QIODevice::ReadOnly | QIODevice::Text)) { diff --git a/examples/mainwindow/mainwindow.h b/examples/mainwindow/mainwindow.h index 48d73cf..a0f7671 100644 --- a/examples/mainwindow/mainwindow.h +++ b/examples/mainwindow/mainwindow.h @@ -28,6 +28,7 @@ private: void installWindowAgent(); + void installStyleAgent(); void loadStyleSheet(Theme theme); Theme currentTheme{}; diff --git a/qmsetup b/qmsetup index 8afc40a..df66d32 160000 --- a/qmsetup +++ b/qmsetup @@ -1 +1 @@ -Subproject commit 8afc40a5443899b779957fb006098ce8155aacee +Subproject commit df66d3235f3ec1c2b19221677319968c86d277c0 diff --git a/share/install.cmake b/share/install.cmake index cb4aec1..b8a6c5d 100644 --- a/share/install.cmake +++ b/share/install.cmake @@ -18,12 +18,10 @@ set(QMAKE_QWK_CORE_NAME_RELEASE QWKCore) set(QMAKE_QWK_WIDGETS_NAME_RELEASE QWKWidgets) set(QMAKE_QWK_QUICK_NAME_RELEASE QWKQuick) - set(QMAKE_QWK_STYLESUPPORT_NAME_RELEASE QWKStyleSupport) set(QMAKE_QWK_CORE_NAME_DEBUG QWKCore${CMAKE_DEBUG_POSTFIX}) set(QMAKE_QWK_WIDGETS_NAME_DEBUG QWKWidgets${CMAKE_DEBUG_POSTFIX}) set(QMAKE_QWK_QUICK_NAME_DEBUG QWKQuick${CMAKE_DEBUG_POSTFIX}) - set(QMAKE_QWK_STYLESUPPORT_NAME_DEBUG QWKStyleSupport${CMAKE_DEBUG_POSTFIX}) file(GLOB _qmake_components "${CMAKE_CURRENT_LIST_DIR}/qmake/*.pri.in") @@ -60,14 +58,12 @@ QWKCore${CMAKE_DEBUG_POSTFIX}.lib QWKWidgets${CMAKE_DEBUG_POSTFIX}.lib QWKQuick${CMAKE_DEBUG_POSTFIX}.lib - QWKStyleSupport${CMAKE_DEBUG_POSTFIX}.lib ) set(MSBUILD_QWK_LIBRARY_LIST_RELEASE QWKCore.lib QWKWidgets.lib QWKQuick.lib - QWKStyleSupport.lib ) to_dos_separator(MSBUILD_QWK_INSTALL_PREFIX) diff --git a/share/qmake/QWKStyleSupport.pri.in b/share/qmake/QWKStyleSupport.pri.in deleted file mode 100644 index 0e7be64..0000000 --- a/share/qmake/QWKStyleSupport.pri.in +++ /dev/null @@ -1,11 +0,0 @@ -!defined(QMAKE_QWK_STYLESUPPORT_INCLUDED, var) { - QMAKE_QWK_STYLESUPPORT_INCLUDED = 1 - - include($$PWD/QWKCore.pri) - - CONFIG(debug, debug|release) { - LIBS += -l@QMAKE_QWK_STYLESUPPORT_NAME_DEBUG@ - } else { - LIBS += -l@QMAKE_QWK_STYLESUPPORT_NAME_RELEASE@ - } -} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a857d44..739c9f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -130,10 +130,6 @@ add_subdirectory(quick) endif() -if(QWINDOWKIT_BUILD_STYLESUPPORT) - add_subdirectory(stylesupport) -endif() - # ---------------------------------- # Documentation # ---------------------------------- diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 30188b9..711937c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -62,6 +62,22 @@ endif() endif() +if(QWINDOWKIT_ENABLE_STYLE_AGENT) + list(APPEND _src + style/styleagent.h + style/styleagent_p.h + style/styleagent.cpp + ) + + if(WIN32) + list(APPEND _src style/styleagent_win.cpp) + elseif(APPLE) + list(APPEND _src style/styleagent_mac.mm) + else() + list(APPEND _src style/styleagent_linux.cpp) + endif() +endif() + qwk_add_library(${PROJECT_NAME} AUTOGEN SOURCES ${_src} LINKS diff --git a/src/core/contexts/abstractwindowcontext.cpp b/src/core/contexts/abstractwindowcontext.cpp index 0d72e3c..d2da16f 100644 --- a/src/core/contexts/abstractwindowcontext.cpp +++ b/src/core/contexts/abstractwindowcontext.cpp @@ -48,6 +48,33 @@ } } + bool AbstractWindowContext::setWindowAttribute(const QString &key, const QVariant &attribute) { + auto it = m_windowAttributes.find(key); + if (it == m_windowAttributes.end()) { + if (!attribute.isValid()) { + return true; + } + if (m_windowHandle && !windowAttributeChanged(key, attribute, {})) { + return false; + } + m_windowAttributes.insert(key, attribute); + return true; + } + + if (it.value() == attribute) + return true; + if (m_windowHandle && !windowAttributeChanged(key, attribute, it.value())) { + return false; + } + + if (attribute.isValid()) { + it.value() = attribute; + } else { + m_windowAttributes.erase(it); + } + return true; + } + bool AbstractWindowContext::setHitTestVisible(const QObject *obj, bool visible) { Q_ASSERT(obj); if (!obj) { @@ -219,6 +246,24 @@ if (oldWindow == m_windowHandle) return; winIdChanged(); + + if (m_windowHandle) { + // Refresh window attributes + auto attributes = m_windowAttributes; + m_windowAttributes.clear(); + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + if (!windowAttributeChanged(it.key(), it.value(), {})) { + continue; + } + m_windowAttributes.insert(it.key(), it.value()); + } + } + } + + bool AbstractWindowContext::windowAttributeChanged(const QString &key, + const QVariant &attribute, + const QVariant &oldAttribute) { + return false; } } diff --git a/src/core/contexts/abstractwindowcontext_p.h b/src/core/contexts/abstractwindowcontext_p.h index f3e05a1..fec421e 100644 --- a/src/core/contexts/abstractwindowcontext_p.h +++ b/src/core/contexts/abstractwindowcontext_p.h @@ -37,6 +37,9 @@ inline QWindow *window() const; inline WindowItemDelegate *delegate() const; + inline QVariant windowAttribute(const QString &key) const; + bool setWindowAttribute(const QString &key, const QVariant &attribute); + inline bool isHitTestVisible(const QObject *obj) const; bool setHitTestVisible(const QObject *obj, bool visible); @@ -71,6 +74,8 @@ protected: virtual void winIdChanged() = 0; + virtual bool windowAttributeChanged(const QString &key, const QVariant &attribute, + const QVariant &oldAttribute); protected: QObject *m_host{}; @@ -85,6 +90,8 @@ QObject *m_titleBar{}; std::array<QObject *, WindowAgentBase::NumSystemButton> m_systemButtons{}; + QVariantHash m_windowAttributes; + std::unique_ptr<QObject> m_winIdChangeEventFilter; }; @@ -100,6 +107,10 @@ return m_delegate.get(); } + inline QVariant AbstractWindowContext::windowAttribute(const QString &key) const { + return m_windowAttributes.value(key); + } + inline bool AbstractWindowContext::isHitTestVisible(const QObject *obj) const { return m_hitTestVisibleItems.contains(obj); } diff --git a/src/core/contexts/cocoawindowcontext.mm b/src/core/contexts/cocoawindowcontext.mm index 96dbe65..949681d 100644 --- a/src/core/contexts/cocoawindowcontext.mm +++ b/src/core/contexts/cocoawindowcontext.mm @@ -400,4 +400,17 @@ cocoaWindowEventFilter = std::make_unique<CocoaWindowEventFilter>(this, this); } + bool CocoaWindowContext::windowAttributeChanged(const QString &key, const QVariant &attribute, + const QVariant &oldAttribute) { + if (key == QStringLiteral("no-system-buttons")) { + if (attribute.toBool()) { + // TODO: set off + } else { + // TODO: set on + } + return true; + } + return false; + } + } diff --git a/src/core/contexts/cocoawindowcontext_p.h b/src/core/contexts/cocoawindowcontext_p.h index e9d09d7..ca1c6cb 100644 --- a/src/core/contexts/cocoawindowcontext_p.h +++ b/src/core/contexts/cocoawindowcontext_p.h @@ -25,6 +25,8 @@ protected: void winIdChanged() override; + bool windowAttributeChanged(const QString &key, const QVariant &attribute, + const QVariant &oldAttribute) override; protected: WId windowId = 0; diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp index 4d1a6ff..969a275 100644 --- a/src/core/contexts/win32windowcontext.cpp +++ b/src/core/contexts/win32windowcontext.cpp @@ -55,7 +55,7 @@ static inline quint32 getDpiForWindow(HWND hwnd) { const DynamicApis &apis = DynamicApis::instance(); - if (apis.pGetDpiForWindow) { // Win10 + if (apis.pGetDpiForWindow) { // Win10 return apis.pGetDpiForWindow(hwnd); } else if (apis.pGetDpiForMonitor) { // Win8.1 HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); @@ -787,6 +787,160 @@ return false; // Not handled } + bool Win32WindowContext::windowAttributeChanged(const QString &key, const QVariant &attribute, + const QVariant &oldAttribute) { + const auto hwnd = reinterpret_cast<HWND>(window->winId()); + const DynamicApis &apis = DynamicApis::instance(); + if (key == QStringLiteral("mica")) { + if (!isWin11OrGreater()) { + return false; + } + if (attribute.toBool()) { + // We need to extend the window frame into the whole client area to be able + // to see the blurred window background. + static constexpr const MARGINS margins = {-1, -1, -1, -1}; + apis.pDwmExtendFrameIntoClientArea(hwnd, &margins); + if (isWin1122H2OrGreater()) { + // Use official DWM API to enable Mica, available since Windows 11 22H2 + // (10.0.22621). + const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_MAINWINDOW; + apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType, + sizeof(backdropType)); + } else { + // Use undocumented DWM API to enable Mica, available since Windows 11 + // (10.0.22000). + const BOOL enable = TRUE; + apis.pDwmSetWindowAttribute(hwnd, _DWMWA_MICA_EFFECT, &enable, sizeof(enable)); + } + } else { + if (isWin1122H2OrGreater()) { + const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_AUTO; + apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType, + sizeof(backdropType)); + } else { + const BOOL enable = FALSE; + apis.pDwmSetWindowAttribute(hwnd, _DWMWA_MICA_EFFECT, &enable, sizeof(enable)); + } + static constexpr const MARGINS margins = {0, 0, 0, 0}; + apis.pDwmExtendFrameIntoClientArea(hwnd, &margins); + } + return true; + } else if (key == QStringLiteral("mica-alt")) { + if (!isWin1122H2OrGreater()) { + return false; + } + if (attribute.toBool()) { + // We need to extend the window frame into the whole client area to be able + // to see the blurred window background. + static constexpr const MARGINS margins = {-1, -1, -1, -1}; + apis.pDwmExtendFrameIntoClientArea(hwnd, &margins); + // Use official DWM API to enable Mica Alt, available since Windows 11 22H2 + // (10.0.22621). + const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_TABBEDWINDOW; + apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType, + sizeof(backdropType)); + } else { + const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_AUTO; + apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType, + sizeof(backdropType)); + static constexpr const MARGINS margins = {0, 0, 0, 0}; + apis.pDwmExtendFrameIntoClientArea(hwnd, &margins); + } + return true; + } else if (key == QStringLiteral("acrylic-material")) { + if (!isWin10OrGreater()) { + return false; + } + if (attribute.userType() == QMetaType::QColor) { + // We need to extend the window frame into the whole client area to be able + // to see the blurred window background. + static constexpr const MARGINS margins = {-1, -1, -1, -1}; + apis.pDwmExtendFrameIntoClientArea(hwnd, &margins); + if (isWin11OrGreater()) { + const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_TRANSIENTWINDOW; + apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType, + sizeof(backdropType)); + } else { + auto gradientColor = attribute.value<QColor>(); + + ACCENT_POLICY policy{}; + policy.dwAccentState = ACCENT_ENABLE_ACRYLICBLURBEHIND; + policy.dwAccentFlags = ACCENT_ENABLE_ACRYLIC_WITH_LUMINOSITY; + // This API expects the #AABBGGRR format. + policy.dwGradientColor = + DWORD(qRgba(gradientColor.blue(), gradientColor.green(), + gradientColor.red(), gradientColor.alpha())); + WINDOWCOMPOSITIONATTRIBDATA wcad{}; + wcad.Attrib = WCA_ACCENT_POLICY; + wcad.pvData = &policy; + wcad.cbData = sizeof(policy); + apis.pSetWindowCompositionAttribute(hwnd, &wcad); + } + } else { + if (isWin11OrGreater()) { + const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_AUTO; + apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType, + sizeof(backdropType)); + } else { + ACCENT_POLICY policy{}; + policy.dwAccentState = ACCENT_DISABLED; + policy.dwAccentFlags = ACCENT_NONE; + WINDOWCOMPOSITIONATTRIBDATA wcad{}; + wcad.Attrib = WCA_ACCENT_POLICY; + wcad.pvData = &policy; + wcad.cbData = sizeof(policy); + apis.pSetWindowCompositionAttribute(hwnd, &wcad); + } + static constexpr const MARGINS margins = {0, 0, 0, 0}; + apis.pDwmExtendFrameIntoClientArea(hwnd, &margins); + } + return true; + } else if (key == QStringLiteral("dwm-blur")) { + if (attribute.toBool()) { + // We need to extend the window frame into the whole client area to be able + // to see the blurred window background. + static constexpr const MARGINS margins = {-1, -1, -1, -1}; + apis.pDwmExtendFrameIntoClientArea(hwnd, &margins); + if (isWin8OrGreater()) { + ACCENT_POLICY policy{}; + policy.dwAccentState = ACCENT_ENABLE_BLURBEHIND; + policy.dwAccentFlags = ACCENT_NONE; + WINDOWCOMPOSITIONATTRIBDATA wcad{}; + wcad.Attrib = WCA_ACCENT_POLICY; + wcad.pvData = &policy; + wcad.cbData = sizeof(policy); + apis.pSetWindowCompositionAttribute(hwnd, &wcad); + } else { + DWM_BLURBEHIND bb{}; + bb.fEnable = TRUE; + bb.fTransitionOnMaximized = TRUE; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_TRANSITIONONMAXIMIZED; + apis.pDwmEnableBlurBehindWindow(hwnd, &bb); + } + } else { + if (isWin8OrGreater()) { + ACCENT_POLICY policy{}; + policy.dwAccentState = ACCENT_DISABLED; + policy.dwAccentFlags = ACCENT_NONE; + WINDOWCOMPOSITIONATTRIBDATA wcad{}; + wcad.Attrib = WCA_ACCENT_POLICY; + wcad.pvData = &policy; + wcad.cbData = sizeof(policy); + apis.pSetWindowCompositionAttribute(hwnd, &wcad); + } else { + DWM_BLURBEHIND bb{}; + bb.fEnable = FALSE; + bb.dwFlags = DWM_BB_ENABLE; + apis.pDwmEnableBlurBehindWindow(hwnd, &bb); + } + static constexpr const MARGINS margins = {0, 0, 0, 0}; + apis.pDwmExtendFrameIntoClientArea(hwnd, &margins); + } + return true; + } + return false; + } + QWK_USED static constexpr const struct { const WPARAM wParam = MAKEWPARAM(44500, 61897); const LPARAM lParam = MAKELPARAM(62662, 44982); // Not used. Reserve for future use. diff --git a/src/core/contexts/win32windowcontext_p.h b/src/core/contexts/win32windowcontext_p.h index 982a89d..d5c6d13 100644 --- a/src/core/contexts/win32windowcontext_p.h +++ b/src/core/contexts/win32windowcontext_p.h @@ -40,6 +40,8 @@ protected: void winIdChanged() override; + bool windowAttributeChanged(const QString &key, const QVariant &attribute, + const QVariant &oldAttribute) override; public: bool windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); diff --git a/src/core/style/styleagent.cpp b/src/core/style/styleagent.cpp new file mode 100644 index 0000000..47ef5de --- /dev/null +++ b/src/core/style/styleagent.cpp @@ -0,0 +1,46 @@ +#include "styleagent.h" +#include "styleagent_p.h" + +#include <QtCore/QVariant> + +namespace QWK { + + StyleAgentPrivate::StyleAgentPrivate() { + } + + StyleAgentPrivate::~StyleAgentPrivate() = default; + + void StyleAgentPrivate::init() { + } + + void StyleAgentPrivate::notifyThemeChanged(StyleAgent::SystemTheme theme) { + if (theme == systemTheme) + return; + systemTheme = theme; + + Q_Q(StyleAgent); + Q_EMIT q->systemThemeChanged(); + } + + StyleAgent::StyleAgent(QObject *parent) : StyleAgent(*new StyleAgentPrivate(), parent) { + Q_D(StyleAgent); + d->setupSystemThemeHook(); + } + + StyleAgent::~StyleAgent() { + Q_D(StyleAgent); + d->removeSystemThemeHook(); + } + + StyleAgent::SystemTheme StyleAgent::systemTheme() const { + Q_D(const StyleAgent); + return d->systemTheme; + } + + StyleAgent::StyleAgent(StyleAgentPrivate &d, QObject *parent) : QObject(parent), d_ptr(&d) { + d.q_ptr = this; + + d.init(); + } + +} diff --git a/src/core/style/styleagent.h b/src/core/style/styleagent.h new file mode 100644 index 0000000..d5e27e4 --- /dev/null +++ b/src/core/style/styleagent.h @@ -0,0 +1,44 @@ +#ifndef STYLEAGENT_H +#define STYLEAGENT_H + +#include <memory> + +#include <QtCore/QObject> +#include <QtGui/QWindow> + +#include <QWKCore/qwkglobal.h> + +namespace QWK { + + class StyleAgentPrivate; + + class QWK_CORE_EXPORT StyleAgent : public QObject { + Q_OBJECT + Q_DECLARE_PRIVATE(StyleAgent) + public: + explicit StyleAgent(QObject *parent = nullptr); + ~StyleAgent() override; + + enum SystemTheme { + Unknown, + Light, + Dark, + HighContrast, + }; + Q_ENUM(SystemTheme) + + public: + SystemTheme systemTheme() const; + + Q_SIGNALS: + void systemThemeChanged(); + + protected: + StyleAgent(StyleAgentPrivate &d, QObject *parent = nullptr); + + const std::unique_ptr<StyleAgentPrivate> d_ptr; + }; + +} + +#endif // STYLEAGENT_H \ No newline at end of file diff --git a/src/core/style/styleagent_linux.cpp b/src/core/style/styleagent_linux.cpp new file mode 100644 index 0000000..3eb3577 --- /dev/null +++ b/src/core/style/styleagent_linux.cpp @@ -0,0 +1,13 @@ +#include "styleagent_p.h" + +#include <QtCore/QVariant> + +namespace QWK { + + void StyleAgentPrivate::setupSystemThemeHook() { + } + + void StyleAgentPrivate::removeSystemThemeHook() { + } + +} \ No newline at end of file diff --git a/src/core/style/styleagent_mac.mm b/src/core/style/styleagent_mac.mm new file mode 100644 index 0000000..3eb3577 --- /dev/null +++ b/src/core/style/styleagent_mac.mm @@ -0,0 +1,13 @@ +#include "styleagent_p.h" + +#include <QtCore/QVariant> + +namespace QWK { + + void StyleAgentPrivate::setupSystemThemeHook() { + } + + void StyleAgentPrivate::removeSystemThemeHook() { + } + +} \ No newline at end of file diff --git a/src/core/style/styleagent_p.h b/src/core/style/styleagent_p.h new file mode 100644 index 0000000..5d8549a --- /dev/null +++ b/src/core/style/styleagent_p.h @@ -0,0 +1,39 @@ +#ifndef STYLEAGENTPRIVATE_H +#define STYLEAGENTPRIVATE_H + +// +// W A R N I N G !!! +// ----------------- +// +// This file is not part of the QWindowKit API. It is used purely as an +// implementation detail. This header file may change from version to +// version without notice, or may even be removed. +// + +#include <QtCore/QHash> + +#include <QWKCore/styleagent.h> + +namespace QWK { + + class StyleAgentPrivate : public QObject { + Q_DECLARE_PUBLIC(StyleAgent) + public: + StyleAgentPrivate(); + ~StyleAgentPrivate() override; + + void init(); + + StyleAgent *q_ptr; + + StyleAgent::SystemTheme systemTheme = StyleAgent::Dark; + + virtual void setupSystemThemeHook(); + virtual void removeSystemThemeHook(); + + void notifyThemeChanged(StyleAgent::SystemTheme theme); + }; + +} + +#endif // STYLEAGENTPRIVATE_H \ No newline at end of file diff --git a/src/core/style/styleagent_win.cpp b/src/core/style/styleagent_win.cpp new file mode 100644 index 0000000..9d6072e --- /dev/null +++ b/src/core/style/styleagent_win.cpp @@ -0,0 +1,84 @@ +#include "styleagent_p.h" + +#include <QtCore/QSet> +#include <QtCore/QVariant> +#include <QtGui/QColor> + +#include <QWKCore/private/qwkwindowsextra_p.h> +#include <QWKCore/private/nativeeventfilter_p.h> + +namespace QWK { + + using StyleAgentSet = QSet<StyleAgentPrivate *>; + Q_GLOBAL_STATIC(StyleAgentSet, g_styleAgentSet) + + class SystemSettingEventFilter : public AppNativeEventFilter { + public: + bool nativeEventFilter(const QByteArray &eventType, void *message, + QT_NATIVE_EVENT_RESULT_TYPE *result) override { + Q_UNUSED(eventType) + if (!result) { + return false; + } + + const auto msg = static_cast<const MSG *>(message); + switch (msg->message) { + case WM_THEMECHANGED: + case WM_SYSCOLORCHANGE: + case WM_DWMCOLORIZATIONCOLORCHANGED: { + // TODO: walk through `g_styleAgentSet` + break; + } + + case WM_SETTINGCHANGE: { + if (!msg->wParam && msg->lParam && + std::wcscmp(reinterpret_cast<LPCWSTR>(msg->lParam), L"ImmersiveColorSet") == + 0) { + // TODO: walk through `g_styleAgentSet` + } + break; + } + + default: + break; + } + return false; + } + + static SystemSettingEventFilter *instance; + + static inline void install() { + if (instance) { + return; + } + instance = new SystemSettingEventFilter(); + } + + static inline void uninstall() { + if (!instance) { + return; + } + delete instance; + instance = nullptr; + } + }; + + SystemSettingEventFilter *SystemSettingEventFilter::instance = nullptr; + + void StyleAgentPrivate::setupSystemThemeHook() { + g_styleAgentSet->insert(this); + SystemSettingEventFilter::install(); + + // Initialize `systemTheme` variable + } + + void StyleAgentPrivate::removeSystemThemeHook() { + if (!g_styleAgentSet->remove(this)) + return; + + if (g_styleAgentSet->isEmpty()) { + SystemSettingEventFilter::uninstall(); + } + } + +} \ No newline at end of file diff --git a/src/core/windowagentbase.cpp b/src/core/windowagentbase.cpp index 72b1229..819dfb2 100644 --- a/src/core/windowagentbase.cpp +++ b/src/core/windowagentbase.cpp @@ -50,6 +50,16 @@ WindowAgentBase::~WindowAgentBase() = default; + QVariant WindowAgentBase::windowAttribute(const QString &key) const { + Q_D(const WindowAgentBase); + return d->context->windowAttribute(key); + } + + bool WindowAgentBase::setWindowAttribute(const QString &key, const QVariant &attribute) { + Q_D(WindowAgentBase); + return d->context->setWindowAttribute(key, attribute); + } + void WindowAgentBase::showSystemMenu(const QPoint &pos) { Q_D(WindowAgentBase); d->context->showSystemMenu(pos); diff --git a/src/core/windowagentbase.h b/src/core/windowagentbase.h index d377ba8..1c6eb96 100644 --- a/src/core/windowagentbase.h +++ b/src/core/windowagentbase.h @@ -28,6 +28,12 @@ }; Q_ENUM(SystemButton) + QVariant windowAttribute(const QString &key) const; + bool setWindowAttribute(const QString &key, const QVariant &attribute); + + Q_SIGNALS: + void systemThemeChanged(); + public Q_SLOTS: void showSystemMenu(const QPoint &pos); // Only available on Windows now void centralize(); -- Gitblit v1.9.1