diff options
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoabackingstore.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaglcontext.mm | 11 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaintegration.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaintegration.mm | 13 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenuloader.mm | 48 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoanativeinterface.mm | 3 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoascreen.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 69 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindowmanager.mm | 3 |
10 files changed, 100 insertions, 53 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 6015257f4e..15e0236107 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -153,7 +153,7 @@ void QNSWindowBackingStore::flush(QWindow *window, const QRegion ®ion, const // context is set up correctly (coordinate system, clipping, etc). Outside // of the normal display cycle there is no focused view, as explained above, // so we have to handle it manually. There's also a corner case inside the - // normal display cycle due to way QWidgetBackingStore composits native child + // normal display cycle due to way QWidgetRepaintManager composits native child // widgets, where we'll get a flush of a native child during the drawRect of // its parent/ancestor, and the parent/ancestor being the one locked by AppKit. // In this case we also need to lock and unlock focus manually. diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 7b124ea517..ba7d12ce30 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -197,8 +197,15 @@ NSOpenGLPixelFormat *QCocoaGLContext::pixelFormatForSurfaceFormat(const QSurface attrs << NSOpenGLPFAStencilSize << format.stencilBufferSize(); if (format.alphaBufferSize() > 0) attrs << NSOpenGLPFAAlphaSize << format.alphaBufferSize(); - if (format.redBufferSize() > 0 && format.greenBufferSize() > 0 && format.blueBufferSize() > 0) { - const int colorSize = format.redBufferSize() + format.greenBufferSize() + format.blueBufferSize(); + + auto rbz = format.redBufferSize(); + auto gbz = format.greenBufferSize(); + auto bbz = format.blueBufferSize(); + if (rbz > 0 || gbz > 0 || bbz > 0) { + auto fallbackSize = qMax(rbz, qMax(gbz, bbz)); + auto colorSize = (rbz > 0 ? rbz : fallbackSize) + + (gbz > 0 ? gbz : fallbackSize) + + (bbz > 0 ? bbz : fallbackSize); attrs << NSOpenGLPFAColorSize << colorSize << NSOpenGLPFAMinimumPolicy; } diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index bfc3bfe9de..0e2656e046 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -124,6 +124,8 @@ public: void beep() const override; + void closePopups(QWindow *forWindow = nullptr); + private Q_SLOTS: void focusWindowChanged(QWindow *); diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 9a2f19c2f2..67ad0b3492 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -487,6 +487,19 @@ void QCocoaIntegration::beep() const NSBeep(); } +void QCocoaIntegration::closePopups(QWindow *forWindow) +{ + for (auto it = m_popupWindowStack.begin(); it != m_popupWindowStack.end();) { + auto *popup = *it; + if (!forWindow || popup->window()->transientParent() == forWindow) { + it = m_popupWindowStack.erase(it); + QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(popup->window()); + } else { + ++it; + } + } +} + void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow) { // Don't revert icon just because we lost focus diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm index da0fc5c6a1..d384078e91 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -59,7 +59,6 @@ NSMenuItem *aboutItem; NSMenuItem *aboutQtItem; NSMenuItem *hideItem; - NSMenuItem *lastAppSpecificItem; NSMenuItem *servicesItem; NSMenuItem *hideAllOthersItem; NSMenuItem *showAllItem; @@ -118,6 +117,9 @@ [appMenu addItem:[NSMenuItem separatorItem]]; // Preferences + // We'll be adding app specific items after this. The macOS HIG state that, + // "In general, a Preferences menu item should be the first app-specific menu item." + // https://developer.apple.com/macos/human-interface-guidelines/menus/menu-bar-menus/ preferencesItem = [[QCocoaNSMenuItem alloc] init]; preferencesItem.title = @"Preferences…"; preferencesItem.keyEquivalent = @","; @@ -126,11 +128,6 @@ preferencesItem.hidden = YES; [appMenu addItem:preferencesItem]; - // We'll be adding app specific items after this. The macOS HIG state that, - // "In general, a Preferences menu item should be the first app-specific menu item." - // https://developer.apple.com/macos/human-interface-guidelines/menus/menu-bar-menus/ - lastAppSpecificItem = preferencesItem; - [appMenu addItem:[NSMenuItem separatorItem]]; // Services item and menu @@ -194,8 +191,6 @@ [showAllItem release]; [quitItem release]; - [lastAppSpecificItem release]; - [super dealloc]; } @@ -272,25 +267,20 @@ // No reason to create the item if it already exists. for (NSMenuItem *item in appMenu.itemArray) if (qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem == platformItem) - return [[item retain] autorelease]; + return item; // Create an App-Specific menu item, insert it into the menu and return // it as an autorelease item. QCocoaNSMenuItem *item; if (platformItem->isSeparator()) - item = [[QCocoaNSMenuItem separatorItemWithPlatformMenuItem:platformItem] retain]; + item = [QCocoaNSMenuItem separatorItemWithPlatformMenuItem:platformItem]; else - item = [[QCocoaNSMenuItem alloc] initWithPlatformMenuItem:platformItem]; - - const auto location = [appMenu indexOfItem:lastAppSpecificItem]; + item = [[[QCocoaNSMenuItem alloc] initWithPlatformMenuItem:platformItem] autorelease]; - if (!lastAppSpecificItem.separatorItem) - [lastAppSpecificItem release]; - lastAppSpecificItem = item; // Keep track of this for later (i.e., don't release it) + const auto location = [self indexOfLastAppSpecificMenuItem]; + [appMenu insertItem:item atIndex:NSInteger(location) + 1]; - [appMenu insertItem:item atIndex:location + 1]; - - return [[item retain] autorelease]; + return item; } - (void)orderFrontStandardAboutPanel:(id)sender @@ -344,8 +334,24 @@ - (NSArray<NSMenuItem *> *)mergeable { // Don't include the quitItem here, since we want it always visible and enabled regardless - // Note that lastAppSpecificItem may be nil, so we can't use @[] here. - return [NSArray arrayWithObjects:preferencesItem, aboutItem, aboutQtItem, lastAppSpecificItem, nil]; + auto items = [NSArray arrayWithObjects:preferencesItem, aboutItem, aboutQtItem, + appMenu.itemArray[[self indexOfLastAppSpecificMenuItem]], nil]; + return items; } +- (NSUInteger)indexOfLastAppSpecificMenuItem +{ + // Either the 'Preferences', which is the first app specific menu item, or something + // else we appended later (thus the reverse order): + const auto location = [appMenu.itemArray indexOfObjectWithOptions:NSEnumerationReverse + passingTest:^BOOL(NSMenuItem *item, NSUInteger, BOOL *) { + if (auto qtItem = qt_objc_cast<QCocoaNSMenuItem*>(item)) + return qtItem != quitItem; + return NO; + }]; + Q_ASSERT(location != NSNotFound); + return location; +} + + @end diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 7979e430ac..9bd19dd07c 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -177,6 +177,9 @@ void *QCocoaNativeInterface::NSPrintInfoForPrintEngine(QPrintEngine *printEngine QPixmap QCocoaNativeInterface::defaultBackgroundPixmapForQWizard() { + // Note: starting with macOS 10.14, the KeyboardSetupAssistant app bundle no + // longer contains the "Background.png" image. This function then returns a + // null pixmap. const int ExpectedImageWidth = 242; const int ExpectedImageHeight = 414; QCFType<CFArrayRef> urls = LSCopyApplicationURLsForBundleIdentifier( diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h index 491af2fe9c..60243b79be 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.h +++ b/src/plugins/platforms/cocoa/qcocoascreen.h @@ -68,6 +68,7 @@ public: qreal devicePixelRatio() const override { return m_devicePixelRatio; } QSizeF physicalSize() const override { return m_physicalSize; } QDpi logicalDpi() const override { return m_logicalDpi; } + QDpi logicalBaseDpi() const override { return m_logicalDpi; } qreal refreshRate() const override { return m_refreshRate; } QString name() const override { return m_name; } QPlatformCursor *cursor() const override { return m_cursor; } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index fef72bc496..1e46cd2dde 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -151,6 +151,7 @@ public: Q_NOTIFICATION_HANDLER(NSWindowDidEndLiveResizeNotification) void windowDidEndLiveResize(); Q_NOTIFICATION_HANDLER(NSWindowDidBecomeKeyNotification) void windowDidBecomeKey(); Q_NOTIFICATION_HANDLER(NSWindowDidResignKeyNotification) void windowDidResignKey(); + Q_NOTIFICATION_HANDLER(NSWindowWillMiniaturizeNotification) void windowWillMiniaturize(); Q_NOTIFICATION_HANDLER(NSWindowDidMiniaturizeNotification) void windowDidMiniaturize(); Q_NOTIFICATION_HANDLER(NSWindowDidDeminiaturizeNotification) void windowDidDeminiaturize(); Q_NOTIFICATION_HANDLER(NSWindowWillEnterFullScreenNotification) void windowWillEnterFullScreen(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 8f3c192745..7621508bdd 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -71,14 +71,6 @@ enum { defaultWindowHeight = 160 }; -static void qt_closePopups() -{ - while (QCocoaWindow *popup = QCocoaIntegration::instance()->popPopupWindow()) { - QWindowSystemInterface::handleCloseEvent(popup->window()); - QWindowSystemInterface::flushWindowSystemEvents(); - } -} - Q_LOGGING_CATEGORY(lcCocoaNotifications, "qt.qpa.cocoa.notifications"); static void qRegisterNotificationCallbacks() @@ -800,6 +792,11 @@ void QCocoaWindow::windowDidExitFullScreen() } } +void QCocoaWindow::windowWillMiniaturize() +{ + QCocoaIntegration::instance()->closePopups(window()); +} + void QCocoaWindow::windowDidMiniaturize() { if (!isContentView()) @@ -1138,7 +1135,7 @@ void QCocoaWindow::viewDidChangeGlobalFrame() void QCocoaWindow::windowWillMove() { // Close any open popups on window move - qt_closePopups(); + QCocoaIntegration::instance()->closePopups(); } void QCocoaWindow::windowDidMove() @@ -1267,7 +1264,7 @@ void QCocoaWindow::windowWillClose() { // Close any open popups on window closing. if (window() && !windowIsPopupType(window()->type())) - qt_closePopups(); + QCocoaIntegration::instance()->closePopups(); } // ----------------------- NSWindowDelegate callbacks ----------------------- @@ -1544,12 +1541,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; @@ -1560,35 +1551,57 @@ 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()); - QCocoaScreen *cocoaScreen = static_cast<QCocoaScreen *>(targetScreen->handle()); - NSRect frame = QCocoaScreen::mapToNative(rect, cocoaScreen); + auto *targetCocoaScreen = static_cast<QCocoaScreen *>(targetScreen->handle()); + 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) 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 = QCocoaScreen::get(nsWindow.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 (targetScreen != window()->screen()) { + if (resultingScreen->screen() != window()->screen()) { QWindowSystemInterface::handleWindowScreenChanged< - QWindowSystemInterface::SynchronousDelivery>(window(), targetScreen); + QWindowSystemInterface::SynchronousDelivery>(window(), resultingScreen->screen()); } static QSharedPointer<QNSWindowDelegate> sharedDelegate([[QNSWindowDelegate alloc] init], diff --git a/src/plugins/platforms/cocoa/qcocoawindowmanager.mm b/src/plugins/platforms/cocoa/qcocoawindowmanager.mm index 879bfaa546..9c45d8c7fc 100644 --- a/src/plugins/platforms/cocoa/qcocoawindowmanager.mm +++ b/src/plugins/platforms/cocoa/qcocoawindowmanager.mm @@ -92,7 +92,8 @@ void QCocoaWindowManager::modalSessionChanged() if (NSApp.modalWindow) { // Lower window to that of the modal windows, but no less nativeWindow.level = NSModalPanelWindowLevel; - [nativeWindow orderBack:nil]; + if ([nativeWindow isVisible]) + [nativeWindow orderBack:nil]; } else { // Restore window's natural window level, whatever that was nativeWindow.level = naturalWindowLevel; |