| | |
| | | #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; |
| | |
| | | |
| | | 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; |
| | | }; |
| | | |
| | | // |
| | |
| | | - (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); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // Delegate |
| | | void windowWillEnterFullScreen() override { |
| | | } |
| | | |
| | | void windowDidEnterFullScreen() override { |
| | | } |
| | | |
| | | void windowWillExitFullScreen() override { |
| | | if (systemButtonRect.isEmpty() || !systemButtonVisible) |
| | | void windowEvent(NSEventType eventType) override { |
| | | switch (eventType) { |
| | | case WillExitFullScreen: { |
| | | 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 |
| | | // 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 windowDidExitFullScreen() override { |
| | | if (systemButtonRect.isEmpty() || !systemButtonVisible) |
| | | case DidExitFullScreen: { |
| | | if (!screenRectCallback || !systemButtonVisible) |
| | | return; |
| | | |
| | | for (const auto &button : systemButtons()) { |
| | | button.hidden = false; |
| | | } |
| | | updateSystemButtonRect(); |
| | | break; |
| | | } |
| | | |
| | | void windowDidResize() override { |
| | | if (systemButtonRect.isEmpty() || !systemButtonVisible) { |
| | | case DidResize: { |
| | | if (!screenRectCallback || !systemButtonVisible) { |
| | | return; |
| | | } |
| | | updateSystemButtonRect(); |
| | | break; |
| | | } |
| | | |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // System buttons visibility |
| | |
| | | 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 = { |
| | |
| | | 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 |
| | |
| | | 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. |
| | |
| | | NSWindow *nswindow = nil; |
| | | |
| | | bool systemButtonVisible = true; |
| | | QRect systemButtonRect; |
| | | ScreenRectCallback screenRectCallback; |
| | | |
| | | static inline QWK_NSWindowObserver *windowObserver = nil; |
| | | |
| | |
| | | void CocoaWindowContext::virtual_hook(int id, void *data) { |
| | | switch (id) { |
| | | case SystemButtonAreaChangedHook: { |
| | | ensureWindowProxy(windowId)->setSystemButtonRect(m_systemButtonArea); |
| | | ensureWindowProxy(windowId)->setScreenRectCallback(m_systemButtonAreaCallback); |
| | | return; |
| | | } |
| | | |
| | |
| | | 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) { |