Cocoa: Do mouse move and cursor update handling separate from view

We are using tracking areas for mouse move, enter/leave and cursor
update events, so we should keep handling of that out of the
"normal" event chain.

If we handle mouse moved events in the views' mouseMoved method,
we need to pass the event up the responder chain if we didn't handle it,
or we would break for example hover behavior in native WebViews,
because these do not handle mouse moved events directly in their
mouseMoved:, but only if the event wasn't handled otherwise
(arguably a bug in Web(HTML)View).
But passing the event up the responder chain is not good either, because
the QNSViews in the parent hierarchy get the event from their tracking
areas already.

Change-Id: I636a84ab1b7ef73070f81a8e33b5fa734ff4a42c
Task-number: QTBUG-26593
Reviewed-by: Morten Johan Sørvig <morten.sorvig@digia.com>
Reviewed-by: Eike Ziller <eike.ziller@digia.com>
This commit is contained in:
Eike Ziller 2014-05-19 14:32:31 +02:00
parent dfc1e23972
commit 432aaf05da
2 changed files with 66 additions and 12 deletions

View File

@ -54,6 +54,8 @@ class QCocoaBackingStore;
class QCocoaGLContext; class QCocoaGLContext;
QT_END_NAMESPACE QT_END_NAMESPACE
Q_FORWARD_DECLARE_OBJC_CLASS(QNSViewMouseMoveHelper);
@interface QNSView : NSView <NSTextInputClient> { @interface QNSView : NSView <NSTextInputClient> {
QCocoaBackingStore* m_backingStore; QCocoaBackingStore* m_backingStore;
QPoint m_backingStoreOffset; QPoint m_backingStoreOffset;
@ -72,6 +74,7 @@ QT_END_NAMESPACE
QCocoaGLContext *m_glContext; QCocoaGLContext *m_glContext;
bool m_shouldSetGLContextinDrawRect; bool m_shouldSetGLContextinDrawRect;
NSString *m_inputSource; NSString *m_inputSource;
QNSViewMouseMoveHelper *m_mouseMoveHelper;
} }
- (id)init; - (id)init;
@ -102,9 +105,10 @@ QT_END_NAMESPACE
- (void)mouseDown:(NSEvent *)theEvent; - (void)mouseDown:(NSEvent *)theEvent;
- (void)mouseDragged:(NSEvent *)theEvent; - (void)mouseDragged:(NSEvent *)theEvent;
- (void)mouseUp:(NSEvent *)theEvent; - (void)mouseUp:(NSEvent *)theEvent;
- (void)mouseMoved:(NSEvent *)theEvent; - (void)mouseMovedImpl:(NSEvent *)theEvent;
- (void)mouseEntered:(NSEvent *)theEvent; - (void)mouseEnteredImpl:(NSEvent *)theEvent;
- (void)mouseExited:(NSEvent *)theEvent; - (void)mouseExitedImpl:(NSEvent *)theEvent;
- (void)cursorUpdateImpl:(NSEvent *)theEvent;
- (void)rightMouseDown:(NSEvent *)theEvent; - (void)rightMouseDown:(NSEvent *)theEvent;
- (void)rightMouseDragged:(NSEvent *)theEvent; - (void)rightMouseDragged:(NSEvent *)theEvent;
- (void)rightMouseUp:(NSEvent *)theEvent; - (void)rightMouseUp:(NSEvent *)theEvent;

View File

@ -75,6 +75,53 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
- (CGFloat)deviceDeltaZ; - (CGFloat)deviceDeltaZ;
@end @end
@interface QNSViewMouseMoveHelper : NSObject
{
QNSView *view;
}
- (id)initWithView:(QNSView *)theView;
- (void)mouseMoved:(NSEvent *)theEvent;
- (void)mouseEntered:(NSEvent *)theEvent;
- (void)mouseExited:(NSEvent *)theEvent;
- (void)cursorUpdate:(NSEvent *)theEvent;
@end
@implementation QNSViewMouseMoveHelper
- (id)initWithView:(QNSView *)theView
{
self = [super init];
if (self) {
view = theView;
}
return self;
}
- (void)mouseMoved:(NSEvent *)theEvent
{
[view mouseMovedImpl:theEvent];
}
- (void)mouseEntered:(NSEvent *)theEvent
{
[view mouseEnteredImpl:theEvent];
}
- (void)mouseExited:(NSEvent *)theEvent
{
[view mouseExitedImpl:theEvent];
}
- (void)cursorUpdate:(NSEvent *)theEvent
{
[view cursorUpdateImpl:theEvent];
}
@end
@implementation QNSView @implementation QNSView
+ (void)initialize + (void)initialize
@ -100,6 +147,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
currentCustomDragTypes = 0; currentCustomDragTypes = 0;
m_sendUpAsRightButton = false; m_sendUpAsRightButton = false;
m_inputSource = 0; m_inputSource = 0;
m_mouseMoveHelper = [[QNSViewMouseMoveHelper alloc] initWithView:self];
if (!touchDevice) { if (!touchDevice) {
touchDevice = new QTouchDevice; touchDevice = new QTouchDevice;
@ -119,6 +167,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
m_subscribesForGlobalFrameNotifications = false; m_subscribesForGlobalFrameNotifications = false;
[m_inputSource release]; [m_inputSource release];
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self];
[m_mouseMoveHelper release];
delete currentCustomDragTypes; delete currentCustomDragTypes;
@ -753,13 +802,13 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
| NSTrackingInVisibleRect | NSTrackingMouseMoved | NSTrackingCursorUpdate; | NSTrackingInVisibleRect | NSTrackingMouseMoved | NSTrackingCursorUpdate;
NSTrackingArea *ta = [[[NSTrackingArea alloc] initWithRect:[self frame] NSTrackingArea *ta = [[[NSTrackingArea alloc] initWithRect:[self frame]
options:trackingOptions options:trackingOptions
owner:self owner:m_mouseMoveHelper
userInfo:nil] userInfo:nil]
autorelease]; autorelease];
[self addTrackingArea:ta]; [self addTrackingArea:ta];
} }
-(void)cursorUpdate:(NSEvent *)theEvent -(void)cursorUpdateImpl:(NSEvent *)theEvent
{ {
Q_UNUSED(theEvent) Q_UNUSED(theEvent)
// Set the cursor manually if there is no NSWindow. // Set the cursor manually if there is no NSWindow.
@ -776,10 +825,10 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
[self addCursorRect:[self visibleRect] cursor:m_platformWindow->m_windowCursor]; [self addCursorRect:[self visibleRect] cursor:m_platformWindow->m_windowCursor];
} }
- (void)mouseMoved:(NSEvent *)theEvent - (void)mouseMovedImpl:(NSEvent *)theEvent
{ {
if (m_window->flags() & Qt::WindowTransparentForInput) if (m_window->flags() & Qt::WindowTransparentForInput)
return [super mouseMoved:theEvent]; return;
QPointF windowPoint; QPointF windowPoint;
QPointF screenPoint; QPointF screenPoint;
@ -806,12 +855,13 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
[self handleMouseEvent: theEvent]; [self handleMouseEvent: theEvent];
} }
- (void)mouseEntered:(NSEvent *)theEvent - (void)mouseEnteredImpl:(NSEvent *)theEvent
{ {
Q_UNUSED(theEvent)
m_platformWindow->m_windowUnderMouse = true; m_platformWindow->m_windowUnderMouse = true;
if (m_window->flags() & Qt::WindowTransparentForInput) if (m_window->flags() & Qt::WindowTransparentForInput)
return [super mouseEntered:theEvent]; return;
// Top-level windows generate enter events for sub-windows. // Top-level windows generate enter events for sub-windows.
if (!m_platformWindow->m_nsWindow) if (!m_platformWindow->m_nsWindow)
@ -824,13 +874,13 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint); QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
} }
- (void)mouseExited:(NSEvent *)theEvent - (void)mouseExitedImpl:(NSEvent *)theEvent
{ {
Q_UNUSED(theEvent);
m_platformWindow->m_windowUnderMouse = false; m_platformWindow->m_windowUnderMouse = false;
if (m_window->flags() & Qt::WindowTransparentForInput) if (m_window->flags() & Qt::WindowTransparentForInput)
return [super mouseExited:theEvent]; return;
Q_UNUSED(theEvent);
// Top-level windows generate leave events for sub-windows. // Top-level windows generate leave events for sub-windows.
if (!m_platformWindow->m_nsWindow) if (!m_platformWindow->m_nsWindow)