diff --git a/examples/mainwindow/TitleBar.ui b/examples/mainwindow/TitleBar.ui index 29686ec..25a5b01 100644 --- a/examples/mainwindow/TitleBar.ui +++ b/examples/mainwindow/TitleBar.ui @@ -126,7 +126,7 @@ - Segoe UI + Arial 9 @@ -283,6 +283,8 @@ + + diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp index ea4461f..47a0e7e 100644 --- a/examples/mainwindow/mainwindow.cpp +++ b/examples/mainwindow/mainwindow.cpp @@ -107,6 +107,7 @@ void MainWindow::showEvent(QShowEvent *event) titleBarWidget->maximizeButton->hide(); titleBarWidget->closeButton->hide(); Utilities::showMacWindowButton(windowHandle()); + Utilities::setStandardWindowButtonsOffset(win, QPoint(0, -5)); #endif // Q_OS_MAC inited = true; } @@ -172,4 +173,4 @@ void MainWindow::paintEvent(QPaintEvent *event) painter.restore(); } } -#endif // Q_OS_MAC \ No newline at end of file +#endif // Q_OS_MAC diff --git a/examples/minimal/flwindow.cpp b/examples/minimal/flwindow.cpp index a32beb3..c5d6a95 100644 --- a/examples/minimal/flwindow.cpp +++ b/examples/minimal/flwindow.cpp @@ -37,6 +37,7 @@ void FLWindow::initFramelessWindow() m_maximizeButton->hide(); m_closeButton->hide(); Utilities::showMacWindowButton(windowHandle()); + Utilities::setStandardWindowButtonsOffset(windowHandle(), QPoint(10, 10)); #endif } @@ -64,6 +65,18 @@ bool FLWindow::nativeEvent(const QByteArray &eventType, void *message, long *res } #endif // Q_OS_WIN +#ifdef Q_OS_MAC +void FLWindow::resizeEvent(QResizeEvent *event) +{ + auto win = windowHandle(); + if (win) { + Utilities::setStandardWindowButtonsOffset(win, QPoint(10, 10)); + } + + QWidget::resizeEvent(event); +} +#endif // Q_OS_MAC + void FLWindow::setupUi() { resize(800, 600); diff --git a/examples/minimal/flwindow.h b/examples/minimal/flwindow.h index 5d1bb19..b599d71 100644 --- a/examples/minimal/flwindow.h +++ b/examples/minimal/flwindow.h @@ -18,6 +18,10 @@ protected: bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; #endif // Q_OS_WIN +#ifdef Q_OS_MAC + void resizeEvent(QResizeEvent *event) override; +#endif // Q_OS_MAC + private: void initFramelessWindow(); void setupUi(); @@ -28,4 +32,4 @@ private: QPushButton *m_minimizeButton = nullptr; QPushButton *m_maximizeButton = nullptr; QPushButton *m_closeButton = nullptr; -}; \ No newline at end of file +}; diff --git a/src/core/framelesshelper.cpp b/src/core/framelesshelper.cpp index 07355d5..59153dd 100644 --- a/src/core/framelesshelper.cpp +++ b/src/core/framelesshelper.cpp @@ -496,7 +496,6 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event) resizeWindow(re->size()); break; } - case QEvent::NonClientAreaMouseMove: case QEvent::MouseMove: { diff --git a/src/core/utilities.h b/src/core/utilities.h index 05b264e..d131665 100644 --- a/src/core/utilities.h +++ b/src/core/utilities.h @@ -76,6 +76,11 @@ FRAMELESSHELPER_API bool unsetMacWindowFrameless(QWindow* w); FRAMELESSHELPER_API bool startMacDrag(QWindow* w, const QPoint& pos); FRAMELESSHELPER_API Qt::MouseButtons getMacMouseButtons(); FRAMELESSHELPER_API bool showMacWindowButton(QWindow *w); +FRAMELESSHELPER_API bool isMacKeyWindow(QWindow *w); +FRAMELESSHELPER_API bool isMacMainWindow(QWindow *w); +FRAMELESSHELPER_API bool makeMacKeyWindow(QWindow *w); +FRAMELESSHELPER_API bool makeMacMainWindow(QWindow *w); +FRAMELESSHELPER_API bool setStandardWindowButtonsOffset(QWindow *w, const QPoint &offset); #endif // Q_OS_MAC } diff --git a/src/core/utilities_macos.mm b/src/core/utilities_macos.mm index 6141aad..12e5ea3 100644 --- a/src/core/utilities_macos.mm +++ b/src/core/utilities_macos.mm @@ -30,6 +30,7 @@ #include #include +#include FRAMELESSHELPER_BEGIN_NAMESPACE @@ -191,6 +192,19 @@ static void __sendEvent(id obj, SEL sel, NSEvent* event) QGuiApplication::processEvents(); } +typedef BOOL (*isFlippedType)(id, SEL); +static isFlippedType gOrigIsFlipped = nullptr; +static BOOL __isFlipped(id obj, SEL sel) +{ + if (!gFlsWindows.contains(reinterpret_cast(obj))) + return true; + + if (gOrigIsFlipped != nullptr) + return gOrigIsFlipped(obj, sel); + + return false; +} + /*! Replace origin method \a origSEL of class \a cls with new one \a newIMP , then return old method as function pointer. @@ -227,6 +241,8 @@ static void overrideNSWindowMethods(NSWindow* window) cls, @selector(canBecomeMainWindow), (IMP) __canBecomeMainWindow); gOrigSendEvent = (sendEventType) replaceMethod( cls, @selector(sendEvent:), (IMP) __sendEvent); + gOrigIsFlipped = (isFlippedType) replaceMethod( + cls, @selector (isFlipped), (IMP) __isFlipped); gNSWindowOverrode = true; } @@ -255,6 +271,9 @@ static void restoreNSWindowMethods(NSWindow* window) restoreMethod(cls, @selector(sendEvent:), (IMP) gOrigSendEvent); gOrigSendEvent = nullptr; + restoreMethod(cls, @selector(isFlipped), (IMP) gOrigIsFlipped); + gOrigIsFlipped = nullptr; + gNSWindowOverrode = false; } @@ -265,9 +284,17 @@ static QHash gQWindowToNSWindow; static NSWindow* getNSWindow(QWindow* w) { NSView* view = reinterpret_cast(w->winId()); - if (view == nullptr) + if (view == nullptr) { + qWarning() << "Unable to get NSView."; return nullptr; - return [view window]; + } + NSWindow* nswindow = [view window]; + if (nswindow == nullptr) { + qWarning() << "Unable to get NSWindow."; + return nullptr; + } + + return nswindow; } bool setMacWindowHook(QWindow* w) @@ -350,10 +377,7 @@ bool unsetMacWindowFrameless(QWindow* w) bool showMacWindowButton(QWindow *w) { - NSView* view = reinterpret_cast(w->winId()); - if (view == nullptr) - return false; - NSWindow* nswindow = [view window]; + NSWindow* nswindow = getNSWindow(w); if (nswindow == nullptr) return false; @@ -367,10 +391,7 @@ bool showMacWindowButton(QWindow *w) bool startMacDrag(QWindow* w, const QPoint& pos) { - NSView* view = reinterpret_cast(w->winId()); - if (view == nullptr) - return false; - NSWindow* nswindow = [view window]; + NSWindow* nswindow = getNSWindow(w); if (nswindow == nullptr) return false; @@ -387,6 +408,85 @@ Qt::MouseButtons getMacMouseButtons() return static_cast((uint)(NSEvent.pressedMouseButtons & Qt::MouseButtonMask)); } +bool isMacKeyWindow(QWindow *w) +{ + NSWindow* nswindow = getNSWindow(w); + if (nswindow == nullptr) { + qWarning() << "Unable to get NSView."; + return false; + } + + return [nswindow isKeyWindow]; +} + +bool isMacMainWindow(QWindow *w) +{ + NSWindow* nswindow = getNSWindow(w); + if (nswindow == nullptr) + return false; + + return [nswindow isMainWindow]; +} + +bool makeMacKeyWindow(QWindow *w) +{ + NSWindow* nswindow = getNSWindow(w); + if (nswindow == nullptr) + return false; + + [nswindow makeKeyWindow]; + return true; +} + +bool makeMacMainWindow(QWindow *w) +{ + NSWindow* nswindow = getNSWindow(w); + if (nswindow == nullptr) + return false; + + [nswindow makeMainWindow]; + return true; +} + +static void setButtonLocation(NSButton * btn, const QPoint &offset, NSView *contentview) +{ + if (btn.superview != contentview) { + [btn.superview willRemoveSubview:btn]; + [btn removeFromSuperview]; + [btn viewWillMoveToSuperview:contentview]; + [contentview addSubview:btn]; + [btn viewDidMoveToSuperview]; + } + + auto frame = btn.frame; + btn.frame = NSMakeRect( + frame.origin.x + offset.x(), + frame.origin.y + offset.y(), + frame.size.width, frame.size.height); +} + +/*! The origin of AppKit coordinate system is bottom-left. */ +bool setStandardWindowButtonsOffset(QWindow *w, const QPoint &offset) +{ + NSWindow* nswindow = getNSWindow(w); + if (nswindow == nullptr) + return false; + + NSView* contentview = nswindow.contentView; + if (contentview == nullptr) + return false; + + auto close = [nswindow standardWindowButton:NSWindowCloseButton]; + auto min = [nswindow standardWindowButton:NSWindowMiniaturizeButton]; + auto zoom = [nswindow standardWindowButton:NSWindowZoomButton]; + + setButtonLocation(close, offset, contentview); + setButtonLocation(min, offset, contentview); + setButtonLocation(zoom, offset, contentview); + + return true; +} + } // namespace Utilities FRAMELESSHELPER_END_NAMESPACE