From a34b0855f160add13d08c21715dd6853094c23e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 30 Jul 2019 15:41:57 +0200 Subject: macOS: Don't assume NSWindows will be created on the screen we request The user may have assigned the application to start up on a specific display, in which case the window's screen is nil after creation, and the resulting screen will be delivered as a normal screen change once the window is ordered on screen. Fixes: QTBUG-77154 Change-Id: Idade6d833e31654db239243f2430166b5d86eca2 Reviewed-by: Volker Hilsheimer --- src/plugins/platforms/cocoa/qcocoawindow.mm | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'src/plugins/platforms/cocoa/qcocoawindow.mm') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index b609fb3995..ab20c7abe9 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1569,8 +1569,8 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel) } rect.translate(-targetScreen->geometry().topLeft()); - QCocoaScreen *cocoaScreen = static_cast(targetScreen->handle()); - NSRect frame = QCocoaScreen::mapToNative(rect, cocoaScreen); + auto *targetCocoaScreen = static_cast(targetScreen->handle()); + NSRect frame = QCocoaScreen::mapToNative(rect, targetCocoaScreen); // Create NSWindow Class windowClass = shouldBePanel ? [QNSPanel class] : [QNSWindow class]; @@ -1579,15 +1579,22 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel) // Deferring window creation breaks OpenGL (the GL context is // set up before the window is shown and needs a proper window) backing:NSBackingStoreBuffered defer:NO - screen:cocoaScreen->nativeScreen() + screen:targetCocoaScreen->nativeScreen() platformWindow:this]; - Q_ASSERT_X(nsWindow.screen == cocoaScreen->nativeScreen(), "QCocoaWindow", - "Resulting NSScreen should match the requested NSScreen"); + // The resulting screen can be different from the screen requested if + // for example the application has been assigned to a specific display. + auto resultingScreen = QCocoaIntegration::instance()->screenForNSScreen(nsWindow.screen); - if (targetScreen != window()->screen()) { + // But may not always be resolved at this point, in which case we fall back + // to the target screen. The real screen will be delivered as a screen change + // when resolved as part of ordering the window on screen. + if (!resultingScreen) + resultingScreen = targetCocoaScreen; + + if (resultingScreen->screen() != window()->screen()) { QWindowSystemInterface::handleWindowScreenChanged< - QWindowSystemInterface::SynchronousDelivery>(window(), targetScreen); + QWindowSystemInterface::SynchronousDelivery>(window(), resultingScreen->screen()); } static QSharedPointer sharedDelegate([[QNSWindowDelegate alloc] init], -- cgit v1.2.3 From 360000342ab095a936d8f09951e2b19c04c2678a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 30 Jul 2019 16:09:11 +0200 Subject: macOS: Improve screen positioning during window creation Allow AppKit to resolve screen for NSWindow lazily in the case where the position is outside any known screen. And explicitly set the style mask if detecting the corner case of positioning a window in the unavailable space on a rotated screen. In testing the effect of creating the window with a borderless style mask and then updating the mask did not seem to have any visual consequences, but we try to limit this mode just in case by only enabling it in the corner cases we detect. Change-Id: I4b7fcc6755a1ad5ff2683bec79d80a78226edae0 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoawindow.mm | 33 ++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'src/plugins/platforms/cocoa/qcocoawindow.mm') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index ab20c7abe9..d6f88b4f23 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1543,12 +1543,6 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel) Qt::WindowType type = window()->type(); Qt::WindowFlags flags = window()->flags(); - // Note: The macOS window manager has a bug, where if a screen is rotated, it will not allow - // a window to be created within the area of the screen that has a Y coordinate (I quadrant) - // higher than the height of the screen in its non-rotated state, unless the window is - // created with the NSWindowStyleMaskBorderless style mask. - NSWindowStyleMask styleMask = windowStyleMask(flags); - QRect rect = geometry(); QScreen *targetScreen = nullptr; @@ -1559,22 +1553,37 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel) } } + NSWindowStyleMask styleMask = windowStyleMask(flags); + if (!targetScreen) { qCWarning(lcQpaWindow) << "Window position" << rect << "outside any known screen, using primary screen"; targetScreen = QGuiApplication::primaryScreen(); - // AppKit will only reposition a window that's outside the target screen area if - // the window has a title bar. If left out, the window ends up with no screen. - // The style mask will be corrected to the original style mask in setWindowFlags. - styleMask |= NSWindowStyleMaskTitled; + // Unless the window is created as borderless AppKit won't find a position and + // screen that's close to the requested invalid position, and will always place + // the window on the primary screen. + styleMask = NSWindowStyleMaskBorderless; } rect.translate(-targetScreen->geometry().topLeft()); auto *targetCocoaScreen = static_cast(targetScreen->handle()); - NSRect frame = QCocoaScreen::mapToNative(rect, targetCocoaScreen); + NSRect contentRect = QCocoaScreen::mapToNative(rect, targetCocoaScreen); + + if (targetScreen->primaryOrientation() == Qt::PortraitOrientation) { + // The macOS window manager has a bug, where if a screen is rotated, it will not allow + // a window to be created within the area of the screen that has a Y coordinate (I quadrant) + // higher than the height of the screen in its non-rotated state (including a magic padding + // of 24 points), unless the window is created with the NSWindowStyleMaskBorderless style mask. + if (styleMask && (contentRect.origin.y + 24 > targetScreen->geometry().width())) { + qCDebug(lcQpaWindow) << "Window positioned on portrait screen." + << "Adjusting style mask during creation"; + styleMask = NSWindowStyleMaskBorderless; + } + } // Create NSWindow Class windowClass = shouldBePanel ? [QNSPanel class] : [QNSWindow class]; - QCocoaNSWindow *nsWindow = [[windowClass alloc] initWithContentRect:frame + QCocoaNSWindow *nsWindow = [[windowClass alloc] initWithContentRect:contentRect + // Mask will be updated in setWindowFlags if not the final mask styleMask:styleMask // Deferring window creation breaks OpenGL (the GL context is // set up before the window is shown and needs a proper window) -- cgit v1.2.3