diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoahelpers.mm | 4 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.h | 28 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 167 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.h | 6 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.mm | 88 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnswindowdelegate.h | 7 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnswindowdelegate.mm | 58 |
7 files changed, 195 insertions, 163 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index f290275b5e..b092d013c5 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -160,10 +160,8 @@ Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions) */ QNSView *qnsview_cast(NSView *view) { - if (![view isKindOfClass:[QNSView class]]) { - qCWarning(lcQpaCocoaWindow) << "NSView is not QNSView, consider checking for Qt::ForeignWindow"; + if (![view isKindOfClass:[QNSView class]]) return nil; - } return static_cast<QNSView *>(view); } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index f757996cf4..05fc37ac1a 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -141,6 +141,13 @@ QT_BEGIN_NAMESPACE // See the qt_on_cocoa manual tests for a working example, located // in tests/manual/cocoa at the time of writing. +#ifdef Q_MOC_RUN +#define Q_NOTIFICATION_HANDLER(notification) Q_INVOKABLE Q_COCOA_NOTIFICATION_##notification +#else +#define Q_NOTIFICATION_HANDLER(notification) +#define Q_NOTIFICATION_PREFIX QT_STRINGIFY2(Q_COCOA_NOTIFICATION_) +#endif + class QCocoaMenuBar; class QCocoaWindow : public QObject, public QPlatformWindow @@ -187,12 +194,23 @@ public: void setEmbeddedInForeignView(bool subwindow); - void windowWillMove(); - void windowDidMove(); - void windowDidResize(); - void windowDidEndLiveResize(); + Q_NOTIFICATION_HANDLER(NSWindowWillMoveNotification) void windowWillMove(); + Q_NOTIFICATION_HANDLER(NSWindowDidMoveNotification) void windowDidMove(); + Q_NOTIFICATION_HANDLER(NSWindowDidResizeNotification) void windowDidResize(); + Q_NOTIFICATION_HANDLER(NSWindowDidEndLiveResizeNotification) void windowDidEndLiveResize(); + Q_NOTIFICATION_HANDLER(NSWindowDidBecomeKeyNotification) void windowDidBecomeKey(); + Q_NOTIFICATION_HANDLER(NSWindowDidResignKeyNotification) void windowDidResignKey(); + Q_NOTIFICATION_HANDLER(NSWindowDidMiniaturizeNotification) void windowDidMiniaturize(); + Q_NOTIFICATION_HANDLER(NSWindowDidDeminiaturizeNotification) void windowDidDeminiaturize(); + Q_NOTIFICATION_HANDLER(NSWindowDidEnterFullScreenNotification) void windowDidEnterFullScreen(); + Q_NOTIFICATION_HANDLER(NSWindowDidExitFullScreenNotification) void windowDidExitFullScreen(); + Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen(); + Q_NOTIFICATION_HANDLER(NSWindowDidOrderOnScreenAndFinishAnimatingNotification) void windowDidOrderOnScreen(); + Q_NOTIFICATION_HANDLER(NSWindowDidChangeOcclusionStateNotification) void windowDidChangeOcclusionState(); + Q_NOTIFICATION_HANDLER(NSWindowDidChangeScreenNotification) void windowDidChangeScreen(); + Q_NOTIFICATION_HANDLER(NSWindowWillCloseNotification) void windowWillClose(); + bool windowShouldClose(); - void windowWillClose(); bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const; void setSynchedWindowStateFromWindow(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index d10d50aca9..9e5b52d1f7 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -343,6 +343,49 @@ static void qt_closePopups() @end +static void qRegisterNotificationCallbacks() +{ + static const QLatin1String notificationHandlerPrefix(Q_NOTIFICATION_PREFIX); + + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + + const QMetaObject *metaObject = QMetaType::metaObjectForType(qRegisterMetaType<QCocoaWindow*>()); + Q_ASSERT(metaObject); + + for (int i = 0; i < metaObject->methodCount(); ++i) { + QMetaMethod method = metaObject->method(i); + const QString methodTag = QString::fromLatin1(method.tag()); + if (!methodTag.startsWith(notificationHandlerPrefix)) + continue; + + const QString notificationName = methodTag.mid(notificationHandlerPrefix.size()); + [center addObserverForName:notificationName.toNSString() object:nil queue:nil + usingBlock:^(NSNotification *notification) { + + NSWindow *window = notification.object; + + // Only top level NSWindows should notify their QNSViews + if (window.parentWindow) + return; + + QCocoaWindow *cocoaWindow = nullptr; + if (QNSView *view = qnsview_cast(window.contentView)) + cocoaWindow = view.platformWindow; + + // FIXME: Could be a foreign window, look up by iterating top level QWindows + + if (!cocoaWindow) + return; + + if (!method.invoke(cocoaWindow, Qt::DirectConnection)) { + qCWarning(lcQpaCocoaWindow) << "Failed to invoke NSNotification callback for" + << notification.name << "on" << cocoaWindow; + } + }]; + } +} +Q_CONSTRUCTOR_FUNCTION(qRegisterNotificationCallbacks) + const int QCocoaWindow::NoAlertRequest = -1; QCocoaWindow::QCocoaWindow(QWindow *tlw) @@ -1180,6 +1223,8 @@ void QCocoaWindow::setEmbeddedInForeignView(bool embedded) m_nsWindow = 0; } +// ----------------------- NSWindow notifications ----------------------- + void QCocoaWindow::windowWillMove() { // Close any open popups on window move @@ -1214,6 +1259,108 @@ void QCocoaWindow::windowDidEndLiveResize() } } +void QCocoaWindow::windowDidBecomeKey() +{ + if (window()->type() == Qt::ForeignWindow) + return; + + if (m_windowUnderMouse) { + QPointF windowPoint; + QPointF screenPoint; + [qnsview_cast(m_view) convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + QWindowSystemInterface::handleEnterEvent(m_enterLeaveTargetWindow, windowPoint, screenPoint); + } + + if (!windowIsPopupType() && !qnsview_cast(m_view).isMenuView) + QWindowSystemInterface::handleWindowActivated(window()); +} + +void QCocoaWindow::windowDidResignKey() +{ + if (window()->type() == Qt::ForeignWindow) + return; + + // Key window will be non-nil if another window became key, so do not + // set the active window to zero here -- the new key window's + // NSWindowDidBecomeKeyNotification hander will change the active window. + NSWindow *keyWindow = [NSApp keyWindow]; + if (!keyWindow || keyWindow == m_view.window) { + // No new key window, go ahead and set the active window to zero + if (!windowIsPopupType() && !qnsview_cast(m_view).isMenuView) + QWindowSystemInterface::handleWindowActivated(0); + } +} + +void QCocoaWindow::windowDidMiniaturize() +{ + [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowMinimized]; +} + +void QCocoaWindow::windowDidDeminiaturize() +{ + [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowNoState]; +} + +void QCocoaWindow::windowDidEnterFullScreen() +{ + [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowFullScreen]; +} + +void QCocoaWindow::windowDidExitFullScreen() +{ + [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowNoState]; +} + +void QCocoaWindow::windowDidOrderOffScreen() +{ + obscureWindow(); +} + +void QCocoaWindow::windowDidOrderOnScreen() +{ + exposeWindow(); +} + +void QCocoaWindow::windowDidChangeOcclusionState() +{ + // Several unit tests expect paint and/or expose events for windows that are + // sometimes (unpredictably) occluded and some unit tests depend on QWindow::isExposed. + // Don't send Expose/Obscure events when running under QTestLib. + static const bool onTestLib = qt_mac_resolveOption(false, "QT_QTESTLIB_RUNNING"); + if (!onTestLib) { + if ((NSUInteger)[m_view.window occlusionState] & NSWindowOcclusionStateVisible) { + exposeWindow(); + } else { + // Send Obscure events on window occlusion to stop animations. + obscureWindow(); + } + } +} + +void QCocoaWindow::windowDidChangeScreen() +{ + if (!window()) + return; + + NSUInteger screenIndex = [[NSScreen screens] indexOfObject:m_view.window.screen]; + if (screenIndex == NSNotFound) + return; + + if (QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex)) + QWindowSystemInterface::handleWindowScreenChanged(window(), cocoaScreen->screen()); + + updateExposedGeometry(); +} + +void QCocoaWindow::windowWillClose() +{ + // Close any open popups on window closing. + if (window() && !windowIsPopupType(window()->type())) + qt_closePopups(); +} + +// ----------------------- NSWindowDelegate callbacks ----------------------- + bool QCocoaWindow::windowShouldClose() { qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::windowShouldClose" << window(); @@ -1227,12 +1374,7 @@ bool QCocoaWindow::windowShouldClose() return accepted; } -void QCocoaWindow::windowWillClose() -{ - // Close any open popups on window closing. - if (window() && !windowIsPopupType(window()->type())) - qt_closePopups(); -} +// -------------------------------------------------------------------------- void QCocoaWindow::setSynchedWindowStateFromWindow() { @@ -1287,11 +1429,6 @@ void QCocoaWindow::recreateWindow() bool usesNSPanel = [m_nsWindow isKindOfClass:[QNSPanel class]]; - // No child QNSWindow should notify its QNSView - if (m_nsWindow && (window()->type() != Qt::ForeignWindow) && m_parentCocoaWindow && !oldParentCocoaWindow) - [[NSNotificationCenter defaultCenter] removeObserver:m_view - name:nil object:m_nsWindow]; - // Remove current window (if any) if ((m_nsWindow && !needsNSWindow) || (usesNSPanel != shouldUseNSPanel())) { [m_nsWindow closeAndRelease]; @@ -1305,14 +1442,6 @@ void QCocoaWindow::recreateWindow() if (noPreviousWindow) m_nsWindow = createNSWindow(); - // Only non-child QNSWindows should notify their QNSViews - // (but don't register more than once). - if ((window()->type() != Qt::ForeignWindow) && (noPreviousWindow || (wasNSWindowChild && !m_isNSWindowChild))) - [[NSNotificationCenter defaultCenter] addObserver:m_view - selector:@selector(windowNotification:) - name:nil // Get all notifications - object:m_nsWindow]; - if (oldParentCocoaWindow) { if (!m_isNSWindowChild || oldParentCocoaWindow != m_parentCocoaWindow) oldParentCocoaWindow->removeChildWindow(this); diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index abaff39e81..c45d7481c6 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -102,7 +102,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); - (void)drawBackingStoreUsingCoreGraphics:(NSRect)dirtyRect; - (void)updateGeometry; - (void)notifyWindowStateChanged:(Qt::WindowState)newState; -- (void)windowNotification : (NSNotification *) windowNotification; - (void)notifyWindowWillZoom:(BOOL)willZoom; - (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification; - (void)viewDidHide; @@ -153,6 +152,11 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); @end +@interface QT_MANGLE_NAMESPACE(QNSView) (QtExtras) +@property (nonatomic, readonly) QCocoaWindow *platformWindow; +@property (nonatomic, readonly) BOOL isMenuView; +@end + QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSView); #endif //QNSVIEW_H diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index dfdc3facb4..504db06900 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -281,22 +281,6 @@ static bool _q_dontOverrideCtrlLMB = false; m_backingStore = Q_NULLPTR; } -- (void)viewWillMoveToWindow:(NSWindow *)newWindow -{ - // ### Merge "normal" window code path with this one for 5.1. - if (!(m_platformWindow->window()->type() & Qt::SubWindow)) - return; - - if (newWindow) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(windowNotification:) - name:nil // Get all notifications - object:newWindow]; - } - if ([self window]) - [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:[self window]]; -} - - (QWindow *)topLevelWindow { QWindow *focusWindow = m_platformWindow->window(); @@ -395,64 +379,6 @@ static bool _q_dontOverrideCtrlLMB = false; m_platformWindow->setSynchedWindowStateFromWindow(); } -- (void)windowNotification : (NSNotification *) windowNotification -{ - //qDebug() << "windowNotification" << QString::fromNSString([windowNotification name]); - - NSString *notificationName = [windowNotification name]; - if (notificationName == NSWindowDidBecomeKeyNotification) { - if (!m_platformWindow->windowIsPopupType() && !m_isMenuView) - QWindowSystemInterface::handleWindowActivated(m_platformWindow->window()); - } else if (notificationName == NSWindowDidResignKeyNotification) { - // key window will be non-nil if another window became key... do not - // set the active window to zero here, the new key window's - // NSWindowDidBecomeKeyNotification hander will change the active window - NSWindow *keyWindow = [NSApp keyWindow]; - if (!keyWindow || keyWindow == windowNotification.object) { - // no new key window, go ahead and set the active window to zero - if (!m_platformWindow->windowIsPopupType() && !m_isMenuView) - QWindowSystemInterface::handleWindowActivated(0); - } - } else if (notificationName == NSWindowDidMiniaturizeNotification - || notificationName == NSWindowDidDeminiaturizeNotification) { - Qt::WindowState newState = notificationName == NSWindowDidMiniaturizeNotification ? - Qt::WindowMinimized : Qt::WindowNoState; - [self notifyWindowStateChanged:newState]; - } else if ([notificationName isEqualToString: @"NSWindowDidOrderOffScreenNotification"]) { - m_platformWindow->obscureWindow(); - } else if ([notificationName isEqualToString: @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification"]) { - m_platformWindow->exposeWindow(); - } else if ([notificationName isEqualToString:NSWindowDidChangeOcclusionStateNotification]) { - // Several unit tests expect paint and/or expose events for windows that are - // sometimes (unpredictably) occluded and some unit tests depend on QWindow::isExposed - - // don't send Expose/Obscure events when running under QTestLib. - static const bool onTestLib = qt_mac_resolveOption(false, "QT_QTESTLIB_RUNNING"); - if (!onTestLib) { - if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible) { - m_platformWindow->exposeWindow(); - } else { - // Send Obscure events on window occlusion to stop animations. - m_platformWindow->obscureWindow(); - } - } - } else if (notificationName == NSWindowDidChangeScreenNotification) { - if (m_platformWindow->window()) { - NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen]; - if (screenIndex != NSNotFound) { - QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex); - if (cocoaScreen) - QWindowSystemInterface::handleWindowScreenChanged(m_platformWindow->window(), cocoaScreen->screen()); - m_platformWindow->updateExposedGeometry(); - } - } - } else if (notificationName == NSWindowDidEnterFullScreenNotification - || notificationName == NSWindowDidExitFullScreenNotification) { - Qt::WindowState newState = notificationName == NSWindowDidEnterFullScreenNotification ? - Qt::WindowFullScreen : Qt::WindowNoState; - [self notifyWindowStateChanged:newState]; - } -} - - (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification { Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification) @@ -2219,3 +2145,17 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin } @end + +@implementation QT_MANGLE_NAMESPACE(QNSView) (QtExtras) + +- (QCocoaWindow*)platformWindow +{ + return m_platformWindow.data();; +} + +- (BOOL)isMenuView +{ + return m_isMenuView; +} + +@end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h index 46e8d40efb..667e08d0c1 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.h +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h @@ -49,15 +49,10 @@ QCocoaWindow *m_cocoaWindow; } -- (id)initWithQCocoaWindow: (QCocoaWindow *) cocoaWindow; +- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow; -- (void)windowDidBecomeKey:(NSNotification *)notification; -- (void)windowDidResize:(NSNotification *)notification; -- (void)windowDidMove:(NSNotification *)notification; -- (void)windowWillMove:(NSNotification *)notification; - (BOOL)windowShouldClose:(NSNotification *)notification; - (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame; -- (void)windowWillClose:(NSNotification *)notification; @end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index cbae4fc50f..7e18c023e5 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -45,57 +45,12 @@ @implementation QNSWindowDelegate -- (id) initWithQCocoaWindow: (QCocoaWindow *) cocoaWindow +- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow { - self = [super init]; - - if (self) { + if (self = [super init]) m_cocoaWindow = cocoaWindow; - } - return self; -} - -- (void)windowDidBecomeKey:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow->m_windowUnderMouse) { - QPointF windowPoint; - QPointF screenPoint; - [qnsview_cast(m_cocoaWindow->view()) convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; - QWindowSystemInterface::handleEnterEvent(m_cocoaWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint); - } -} - -- (void)windowDidResize:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow) { - m_cocoaWindow->windowDidResize(); - } -} - -- (void)windowDidEndLiveResize:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow) { - m_cocoaWindow->windowDidEndLiveResize(); - } -} - -- (void)windowWillMove:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow) { - m_cocoaWindow->windowWillMove(); - } -} -- (void)windowDidMove:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow) { - m_cocoaWindow->windowDidMove(); - } + return self; } - (BOOL)windowShouldClose:(NSNotification *)notification @@ -116,11 +71,4 @@ return YES; } -- (void)windowWillClose:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (m_cocoaWindow) - m_cocoaWindow->windowWillClose(); -} - @end |