diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qnsview.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.mm | 142 |
1 files changed, 91 insertions, 51 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 6d75ce59f3..3a3a17a474 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -160,11 +152,12 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_inputSource = 0; m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self]; m_resendKeyEvent = false; + m_scrolling = false; if (!touchDevice) { touchDevice = new QTouchDevice; touchDevice->setType(QTouchDevice::TouchPad); - touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition); + touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition | QTouchDevice::MouseEmulation); QWindowSystemInterface::registerTouchDevice(touchDevice); } } @@ -221,6 +214,12 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; return self; } +- (void) clearQWindowPointers +{ + m_window = 0; + m_platformWindow = 0; +} + #ifndef QT_NO_OPENGL - (void) setQCocoaGLContext:(QCocoaGLContext *)context { @@ -271,10 +270,13 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; 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"]) + if ((!_q_NSWindowDidChangeOcclusionStateNotification + && [self.window.className isEqualToString:@"NSCarbonMenuWindow"])) { + m_exposedOnMoveToWindow = true; m_platformWindow->exposeWindow(); - } else { + } + } else if (m_exposedOnMoveToWindow) { + m_exposedOnMoveToWindow = false; m_platformWindow->obscureWindow(); } } @@ -417,8 +419,8 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; && [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" +QT_WARNING_PUSH +QT_WARNING_DISABLE_CLANG("-Wobjc-method-access") enum { NSWindowOcclusionStateVisible = 1UL << 1 }; #endif if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible) { @@ -433,7 +435,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_platformWindow->obscureWindow(); } #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 -#pragma clang diagnostic pop +QT_WARNING_POP #endif } else if (notificationName == NSWindowDidChangeScreenNotification) { if (m_window) { @@ -487,6 +489,8 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; - (BOOL) isOpaque { + if (!m_platformWindow) + return true; return m_platformWindow->isOpaque(); } @@ -691,6 +695,10 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_platformWindow->m_forwardWindow = 0; } + // Popups implicitly grap mouse events; forward to the active popup if there is one + if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) + targetView = popup->contentView(); + [targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; ulong timestamp = [theEvent timestamp] * 1000; @@ -758,16 +766,39 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; if (m_window->flags() & Qt::WindowTransparentForInput) 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; - // 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; + + // Handle any active poup windows; clicking outisde them should close them + // all. Don't do anything or clicks inside one of the menus, let Cocoa + // handle that case. Note that in practice many windows of the Qt::Popup type + // will actually close themselves in this case using logic implemented in + // that particular poup type (for example context menus). However, Qt expects + // that plain popup QWindows will also be closed, so we implement the logic + // here as well. + QList<QCocoaWindow *> *popups = QCocoaIntegration::instance()->popupWindowStack(); + if (!popups->isEmpty()) { + // Check if the click is outside all popups. + bool inside = false; + QPointF qtScreenPoint = qt_mac_flipPoint([self screenMousePoint:theEvent]); + for (QList<QCocoaWindow *>::const_iterator it = popups->begin(); it != popups->end(); ++it) { + if ((*it)->geometry().contains(qtScreenPoint.toPoint())) { + inside = true; + break; + } + } + // Close the popups if the click was outside. + if (!inside) { + Qt::WindowType type = QCocoaIntegration::instance()->activePopupWindow()->window()->type(); + while (QCocoaWindow *popup = QCocoaIntegration::instance()->popPopupWindow()) { + QWindowSystemInterface::handleCloseEvent(popup->window()); + QWindowSystemInterface::flushWindowSystemEvents(); + } + // 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]; if ([inputManager wantsToHandleMouseEvents]) { @@ -1269,12 +1300,10 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) { if (m_window->flags() & Qt::WindowTransparentForInput) return [super scrollWheel:theEvent]; - const EventRef carbonEvent = (EventRef)[theEvent eventRef]; - const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0; - const bool scrollEvent = carbonEventKind == kEventMouseScroll; QPoint angleDelta; - if (scrollEvent) { + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized; + if ([theEvent hasPreciseScrollingDeltas]) { // The mouse device contains pixel scroll wheel support (Mighty Mouse, Trackpad). // Since deviceDelta is delivered as pixels rather than degrees, we need to // convert from pixels to degrees in a sensible manner. @@ -1283,8 +1312,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) const int pixelsToDegrees = 2; // 8 * 1/4 angleDelta.setX([theEvent scrollingDeltaX] * pixelsToDegrees); angleDelta.setY([theEvent scrollingDeltaY] * pixelsToDegrees); + source = Qt::MouseEventSynthesizedBySystem; } else { - // carbonEventKind == kEventMouseWheelMoved // Remove acceleration, and use either -120 or 120 as delta: angleDelta.setX(qBound(-120, int([theEvent deltaX] * 10000), 120)); angleDelta.setY(qBound(-120, int([theEvent deltaY] * 10000), 120)); @@ -1325,19 +1354,24 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { // On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin. - if (phase == NSEventPhaseMayBegin) + if (phase == NSEventPhaseMayBegin) { + m_scrolling = true; ph = Qt::ScrollBegin; - } else + } + } #endif - if (phase == NSEventPhaseBegan) { - // On 10.7, MayBegin will not happen, so Began is the actual beginning. + if (phase == NSEventPhaseBegan) { + // If MayBegin did not happen, Began is the actual beginning. + if (!m_scrolling) ph = Qt::ScrollBegin; - } - if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled) { + m_scrolling = true; + } else if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled || + momentumPhase == NSEventPhaseEnded || momentumPhase == NSEventPhaseCancelled) { ph = Qt::ScrollEnd; + m_scrolling = false; } - QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph); + QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph, source); } #endif //QT_NO_WHEELEVENT @@ -1407,6 +1441,10 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) 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(); @@ -1416,6 +1454,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) [self interpretKeyEvents:[NSArray arrayWithObject:nsevent]]; } } + + m_platformWindow->m_ignoreWindowShouldClose = false;; } if (m_resendKeyEvent) m_sendKeyEvent = true; @@ -1423,7 +1463,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) if (m_sendKeyEvent && m_composingText.isEmpty()) QWindowSystemInterface::handleExtendedKeyEvent(focusWindow, timestamp, QEvent::Type(eventType), keyCode, modifiers, - nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat]); + nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1, false); m_sendKeyEvent = false; m_resendKeyEvent = false; |