diff options
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r-- | src/plugins/platforms/cocoa/cocoa.pro | 1 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 41 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaeventdispatcher.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm | 25 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenu.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenu.mm | 5 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenubar.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenuitem.h | 4 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenuitem.mm | 15 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 3 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.mm | 47 |
11 files changed, 132 insertions, 15 deletions
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index a60f4adc28..1f9c0e051d 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -2,6 +2,7 @@ TARGET = qcocoa PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) OBJECTIVE_SOURCES += main.mm \ diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 1df4230385..dd3b9f53db 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -168,6 +168,14 @@ // TODO: multi-selection: NSAccessibilitySelectedTextRangesAttribute, } + if (iface->valueInterface()) { + [attributes addObjectsFromArray: [[NSArray alloc] initWithObjects: + NSAccessibilityMinValueAttribute, + NSAccessibilityMaxValueAttribute, + nil + ]]; + } + return [attributes autorelease]; } @@ -191,6 +199,19 @@ return [QCocoaAccessibleElement elementWithId: parentId]; } + +- (id) minValueAttribute:(QAccessibleInterface*)iface { + if (QAccessibleValueInterface *val = iface->valueInterface()) + return [NSNumber numberWithDouble: val->minimumValue().toDouble()]; + return nil; +} + +- (id) maxValueAttribute:(QAccessibleInterface*)iface { + if (QAccessibleValueInterface *val = iface->valueInterface()) + return [NSNumber numberWithDouble: val->maximumValue().toDouble()]; + return nil; +} + - (id)accessibilityAttributeValue:(NSString *)attribute { QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); if (!iface) { @@ -272,6 +293,10 @@ return [NSNumber numberWithInt: textBeforeCursor.count(QLatin1Char('\n'))]; } return nil; + } else if ([attribute isEqualToString:NSAccessibilityMinValueAttribute]) { + return [self minValueAttribute:iface]; + } else if ([attribute isEqualToString:NSAccessibilityMaxValueAttribute]) { + return [self maxValueAttribute:iface]; } return nil; @@ -332,7 +357,7 @@ startOffset = text.indexOf(QLatin1Char('\n'), startOffset) + 1; if (startOffset < 0) // invalid line number, return the first line startOffset = 0; - int endOffset = text.indexOf(QLatin1Char('\n'), startOffset + 1); + int endOffset = text.indexOf(QLatin1Char('\n'), startOffset); if (endOffset == -1) endOffset = text.length(); return [NSValue valueWithRange:NSMakeRange(quint32(startOffset), quint32(endOffset - startOffset))]; @@ -359,6 +384,12 @@ if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { return iface->state().focusable ? YES : NO; + } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { + if (iface->textInterface() && iface->state().editable) + return YES; + if (iface->valueInterface()) + return YES; + return NO; } else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { return iface->textInterface() ? YES : NO; } @@ -372,6 +403,14 @@ if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { if (QAccessibleActionInterface *action = iface->actionInterface()) action->doAction(QAccessibleActionInterface::setFocusAction()); + } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { + if (iface->textInterface()) { + QString text = QString::fromNSString((NSString *)value); + iface->setText(QAccessible::Value, text); + } else if (QAccessibleValueInterface *valueIface = iface->valueInterface()) { + double val = [value doubleValue]; + valueIface->setCurrentValue(val); + } } else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { if (QAccessibleTextInterface *text = iface->textInterface()) { NSRange range = [value rangeValue]; diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index 0274ed8201..de6c6585e9 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -134,6 +134,8 @@ public: void interrupt(); void flush(); + bool event(QEvent *); + friend void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher); }; @@ -163,7 +165,6 @@ 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 495a54cac4..e0ce9f9648 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -734,13 +734,25 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window) updateChildrenWorksWhenModal(); currentModalSessionCached = 0; if (currentExecIsNSAppRun) { - modalSessionOnNSAppRun = true; - q->wakeUp(); + QEvent *e = new QEvent(QEvent::User); + qApp->postEvent(q, e, Qt::HighEventPriority); } else { q->interrupt(); } } +bool QCocoaEventDispatcher::event(QEvent *e) +{ + Q_D(QCocoaEventDispatcher); + + if (e->type() == QEvent::User) { + d->q_func()->processEvents(QEventLoop::DialogExec | QEventLoop::EventLoopExec | QEventLoop::WaitForMoreEvents); + return true; + } + + return QObject::event(e); +} + void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window) { Q_Q(QCocoaEventDispatcher); @@ -777,7 +789,6 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate() runLoopTimerRef(0), blockSendPostedEvents(false), currentExecIsNSAppRun(false), - modalSessionOnNSAppRun(false), nsAppRunCalledByQt(false), cleanupModalSessionsNeeded(false), processEventsCalled(0), @@ -908,14 +919,6 @@ 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/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h index 59fda96dff..3ee1dab84d 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.h +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -68,6 +68,7 @@ public: void setEnabled(bool enabled); void setVisible(bool visible); void showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item); + void dismiss(); void syncSeparatorsCollapsible(bool enable); diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 6acc062eb9..44bc3b8f69 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -490,6 +490,11 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, QPoint pos, const QPlatf [(QNSView *)view resetMouseButtons]; } +void QCocoaMenu::dismiss() +{ + [m_nativeMenu cancelTracking]; +} + QPlatformMenuItem *QCocoaMenu::menuItemAt(int position) const { if (0 <= position && position < m_menuItems.count()) diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index ffc0fabdce..aceb9b619b 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -124,6 +124,8 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor m_menus.insert(beforeMenu ? m_menus.indexOf(beforeMenu) : m_menus.size(), menu); if (!menu->menuBar()) insertNativeMenu(menu, beforeMenu); + if (m_window && m_window->window()->isActive()) + updateMenuBarImmediately(); } void QCocoaMenuBar::removeNativeMenu(QCocoaMenu *menu) diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h index 61706c19bc..1efc9f9bfd 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.h +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h @@ -57,6 +57,7 @@ QT_FORWARD_DECLARE_OBJC_CLASS(NSMenuItem); QT_FORWARD_DECLARE_OBJC_CLASS(NSMenu); QT_FORWARD_DECLARE_OBJC_CLASS(NSObject); +QT_FORWARD_DECLARE_OBJC_CLASS(NSView); QT_BEGIN_NAMESPACE @@ -86,6 +87,8 @@ public: void setChecked(bool isChecked); void setEnabled(bool isEnabled); + void setNativeContents(WId item); + inline QString text() const { return m_text; } inline NSMenuItem * nsItem() { return m_native; } NSMenuItem *sync(); @@ -105,6 +108,7 @@ private: QKeySequence mergeAccel(); NSMenuItem *m_native; + NSView *m_itemView; QString m_text; bool m_textSynced; QIcon m_icon; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 58fe07bc62..99d26034bf 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -91,6 +91,7 @@ NSUInteger keySequenceModifierMask(const QKeySequence &accel) QCocoaMenuItem::QCocoaMenuItem() : m_native(NULL), + m_itemView(nil), m_textSynced(false), m_menu(NULL), m_isVisible(true), @@ -110,6 +111,8 @@ QCocoaMenuItem::~QCocoaMenuItem() } else { [m_native release]; } + + [m_itemView release]; } void QCocoaMenuItem::setText(const QString &text) @@ -178,6 +181,17 @@ void QCocoaMenuItem::setEnabled(bool enabled) m_enabled = enabled; } +void QCocoaMenuItem::setNativeContents(WId item) +{ + NSView *itemView = (NSView *)item; + [m_itemView release]; + m_itemView = [itemView retain]; + [m_itemView setAutoresizesSubviews:YES]; + [m_itemView setAutoresizingMask:NSViewWidthSizable]; + [m_itemView setHidden:NO]; + [m_itemView setNeedsDisplay:YES]; +} + NSMenuItem *QCocoaMenuItem::sync() { if (m_isSeparator != [m_native isSeparatorItem]) { @@ -281,6 +295,7 @@ NSMenuItem *QCocoaMenuItem::sync() [m_native setHidden: !m_isVisible]; [m_native setEnabled: m_enabled]; + [m_native setView:m_itemView]; QString text = mergeText(); QKeySequence accel = mergeAccel(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 5def64ee0a..60152b56b2 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1375,7 +1375,8 @@ QCocoaNSWindow * QCocoaWindow::createNSWindow() qPlatformWindow:this]; if ((type & Qt::Popup) == Qt::Popup) [window setHasShadow:YES]; - [window setHidesOnDeactivate: NO]; + + [window setHidesOnDeactivate:(type & Qt::Tool) == Qt::Tool]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 0b9683a3ef..24a9f6fff0 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -42,6 +42,7 @@ #include <QtCore/qglobal.h> #include <Carbon/Carbon.h> +#include <dlfcn.h> #include "qnsview.h" #include "qcocoawindow.h" @@ -65,6 +66,9 @@ static QTouchDevice *touchDevice = 0; +// ### HACK Remove once 10.8 is unsupported +static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; + @interface NSEvent (Qt_Compile_Leopard_DeviceDelta) - (CGFloat)deviceDeltaX; - (CGFloat)deviceDeltaY; @@ -73,6 +77,13 @@ static QTouchDevice *touchDevice = 0; @implementation QNSView ++ (void)initialize +{ + NSString **notificationNameVar = (NSString **)dlsym(RTLD_NEXT, "NSWindowDidChangeOcclusionStateNotification"); + if (notificationNameVar) + _q_NSWindowDidChangeOcclusionStateNotification = *notificationNameVar; +} + - (id) init { self = [super initWithFrame : NSMakeRect(0,0, 300,300)]; @@ -192,6 +203,19 @@ static QTouchDevice *touchDevice = 0; } } +- (void)viewDidMoveToWindow +{ + if (self.window) { + // This is the case of QWidgetAction's generated QWidget inserted in an NSMenu. + // 10.9 and newer get the NSWindowDidChangeOcclusionStateNotification + if (!_q_NSWindowDidChangeOcclusionStateNotification + && [self.window.className isEqualToString:@"NSCarbonMenuWindow"]) + m_platformWindow->exposeWindow(); + } else { + m_platformWindow->obscureWindow(); + } +} + - (void)viewWillMoveToWindow:(NSWindow *)newWindow { // ### Merge "normal" window code path with this one for 5.1. @@ -325,6 +349,23 @@ static QTouchDevice *touchDevice = 0; m_platformWindow->obscureWindow(); } else if ([notificationName isEqualToString: @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification"]) { m_platformWindow->exposeWindow(); + } else if (_q_NSWindowDidChangeOcclusionStateNotification + && [notificationName isEqualToString:_q_NSWindowDidChangeOcclusionStateNotification]) { +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 +// ### HACK Remove the enum declaration, the warning disabling and the cast further down once 10.8 is unsupported +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-method-access" + enum { NSWindowOcclusionStateVisible = 1UL << 1 }; +#endif + // Older versions managed in -[QNSView viewDidMoveToWindow]. + // Support QWidgetAction in NSMenu. Mavericks only sends this notification. + // Ideally we should support this in Qt as well, in order to disable animations + // when the window is occluded. + if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible) + m_platformWindow->exposeWindow(); +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 +#pragma clang diagnostic pop +#endif } else if (notificationName == NSWindowDidChangeScreenNotification) { if (m_window) { NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen]; @@ -637,10 +678,14 @@ static QTouchDevice *touchDevice = 0; return [super mouseDown:theEvent]; m_sendUpAsRightButton = false; if (m_platformWindow->m_activePopupWindow) { + Qt::WindowType type = m_platformWindow->m_activePopupWindow->type(); QWindowSystemInterface::handleCloseEvent(m_platformWindow->m_activePopupWindow); QWindowSystemInterface::flushWindowSystemEvents(); m_platformWindow->m_activePopupWindow = 0; - return; + // Consume the mouse event when closing the popup, except for tool tips + // were it's expected that the event is processed normally. + if (type != Qt::ToolTip) + return; } if ([self hasMarkedText]) { NSInputManager* inputManager = [NSInputManager currentInputManager]; |