examples/mainwindow/mainwindow.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/core/contexts/abstractwindowcontext.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/core/contexts/abstractwindowcontext_p.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/core/contexts/cocoawindowcontext.mm | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/core/contexts/cocoawindowcontext_p.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/core/qwkglobal.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/core/windowagentbase.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/quick/quickwindowagent.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/quick/quickwindowagent.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/quick/quickwindowagent_mac.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/widgets/widgetwindowagent.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/widgets/widgetwindowagent_mac.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
examples/mainwindow/mainwindow.cpp
@@ -289,6 +289,13 @@ #endif windowAgent->setHitTestVisible(menuBar, true); #ifdef Q_OS_MAC windowAgent->setSystemButtonAreaCallback([](const QSize &size) { static constexpr const int width = 75; return QRect(QPoint(size.width() - width, 0), QSize(width, size.height())); // }); #endif setMenuWidget(windowBar); // 3. Adds simulated mouse events to the title bar buttons src/core/contexts/abstractwindowcontext.cpp
@@ -120,8 +120,9 @@ } #ifdef Q_OS_MAC void AbstractWindowContext::setSystemButtonArea(const QRect &rect) { m_systemButtonArea = rect; void AbstractWindowContext::setSystemButtonAreaCallback(const ScreenRectCallback &callback) { m_systemButtonAreaCallback = callback; virtual_hook(SystemButtonAreaChangedHook, nullptr); } #endif src/core/contexts/abstractwindowcontext_p.h
@@ -50,8 +50,8 @@ bool setTitleBar(QObject *obj); #ifdef Q_OS_MAC inline QRect systemButtonArea() const; void setSystemButtonArea(const QRect &rect); inline ScreenRectCallback systemButtonAreaCallback() const; void setSystemButtonAreaCallback(const ScreenRectCallback &callback); #endif bool isInSystemButtons(const QPoint &pos, WindowAgentBase::SystemButton *button) const; @@ -88,7 +88,7 @@ QSet<const QObject *> m_hitTestVisibleItems; #ifdef Q_OS_MAC QRect m_systemButtonArea; ScreenRectCallback m_systemButtonAreaCallback; #endif QObject *m_titleBar{}; @@ -126,8 +126,8 @@ } #ifdef Q_OS_MAC inline QRect AbstractWindowContext::systemButtonArea() const { return m_systemButtonArea; inline ScreenRectCallback AbstractWindowContext::systemButtonAreaCallback() const { return m_systemButtonAreaCallback; } #endif src/core/contexts/cocoawindowcontext.mm
@@ -10,6 +10,9 @@ #include "qwkglobal_p.h" #include "systemwindow_p.h" // https://forgetsou.github.io/2020/11/06/macos%E5%BC%80%E5%8F%91-%E5%85%B3%E9%97%AD-%E6%9C%80%E5%B0%8F%E5%8C%96-%E5%85%A8%E5%B1%8F%E5%B1%85%E4%B8%AD%E5%A4%84%E7%90%86(%E4%BB%BFMac%20QQ)/ // https://nyrra33.com/2019/03/26/changing-titlebars-height/ namespace QWK { struct NSWindowProxy; @@ -24,12 +27,16 @@ struct QWK_NSWindowDelegate { public: enum NSEventType { WillEnterFullScreen, DidEnterFullScreen, WillExitFullScreen, DidExitFullScreen, DidResize, }; virtual ~QWK_NSWindowDelegate() = default; virtual void windowWillEnterFullScreen(){}; virtual void windowDidEnterFullScreen(){}; virtual void windowWillExitFullScreen(){}; virtual void windowDidExitFullScreen(){}; virtual void windowDidResize(){}; virtual void windowEvent(NSEventType eventType) = 0; }; // @@ -77,35 +84,40 @@ - (void)windowWillEnterFullScreen:(NSNotification *)notification { auto nswindow = reinterpret_cast<NSWindow *>(notification.object); if (auto proxy = QWK::g_proxyIndexes->value(nswindow)) { reinterpret_cast<QWK_NSWindowDelegate *>(proxy)->windowWillEnterFullScreen(); reinterpret_cast<QWK_NSWindowDelegate *>(proxy)->windowEvent( QWK_NSWindowDelegate::WillEnterFullScreen); } } - (void)windowDidEnterFullScreen:(NSNotification *)notification { auto nswindow = reinterpret_cast<NSWindow *>(notification.object); if (auto proxy = QWK::g_proxyIndexes->value(nswindow)) { reinterpret_cast<QWK_NSWindowDelegate *>(proxy)->windowDidEnterFullScreen(); reinterpret_cast<QWK_NSWindowDelegate *>(proxy)->windowEvent( QWK_NSWindowDelegate::DidEnterFullScreen); } } - (void)windowWillExitFullScreen:(NSNotification *)notification { auto nswindow = reinterpret_cast<NSWindow *>(notification.object); if (auto proxy = QWK::g_proxyIndexes->value(nswindow)) { reinterpret_cast<QWK_NSWindowDelegate *>(proxy)->windowWillExitFullScreen(); reinterpret_cast<QWK_NSWindowDelegate *>(proxy)->windowEvent( QWK_NSWindowDelegate::WillExitFullScreen); } } - (void)windowDidExitFullScreen:(NSNotification *)notification { auto nswindow = reinterpret_cast<NSWindow *>(notification.object); if (auto proxy = QWK::g_proxyIndexes->value(nswindow)) { reinterpret_cast<QWK_NSWindowDelegate *>(proxy)->windowDidExitFullScreen(); reinterpret_cast<QWK_NSWindowDelegate *>(proxy)->windowEvent( QWK_NSWindowDelegate::DidExitFullScreen); } } - (void)windowDidResize:(NSNotification *)notification { auto nswindow = reinterpret_cast<NSWindow *>(notification.object); if (auto proxy = QWK::g_proxyIndexes->value(nswindow)) { reinterpret_cast<QWK_NSWindowDelegate *>(proxy)->windowDidResize(); reinterpret_cast<QWK_NSWindowDelegate *>(proxy)->windowEvent( QWK_NSWindowDelegate::DidResize); } } @@ -134,38 +146,43 @@ } // Delegate void windowWillEnterFullScreen() override { } void windowEvent(NSEventType eventType) override { switch (eventType) { case WillExitFullScreen: { if (!screenRectCallback || !systemButtonVisible) return; void windowDidEnterFullScreen() override { } // The system buttons will stuck at their default positions when the // exit-fullscreen animation is running, we need to hide them until the // animation finishes for (const auto &button : systemButtons()) { button.hidden = true; } break; } void windowWillExitFullScreen() override { if (systemButtonRect.isEmpty() || !systemButtonVisible) return; case DidExitFullScreen: { if (!screenRectCallback || !systemButtonVisible) return; // The system buttons will stuck at their default positions when the exit-fullscreen // animation is running, we need to hide them until the animation finishes for (const auto &button : systemButtons()) { button.hidden = true; for (const auto &button : systemButtons()) { button.hidden = false; } updateSystemButtonRect(); break; } case DidResize: { if (!screenRectCallback || !systemButtonVisible) { return; } updateSystemButtonRect(); break; } default: break; } } void windowDidExitFullScreen() override { if (systemButtonRect.isEmpty() || !systemButtonVisible) return; for (const auto &button : systemButtons()) { button.hidden = false; } updateSystemButtonRect(); } void windowDidResize() override { if (systemButtonRect.isEmpty() || !systemButtonVisible) { return; } updateSystemButtonRect(); } // System buttons visibility @@ -175,35 +192,42 @@ button.hidden = !visible; } if (systemButtonRect.isEmpty() || !visible) { if (!screenRectCallback || !visible) { return; } updateSystemButtonRect(); } // System buttons area void setSystemButtonRect(const QRect &rect) { systemButtonRect = rect; void setScreenRectCallback(const ScreenRectCallback &callback) { screenRectCallback = callback; if (rect.isEmpty() || !systemButtonVisible) { if (!callback || !systemButtonVisible) { return; } updateSystemButtonRect(); } void updateSystemButtonRect() { // https://forgetsou.github.io/2020/11/06/macos%E5%BC%80%E5%8F%91-%E5%85%B3%E9%97%AD-%E6%9C%80%E5%B0%8F%E5%8C%96-%E5%85%A8%E5%B1%8F%E5%B1%85%E4%B8%AD%E5%A4%84%E7%90%86(%E4%BB%BFMac%20QQ)/ const auto &buttons = systemButtons(); const auto &leftButton = buttons[0]; const auto &midButton = buttons[1]; const auto &rightButton = buttons[2]; auto titlebar = rightButton.superview; int titlebarHeight = titlebar.frame.size.height; auto spacing = midButton.frame.origin.x - leftButton.frame.origin.x; auto width = midButton.frame.size.width; auto height = midButton.frame.size.height; QPoint center = systemButtonRect.center(); auto viewSize = nswindow.contentView ? nswindow.contentView.frame.size : nswindow.frame.size; QPoint center = screenRectCallback(QSize(viewSize.width, titlebarHeight)).center(); // The origin of the NSWindow coordinate system is in the lower left corner, we // do the necessary transformations center.ry() = titlebarHeight - center.y(); // Mid button NSPoint centerOrigin = { @@ -232,6 +256,11 @@ NSButton *minimizeBtn = [nswindow standardWindowButton:NSWindowMiniaturizeButton]; NSButton *zoomBtn = [nswindow standardWindowButton:NSWindowZoomButton]; return {closeBtn, minimizeBtn, zoomBtn}; } inline int titleBarHeight() const { NSButton *closeBtn = [nswindow standardWindowButton:NSWindowCloseButton]; return closeBtn.superview.frame.size.height; } // Blur effect @@ -293,7 +322,7 @@ nswindow.titlebarAppearsTransparent = (visible ? NO : YES); nswindow.titleVisibility = (visible ? NSWindowTitleVisible : NSWindowTitleHidden); nswindow.hasShadow = YES; nswindow.showsToolbarButton = NO; // nswindow.showsToolbarButton = NO; nswindow.movableByWindowBackground = NO; nswindow.movable = NO; // This line causes the window in the wrong position when // become fullscreen. @@ -437,7 +466,7 @@ NSWindow *nswindow = nil; bool systemButtonVisible = true; QRect systemButtonRect; ScreenRectCallback screenRectCallback; static inline QWK_NSWindowObserver *windowObserver = nil; @@ -638,7 +667,7 @@ void CocoaWindowContext::virtual_hook(int id, void *data) { switch (id) { case SystemButtonAreaChangedHook: { ensureWindowProxy(windowId)->setSystemButtonRect(m_systemButtonArea); ensureWindowProxy(windowId)->setScreenRectCallback(m_systemButtonAreaCallback); return; } @@ -648,6 +677,15 @@ AbstractWindowContext::virtual_hook(id, data); } QVariant CocoaWindowContext::windowAttribute(const QString &key) const { if (key == QStringLiteral("title-bar-height")) { if (!m_windowHandle) return 0; return ensureWindowProxy(windowId)->titleBarHeight(); } return AbstractWindowContext::windowAttribute(key); } void CocoaWindowContext::winIdChanged() { // If the original window id is valid, remove all resources related if (windowId) { src/core/contexts/cocoawindowcontext_p.h
@@ -23,6 +23,8 @@ QString key() const override; void virtual_hook(int id, void *data) override; QVariant windowAttribute(const QString &key) const override; protected: void winIdChanged() override; bool windowAttributeChanged(const QString &key, const QVariant &attribute, src/core/qwkglobal.h
@@ -1,6 +1,8 @@ #ifndef QWKGLOBAL_H #define QWKGLOBAL_H #include <functional> #include <QtCore/QEvent> #include <QtGui/QtEvents> @@ -28,4 +30,10 @@ # define QWINDOWKIT_CONFIG(feature) ((1 / QWINDOWKIT_##feature) == 1) #endif namespace QWK { using ScreenRectCallback = std::function<QRect(const QSize &)>; } #endif // QWKGLOBAL_H src/core/windowagentbase.cpp
@@ -102,6 +102,8 @@ \li \c blur-effect: You can specify a string value, "dark" to enable dark mode, "light" to set enable mode, "none" to disable. You can also specify a boolean value, \c true to enable current theme mode, \c false to disable. \li \c title-bar-height: Returns the system title bar height, the system button display area will be limited to this height. (Readonly) */ bool WindowAgentBase::setWindowAttribute(const QString &key, const QVariant &attribute) { Q_D(WindowAgentBase); src/quick/quickwindowagent.cpp
@@ -59,6 +59,9 @@ if (!d->context->setTitleBar(item)) { return; } #ifdef Q_OS_MAC setSystemButtonArea(nullptr); #endif Q_EMIT titleBarWidgetChanged(item); } src/quick/quickwindowagent.h
@@ -31,8 +31,12 @@ Q_INVOKABLE void setHitTestVisible(const QQuickItem *item, bool visible = true); #ifdef Q_OS_MAC // The system button area APIs are experimental, may be changed in the future. Q_INVOKABLE QQuickItem *systemButtonArea() const; Q_INVOKABLE void setSystemButtonArea(QQuickItem *item); Q_INVOKABLE ScreenRectCallback systemButtonAreaCallback() const; Q_INVOKABLE void setSystemButtonAreaCallback(const ScreenRectCallback &callback); #endif Q_SIGNALS: src/quick/quickwindowagent_mac.cpp
@@ -27,11 +27,14 @@ &SystemButtonAreaItemHandler::updateSystemButtonArea); connect(item, &QQuickItem::heightChanged, this, &SystemButtonAreaItemHandler::updateSystemButtonArea); updateSystemButtonArea(); ctx->setSystemButtonAreaCallback([item](const QSize &) { return QRectF(item->mapToScene(QPointF(0, 0)), item->size()).toRect(); // }); } void SystemButtonAreaItemHandler::updateSystemButtonArea() { ctx->setSystemButtonArea(QRectF(item->mapToScene(QPointF(0, 0)), item->size()).toRect()); ctx->virtual_hook(AbstractWindowContext::SystemButtonAreaChangedHook, nullptr); } QQuickItem *QuickWindowAgent::systemButtonArea() const { @@ -48,10 +51,21 @@ d->systemButtonAreaItem = item; if (!item) { d->systemButtonAreaItemHandler.reset(); ctx->setSystemButtonArea({}); ctx->setSystemButtonAreaCallback({}); return; } d->systemButtonAreaItemHandler = std::make_unique<SystemButtonAreaItemHandler>(item, ctx); } ScreenRectCallback QuickWindowAgent::systemButtonAreaCallback() const { Q_D(const QuickWindowAgent); return d->systemButtonAreaItem ? nullptr : d->context->systemButtonAreaCallback(); } void QuickWindowAgent::setSystemButtonAreaCallback(const ScreenRectCallback &callback) { Q_D(QuickWindowAgent); setSystemButtonArea(nullptr); d->context->setSystemButtonAreaCallback(callback); } } src/widgets/widgetwindowagent.h
@@ -27,8 +27,12 @@ void setSystemButton(SystemButton button, QWidget *w); #ifdef Q_OS_MAC // The system button area APIs are experimental, may be changed in the future. QWidget *systemButtonArea() const; void setSystemButtonArea(QWidget *widget); ScreenRectCallback systemButtonAreaCallback() const; void setSystemButtonAreaCallback(const ScreenRectCallback &callback); #endif bool isHitTestVisible(const QWidget *w) const; src/widgets/widgetwindowagent_mac.cpp
@@ -14,6 +14,9 @@ QObject *parent = nullptr) : QObject(parent), widget(widget), ctx(ctx) { widget->installEventFilter(this); ctx->setSystemButtonAreaCallback([widget](const QSize &) { return getWidgetSceneRect(widget); // }); } ~SystemButtonAreaWidgetEventFilter() override = default; @@ -23,7 +26,7 @@ switch (event->type()) { case QEvent::Move: case QEvent::Resize: { ctx->setSystemButtonArea(getWidgetSceneRect(widget)); ctx->virtual_hook(AbstractWindowContext::SystemButtonAreaChangedHook, nullptr); break; } @@ -49,6 +52,8 @@ /*! Sets the widget that acts as the system button area. The system button will be centered in its area, it is recommended to place the widget in a layout and set a fixed size policy. The system button will be visible in the system title bar area. */ void WidgetWindowAgent::setSystemButtonArea(QWidget *widget) { Q_D(WidgetWindowAgent); @@ -58,13 +63,32 @@ auto ctx = d->context.get(); d->systemButtonAreaWidget = widget; if (!widget) { d->context->setSystemButtonAreaCallback({}); d->systemButtonAreaWidgetEventFilter.reset(); ctx->setSystemButtonArea({}); return; } d->systemButtonAreaWidgetEventFilter = std::make_unique<SystemButtonAreaWidgetEventFilter>(widget, ctx); ctx->setSystemButtonArea(getWidgetSceneRect(widget)); } /*! Returns the the system button area callback. */ ScreenRectCallback WidgetWindowAgent::systemButtonAreaCallback() const { Q_D(const WidgetWindowAgent); return d->systemButtonAreaWidget ? nullptr : d->context->systemButtonAreaCallback(); } /*! Sets the the system button area callback, the \c size of the callback is the native title bar size. The system button position will be updated when the window resizes. */ void WidgetWindowAgent::setSystemButtonAreaCallback(const ScreenRectCallback &callback) { Q_D(WidgetWindowAgent); setSystemButtonArea(nullptr); d->context->setSystemButtonAreaCallback(callback); } }