From d86e9144a2b3f473be25265c6695fadf20bea973 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Tue, 19 Apr 2022 15:33:37 +0800 Subject: [PATCH] general improvement Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- .../Core/framelesswindowsmanager.h | 2 + include/FramelessHelper/Core/utils.h | 7 +- .../Widgets/framelesswidgetshelper.h | 2 + src/core/framelesswindowsmanager.cpp | 28 ++- src/core/framelesswindowsmanager_p.h | 3 +- src/core/utils.cpp | 10 +- src/core/utils_linux.cpp | 214 ++++-------------- src/core/utils_mac.mm | 121 +++++----- src/quick/framelessquickutils.cpp | 16 +- src/quick/framelessquickwindow.cpp | 59 +++-- src/quick/framelessquickwindow_p.h | 2 + src/quick/quickstandardclosebutton.cpp | 13 +- src/quick/quickstandardmaximizebutton.cpp | 13 +- src/quick/quickstandardminimizebutton.cpp | 13 +- src/quick/quickstandardtitlebar.cpp | 25 +- src/widgets/framelesswidgetshelper.cpp | 59 +++-- 16 files changed, 268 insertions(+), 319 deletions(-) diff --git a/include/FramelessHelper/Core/framelesswindowsmanager.h b/include/FramelessHelper/Core/framelesswindowsmanager.h index 86532da..eb9e22a 100644 --- a/include/FramelessHelper/Core/framelesswindowsmanager.h +++ b/include/FramelessHelper/Core/framelesswindowsmanager.h @@ -38,6 +38,7 @@ class FRAMELESSHELPER_CORE_API FramelessWindowsManager : public QObject Q_DISABLE_COPY_MOVE(FramelessWindowsManager) Q_PROPERTY(bool usePureQtImplementation READ usePureQtImplementation CONSTANT FINAL) Q_PROPERTY(Global::SystemTheme systemTheme READ systemTheme NOTIFY systemThemeChanged FINAL) + Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemThemeChanged FINAL) public: explicit FramelessWindowsManager(QObject *parent = nullptr); @@ -47,6 +48,7 @@ public: Q_NODISCARD bool usePureQtImplementation() const; Q_NODISCARD Global::SystemTheme systemTheme() const; + Q_NODISCARD QColor systemAccentColor() const; public Q_SLOTS: void addWindow(const Global::UserSettings &settings, const Global::SystemParameters ¶ms); diff --git a/include/FramelessHelper/Core/utils.h b/include/FramelessHelper/Core/utils.h index 00d746b..04e4820 100644 --- a/include/FramelessHelper/Core/utils.h +++ b/include/FramelessHelper/Core/utils.h @@ -55,6 +55,7 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter( [[nodiscard]] FRAMELESSHELPER_CORE_API QColor calculateSystemButtonBackgroundColor( const Global::SystemButtonType button, const Global::ButtonState state); [[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode(); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool isTitleBarColorized(); #ifdef Q_OS_WINDOWS [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin8OrGreater(); @@ -95,7 +96,6 @@ FRAMELESSHELPER_CORE_API void showSystemMenu( FRAMELESSHELPER_CORE_API void updateWindowFrameBorderColor(const WId windowId, const bool dark); FRAMELESSHELPER_CORE_API void fixupQtInternals(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFrameBorderVisible(); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool isTitleBarColorized(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized(); FRAMELESSHELPER_CORE_API void installSystemMenuHook( const WId windowId, @@ -114,9 +114,8 @@ FRAMELESSHELPER_CORE_API void updateGlobalWin32ControlsTheme(const WId windowId, #endif // Q_OS_WINDOWS #ifdef Q_OS_MACOS -FRAMELESSHELPER_CORE_API void setWindowHook(const WId windowId); -FRAMELESSHELPER_CORE_API void unsetWindowHook(const WId windowId); -FRAMELESSHELPER_CORE_API void removeWindowFrame(const WId windowId); +FRAMELESSHELPER_CORE_API void setSystemTitleBarVisible(const WId windowId, const bool visible); +[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getControlsAccentColor(); #endif // Q_OS_MACOS } // namespace Utils diff --git a/include/FramelessHelper/Widgets/framelesswidgetshelper.h b/include/FramelessHelper/Widgets/framelesswidgetshelper.h index b15eef5..ccf7abf 100644 --- a/include/FramelessHelper/Widgets/framelesswidgetshelper.h +++ b/include/FramelessHelper/Widgets/framelesswidgetshelper.h @@ -67,6 +67,7 @@ public: Q_INVOKABLE void changeEventHandler(QEvent *event); Q_INVOKABLE void paintEventHandler(QPaintEvent *event); Q_INVOKABLE void mouseMoveEventHandler(QMouseEvent *event); + Q_INVOKABLE void mousePressEventHandler(QMouseEvent *event); Q_INVOKABLE void mouseReleaseEventHandler(QMouseEvent *event); Q_INVOKABLE void mouseDoubleClickEventHandler(QMouseEvent *event); @@ -93,6 +94,7 @@ private: Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const; Q_NODISCARD bool shouldDrawFrameBorder() const; Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const; + void doStartSystemMove2(QMouseEvent *event); private Q_SLOTS: void updateContentsMargins(); diff --git a/src/core/framelesswindowsmanager.cpp b/src/core/framelesswindowsmanager.cpp index f4abaef..9735760 100644 --- a/src/core/framelesswindowsmanager.cpp +++ b/src/core/framelesswindowsmanager.cpp @@ -107,6 +107,11 @@ SystemTheme FramelessWindowsManagerPrivate::systemTheme() const return m_systemTheme; } +QColor FramelessWindowsManagerPrivate::systemAccentColor() const +{ + return m_accentColor; +} + void FramelessWindowsManagerPrivate::addWindow(const UserSettings &settings, const SystemParameters ¶ms) { Q_ASSERT(params.isValid()); @@ -160,21 +165,27 @@ void FramelessWindowsManagerPrivate::notifySystemThemeHasChangedOrNot() #ifdef Q_OS_WINDOWS const DwmColorizationArea currentColorizationArea = Utils::getDwmColorizationArea(); const QColor currentAccentColor = Utils::getDwmColorizationColor(); +#endif +#ifdef Q_OS_LINUX + const QColor currentAccentColor = {}; // ### TODO +#endif +#ifdef Q_OS_MACOS + const QColor currentAccentColor = Utils::getControlsAccentColor(); #endif bool notify = false; if (m_systemTheme != currentSystemTheme) { m_systemTheme = currentSystemTheme; notify = true; } + if (m_accentColor != currentAccentColor) { + m_accentColor = currentAccentColor; + notify = true; + } #ifdef Q_OS_WINDOWS if (m_colorizationArea != currentColorizationArea) { m_colorizationArea = currentColorizationArea; notify = true; } - if (m_accentColor != currentAccentColor) { - m_accentColor = currentAccentColor; - notify = true; - } #endif if (notify) { Q_EMIT q->systemThemeChanged(); @@ -188,6 +199,9 @@ void FramelessWindowsManagerPrivate::initialize() m_colorizationArea = Utils::getDwmColorizationArea(); m_accentColor = Utils::getDwmColorizationColor(); #endif +#ifdef Q_OS_MACOS + m_accentColor = Utils::getControlsAccentColor(); +#endif } FramelessWindowsManager::FramelessWindowsManager(QObject *parent) : QObject(parent), d_ptr(new FramelessWindowsManagerPrivate(this)) @@ -213,6 +227,12 @@ SystemTheme FramelessWindowsManager::systemTheme() const return d->systemTheme(); } +QColor FramelessWindowsManager::systemAccentColor() const +{ + Q_D(const FramelessWindowsManager); + return d->systemAccentColor(); +} + void FramelessWindowsManager::addWindow(const UserSettings &settings, const SystemParameters ¶ms) { Q_D(FramelessWindowsManager); diff --git a/src/core/framelesswindowsmanager_p.h b/src/core/framelesswindowsmanager_p.h index e003612..9faa69a 100644 --- a/src/core/framelesswindowsmanager_p.h +++ b/src/core/framelesswindowsmanager_p.h @@ -46,6 +46,7 @@ public: Q_NODISCARD static bool usePureQtImplementation(); Q_NODISCARD Global::SystemTheme systemTheme() const; + Q_NODISCARD QColor systemAccentColor() const; public Q_SLOTS: static void addWindow(const Global::UserSettings &settings, const Global::SystemParameters ¶ms); @@ -57,9 +58,9 @@ private: private: FramelessWindowsManager *q_ptr = nullptr; Global::SystemTheme m_systemTheme = Global::SystemTheme::Unknown; + QColor m_accentColor = {}; #ifdef Q_OS_WINDOWS Global::DwmColorizationArea m_colorizationArea = Global::DwmColorizationArea::None_; - QColor m_accentColor = {}; #endif }; diff --git a/src/core/utils.cpp b/src/core/utils.cpp index b348224..b7098b0 100644 --- a/src/core/utils.cpp +++ b/src/core/utils.cpp @@ -251,11 +251,17 @@ QColor Utils::calculateSystemButtonBackgroundColor(const SystemButtonType button if (button == SystemButtonType::Close) { return kDefaultSystemCloseButtonBackgroundColor; } -#ifdef Q_OS_WINDOWS if (isTitleBarColorized()) { +#ifdef Q_OS_WINDOWS return getDwmColorizationColor(); - } #endif +#ifdef Q_OS_LINUX + return {}; +#endif +#ifdef Q_OS_MACOS + return getControlsAccentColor(); +#endif + } return kDefaultSystemButtonBackgroundColor; }(); return ((state == ButtonState::Hovered) ? result.lighter(110) : result.lighter(105)); diff --git a/src/core/utils_linux.cpp b/src/core/utils_linux.cpp index c33d4b7..a90b4f6 100644 --- a/src/core/utils_linux.cpp +++ b/src/core/utils_linux.cpp @@ -25,12 +25,11 @@ #include "utils.h" #include #include -#include #include -#include -#include -#if ((QT_VERSION >= QT_VERSION_CHECK(5, 9, 1)) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))) -# include +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +# include +#else +# include #endif #include #include @@ -52,11 +51,6 @@ static constexpr const auto _NET_WM_MOVERESIZE_MOVE = 8; static constexpr const char GTK_THEME_NAME_ENV_VAR[] = "GTK_THEME"; static constexpr const char GTK_THEME_NAME_PROP[] = "gtk-theme-name"; static constexpr const char GTK_THEME_PREFER_DARK_PROP[] = "gtk-application-prefer-dark-theme"; - -FRAMELESSHELPER_BYTEARRAY_CONSTANT(display) -FRAMELESSHELPER_BYTEARRAY_CONSTANT(x11screen) -FRAMELESSHELPER_BYTEARRAY_CONSTANT(rootwindow) - FRAMELESSHELPER_STRING_CONSTANT2(GTK_THEME_DARK_REGEX, "[:-]dark") static constexpr const char WM_MOVERESIZE_OPERATION_NAME[] = "_NET_WM_MOVERESIZE"; @@ -166,168 +160,41 @@ template return false; } -[[nodiscard]] static inline Display *x11_get_display() -{ - if (!qGuiApp) { - return nullptr; - } - QPlatformNativeInterface * const iface = qGuiApp->platformNativeInterface(); - Q_ASSERT(iface); - if (!iface) { - return nullptr; - } - const auto display = iface->nativeResourceForIntegration(kdisplay); - Q_ASSERT(display); - if (!display) { - return nullptr; - } - return static_cast(display); -} - -[[nodiscard]] static inline qintptr x11_get_desktop() -{ - if (!qGuiApp) { - return 0; - } - QPlatformNativeInterface * const iface = qGuiApp->platformNativeInterface(); - Q_ASSERT(iface); - if (!iface) { - return 0; - } - const auto screen = iface->nativeResourceForIntegration(kx11screen); - //Q_ASSERT(screen); // Always zero on both X11 and Wayland. Why? Is zero a valid value? - if (!screen) { - return 0; - } - return reinterpret_cast(screen); -} - -[[nodiscard]] static inline QScreen *x11_getScreenForVirtualDesktop(const int virtualDesktopNumber) -{ -#if ((QT_VERSION >= QT_VERSION_CHECK(5, 9, 1)) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))) - if (virtualDesktopNumber == -1) { - return QGuiApplication::primaryScreen(); - } - const QList screens = QGuiApplication::screens(); - if (screens.isEmpty()) { - return nullptr; - } - for (auto &&screen : qAsConst(screens)) { - if (QXcbScreenFunctions::virtualDesktopNumber(screen) == virtualDesktopNumber) { - return screen; - } - } - return nullptr; -#else - Q_UNUSED(virtualDesktopNumber); - return QGuiApplication::primaryScreen(); -#endif -} - -[[nodiscard]] static inline quintptr x11_get_window(const int desktop) -{ - if (!qGuiApp) { - return 0; - } - QPlatformNativeInterface * const iface = qGuiApp->platformNativeInterface(); - Q_ASSERT(iface); - if (!iface) { - return 0; - } - QScreen * const screen = x11_getScreenForVirtualDesktop(desktop); - Q_ASSERT(screen); - if (!screen) { - return 0; - } - const auto window = iface->nativeResourceForScreen(krootwindow, screen); - Q_ASSERT(window); // Always zero on Wayland, non-zero on X11. - if (!window) { - return 0; - } - return reinterpret_cast(window); -} - -static inline void x11_emulateButtonRelease(const WId windowId, const QPoint &globalPos, const QPoint &localPos) +static inline void doStartSystemMoveResize(const WId windowId, const QPoint &globalPos, const int edges) { Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(edges >= 0); + if (!windowId || (edges < 0)) { return; } - Display * const display = x11_get_display(); - Q_ASSERT(display); - if (!display) { - return; - } - const Window window = windowId; - XEvent event; - memset(&event, 0, sizeof(event)); - event.xbutton.same_screen = True; - event.xbutton.send_event = True; - event.xbutton.window = window; - event.xbutton.root = x11_get_window(x11_get_desktop()); - event.xbutton.x_root = globalPos.x(); - event.xbutton.y_root = globalPos.y(); - event.xbutton.x = localPos.x(); - event.xbutton.y = localPos.y(); - event.xbutton.type = ButtonRelease; - event.xbutton.time = CurrentTime; - if (XSendEvent(display, window, True, ButtonReleaseMask, &event) == 0) { - qWarning() << "Failed to send ButtonRelease event for native dragging."; - } - XFlush(display); -} - -static inline void x11_moveOrResizeWindow(const WId windowId, const QPoint &pos, const int section) -{ - Q_ASSERT(windowId); - Q_ASSERT(section >= 0); - if (!windowId || (section < 0)) { - return; - } - Display * const display = x11_get_display(); - Q_ASSERT(display); - if (!display) { - return; - } - static const Atom netMoveResize = XInternAtom(display, WM_MOVERESIZE_OPERATION_NAME, False); - Q_ASSERT(netMoveResize); - if (!netMoveResize) { - return; - } - // First we need to ungrab the pointer that may have been - // automatically grabbed by Qt on ButtonPressEvent - XUngrabPointer(display, CurrentTime); - XEvent event; - memset(&event, 0, sizeof(event)); - event.xclient.type = ClientMessage; - event.xclient.window = windowId; - event.xclient.message_type = netMoveResize; - event.xclient.display = display; - event.xclient.send_event = True; - event.xclient.format = 32; - event.xclient.data.l[0] = pos.x(); - event.xclient.data.l[1] = pos.y(); - event.xclient.data.l[2] = section; - event.xclient.data.l[3] = Button1; - if (XSendEvent(display, x11_get_window(x11_get_desktop()), - False, (SubstructureRedirectMask | SubstructureNotifyMask), &event) == 0) { - qWarning() << "Failed to send _NET_WM_MOVERESIZE event for native dragging."; - } - XFlush(display); -} - -static inline void x11_windowStartNativeDrag(const WId windowId, const QPoint &globalPos, const QPoint &localPos, const int section) -{ - Q_ASSERT(windowId); - if (!windowId) { - return; - } - if (section < 0) { - return; - } - // Before we start dragging we need to tell Qt that the mouse is released. - x11_emulateButtonRelease(windowId, globalPos, localPos); - x11_moveOrResizeWindow(windowId, globalPos, section); + xcb_connection_t * const connection = QX11Info::connection(); + Q_ASSERT(connection); + static const xcb_atom_t moveResize = [connection]() -> xcb_atom_t { + const xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, false, + qstrlen(WM_MOVERESIZE_OPERATION_NAME), WM_MOVERESIZE_OPERATION_NAME); + xcb_intern_atom_reply_t * const reply = xcb_intern_atom_reply(connection, cookie, nullptr); + Q_ASSERT(reply); + const xcb_atom_t atom = reply->atom; + Q_ASSERT(atom); + std::free(reply); + return atom; + }(); + const quint32 rootWindow = QX11Info::appRootWindow(QX11Info::appScreen()); + Q_ASSERT(rootWindow); + xcb_client_message_event_t xev; + memset(&xev, 0, sizeof(xev)); + xev.response_type = XCB_CLIENT_MESSAGE; + xev.type = moveResize; + xev.window = windowId; + xev.format = 32; + xev.data.data32[0] = globalPos.x(); + xev.data.data32[1] = globalPos.y(); + xev.data.data32[2] = edges; + xev.data.data32[3] = XCB_BUTTON_INDEX_1; + xcb_ungrab_pointer(connection, XCB_CURRENT_TIME); + xcb_send_event(connection, false, rootWindow, + (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), + reinterpret_cast(&xev)); } SystemTheme Utils::getSystemTheme() @@ -346,8 +213,7 @@ void Utils::startSystemMove(QWindow *window, const QPoint &globalPos) // are expecting device coordinates. const qreal dpr = window->devicePixelRatio(); const QPoint globalPos2 = QPointF(QPointF(globalPos) * dpr).toPoint(); - const QPoint localPos2 = QPointF(QPointF(window->mapFromGlobal(globalPos)) * dpr).toPoint(); - x11_windowStartNativeDrag(window->winId(), globalPos2, localPos2, _NET_WM_MOVERESIZE_MOVE); + doStartSystemMoveResize(window->winId(), globalPos2, _NET_WM_MOVERESIZE_MOVE); } void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoint &globalPos) @@ -367,8 +233,12 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi // are expecting device coordinates. const qreal dpr = window->devicePixelRatio(); const QPoint globalPos2 = QPointF(QPointF(globalPos) * dpr).toPoint(); - const QPoint localPos2 = QPointF(QPointF(window->mapFromGlobal(globalPos)) * dpr).toPoint(); - x11_windowStartNativeDrag(window->winId(), globalPos2, localPos2, section); + doStartSystemMoveResize(window->winId(), globalPos2, section); +} + +bool Utils::isTitleBarColorized() +{ + return false; } FRAMELESSHELPER_END_NAMESPACE diff --git a/src/core/utils_mac.mm b/src/core/utils_mac.mm index 2023743..065444e 100644 --- a/src/core/utils_mac.mm +++ b/src/core/utils_mac.mm @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -94,39 +95,42 @@ public: [nswindow standardWindowButton:NSWindowZoomButton].hidden = !oldZoomButtonVisible; } - void removeWindowFrame() + void setSystemTitleBarVisible(const bool visible) { - NSView *nsview = [nswindow contentView]; + NSView * const nsview = [nswindow contentView]; Q_ASSERT(nsview); if (!nsview) { return; } nsview.wantsLayer = YES; - nswindow.styleMask |= NSWindowStyleMaskFullSizeContentView; - nswindow.titlebarAppearsTransparent = true; - nswindow.titleVisibility = NSWindowTitleHidden; - nswindow.hasShadow = true; - nswindow.showsToolbarButton = false; - nswindow.movableByWindowBackground = false; - nswindow.movable = false; - [nswindow standardWindowButton:NSWindowCloseButton].hidden = true; - [nswindow standardWindowButton:NSWindowMiniaturizeButton].hidden = true; - [nswindow standardWindowButton:NSWindowZoomButton].hidden = true; + if (visible) { + nswindow.styleMask &= ~NSWindowStyleMaskFullSizeContentView; + } else { + nswindow.styleMask |= NSWindowStyleMaskFullSizeContentView; + } + nswindow.titlebarAppearsTransparent = (visible ? NO : YES); + nswindow.titleVisibility = (visible ? NSWindowTitleVisible : NSWindowTitleHidden); + nswindow.hasShadow = YES; + nswindow.showsToolbarButton = NO; + nswindow.movableByWindowBackground = NO; + nswindow.movable = NO; + [nswindow standardWindowButton:NSWindowCloseButton].hidden = (visible ? NO : YES); + [nswindow standardWindowButton:NSWindowMiniaturizeButton].hidden = (visible ? NO : YES); + [nswindow standardWindowButton:NSWindowZoomButton].hidden = (visible ? NO : YES); } private: - NSWindow *nswindow; - - NSWindowStyleMask oldStyleMask; - BOOL oldTitlebarAppearsTransparent; - BOOL oldHasShadow; - BOOL oldShowsToolbarButton; - BOOL oldMovableByWindowBackground; - BOOL oldMovable; - BOOL oldCloseButtonVisible; - BOOL oldMiniaturizeButtonVisible; - BOOL oldZoomButtonVisible; - NSWindowTitleVisibility oldTitleVisibility; + NSWindow *nswindow = nullptr; + NSWindowStyleMask oldStyleMask = 0; + BOOL oldTitlebarAppearsTransparent = NO; + BOOL oldHasShadow = NO; + BOOL oldShowsToolbarButton = NO; + BOOL oldMovableByWindowBackground = NO; + BOOL oldMovable = NO; + BOOL oldCloseButtonVisible = NO; + BOOL oldMiniaturizeButtonVisible = NO; + BOOL oldZoomButtonVisible = NO; + NSWindowTitleVisibility oldTitleVisibility = NSWindowTitleVisible; }; using NSWindowProxyHash = QHash; @@ -153,6 +157,7 @@ static inline void mac_windowStartNativeDrag(const WId windowId, const QPoint &g return; } const NSWindow * const nswindow = mac_getNSWindow(windowId); + Q_ASSERT(nswindow); if (!nswindow) { return; } @@ -174,56 +179,27 @@ SystemTheme Utils::getSystemTheme() return (shouldAppsUseDarkMode() ? SystemTheme::Dark : SystemTheme::Light); } -void Utils::setWindowHook(const WId windowId) -{ - Q_ASSERT(windowId); - if (!windowId) { - return; - } - if (g_nswindowOverrideHash()->contains(windowId)) { - return; - } - NSWindow * const nswindow = mac_getNSWindow(windowId); - if (!nswindow) { - return; - } - const auto proxy = new NSWindowProxy(nswindow); - g_nswindowOverrideHash()->insert(windowId, proxy); -} - -void Utils::unsetWindowHook(const WId windowId) +void Utils::setSystemTitleBarVisible(const WId windowId, const bool visible) { Q_ASSERT(windowId); if (!windowId) { return; } if (!g_nswindowOverrideHash()->contains(windowId)) { - return; - } - const NSWindowProxy * const proxy = g_nswindowOverrideHash()->value(windowId); - g_nswindowOverrideHash()->remove(windowId); - Q_ASSERT(proxy); - if (!proxy) { - return; - } - delete proxy; -} - -void Utils::removeWindowFrame(const WId windowId) -{ - Q_ASSERT(windowId); - if (!windowId) { - return; - } - if (!g_nswindowOverrideHash()->contains(windowId)) { - return; + NSWindow * const nswindow = mac_getNSWindow(windowId); + Q_ASSERT(nswindow); + if (!nswindow) { + return; + } + const auto proxy = new NSWindowProxy(nswindow); + g_nswindowOverrideHash()->insert(windowId, proxy); } NSWindowProxy * const proxy = g_nswindowOverrideHash()->value(windowId); Q_ASSERT(proxy); if (!proxy) { return; } - proxy->removeWindowFrame(); + proxy->setSystemTitleBarVisible(visible); } void Utils::startSystemMove(QWindow *window, const QPoint &globalPos) @@ -237,14 +213,19 @@ void Utils::startSystemMove(QWindow *window, const QPoint &globalPos) void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoint &globalPos) { - Q_ASSERT(window); - if (!window) { - return; - } - if (edges == Qt::Edges{}) { - return; - } - mac_windowStartNativeDrag(window->winId(), globalPos); + Q_UNUSED(window); + Q_UNUSED(edges); + Q_UNUSED(globalPos); +} + +QColor Utils::getControlsAccentColor() +{ + return qt_mac_toQColor([NSColor controlAccentColor]); +} + +bool Utils::isTitleBarColorized() +{ + return false; } FRAMELESSHELPER_END_NAMESPACE diff --git a/src/quick/framelessquickutils.cpp b/src/quick/framelessquickutils.cpp index 6eb92bc..c11abf9 100644 --- a/src/quick/framelessquickutils.cpp +++ b/src/quick/framelessquickutils.cpp @@ -50,7 +50,7 @@ FramelessQuickUtils *FramelessQuickUtils::instance() qreal FramelessQuickUtils::titleBarHeight() { - return 30.0; + return kDefaultTitleBarHeight; } bool FramelessQuickUtils::frameBorderVisible() @@ -65,9 +65,9 @@ bool FramelessQuickUtils::frameBorderVisible() qreal FramelessQuickUtils::frameBorderThickness() { #ifdef Q_OS_WINDOWS - return 1.0; + return kDefaultWindowFrameBorderThickness; #else - return 0.0; + return 0; #endif } @@ -80,18 +80,18 @@ QColor FramelessQuickUtils::systemAccentColor() { #ifdef Q_OS_WINDOWS return Utils::getDwmColorizationColor(); -#else +#endif +#ifdef Q_OS_LINUX return {}; #endif +#ifdef Q_OS_MACOS + return Utils::getControlsAccentColor(); +#endif } bool FramelessQuickUtils::titleBarColorized() { -#ifdef Q_OS_WINDOWS return Utils::isTitleBarColorized(); -#else - return false; -#endif } QColor FramelessQuickUtils::defaultSystemLightColor() diff --git a/src/quick/framelessquickwindow.cpp b/src/quick/framelessquickwindow.cpp index 7b6be07..39021a5 100644 --- a/src/quick/framelessquickwindow.cpp +++ b/src/quick/framelessquickwindow.cpp @@ -298,10 +298,17 @@ bool FramelessQuickWindowPrivate::eventFilter(QObject *object, QEvent *event) const auto showEvent = static_cast(event); showEventHandler(showEvent); } break; +#ifdef Q_OS_WINDOWS case QEvent::MouseMove: { const auto mouseEvent = static_cast(event); mouseMoveEventHandler(mouseEvent); } break; +#else + case QEvent::MouseButtonPress: { + const auto mouseEvent = static_cast(event); + mousePressEventHandler(mouseEvent); + } break; +#endif case QEvent::MouseButtonRelease: { const auto mouseEvent = static_cast(event); mouseReleaseEventHandler(mouseEvent); @@ -570,6 +577,31 @@ bool FramelessQuickWindowPrivate::shouldIgnoreMouseEvents(const QPoint &pos) con return (isNormal() && withinFrameBorder); } +void FramelessQuickWindowPrivate::doStartSystemMove2(QMouseEvent *event) +{ + Q_ASSERT(event); + if (!event) { + return; + } + if (m_settings.options & Option::DisableDragging) { + return; + } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + const QPoint scenePos = event->scenePosition().toPoint(); + const QPoint globalPos = event->globalPosition().toPoint(); +#else + const QPoint scenePos = event->windowPos().toPoint(); + const QPoint globalPos = event->screenPos().toPoint(); +#endif + if (shouldIgnoreMouseEvents(scenePos)) { + return; + } + if (!isInTitleBarDraggableArea(scenePos)) { + return; + } + startSystemMove2(globalPos); +} + void FramelessQuickWindowPrivate::showEventHandler(QShowEvent *event) { Q_ASSERT(event); @@ -597,27 +629,28 @@ void FramelessQuickWindowPrivate::showEventHandler(QShowEvent *event) void FramelessQuickWindowPrivate::mouseMoveEventHandler(QMouseEvent *event) { +#ifdef Q_OS_WINDOWS Q_ASSERT(event); if (!event) { return; } - if (m_settings.options & Option::DisableDragging) { - return; - } -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - const QPoint scenePos = event->scenePosition().toPoint(); - const QPoint globalPos = event->globalPosition().toPoint(); + doStartSystemMove2(event); #else - const QPoint scenePos = event->windowPos().toPoint(); - const QPoint globalPos = event->screenPos().toPoint(); + Q_UNUSED(event); #endif - if (shouldIgnoreMouseEvents(scenePos)) { +} + +void FramelessQuickWindowPrivate::mousePressEventHandler(QMouseEvent *event) +{ +#ifdef Q_OS_WINDOWS + Q_UNUSED(event); +#else + Q_ASSERT(event); + if (!event) { return; } - if (!isInTitleBarDraggableArea(scenePos)) { - return; - } - startSystemMove2(globalPos); + doStartSystemMove2(event); +#endif } void FramelessQuickWindowPrivate::mouseReleaseEventHandler(QMouseEvent *event) diff --git a/src/quick/framelessquickwindow_p.h b/src/quick/framelessquickwindow_p.h index 6f5a76c..00773c5 100644 --- a/src/quick/framelessquickwindow_p.h +++ b/src/quick/framelessquickwindow_p.h @@ -67,6 +67,7 @@ public: Q_INVOKABLE void showEventHandler(QShowEvent *event); Q_INVOKABLE void mouseMoveEventHandler(QMouseEvent *event); + Q_INVOKABLE void mousePressEventHandler(QMouseEvent *event); Q_INVOKABLE void mouseReleaseEventHandler(QMouseEvent *event); Q_INVOKABLE void mouseDoubleClickEventHandler(QMouseEvent *event); @@ -93,6 +94,7 @@ private: Q_NODISCARD bool isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const; Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const; Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const; + void doStartSystemMove2(QMouseEvent *event); private Q_SLOTS: void updateTopBorderColor(); diff --git a/src/quick/quickstandardclosebutton.cpp b/src/quick/quickstandardclosebutton.cpp index e23f70b..553c7e2 100644 --- a/src/quick/quickstandardclosebutton.cpp +++ b/src/quick/quickstandardclosebutton.cpp @@ -23,7 +23,8 @@ */ #include "quickstandardclosebutton_p.h" -#include "framelessquickutils.h" +#include +#include #include #include #include @@ -51,7 +52,7 @@ QuickStandardCloseButton::~QuickStandardCloseButton() = default; void QuickStandardCloseButton::updateForeground() { - const bool dark = (FramelessQuickUtils::darkModeEnabled() || FramelessQuickUtils::titleBarColorized()); + const bool dark = (Utils::shouldAppsUseDarkMode() || Utils::isTitleBarColorized()); const auto url = QUrl((dark || isHovered() || isPressed()) ? kDarkUrl : kLightUrl); initResource(); m_image->setSource(url); @@ -62,7 +63,7 @@ void QuickStandardCloseButton::updateBackground() static constexpr const auto button = SystemButtonType::Close; const ButtonState state = (isPressed() ? ButtonState::Pressed : ButtonState::Hovered); const bool visible = (isHovered() || isPressed()); - m_backgroundItem->setColor(FramelessQuickUtils::getSystemButtonBackgroundColor(button, state)); + m_backgroundItem->setColor(Utils::calculateSystemButtonBackgroundColor(button, state)); m_backgroundItem->setVisible(visible); } @@ -87,9 +88,7 @@ void QuickStandardCloseButton::initialize() imageAnchors->setCenterIn(m_contentItem.data()); connect(this, &QuickStandardCloseButton::hoveredChanged, this, &QuickStandardCloseButton::updateForeground); connect(this, &QuickStandardCloseButton::pressedChanged, this, &QuickStandardCloseButton::updateForeground); - const FramelessQuickUtils * const utils = FramelessQuickUtils::instance(); - connect(utils, &FramelessQuickUtils::darkModeEnabledChanged, this, &QuickStandardCloseButton::updateForeground); - connect(utils, &FramelessQuickUtils::titleBarColorizedChanged, this, &QuickStandardCloseButton::updateForeground); + connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, &QuickStandardCloseButton::updateForeground); m_backgroundItem.reset(new QQuickRectangle(this)); QQuickPen * const border = m_backgroundItem->border(); @@ -100,7 +99,7 @@ void QuickStandardCloseButton::initialize() m_tooltip = qobject_cast(qmlAttachedPropertiesObject(this)); m_tooltip->setText(tr("Close")); - connect(QGuiApplication::styleHints(), &QStyleHints::mousePressAndHoldIntervalChanged, this, [this](int interval){ + connect(QGuiApplication::styleHints(), &QStyleHints::mousePressAndHoldIntervalChanged, this, [this](const int interval){ Q_UNUSED(interval); updateToolTip(); }); diff --git a/src/quick/quickstandardmaximizebutton.cpp b/src/quick/quickstandardmaximizebutton.cpp index c0ffce4..e7c1620 100644 --- a/src/quick/quickstandardmaximizebutton.cpp +++ b/src/quick/quickstandardmaximizebutton.cpp @@ -23,7 +23,8 @@ */ #include "quickstandardmaximizebutton_p.h" -#include "framelessquickutils.h" +#include +#include #include #include #include @@ -67,7 +68,7 @@ void QuickStandardMaximizeButton::setMaximized(const bool max) void QuickStandardMaximizeButton::updateForeground() { - const bool dark = (FramelessQuickUtils::darkModeEnabled() || FramelessQuickUtils::titleBarColorized()); + const bool dark = (Utils::shouldAppsUseDarkMode() || Utils::isTitleBarColorized()); const auto url = QUrl(dark ? (m_max ? kDarkRestoreUrl : kDarkMaxUrl) : (m_max ? kLightRestoreUrl : kLightMaxUrl)); initResource(); m_image->setSource(url); @@ -78,7 +79,7 @@ void QuickStandardMaximizeButton::updateBackground() const SystemButtonType button = (m_max ? SystemButtonType::Restore : SystemButtonType::Maximize); const ButtonState state = (isPressed() ? ButtonState::Pressed : ButtonState::Hovered); const bool visible = (isHovered() || isPressed()); - m_backgroundItem->setColor(FramelessQuickUtils::getSystemButtonBackgroundColor(button, state)); + m_backgroundItem->setColor(Utils::calculateSystemButtonBackgroundColor(button, state)); m_backgroundItem->setVisible(visible); } @@ -103,9 +104,7 @@ void QuickStandardMaximizeButton::initialize() m_image.reset(new QQuickImage(m_contentItem.data())); const auto imageAnchors = new QQuickAnchors(m_image.data(), m_image.data()); imageAnchors->setCenterIn(m_contentItem.data()); - const FramelessQuickUtils * const utils = FramelessQuickUtils::instance(); - connect(utils, &FramelessQuickUtils::darkModeEnabledChanged, this, &QuickStandardMaximizeButton::updateForeground); - connect(utils, &FramelessQuickUtils::titleBarColorizedChanged, this, &QuickStandardMaximizeButton::updateForeground); + connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, &QuickStandardMaximizeButton::updateForeground); connect(this, &QuickStandardMaximizeButton::maximizedChanged, this, &QuickStandardMaximizeButton::updateForeground); m_backgroundItem.reset(new QQuickRectangle(this)); @@ -116,7 +115,7 @@ void QuickStandardMaximizeButton::initialize() connect(this, &QuickStandardMaximizeButton::pressedChanged, this, &QuickStandardMaximizeButton::updateBackground); m_tooltip = qobject_cast(qmlAttachedPropertiesObject(this)); - connect(QGuiApplication::styleHints(), &QStyleHints::mousePressAndHoldIntervalChanged, this, [this](int interval){ + connect(QGuiApplication::styleHints(), &QStyleHints::mousePressAndHoldIntervalChanged, this, [this](const int interval){ Q_UNUSED(interval); updateToolTip(); }); diff --git a/src/quick/quickstandardminimizebutton.cpp b/src/quick/quickstandardminimizebutton.cpp index 9b5885f..866a8e3 100644 --- a/src/quick/quickstandardminimizebutton.cpp +++ b/src/quick/quickstandardminimizebutton.cpp @@ -23,7 +23,8 @@ */ #include "quickstandardminimizebutton_p.h" -#include "framelessquickutils.h" +#include +#include #include #include #include @@ -51,7 +52,7 @@ QuickStandardMinimizeButton::~QuickStandardMinimizeButton() = default; void QuickStandardMinimizeButton::updateForeground() { - const bool dark = (FramelessQuickUtils::darkModeEnabled() || FramelessQuickUtils::titleBarColorized()); + const bool dark = (Utils::shouldAppsUseDarkMode() || Utils::isTitleBarColorized()); const auto url = QUrl(dark ? kDarkUrl : kLightUrl); initResource(); m_image->setSource(url); @@ -62,7 +63,7 @@ void QuickStandardMinimizeButton::updateBackground() static constexpr const auto button = SystemButtonType::Minimize; const ButtonState state = (isPressed() ? ButtonState::Pressed : ButtonState::Hovered); const bool visible = (isHovered() || isPressed()); - m_backgroundItem->setColor(FramelessQuickUtils::getSystemButtonBackgroundColor(button, state)); + m_backgroundItem->setColor(Utils::calculateSystemButtonBackgroundColor(button, state)); m_backgroundItem->setVisible(visible); } @@ -85,9 +86,7 @@ void QuickStandardMinimizeButton::initialize() m_image.reset(new QQuickImage(m_contentItem.data())); const auto imageAnchors = new QQuickAnchors(m_image.data(), m_image.data()); imageAnchors->setCenterIn(m_contentItem.data()); - const FramelessQuickUtils * const utils = FramelessQuickUtils::instance(); - connect(utils, &FramelessQuickUtils::darkModeEnabledChanged, this, &QuickStandardMinimizeButton::updateForeground); - connect(utils, &FramelessQuickUtils::titleBarColorizedChanged, this, &QuickStandardMinimizeButton::updateForeground); + connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, &QuickStandardMinimizeButton::updateForeground); m_backgroundItem.reset(new QQuickRectangle(this)); QQuickPen * const border = m_backgroundItem->border(); @@ -98,7 +97,7 @@ void QuickStandardMinimizeButton::initialize() m_tooltip = qobject_cast(qmlAttachedPropertiesObject(this)); m_tooltip->setText(tr("Minimize")); - connect(QGuiApplication::styleHints(), &QStyleHints::mousePressAndHoldIntervalChanged, this, [this](int interval){ + connect(QGuiApplication::styleHints(), &QStyleHints::mousePressAndHoldIntervalChanged, this, [this](const int interval){ Q_UNUSED(interval); updateToolTip(); }); diff --git a/src/quick/quickstandardtitlebar.cpp b/src/quick/quickstandardtitlebar.cpp index 12963ea..e2ee483 100644 --- a/src/quick/quickstandardtitlebar.cpp +++ b/src/quick/quickstandardtitlebar.cpp @@ -26,7 +26,8 @@ #include "quickstandardminimizebutton_p.h" #include "quickstandardmaximizebutton_p.h" #include "quickstandardclosebutton_p.h" -#include "framelessquickutils.h" +#include +#include #include #include #include @@ -140,11 +141,16 @@ void QuickStandardTitleBar::updateTitleBarColor() QColor backgroundColor = {}; QColor foregroundColor = {}; if (m_active) { - if (FramelessQuickUtils::titleBarColorized()) { - backgroundColor = FramelessQuickUtils::systemAccentColor(); + if (Utils::isTitleBarColorized()) { +#ifdef Q_OS_WINDOWS + backgroundColor = Utils::getDwmColorizationColor(); +#endif +#ifdef Q_OS_MACOS + backgroundColor = Utils::getControlsAccentColor(); +#endif foregroundColor = kDefaultWhiteColor; } else { - if (FramelessQuickUtils::darkModeEnabled()) { + if (Utils::shouldAppsUseDarkMode()) { backgroundColor = kDefaultBlackColor; foregroundColor = kDefaultWhiteColor; } else { @@ -153,8 +159,8 @@ void QuickStandardTitleBar::updateTitleBarColor() } } } else { - if (FramelessQuickUtils::darkModeEnabled()) { - backgroundColor = FramelessQuickUtils::defaultSystemDarkColor(); + if (Utils::shouldAppsUseDarkMode()) { + backgroundColor = kDefaultSystemDarkColor; } else { backgroundColor = kDefaultWhiteColor; } @@ -169,7 +175,7 @@ void QuickStandardTitleBar::initialize() QQuickPen * const _border = border(); _border->setWidth(0.0); _border->setColor(kDefaultTransparentColor); - setHeight(FramelessQuickUtils::titleBarHeight()); + setHeight(kDefaultTitleBarHeight); m_label.reset(new QQuickLabel(this)); QFont f = m_label->font(); @@ -185,10 +191,7 @@ void QuickStandardTitleBar::initialize() m_maxBtn.reset(new QuickStandardMaximizeButton(m_row.data())); m_closeBtn.reset(new QuickStandardCloseButton(m_row.data())); - const FramelessQuickUtils * const utils = FramelessQuickUtils::instance(); - connect(utils, &FramelessQuickUtils::darkModeEnabledChanged, this, &QuickStandardTitleBar::updateTitleBarColor); - connect(utils, &FramelessQuickUtils::systemAccentColorChanged, this, &QuickStandardTitleBar::updateTitleBarColor); - connect(utils, &FramelessQuickUtils::titleBarColorizedChanged, this, &QuickStandardTitleBar::updateTitleBarColor); + connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, &QuickStandardTitleBar::updateTitleBarColor); connect(this, &QuickStandardTitleBar::activeChanged, this, &QuickStandardTitleBar::updateTitleBarColor); connect(m_label.data(), &QQuickLabel::textChanged, this, &QuickStandardTitleBar::titleChanged); connect(m_maxBtn.data(), &QuickStandardMaximizeButton::maximizedChanged, this, &QuickStandardTitleBar::maximizedChanged); diff --git a/src/widgets/framelesswidgetshelper.cpp b/src/widgets/framelesswidgetshelper.cpp index a9fd0de..9da0246 100644 --- a/src/widgets/framelesswidgetshelper.cpp +++ b/src/widgets/framelesswidgetshelper.cpp @@ -267,27 +267,28 @@ void FramelessWidgetsHelper::paintEventHandler(QPaintEvent *event) void FramelessWidgetsHelper::mouseMoveEventHandler(QMouseEvent *event) { +#ifdef Q_OS_WINDOWS Q_ASSERT(event); if (!event) { return; } - if (m_settings.options & Option::DisableDragging) { - return; - } -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - const QPoint scenePos = event->scenePosition().toPoint(); - const QPoint globalPos = event->globalPosition().toPoint(); + doStartSystemMove2(event); #else - const QPoint scenePos = event->windowPos().toPoint(); - const QPoint globalPos = event->screenPos().toPoint(); + Q_UNUSED(event); #endif - if (shouldIgnoreMouseEvents(scenePos)) { +} + +void FramelessWidgetsHelper::mousePressEventHandler(QMouseEvent *event) +{ +#ifdef Q_OS_WINDOWS + Q_UNUSED(event); +#else + Q_ASSERT(event); + if (!event) { return; } - if (!isInTitleBarDraggableArea(scenePos)) { - return; - } - startSystemMove2(globalPos); + doStartSystemMove2(event); +#endif } void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event) @@ -661,6 +662,31 @@ bool FramelessWidgetsHelper::shouldIgnoreMouseEvents(const QPoint &pos) const return (isNormal() && withinFrameBorder); } +void FramelessWidgetsHelper::doStartSystemMove2(QMouseEvent *event) +{ + Q_ASSERT(event); + if (!event) { + return; + } + if (m_settings.options & Option::DisableDragging) { + return; + } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + const QPoint scenePos = event->scenePosition().toPoint(); + const QPoint globalPos = event->globalPosition().toPoint(); +#else + const QPoint scenePos = event->windowPos().toPoint(); + const QPoint globalPos = event->screenPos().toPoint(); +#endif + if (shouldIgnoreMouseEvents(scenePos)) { + return; + } + if (!isInTitleBarDraggableArea(scenePos)) { + return; + } + startSystemMove2(globalPos); +} + void FramelessWidgetsHelper::updateContentsMargins() { #ifdef Q_OS_WINDOWS @@ -810,10 +836,17 @@ bool FramelessWidgetsHelper::eventFilter(QObject *object, QEvent *event) const auto paintEvent = static_cast(event); paintEventHandler(paintEvent); } break; +#ifdef Q_OS_WINDOWS case QEvent::MouseMove: { const auto mouseEvent = static_cast(event); mouseMoveEventHandler(mouseEvent); } break; +#else + case QEvent::MouseButtonPress: { + const auto mouseEvent = static_cast(event); + mousePressEventHandler(mouseEvent); + } break; +#endif case QEvent::MouseButtonRelease: { const auto mouseEvent = static_cast(event); mouseReleaseEventHandler(mouseEvent);