summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa/qnsview.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa/qnsview.mm')
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm209
1 files changed, 84 insertions, 125 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 1f58a0457f..0ce5b3b332 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -143,7 +143,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
{
self = [super initWithFrame : NSMakeRect(0,0, 300,300)];
if (self) {
- m_backingStore = 0;
+ m_pixelRatio = 1.;
m_maskImage = 0;
m_shouldInvalidateWindowShadow = false;
m_window = 0;
@@ -361,12 +361,11 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
// Send a geometry change event to Qt, if it's ready to handle events
if (!m_platformWindow->m_inConstructor) {
QWindowSystemInterface::handleGeometryChange(m_window, geometry);
- // Do not send incorrect exposes in case the window is not even visible yet.
- // We might get here as a result of a resize() from QWidget's show(), for instance.
- if (m_platformWindow->window()->isVisible()) {
- m_platformWindow->updateExposedGeometry();
+ m_platformWindow->updateExposedGeometry();
+ // Guard against processing window system events during QWindow::setGeometry
+ // calles, which Qt and Qt applications do not excpect.
+ if (!m_platformWindow->m_inSetGeometry)
QWindowSystemInterface::flushWindowSystemEvents();
- }
}
}
@@ -408,10 +407,6 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
Qt::WindowState newState = notificationName == NSWindowDidMiniaturizeNotification ?
Qt::WindowMinimized : Qt::WindowNoState;
[self notifyWindowStateChanged:newState];
- // NSWindowDidOrderOnScreenAndFinishAnimatingNotification is private API, and not
- // emitted in 10.6, so we bring back the old behavior for that case alone.
- if (newState == Qt::WindowNoState && QSysInfo::QSysInfo::MacintoshVersion == QSysInfo::MV_10_6)
- m_platformWindow->exposeWindow();
} else if ([notificationName isEqualToString: @"NSWindowDidOrderOffScreenNotification"]) {
m_platformWindow->obscureWindow();
} else if ([notificationName isEqualToString: @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification"]) {
@@ -424,12 +419,17 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
#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)
+ if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible) {
m_platformWindow->exposeWindow();
+ } else {
+ // Send Obscure events on window occlusion to stop animations. Several
+ // unit tests expect paint and/or expose events for windows that are
+ // sometimes (unpredictably) occlouded: Don't send Obscure events when
+ // running under QTestLib.
+ static bool onTestLib = qt_mac_resolveOption(false, "QT_QTESTLIB_RUNNING");
+ if (!onTestLib)
+ m_platformWindow->obscureWindow();
+ }
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
#pragma clang diagnostic pop
#endif
@@ -437,24 +437,16 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
if (m_window) {
NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen];
if (screenIndex != NSNotFound) {
- m_platformWindow->updateExposedGeometry();
QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex);
QWindowSystemInterface::handleWindowScreenChanged(m_window, cocoaScreen->screen());
+ m_platformWindow->updateExposedGeometry();
}
}
- } else {
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
- if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
- if (notificationName == NSWindowDidEnterFullScreenNotification
- || notificationName == NSWindowDidExitFullScreenNotification) {
- Qt::WindowState newState = notificationName == NSWindowDidEnterFullScreenNotification ?
- Qt::WindowFullScreen : Qt::WindowNoState;
- [self notifyWindowStateChanged:newState];
- }
- }
-#endif
-
+ } else if (notificationName == NSWindowDidEnterFullScreenNotification
+ || notificationName == NSWindowDidExitFullScreenNotification) {
+ Qt::WindowState newState = notificationName == NSWindowDidEnterFullScreenNotification ?
+ Qt::WindowFullScreen : Qt::WindowNoState;
+ [self notifyWindowStateChanged:newState];
}
}
@@ -478,8 +470,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
- (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset
{
- m_backingStore = backingStore;
- m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio();
+ m_backingStore = backingStore->toImage();
+ m_pixelRatio = backingStore->getBackingStoreDevicePixelRatio();
+ m_backingStoreOffset = offset * m_pixelRatio;
foreach (QRect rect, region.rects()) {
[self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
}
@@ -543,7 +536,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
if (m_platformWindow->m_drawContentBorderGradient)
NSDrawWindowBackground(dirtyRect);
- if (!m_backingStore)
+ if (m_backingStore.isNull())
return;
// Calculate source and target rects. The target rect is the dirtyRect:
@@ -551,11 +544,10 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
// The backing store source rect will be larger on retina displays.
// Scale dirtyRect by the device pixel ratio:
- const qreal devicePixelRatio = m_backingStore->getBackingStoreDevicePixelRatio();
- CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * devicePixelRatio,
- dirtyRect.origin.y * devicePixelRatio,
- dirtyRect.size.width * devicePixelRatio,
- dirtyRect.size.height * devicePixelRatio);
+ CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * m_pixelRatio,
+ dirtyRect.origin.y * m_pixelRatio,
+ dirtyRect.size.width * m_pixelRatio,
+ dirtyRect.size.height * m_pixelRatio);
NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext];
CGContextRef cgContext = (CGContextRef) [nsGraphicsContext graphicsPort];
@@ -581,7 +573,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
dirtyBackingRect.size.width,
dirtyBackingRect.size.height
);
- CGImageRef bsCGImage = m_backingStore->getBackingStoreCGImage();
+ CGImageRef bsCGImage = qt_mac_toCGImage(m_backingStore);
CGImageRef cleanImg = CGImageCreateWithImageInRect(bsCGImage, backingStoreRect);
// Optimization: Copy frame buffer content instead of blending for
@@ -596,10 +588,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
CGContextRestoreGState(cgContext);
CGImageRelease(cleanImg);
CGImageRelease(subMask);
+ CGImageRelease(bsCGImage);
[self invalidateWindowShadowIfNeeded];
-
- m_backingStore = 0;
}
- (BOOL) isFlipped
@@ -611,7 +602,8 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
{
if (m_window->flags() & Qt::WindowTransparentForInput)
return NO;
- QWindowSystemInterface::handleWindowActivated([self topLevelWindow]);
+ if (!m_platformWindow->windowIsPopupType())
+ QWindowSystemInterface::handleWindowActivated([self topLevelWindow]);
return YES;
}
@@ -656,16 +648,8 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
NSWindow *window = [self window];
NSPoint nsWindowPoint;
- // Use convertRectToScreen if available (added in 10.7).
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
- if ([window respondsToSelector:@selector(convertRectFromScreen:)]) {
- NSRect windowRect = [window convertRectFromScreen:NSMakeRect(mouseLocation.x, mouseLocation.y, 1, 1)];
- nsWindowPoint = windowRect.origin; // NSWindow coordinates
- } else
-#endif
- {
- nsWindowPoint = [window convertScreenToBase:mouseLocation]; // NSWindow coordinates
- }
+ NSRect windowRect = [window convertRectFromScreen:NSMakeRect(mouseLocation.x, mouseLocation.y, 1, 1)];
+ nsWindowPoint = windowRect.origin; // NSWindow coordinates
NSPoint nsViewPoint = [self convertPoint: nsWindowPoint fromView: nil]; // NSView/QWindow coordinates
*qtWindowPoint = QPointF(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates
@@ -678,6 +662,19 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
m_frameStrutButtons = Qt::NoButton;
}
+- (NSPoint) screenMousePoint:(NSEvent *)theEvent
+{
+ NSPoint screenPoint;
+ if (theEvent) {
+ NSPoint windowPoint = [theEvent locationInWindow];
+ NSRect screenRect = [[theEvent window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
+ screenPoint = screenRect.origin;
+ } else {
+ screenPoint = [NSEvent mouseLocation];
+ }
+ return screenPoint;
+}
+
- (void)handleMouseEvent:(NSEvent *)theEvent
{
[self handleTabletEvent: theEvent];
@@ -692,23 +689,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
m_platformWindow->m_forwardWindow = 0;
}
- NSPoint globalPos = [NSEvent mouseLocation];
-
- if ([self.window parentWindow]
- && (theEvent.type == NSLeftMouseDragged || theEvent.type == NSLeftMouseUp)) {
- // QToolBar can be implemented as a child window on top of its main window
- // (with a borderless NSWindow). If an option "unified toolbar" set on the main window,
- // it's possible to drag such a window using this toolbar.
- // While handling mouse drag events, QToolBar moves the window (QWidget::move).
- // In such a combination [NSEvent mouseLocation] is very different from the
- // real event location and as a result a window will move chaotically.
- NSPoint winPoint = [theEvent locationInWindow];
- NSRect tmpRect = NSMakeRect(winPoint.x, winPoint.y, 1., 1.);
- tmpRect = [[theEvent window] convertRectToScreen:tmpRect];
- globalPos = tmpRect.origin;
- }
-
- [targetView convertFromScreen:globalPos toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ [targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
ulong timestamp = [theEvent timestamp] * 1000;
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
@@ -881,7 +862,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
QPointF windowPoint;
QPointF screenPoint;
- [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
// Top-level windows generate enter-leave events for sub-windows.
@@ -1296,18 +1277,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
// It looks like 1/4 degrees per pixel behaves most native.
// (NB: Qt expects the unit for delta to be 8 per degree):
const int pixelsToDegrees = 2; // 8 * 1/4
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
- if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) {
- angleDelta.setX([theEvent scrollingDeltaX] * pixelsToDegrees);
- angleDelta.setY([theEvent scrollingDeltaY] * pixelsToDegrees);
- } else
-#endif
- {
- angleDelta.setX([theEvent deviceDeltaX] * pixelsToDegrees);
- angleDelta.setY([theEvent deviceDeltaY] * pixelsToDegrees);
- }
-
+ angleDelta.setX([theEvent scrollingDeltaX] * pixelsToDegrees);
+ angleDelta.setY([theEvent scrollingDeltaY] * pixelsToDegrees);
} else {
// carbonEventKind == kEventMouseWheelMoved
// Remove acceleration, and use either -120 or 120 as delta:
@@ -1316,20 +1287,16 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
}
QPoint pixelDelta;
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
- if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) {
- if ([theEvent hasPreciseScrollingDeltas]) {
- pixelDelta.setX([theEvent scrollingDeltaX]);
- pixelDelta.setY([theEvent scrollingDeltaY]);
- } else {
- // docs: "In the case of !hasPreciseScrollingDeltas, multiply the delta with the line width."
- // scrollingDeltaX seems to return a minimum value of 0.1 in this case, map that to two pixels.
- const CGFloat lineWithEstimate = 20.0;
- pixelDelta.setX([theEvent scrollingDeltaX] * lineWithEstimate);
- pixelDelta.setY([theEvent scrollingDeltaY] * lineWithEstimate);
- }
+ if ([theEvent hasPreciseScrollingDeltas]) {
+ pixelDelta.setX([theEvent scrollingDeltaX]);
+ pixelDelta.setY([theEvent scrollingDeltaY]);
+ } else {
+ // docs: "In the case of !hasPreciseScrollingDeltas, multiply the delta with the line width."
+ // scrollingDeltaX seems to return a minimum value of 0.1 in this case, map that to two pixels.
+ const CGFloat lineWithEstimate = 20.0;
+ pixelDelta.setX([theEvent scrollingDeltaX] * lineWithEstimate);
+ pixelDelta.setY([theEvent scrollingDeltaY] * lineWithEstimate);
}
-#endif
QPointF qt_windowPoint;
QPointF qt_screenPoint;
@@ -1337,44 +1304,36 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
NSTimeInterval timestamp = [theEvent timestamp];
ulong qt_timestamp = timestamp * 1000;
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
- if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) {
- // Prevent keyboard modifier state from changing during scroll event streams.
- // A two-finger trackpad flick generates a stream of scroll events. We want
- // the keyboard modifier state to be the state at the beginning of the
- // flick in order to avoid changing the interpretation of the events
- // mid-stream. One example of this happening would be when pressing cmd
- // after scrolling in Qt Creator: not taking the phase into account causes
- // the end of the event stream to be interpreted as font size changes.
- NSEventPhase momentumPhase = [theEvent momentumPhase];
- if (momentumPhase == NSEventPhaseNone) {
- currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
- }
+ // Prevent keyboard modifier state from changing during scroll event streams.
+ // A two-finger trackpad flick generates a stream of scroll events. We want
+ // the keyboard modifier state to be the state at the beginning of the
+ // flick in order to avoid changing the interpretation of the events
+ // mid-stream. One example of this happening would be when pressing cmd
+ // after scrolling in Qt Creator: not taking the phase into account causes
+ // the end of the event stream to be interpreted as font size changes.
+ NSEventPhase momentumPhase = [theEvent momentumPhase];
+ if (momentumPhase == NSEventPhaseNone) {
+ currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
+ }
- NSEventPhase phase = [theEvent phase];
- Qt::ScrollPhase ph = Qt::ScrollUpdate;
+ NSEventPhase phase = [theEvent phase];
+ Qt::ScrollPhase ph = Qt::ScrollUpdate;
#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)
- ph = Qt::ScrollBegin;
- } else
+ 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)
+ ph = Qt::ScrollBegin;
+ } else
#endif
if (phase == NSEventPhaseBegan) {
// On 10.7, MayBegin will not happen, so Began is the actual beginning.
ph = Qt::ScrollBegin;
}
- if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled) {
- ph = Qt::ScrollEnd;
- }
-
- QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph);
- } else
-#endif
- {
- QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta,
- [QNSView convertKeyModifiers:[theEvent modifierFlags]]);
+ if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled) {
+ ph = Qt::ScrollEnd;
}
+
+ QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph);
}
#endif //QT_NO_WHEELEVENT
@@ -1432,7 +1391,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QString text;
// ignore text for the U+F700-U+F8FF range. This is used by Cocoa when
// delivering function keys (e.g. arrow keys, backspace, F1-F35, etc.)
- if (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff)
+ if (!(modifiers & (Qt::ControlModifier | Qt::MetaModifier)) && (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff))
text = QCFString::toQString(characters);
QWindow *focusWindow = [self topLevelWindow];