diff options
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoabackingstore.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoabackingstore.mm | 24 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaeventdispatcher.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm | 31 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaglcontext.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaglcontext.mm | 8 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoahelpers.mm | 5 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaintegration.mm | 19 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenu.h | 4 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenu.mm | 10 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenuitem.mm | 8 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoansmenu.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoatheme.h | 5 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoatheme.mm | 62 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoavulkaninstance.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 20 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview_mouse.mm | 7 |
17 files changed, 125 insertions, 86 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index acddc3ecc8..2398e6351e 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -55,6 +55,7 @@ public: QNSWindowBackingStore(QWindow *window); ~QNSWindowBackingStore(); + void resize(const QSize &size, const QRegion &staticContents) override; void flush(QWindow *, const QRegion &, const QPoint &) override; private: diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index c381f87844..01b4894324 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -71,6 +71,24 @@ QImage::Format QNSWindowBackingStore::format() const return QRasterBackingStore::format(); } +void QNSWindowBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + qCDebug(lcQpaBackingStore) << "Resize requested to" << size; + QRasterBackingStore::resize(size, staticContents); + + // The window shadow rendered by AppKit is based on the shape/content of the + // NSWindow surface. Technically any flush of the backingstore can result in + // a potentially new shape of the window, and would need a shadow invalidation, + // but this is likely too expensive to do at every flush for the few cases where + // clients change the shape dynamically. One case where we do know that the shadow + // likely needs invalidation, if the window has partially transparent content, + // is after a resize, where AppKit's default shadow may be based on the previous + // window content. + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle()); + if (cocoaWindow->isContentView() && !cocoaWindow->isOpaque()) + cocoaWindow->m_needsInvalidateShadow = true; +} + /*! Flushes the given \a region from the specified \a window onto the screen. @@ -217,6 +235,7 @@ void QNSWindowBackingStore::flush(QWindow *window, const QRegion ®ion, const QCocoaWindow *topLevelCocoaWindow = static_cast<QCocoaWindow *>(topLevelWindow->handle()); if (Q_UNLIKELY(topLevelCocoaWindow->m_needsInvalidateShadow)) { + qCDebug(lcQpaBackingStore) << "Invalidating window shadow for" << topLevelCocoaWindow; [topLevelView.window invalidateShadow]; topLevelCocoaWindow->m_needsInvalidateShadow = false; } @@ -382,10 +401,11 @@ void QCALayerBackingStore::ensureBackBuffer() bool QCALayerBackingStore::recreateBackBufferIfNeeded() { - const qreal devicePixelRatio = window()->devicePixelRatio(); + const QCocoaWindow *platformWindow = static_cast<QCocoaWindow *>(window()->handle()); + const qreal devicePixelRatio = platformWindow->devicePixelRatio(); QSize requestedBufferSize = m_requestedSize * devicePixelRatio; - const NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view(); + const NSView *backingStoreView = platformWindow->view(); Q_UNUSED(backingStoreView); auto bufferSizeMismatch = [&](const QSize requested, const QSize actual) { diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index 9771cd0289..69587a24be 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -191,6 +191,7 @@ public: static void waitingObserverCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); static void firstLoopEntry(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info); + bool sendQueuedUserInputEvents(); void processPostedEvents(); }; diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index 84ffadea83..d3bb0711f0 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -377,16 +377,9 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) NSEvent* event = nil; // First, send all previously excluded input events, if any: - if (!excludeUserEvents) { - while (!d->queuedUserInputEvents.isEmpty()) { - event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst()); - if (!filterNativeEvent("NSEvent", event, nullptr)) { - [NSApp sendEvent:event]; - retVal = true; - } - [event release]; - } - } + if (d->sendQueuedUserInputEvents()) + retVal = true; + // If Qt is used as a plugin, or as an extension in a native cocoa // application, we should not run or stop NSApplication; This will be @@ -843,6 +836,23 @@ void QCocoaEventDispatcherPrivate::waitingObserverCallback(CFRunLoopObserverRef, emit static_cast<QCocoaEventDispatcher*>(info)->awake(); } +bool QCocoaEventDispatcherPrivate::sendQueuedUserInputEvents() +{ + Q_Q(QCocoaEventDispatcher); + if (processEventsFlags & QEventLoop::ExcludeUserInputEvents) + return false; + bool didSendEvent = false; + while (!queuedUserInputEvents.isEmpty()) { + NSEvent *event = static_cast<NSEvent *>(queuedUserInputEvents.takeFirst()); + if (!q->filterNativeEvent("NSEvent", event, nullptr)) { + [NSApp sendEvent:event]; + didSendEvent = true; + } + [event release]; + } + return didSendEvent; +} + void QCocoaEventDispatcherPrivate::processPostedEvents() { if (blockSendPostedEvents) { @@ -896,6 +906,7 @@ void QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void *info) d->maybeCancelWaitForMoreEvents(); return; } + d->sendQueuedUserInputEvents(); d->processPostedEvents(); d->maybeCancelWaitForMoreEvents(); } diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index eefb1cd0fb..c1041ac2da 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -80,7 +80,7 @@ private: NSOpenGLContext *m_shareContext = nil; QSurfaceFormat m_format; bool m_didCheckForSoftwareContext = false; - QVarLengthArray<QMacScopedObserver, 3> m_updateObservers; + QVarLengthArray<QMacNotificationObserver, 3> m_updateObservers; QAtomicInt m_needsUpdate = false; }; diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index fe1fc31553..0f8fec0548 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -404,13 +404,13 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface) m_updateObservers.clear(); if (view.layer) { - m_updateObservers.append(QMacScopedObserver(view, NSViewFrameDidChangeNotification, updateCallback)); - m_updateObservers.append(QMacScopedObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback)); + m_updateObservers.append(QMacNotificationObserver(view, NSViewFrameDidChangeNotification, updateCallback)); + m_updateObservers.append(QMacNotificationObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback)); } else { - m_updateObservers.append(QMacScopedObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback)); + m_updateObservers.append(QMacNotificationObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback)); } - m_updateObservers.append(QMacScopedObserver([NSApplication sharedApplication], + m_updateObservers.append(QMacNotificationObserver([NSApplication sharedApplication], NSApplicationDidChangeScreenParametersNotification, updateCallback)); // If any of the observers fire at this point it's fine. We check the diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 1b184cd60f..c9eafa81d0 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -297,13 +297,12 @@ Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum) */ Qt::MouseButton cocoaButton2QtButton(NSEvent *event) { - switch (event.type) { - case NSEventTypeMouseMoved: + if (cocoaEvent2QtMouseEvent(event) == QEvent::MouseMove) return Qt::NoButton; + switch (event.type) { case NSEventTypeRightMouseUp: case NSEventTypeRightMouseDown: - case NSEventTypeRightMouseDragged: return Qt::RightButton; default: diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 300082d694..08e7447a75 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -215,6 +215,25 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QCocoaIntegration::focusWindowChanged); + + static auto splashScreenHider = QMacKeyValueObserver(NSApp, @"modalWindow", []{ + const QWindowList allWindows = QGuiApplication::topLevelWindows(); + for (QWindow *window : allWindows) { + if ((window->flags() & Qt::SplashScreen) == Qt::SplashScreen) { + QCocoaWindow *platformWindow = static_cast<QCocoaWindow*>(window->handle()); + NSWindow *splashWindow = platformWindow->view().window; + if (!splashWindow) + continue; + if (NSApp.modalWindow) { + NSInteger originalLevel = splashWindow.level; + splashWindow.level = NSNormalWindowLevel; + window->setProperty("_q_levelBeforeModalSession", (qlonglong)originalLevel); + } else if (NSInteger originalLevel = window->property("_q_levelBeforeModalSession").toLongLong()) { + splashWindow.level = originalLevel; + } + } + } + }); } QCocoaIntegration::~QCocoaIntegration() diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h index 34d8428188..a957710a88 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.h +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -92,6 +92,9 @@ public: bool isOpen() const; void setIsOpen(bool isOpen); + bool isAboutToShow() const; + void setIsAboutToShow(bool isAbout); + void timerEvent(QTimerEvent *e) override; void syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUpdate); @@ -111,6 +114,7 @@ private: bool m_parentEnabled:1; bool m_visible:1; bool m_isOpen:1; + bool m_isAboutToShow:1; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index f34988721d..8c4fca0d29 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -178,6 +178,16 @@ void QCocoaMenu::setIsOpen(bool isOpen) m_isOpen = isOpen; } +bool QCocoaMenu::isAboutToShow() const +{ + return m_isAboutToShow; +} + +void QCocoaMenu::setIsAboutToShow(bool isAbout) +{ + m_isAboutToShow = isAbout; +} + void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem) { QMacAutoReleasePool pool; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 32fc3ab660..c35cf6d799 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -141,6 +141,12 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu) if (menu == m_menu) return; + bool setAttached = false; + if ([m_native.menu isKindOfClass:[QCocoaNSMenu class]]) { + auto parentMenu = static_cast<QCocoaNSMenu *>(m_native.menu); + setAttached = parentMenu.platformMenu && parentMenu.platformMenu->isAboutToShow(); + } + if (m_menu && m_menu->menuParent() == this) { m_menu->setMenuParent(nullptr); // Free the menu from its parent's influence @@ -154,6 +160,8 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu) if (m_menu) { m_menu->setMenuParent(this); m_menu->propagateEnabledState(isEnabled()); + if (setAttached) + m_menu->setAttachedItem(m_native); } else { // we previously had a menu, but no longer // clear out our item so the nexy sync() call builds a new one diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.mm b/src/plugins/platforms/cocoa/qcocoansmenu.mm index 65b0832d9f..c51460282a 100644 --- a/src/plugins/platforms/cocoa/qcocoansmenu.mm +++ b/src/plugins/platforms/cocoa/qcocoansmenu.mm @@ -195,7 +195,9 @@ static NSString *qt_mac_removePrivateUnicode(NSString *string) return; platformMenu->setIsOpen(true); + platformMenu->setIsAboutToShow(true); emit platformMenu->aboutToShow(); + platformMenu->setIsAboutToShow(false); } - (void)menuDidClose:(NSMenu *)menu diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index c42fa7d2e8..788b616e78 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -45,6 +45,8 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver)); +#include <QtCore/private/qcore_mac_p.h> + QT_BEGIN_NAMESPACE class QPalette; @@ -82,9 +84,10 @@ public: private: mutable QPalette *m_systemPalette; + QMacNotificationObserver m_systemColorObserver; mutable QHash<QPlatformTheme::Palette, QPalette*> m_palettes; mutable QHash<QPlatformTheme::Font, QFont*> m_fonts; - QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) *m_appearanceObserver; + QMacKeyValueObserver m_appearanceObserver; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index efe670abed..7c10456824 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -80,70 +80,32 @@ #include <CoreServices/CoreServices.h> -#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) -@interface QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) : NSObject -@property (readonly, nonatomic) QCocoaTheme *theme; -- (instancetype)initWithTheme:(QCocoaTheme *)theme; -@end - -QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeAppAppearanceObserver); - -@implementation QCocoaThemeAppAppearanceObserver -- (instancetype)initWithTheme:(QCocoaTheme *)theme -{ - if ((self = [super init])) { - _theme = theme; - [NSApp addObserver:self forKeyPath:@"effectiveAppearance" options:NSKeyValueObservingOptionNew context:nullptr]; - } - return self; -} - -- (void)dealloc -{ - [NSApp removeObserver:self forKeyPath:@"effectiveAppearance"]; - [super dealloc]; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object - change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context -{ - Q_UNUSED(change); - Q_UNUSED(context); - - Q_ASSERT(object == NSApp); - Q_ASSERT([keyPath isEqualToString:@"effectiveAppearance"]); - - if (__builtin_available(macOS 10.14, *)) - NSAppearance.currentAppearance = NSApp.effectiveAppearance; - - self.theme->handleSystemThemeChange(); -} -@end -#endif // QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) - QT_BEGIN_NAMESPACE const char *QCocoaTheme::name = "cocoa"; QCocoaTheme::QCocoaTheme() - : m_systemPalette(nullptr), m_appearanceObserver(nil) + : m_systemPalette(nullptr) { #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) - m_appearanceObserver = [[QCocoaThemeAppAppearanceObserver alloc] initWithTheme:this]; + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) { + m_appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] { + if (__builtin_available(macOS 10.14, *)) + NSAppearance.currentAppearance = NSApp.effectiveAppearance; + + handleSystemThemeChange(); + }); + } #endif - [[NSNotificationCenter defaultCenter] addObserverForName:NSSystemColorsDidChangeNotification - object:nil queue:nil usingBlock:^(NSNotification *) { + m_systemColorObserver = QMacNotificationObserver(nil, + NSSystemColorsDidChangeNotification, [this] { handleSystemThemeChange(); - }]; + }); } QCocoaTheme::~QCocoaTheme() { - if (m_appearanceObserver) - [m_appearanceObserver release]; - reset(); qDeleteAll(m_fonts); } diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm index b00fde6c6f..7ce78ee738 100644 --- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm +++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm @@ -54,7 +54,7 @@ QCocoaVulkanInstance::~QCocoaVulkanInstance() void QCocoaVulkanInstance::createOrAdoptInstance() { - initInstance(m_instance, QByteArrayList()); + initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_MVK_macos_surface")); } VkSurfaceKHR *QCocoaVulkanInstance::createSurface(QWindow *window) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 67b0cbdfe9..363a026e71 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1011,16 +1011,16 @@ void QCocoaWindow::setMask(const QRegion ®ion) } else { m_view.layer.mask = nil; } - } - - if (isContentView()) { - // Setting the mask requires invalidating the NSWindow shadow, but that needs - // to happen after the backingstore has been redrawn, so that AppKit can pick - // up the new window shape based on the backingstore content. Doing a display - // directly here is not an option, as the window might not be exposed at this - // time, and so would not result in an updated backingstore. - m_needsInvalidateShadow = true; - [m_view setNeedsDisplay:YES]; + } else { + if (isContentView()) { + // Setting the mask requires invalidating the NSWindow shadow, but that needs + // to happen after the backingstore has been redrawn, so that AppKit can pick + // up the new window shape based on the backingstore content. Doing a display + // directly here is not an option, as the window might not be exposed at this + // time, and so would not result in an updated backingstore. + m_needsInvalidateShadow = true; + [m_view setNeedsDisplay:YES]; + } } } diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm index 4408385aa8..7c566442f0 100644 --- a/src/plugins/platforms/cocoa/qnsview_mouse.mm +++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm @@ -282,20 +282,19 @@ nativeDrag->setLastMouseEvent(theEvent, self); const auto modifiers = [QNSView convertKeyModifiers:theEvent.modifierFlags]; - const auto buttons = currentlyPressedMouseButtons(); auto button = cocoaButton2QtButton(theEvent); if (button == Qt::LeftButton && m_sendUpAsRightButton) button = Qt::RightButton; const auto eventType = cocoaEvent2QtMouseEvent(theEvent); if (eventType == QEvent::MouseMove) - qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << buttons; + qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << m_buttons; else - qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << buttons; + qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << m_buttons; QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint, - buttons, button, eventType, modifiers); + m_buttons, button, eventType, modifiers); } - (bool)handleMouseDownEvent:(NSEvent *)theEvent |