summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm11
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm13
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm48
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.mm3
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm69
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindowmanager.mm3
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 &region, 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;