diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 98c74c07f3..533ad3444b 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -226,6 +226,8 @@ public: // for QNSView bool alwaysShowToolWindow() const; void removeMonitor(); + void handleGeometryChange(); + NSView *m_view; QCocoaNSWindow *m_nsWindow; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 6431480116..af9f6da37c 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -558,7 +558,7 @@ void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags) void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) { if (isContentView()) { - // While setting style mask we can have -updateGeometry calls on a content + // While setting style mask we can have handleGeometryChange calls on a content // view with null geometry, reporting an invalid coordinates as a result. m_inSetStyleMask = true; m_view.window.styleMask = windowStyleMask(flags); @@ -837,7 +837,7 @@ void QCocoaWindow::windowWillMove() void QCocoaWindow::windowDidMove() { - [qnsview_cast(m_view) updateGeometry]; + handleGeometryChange(); // Moving a window might bring it out of maximized state reportCurrentWindowState(); @@ -848,7 +848,7 @@ void QCocoaWindow::windowDidResize() if (!isContentView()) return; - [qnsview_cast(m_view) updateGeometry]; + handleGeometryChange(); if (!m_view.inLiveResize) reportCurrentWindowState(); @@ -856,7 +856,7 @@ void QCocoaWindow::windowDidResize() void QCocoaWindow::viewDidChangeFrame() { - [qnsview_cast(m_view) updateGeometry]; + handleGeometryChange(); } /*! @@ -1023,6 +1023,55 @@ bool QCocoaWindow::windowShouldClose() return accepted; } +// ----------------------------- QPA forwarding ----------------------------- + +void QCocoaWindow::handleGeometryChange() +{ + // Don't send geometry change event to Qt unless it's ready to handle events + if (m_inConstructor) + return; + + // Don't send the geometry change if the QWindow is designated to be + // embedded in a foreign view hierarchy but has not actually been + // embedded yet - it's too early. + if (m_viewIsToBeEmbedded && !m_viewIsEmbedded) + return; + + // It can happen that the current NSWindow is nil (if we are changing styleMask + // from/to borderless, and the content view is being re-parented), which results + // in invalid coordinates. + if (m_inSetStyleMask && !m_view.window) + return; + + QRect newGeometry; + + if (isContentView()) { + // Top level window, get window rect and flip y + NSRect rect = m_view.frame; + NSRect windowRect = m_view.window.frame; + newGeometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height); + } else if (m_viewIsToBeEmbedded) { + // Embedded child window, use the frame rect ### merge with case below + newGeometry = QRectF::fromCGRect(NSRectToCGRect(m_view.bounds)).toRect(); + } else { + // Child window, use the frame rect + newGeometry = QRectF::fromCGRect(NSRectToCGRect(m_view.frame)).toRect(); + } + + qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleGeometryChange" << window() + << "current" << geometry() << "new" << newGeometry; + + QWindowSystemInterface::handleGeometryChange(window(), newGeometry); + updateExposedGeometry(); + + // Guard against processing window system events during QWindow::setGeometry + // calls, which Qt and Qt applications do not expect. + if (!m_inSetGeometry) + QWindowSystemInterface::flushWindowSystemEvents(); + else if (newGeometry.size() != geometry().size()) + [qnsview_cast(m_view) clearBackingStore]; +} + // -------------------------------------------------------------------------- bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 5d25063661..cdcc9719f6 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -95,12 +95,12 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); - (void)setQCocoaGLContext:(QCocoaGLContext *)context; #endif - (void)flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset; +- (void)clearBackingStore; - (void)clearBackingStore:(QCocoaBackingStore *)backingStore; - (void)setMaskRegion:(const QRegion *)region; - (void)invalidateWindowShadowIfNeeded; - (void)drawRect:(NSRect)dirtyRect; - (void)drawBackingStoreUsingCoreGraphics:(NSRect)dirtyRect; -- (void)updateGeometry; - (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification; - (void)viewDidHide; - (void)viewDidUnhide; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 20d90f501e..49af4834b9 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -274,56 +274,6 @@ static QTouchDevice *touchDevice = 0; return focusWindow; } -- (void)updateGeometry -{ - if (!m_platformWindow) - return; - - QRect geometry; - - if (m_platformWindow->isContentView()) { - // top level window, get window rect and flip y. - NSRect rect = [self frame]; - NSRect windowRect = [[self window] frame]; - geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height); - } else if (m_platformWindow->m_viewIsToBeEmbedded) { - // embedded child window, use the frame rect ### merge with case below - geometry = QRectF::fromCGRect(NSRectToCGRect([self bounds])).toRect(); - } else { - // child window, use the frame rect - geometry = QRectF::fromCGRect(NSRectToCGRect([self frame])).toRect(); - } - - const bool isResize = geometry.size() != m_platformWindow->geometry().size(); - - // It can happen that self.window is nil (if we are changing - // styleMask from/to borderless and content view is being re-parented) - // - this results in an invalid coordinates. - if (m_platformWindow->m_inSetStyleMask && !self.window) - return; - - qCDebug(lcQpaCocoaWindow) << "[QNSView udpateGeometry:]" << m_platformWindow->window() - << "current" << m_platformWindow->geometry() << "new" << geometry; - - // Don't send the geometry change if the QWindow is designated to be - // embedded in a foreign view hiearchy but has not actually been - // embedded yet - it's too early. - if (m_platformWindow->m_viewIsToBeEmbedded && !m_platformWindow->m_viewIsEmbedded) - return; - - // Send a geometry change event to Qt, if it's ready to handle events - if (!m_platformWindow->m_inConstructor) { - QWindowSystemInterface::handleGeometryChange(m_platformWindow->window(), geometry); - m_platformWindow->updateExposedGeometry(); - // Guard against processing window system events during QWindow::setGeometry - // calles, which Qt and Qt applications do not excpect. - if (!m_platformWindow->m_inSetGeometry) - QWindowSystemInterface::flushWindowSystemEvents(); - else if (isResize) - m_backingStore = 0; - } -} - - (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification { Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification) @@ -367,6 +317,11 @@ static QTouchDevice *touchDevice = 0; [self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())]; } +- (void)clearBackingStore +{ + m_backingStore = nullptr; +} + - (void)clearBackingStore:(QCocoaBackingStore *)backingStore { if (backingStore == m_backingStore)