summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa/qcocoascreen.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoascreen.mm')
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.mm115
1 files changed, 35 insertions, 80 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm
index 6a3172fb19..581ea01fcc 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.mm
+++ b/src/plugins/platforms/cocoa/qcocoascreen.mm
@@ -72,91 +72,33 @@ namespace CoreGraphics {
Q_ENUM_NS(DisplayChange)
}
-NSArray *QCocoaScreen::s_screenConfigurationBeforeUpdate = nil;
+QMacNotificationObserver QCocoaScreen::s_screenParameterObserver;
+CGDisplayReconfigurationCallBack QCocoaScreen::s_displayReconfigurationCallBack = nullptr;
void QCocoaScreen::initializeScreens()
{
updateScreens();
- CGDisplayRegisterReconfigurationCallback([](CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo) {
+ s_displayReconfigurationCallBack = [](CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo) {
Q_UNUSED(userInfo);
- // Displays are reconfigured in batches, and we want to update our screens
- // once a batch ends, so that all the states of the displays are up to date.
- static int displayReconfigurationsInProgress = 0;
-
const bool beforeReconfigure = flags & kCGDisplayBeginConfigurationFlag;
- qCDebug(lcQpaScreen).verbosity(0).nospace() << "Display " << displayId
- << (beforeReconfigure ? " about to reconfigure" : " was ")
- << QFlags<CoreGraphics::DisplayChange>(flags)
- << " with " << displayReconfigurationsInProgress
- << " display configuration(s) in progress";
-
- if (!flags) {
- // CGDisplayRegisterReconfigurationCallback has been observed to be called
- // with flags unset. This seems like a bug. The callback is not paired with
- // a matching "completion" callback either, so we don't know whether to treat
- // it as a begin or end of reconfigure.
- return;
- }
-
- if (beforeReconfigure) {
- if (!displayReconfigurationsInProgress++) {
- // There might have been a screen reconfigure before this that
- // we didn't process yet, so do that now if that's the case.
- updateScreensIfNeeded();
-
- Q_ASSERT(!s_screenConfigurationBeforeUpdate);
- s_screenConfigurationBeforeUpdate = NSScreen.screens;
- qCDebug(lcQpaScreen, "Display reconfigure transaction started"
- " with screen configuration %p", s_screenConfigurationBeforeUpdate);
-
- static void (^tryScreenUpdate)();
- tryScreenUpdate = ^void () {
- qCDebug(lcQpaScreen) << "Attempting screen update from runloop block";
- if (!updateScreensIfNeeded())
- CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, tryScreenUpdate);
- };
- CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, tryScreenUpdate);
- }
- } else {
- Q_ASSERT_X(displayReconfigurationsInProgress, "QCococaScreen",
- "Display configuration transactions are expected to be balanced");
+ qCDebug(lcQpaScreen).verbosity(0) << "Display" << displayId
+ << (beforeReconfigure ? "beginning" : "finished") << "reconfigure"
+ << QFlags<CoreGraphics::DisplayChange>(flags);
- if (!--displayReconfigurationsInProgress) {
- qCDebug(lcQpaScreen) << "Display reconfigure transaction completed";
- // We optimistically update now, in case the NSScreens have changed
- updateScreensIfNeeded();
- }
- }
- }, nullptr);
+ if (!beforeReconfigure)
+ updateScreens();
+ };
+ CGDisplayRegisterReconfigurationCallback(s_displayReconfigurationCallBack, nullptr);
- static QMacNotificationObserver screenParameterObserver(NSApplication.sharedApplication,
+ s_screenParameterObserver = QMacNotificationObserver(NSApplication.sharedApplication,
NSApplicationDidChangeScreenParametersNotification, [&]() {
qCDebug(lcQpaScreen) << "Received screen parameter change notification";
- updateScreensIfNeeded(); // As a last resort we update screens here
+ updateScreens();
});
}
-bool QCocoaScreen::updateScreensIfNeeded()
-{
- if (!s_screenConfigurationBeforeUpdate) {
- qCDebug(lcQpaScreen) << "QScreens have already been updated, all good";
- return true;
- }
-
- if (s_screenConfigurationBeforeUpdate == NSScreen.screens) {
- qCDebug(lcQpaScreen) << "Still waiting for NSScreen configuration change";
- return false;
- }
-
- qCDebug(lcQpaScreen, "NSScreen configuration changed to %p", NSScreen.screens);
- updateScreens();
-
- s_screenConfigurationBeforeUpdate = nil;
- return true;
-}
-
/*
Update the list of available QScreens, and the properties of existing screens.
@@ -239,6 +181,12 @@ void QCocoaScreen::cleanupScreens()
// Remove screens in reverse order to avoid crash in case of multiple screens
for (QScreen *screen : backwards(QGuiApplication::screens()))
static_cast<QCocoaScreen*>(screen->handle())->remove();
+
+ Q_ASSERT(s_displayReconfigurationCallBack);
+ CGDisplayRemoveReconfigurationCallback(s_displayReconfigurationCallBack, nullptr);
+ s_displayReconfigurationCallBack = nullptr;
+
+ s_screenParameterObserver.remove();
}
void QCocoaScreen::remove()
@@ -310,15 +258,18 @@ void QCocoaScreen::update(CGDirectDisplayID displayId)
Q_ASSERT(isOnline());
+ // Some properties are only available via NSScreen
+ NSScreen *nsScreen = nativeScreen();
+ if (!nsScreen) {
+ qCDebug(lcQpaScreen) << "Corresponding NSScreen not yet available. Deferring update";
+ return;
+ }
+
const QRect previousGeometry = m_geometry;
const QRect previousAvailableGeometry = m_availableGeometry;
const QDpi previousLogicalDpi = m_logicalDpi;
const qreal previousRefreshRate = m_refreshRate;
- // Some properties are only available via NSScreen
- NSScreen *nsScreen = nativeScreen();
- Q_ASSERT(nsScreen);
-
// The reference screen for the geometry is always the primary screen
QRectF primaryScreenGeometry = QRectF::fromCGRect(CGDisplayBounds(CGMainDisplayID()));
m_geometry = qt_mac_flip(QRectF::fromCGRect(nsScreen.frame), primaryScreenGeometry).toRect();
@@ -714,13 +665,17 @@ QList<QPlatformScreen*> QCocoaScreen::virtualSiblings() const
QCocoaScreen *QCocoaScreen::get(NSScreen *nsScreen)
{
- if (s_screenConfigurationBeforeUpdate) {
- qCWarning(lcQpaScreen) << "Trying to resolve screen while waiting for screen reconfigure!";
- if (!updateScreensIfNeeded())
- qCWarning(lcQpaScreen) << "Failed to do last minute screen update. Expect crashes.";
+ auto displayId = nsScreen.qt_displayId;
+ auto *cocoaScreen = get(displayId);
+ if (!cocoaScreen) {
+ qCWarning(lcQpaScreen) << "Failed to map" << nsScreen
+ << "to QCocoaScreen. Doing last minute update.";
+ updateScreens();
+ cocoaScreen = get(displayId);
+ if (!cocoaScreen)
+ qCWarning(lcQpaScreen) << "Last minute update failed!";
}
-
- return get(nsScreen.qt_displayId);
+ return cocoaScreen;
}
QCocoaScreen *QCocoaScreen::get(CGDirectDisplayID displayId)