diff options
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoacursor.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoahelpers.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenu.mm | 41 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 18 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.mm | 60 |
7 files changed, 76 insertions, 50 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm index 2098f0dc8c..8e38181c29 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.mm +++ b/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -303,7 +303,7 @@ NSCursor *QCocoaCursor::createCursorFromPixmap(const QPixmap pixmap, const QPoin NSImage *nsimage; if (pixmap.devicePixelRatio() > 1.0) { QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio(); - QPixmap scaledPixmap = pixmap.scaled(layoutSize); + QPixmap scaledPixmap = pixmap.scaled(layoutSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(scaledPixmap)); CGImageRef cgImage = qt_mac_toCGImage(pixmap.toImage()); NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index bb493ef2be..8ad80333f8 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -622,7 +622,7 @@ QString qt_mac_applicationName() if (appName.isEmpty()) { QString arg0 = QGuiApplicationPrivate::instance()->appName(); if (arg0.contains("/")) { - QStringList parts = arg0.split("/"); + QStringList parts = arg0.split(QLatin1Char('/')); appName = parts.at(parts.count() - 1); } else { appName = arg0; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 57739f3a58..aa7a09805a 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -463,6 +463,13 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, NSView *view = cocoaWindow ? cocoaWindow->contentView() : nil; NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil; + QScreen *screen = 0; + if (parentWindow) + screen = parentWindow->screen(); + if (!screen && !QGuiApplication::screens().isEmpty()) + screen = QGuiApplication::screens().at(0); + Q_ASSERT(screen); + // Ideally, we would call -popUpMenuPositioningItem:atLocation:inView:. // However, this showed not to work with modal windows where the menu items // would appear disabled. So, we resort to a more artisanal solution. Note @@ -479,6 +486,21 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, [popupCell setTransparent:YES]; [popupCell setMenu:m_nativeMenu]; [popupCell selectItem:nsItem]; + + int availableHeight = screen->availableSize().height(); + const QPoint &globalPos = parentWindow->mapToGlobal(pos); + int menuHeight = m_nativeMenu.size.height; + if (globalPos.y() + menuHeight > availableHeight) { + // Maybe we need to fix the vertical popup position but we don't know the + // exact popup height at the moment (and Cocoa is just guessing) nor its + // position. So, instead of translating by the popup's full height, we need + // to estimate where the menu will show up and translate by the remaining height. + float idx = ([m_nativeMenu indexOfItem:nsItem] + 1.0f) / m_nativeMenu.numberOfItems; + float heightBelowPos = (1.0 - idx) * menuHeight; + if (globalPos.y() + heightBelowPos > availableHeight) + pos.setY(pos.y() - globalPos.y() + availableHeight - heightBelowPos); + } + NSRect cellFrame = NSMakeRect(pos.x(), pos.y(), m_nativeMenu.minimumWidth, 10); [popupCell performClickWithFrame:cellFrame inView:view]; } else { @@ -487,22 +509,21 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, if (view) { // convert coordinates from view to the view's window nsPos = [view convertPoint:nsPos toView:nil]; - } else if (!QGuiApplication::screens().isEmpty()) { - QScreen *screen = QGuiApplication::screens().at(0); + } else { nsPos.y = screen->availableVirtualSize().height() - nsPos.y; } if (view) { // Finally, we need to synthesize an event. NSEvent *menuEvent = [NSEvent mouseEventWithType:NSRightMouseDown - location:nsPos - modifierFlags:0 - timestamp:0 - windowNumber:view ? view.window.windowNumber : 0 - context:nil - eventNumber:0 - clickCount:1 - pressure:1.0]; + location:nsPos + modifierFlags:0 + timestamp:0 + windowNumber:view ? view.window.windowNumber : 0 + context:nil + eventNumber:0 + clickCount:1 + pressure:1.0]; [NSMenu popUpContextMenu:m_nativeMenu withEvent:menuEvent forView:view]; } else { [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:0]; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index f78a27614e..e830be212a 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -270,7 +270,6 @@ public: // for QNSView QPointer<QWindow> m_enterLeaveTargetWindow; bool m_windowUnderMouse; - bool m_ignoreWindowShouldClose; bool m_inConstructor; bool m_inSetVisible; bool m_inSetGeometry; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index f790259f0e..adfef81117 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -345,7 +345,6 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_synchedWindowState(Qt::WindowActive) , m_windowModality(Qt::NonModal) , m_windowUnderMouse(false) - , m_ignoreWindowShouldClose(false) , m_inConstructor(true) , m_inSetVisible(false) , m_inSetGeometry(false) @@ -809,13 +808,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) return styleMask; if ((type & Qt::Popup) == Qt::Popup) { if (!windowIsPopupType(type)) { - styleMask = NSUtilityWindowMask; + styleMask = NSUtilityWindowMask | NSResizableWindowMask; if (!(flags & Qt::CustomizeWindowHint)) { - styleMask |= NSResizableWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSTitledWindowMask; + styleMask |= NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask; } else { - if (flags & Qt::WindowMaximizeButtonHint) - styleMask |= NSResizableWindowMask; if (flags & Qt::WindowTitleHint) styleMask |= NSTitledWindowMask; if (flags & Qt::WindowCloseButtonHint) @@ -1228,9 +1224,10 @@ void QCocoaWindow::windowDidEndLiveResize() bool QCocoaWindow::windowShouldClose() { - // might have been set from qnsview.mm - if (m_ignoreWindowShouldClose) - return false; + // This callback should technically only determine if the window + // should (be allowed to) close, but since our QPA API to determine + // that also involves actually closing the window we do both at the + // same time, instead of doing the latter in windowWillClose. bool accepted = false; QWindowSystemInterface::handleCloseEvent(window(), &accepted); QWindowSystemInterface::flushWindowSystemEvents(); @@ -1364,6 +1361,9 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) [m_contentView setHidden: YES]; } + m_nsWindow.ignoresMouseEvents = + (window()->flags() & Qt::WindowTransparentForInput) == Qt::WindowTransparentForInput; + const qreal opacity = qt_window_private(window())->opacity; if (!qFuzzyCompare(opacity, qreal(1.0))) setOpacity(opacity); diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index a49a42378d..d7b9c3831b 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -76,6 +76,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); bool m_resendKeyEvent; bool m_scrolling; bool m_exposedOnMoveToWindow; + NSEvent *m_currentlyInterpretedKeyEvent; } - (id)init; @@ -131,7 +132,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); - (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType; - (void)keyDown:(NSEvent *)theEvent; - (void)keyUp:(NSEvent *)theEvent; -- (BOOL)performKeyEquivalent:(NSEvent *)theEvent; - (void)registerDragTypes; - (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 4db55c1b73..8c22e51fe2 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -152,6 +152,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self]; m_resendKeyEvent = false; m_scrolling = false; + m_currentlyInterpretedKeyEvent = 0; if (!touchDevice) { touchDevice = new QTouchDevice; @@ -709,8 +710,12 @@ QT_WARNING_POP // Popups implicitly grap mouse events; forward to the active popup if there is one if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) { - if (QNSView *popupView = popup->qtView()) - targetView = popupView; + // Tooltips must be transparent for mouse events + // The bug reference is QTBUG-46379 + if (!popup->m_windowFlags.testFlag(Qt::ToolTip)) { + if (QNSView *popupView = popup->qtView()) + targetView = popupView; + } } [targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; @@ -1436,41 +1441,40 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) if (!(modifiers & (Qt::ControlModifier | Qt::MetaModifier)) && (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff)) text = QCFString::toQString(characters); - QWindow *focusWindow = [self topLevelWindow]; + QWindow *window = [self topLevelWindow]; + + // Popups implicitly grab key events; forward to the active popup if there is one. + // This allows popups to e.g. intercept shortcuts and close the popup in response. + if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) + window = popup->window(); if (eventType == QEvent::KeyPress) { if (m_composingText.isEmpty()) { - QKeyEvent override(QEvent::ShortcutOverride, keyCode, modifiers, - nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1); - override.setTimestamp(timestamp); - m_sendKeyEvent = !QWindowSystemInterface::tryHandleShortcutOverrideEvent(focusWindow, &override); + m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode, + modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1); } QObject *fo = QGuiApplication::focusObject(); if (m_sendKeyEvent && fo) { - // if escape is pressed we don't want interpretKeyEvents to close a dialog. This will be done via QWindowSystemInterface - if (keyCode == Qt::Key_Escape) - m_platformWindow->m_ignoreWindowShouldClose = true; - QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints); if (QCoreApplication::sendEvent(fo, &queryEvent)) { bool imEnabled = queryEvent.value(Qt::ImEnabled).toBool(); Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt()); if (imEnabled && !(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || hints & Qt::ImhHiddenText)) { // pass the key event to the input method. note that m_sendKeyEvent may be set to false during this call + m_currentlyInterpretedKeyEvent = nsevent; [self interpretKeyEvents:[NSArray arrayWithObject:nsevent]]; + m_currentlyInterpretedKeyEvent = 0; } } - - m_platformWindow->m_ignoreWindowShouldClose = false;; } if (m_resendKeyEvent) m_sendKeyEvent = true; } if (m_sendKeyEvent && m_composingText.isEmpty()) - QWindowSystemInterface::handleExtendedKeyEvent(focusWindow, timestamp, QEvent::Type(eventType), keyCode, modifiers, + QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, QEvent::Type(eventType), keyCode, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1, false); m_sendKeyEvent = false; @@ -1491,21 +1495,23 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)]; } -- (BOOL)performKeyEquivalent:(NSEvent *)nsevent +- (void)cancelOperation:(id)sender { - NSString *chars = [nsevent charactersIgnoringModifiers]; + Q_UNUSED(sender); - if ([nsevent type] == NSKeyDown && [chars length] > 0) { - QChar ch = [chars characterAtIndex:0]; - Qt::Key qtKey = qt_mac_cocoaKey2QtKey(ch); - // check for Command + Key_Period - if ([nsevent modifierFlags] & NSCommandKeyMask - && qtKey == Qt::Key_Period) { - [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)]; - return YES; - } - } - return [super performKeyEquivalent:nsevent]; + NSEvent *currentEvent = [NSApp currentEvent]; + if (!currentEvent || currentEvent.type != NSKeyDown) + return; + + // Handling the key event may recurse back here through interpretKeyEvents + // (when IM is enabled), so we need to guard against that. + if (currentEvent == m_currentlyInterpretedKeyEvent) + return; + + // Send Command+Key_Period and Escape as normal keypresses so that + // the key sequence is delivered through Qt. That way clients can + // intercept the shortcut and override its effect. + [self handleKeyEvent:currentEvent eventType:int(QEvent::KeyPress)]; } - (void)flagsChanged:(NSEvent *)nsevent |