diff options
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaaccessibility.mm | 7 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 18 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaeventdispatcher.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm | 16 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaintegration.mm | 10 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 34 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.mm | 8 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsviewaccessibility.mm | 53 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnswindowdelegate.mm | 8 |
10 files changed, 107 insertions, 50 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 0f99a414a0..990acd5301 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -298,7 +298,8 @@ bool hasValueAttribute(QAccessibleInterface *interface) Q_ASSERT(interface); const QAccessible::Role qtrole = interface->role(); if (qtrole == QAccessible::EditableText - || interface->valueInterface()) { + || interface->valueInterface() + || interface->state().checkable) { return true; } @@ -330,6 +331,10 @@ id getValueAttribute(QAccessibleInterface *interface) return QCFString::toNSString(QString::number(valueInterface->currentValue().toDouble())); } + if (interface->state().checkable) { + return [NSNumber numberWithInt: (interface->state().checked ? 1 : 0)]; + } + return nil; } diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index bc98d002f0..0b674b8d2f 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -417,7 +417,23 @@ } - (id)accessibilityFocusedUIElement { - return NSAccessibilityUnignoredAncestor(self); + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + + if (!iface || !iface->isValid()) { + qWarning() << "FocusedUIElement for INVALID"; + return nil; + } + QAccessibleInterface *childInterface = iface->focusChild(); + if (childInterface) { + QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); + // FIXME: parent could be wrong + QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self]; + [accessibleElement autorelease]; + return accessibleElement; + } + + // no focus found + return nil; } @end diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index 33d7dcbcf4..0274ed8201 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -163,6 +163,7 @@ public: // The following variables help organizing modal sessions: QStack<QCocoaModalSessionInfo> cocoaModalSessionStack; bool currentExecIsNSAppRun; + bool modalSessionOnNSAppRun; bool nsAppRunCalledByQt; bool cleanupModalSessionsNeeded; uint processEventsCalled; diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index 91b631bff9..495a54cac4 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -721,7 +721,6 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window) // setting currentModalSessionCached to zero, so that interrupt() calls // [NSApp abortModal] if another modal session is currently running Q_Q(QCocoaEventDispatcher); - q->interrupt(); // Add a new, empty (null), NSModalSession to the stack. // It will become active the next time QEventDispatcher::processEvents is called. @@ -734,6 +733,12 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window) cocoaModalSessionStack.push(info); updateChildrenWorksWhenModal(); currentModalSessionCached = 0; + if (currentExecIsNSAppRun) { + modalSessionOnNSAppRun = true; + q->wakeUp(); + } else { + q->interrupt(); + } } void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window) @@ -772,6 +777,7 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate() runLoopTimerRef(0), blockSendPostedEvents(false), currentExecIsNSAppRun(false), + modalSessionOnNSAppRun(false), nsAppRunCalledByQt(false), cleanupModalSessionsNeeded(false), processEventsCalled(0), @@ -902,6 +908,14 @@ void QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void *info) // processEvents() was called "manually," ignore this source for now d->maybeCancelWaitForMoreEvents(); return; + } else if (d->modalSessionOnNSAppRun) { + // We're about to spawn the 1st modal session on top of the main runloop. + // Instead of calling processPostedEvents(), which would need us stop + // NSApp, we just re-enter processEvents(). This is equivalent to calling + // QDialog::exec() except that it's done in a non-blocking way. + d->modalSessionOnNSAppRun = false; + d->q_func()->processEvents(QEventLoop::DialogExec | QEventLoop::EventLoopExec | QEventLoop::WaitForMoreEvents); + return; } d->processPostedEvents(); d->maybeCancelWaitForMoreEvents(); diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 65a9f87e2d..412818ae47 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -316,11 +316,17 @@ QCocoaIntegration *QCocoaIntegration::instance() */ void QCocoaIntegration::updateScreens() { - NSArray *screens = [NSScreen screens]; + NSArray *scrs = [NSScreen screens]; + NSMutableArray *screens = [NSMutableArray arrayWithArray:scrs]; + if ([screens count] == 0) + if ([NSScreen mainScreen]) + [screens addObject:[NSScreen mainScreen]]; + if ([screens count] == 0) + return; QSet<QCocoaScreen*> remainingScreens = QSet<QCocoaScreen*>::fromList(mScreens); QList<QPlatformScreen *> siblings; for (uint i = 0; i < [screens count]; i++) { - NSScreen* scr = [[NSScreen screens] objectAtIndex:i]; + NSScreen* scr = [screens objectAtIndex:i]; CGDirectDisplayID dpy = [[[scr deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; // If this screen is a mirror and is not the primary one of the mirror set, ignore it. if (CGDisplayIsInMirrorSet(dpy)) { diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 6e1f00eebe..b7a6a14d4a 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -183,6 +183,7 @@ public: void windowWillMove(); void windowDidMove(); void windowDidResize(); + void windowDidEndLiveResize(); bool windowShouldClose(); bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const; @@ -252,6 +253,7 @@ public: // for QNSView QList<QCocoaWindow *> m_childWindows; Qt::WindowFlags m_windowFlags; + bool m_effectivelyMaximized; Qt::WindowState m_synchedWindowState; Qt::WindowModality m_windowModality; QPointer<QWindow> m_activePopupWindow; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index c7fba4eef0..b27e1b03db 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -352,6 +352,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_contentViewIsToBeEmbedded(false) , m_parentCocoaWindow(0) , m_isNSWindowChild(false) + , m_effectivelyMaximized(false) , m_synchedWindowState(Qt::WindowActive) , m_windowModality(Qt::NonModal) , m_windowUnderMouse(false) @@ -1164,6 +1165,14 @@ void QCocoaWindow::windowDidResize() [m_qtView updateGeometry]; } +void QCocoaWindow::windowDidEndLiveResize() +{ + if (m_synchedWindowState == Qt::WindowMaximized && ![m_nsWindow isZoomed]) { + m_effectivelyMaximized = false; + [m_qtView notifyWindowStateChanged:Qt::WindowNoState]; + } +} + bool QCocoaWindow::windowShouldClose() { bool accepted = false; @@ -1436,7 +1445,6 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) { if (!m_nsWindow) return; - // if content view width or height is 0 then the window animations will crash so // do nothing except set the new state NSRect contentRect = [contentView() frame]; @@ -1446,9 +1454,7 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) return; } - if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) { - [m_nsWindow performZoom : m_nsWindow]; // toggles - } + Qt::WindowState predictedState = newState; if ((m_synchedWindowState & Qt::WindowMinimized) != (newState & Qt::WindowMinimized)) { if (newState & Qt::WindowMinimized) { @@ -1458,12 +1464,26 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) } } + if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized) || (m_effectivelyMaximized && newState == Qt::WindowNoState)) { + if ((m_synchedWindowState & Qt::WindowFullScreen) == (newState & Qt::WindowFullScreen)) { + [m_nsWindow performZoom : m_nsWindow]; // toggles + m_effectivelyMaximized = !m_effectivelyMaximized; + } else if (!(newState & Qt::WindowMaximized)) { + // it would be nice to change the target geometry that toggleFullScreen will animate toward + // but there is no known way, so the maximized state is not possible at this time + predictedState = static_cast<Qt::WindowState>(static_cast<int>(newState) | Qt::WindowMaximized); + m_effectivelyMaximized = true; + } + } + if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) { bool fakeFullScreen = true; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { if (window()->flags() & Qt::WindowFullscreenButtonHint) { fakeFullScreen = false; + if (m_effectivelyMaximized && m_synchedWindowState == Qt::WindowFullScreen) + predictedState = Qt::WindowMaximized; [m_nsWindow toggleFullScreen : m_nsWindow]; } } @@ -1490,8 +1510,12 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) } } +#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG + qDebug() << "QCocoaWindow::syncWindowState" << newState << "actual" << predictedState << "was" << m_synchedWindowState << "effectively maximized" << m_effectivelyMaximized; +#endif + // New state is now the current synched state - m_synchedWindowState = newState; + m_synchedWindowState = predictedState; } bool QCocoaWindow::setWindowModified(bool modified) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 47081ab890..1197aa9148 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -281,6 +281,12 @@ static QTouchDevice *touchDevice = 0; - (void)notifyWindowStateChanged:(Qt::WindowState)newState { + // If the window was maximized, then fullscreen, then tried to go directly to "normal" state, + // this notification will say that it is "normal", but it will still look maximized, and + // if you called performZoom it would actually take it back to "normal". + // So we should say that it is maximized because it actually is. + if (newState == Qt::WindowNoState && m_platformWindow->m_effectivelyMaximized) + newState = Qt::WindowMaximized; QWindowSystemInterface::handleWindowStateChanged(m_window, newState); // We want to read the window state back from the window, // but the event we just sent may be asynchronous. @@ -346,6 +352,8 @@ static QTouchDevice *touchDevice = 0; - (void)notifyWindowWillZoom:(BOOL)willZoom { Qt::WindowState newState = willZoom ? Qt::WindowMaximized : Qt::WindowNoState; + if (!willZoom) + m_platformWindow->m_effectivelyMaximized = false; [self notifyWindowStateChanged:newState]; } diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index a438950a55..31e3e343b9 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -54,6 +54,15 @@ @implementation QNSView (QNSViewAccessibility) +- (id)childAccessibleElement { + if (!m_window->accessibleRoot()) + return nil; + + QAccessible::Id childId = QAccessible::uniqueId(m_window->accessibleRoot()); + QCocoaAccessibleElement *child = [QCocoaAccessibleElement createElementWithId: childId parent: self]; + return [child autorelease]; +} + // The QNSView is a container that the user does not interact directly with: // Remove it from the user-visible accessibility tree. - (BOOL)accessibilityIsIgnored { @@ -61,58 +70,22 @@ } - (id)accessibilityAttributeValue:(NSString *)attribute { - // activate accessibility updates QCocoaIntegration::instance()->accessibility()->setActive(true); - if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { - if (m_window->accessibleRoot()) - return QCocoaAccessible::macRole(m_window->accessibleRoot()); - return NSAccessibilityUnknownRole; - } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { - return NSAccessibilityRoleDescriptionForUIElement(self); - } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { - if (!m_window->accessibleRoot()) - return [super accessibilityAttributeValue:attribute]; - return QCocoaAccessible::unignoredChildren(self, m_window->accessibleRoot()); + if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { + return NSAccessibilityUnignoredChildrenForOnlyChild([self childAccessibleElement]); } else { return [super accessibilityAttributeValue:attribute]; } } - (id)accessibilityHitTest:(NSPoint)point { - if (!m_window->accessibleRoot()) - return [super accessibilityHitTest:point]; - - QAccessibleInterface *childInterface = m_window->accessibleRoot()->childAt(point.x, qt_mac_flipYCoordinate(point.y)); - // No child found, meaning we hit the NSView - if (!childInterface) { - return [super accessibilityHitTest:point]; - } - - // Hit a child, forward to child accessible interface. - QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); - // FIXME: parent could be wrong - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self ]; - [accessibleElement autorelease]; - return [accessibleElement accessibilityHitTest:point]; + return [[self childAccessibleElement] accessibilityHitTest: point]; } - (id)accessibilityFocusedUIElement { - if (!m_window->accessibleRoot()) - return [super accessibilityFocusedUIElement]; - - QAccessibleInterface *childInterface = m_window->accessibleRoot()->focusChild(); - if (childInterface) { - QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); - // FIXME: parent could be wrong - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self]; - [accessibleElement autorelease]; - return accessibleElement; - } - - // should not happen - return nil; + return [[self childAccessibleElement] accessibilityFocusedUIElement]; } @end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index c9b3d69381..d9509098c6 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -75,6 +75,14 @@ } } +- (void)windowDidEndLiveResize:(NSNotification *)notification +{ + Q_UNUSED(notification); + if (m_cocoaWindow) { + m_cocoaWindow->windowDidEndLiveResize(); + } +} + - (void)windowWillMove:(NSNotification *)notification { Q_UNUSED(notification); |