mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
fix multiple bugs related to mouse event handling. b=407876, 396952, 408319 r=smichaud sr=roc
This commit is contained in:
parent
66002db1fa
commit
e79f8c4bac
@ -2319,13 +2319,8 @@ NSEvent* gLastDragEvent = nil;
|
||||
#endif
|
||||
|
||||
|
||||
// Events should always go to the window that is directly under the point where
|
||||
// the event happened, with one exception. If there is no window under the event,
|
||||
// mouse moved events should go to the rollup widget if it exists. The return value
|
||||
// of this method indicates whether or not the event was supposed to be sent to this
|
||||
// view. If the return value is YES, then this view should continue to process the
|
||||
// event. If the return value is NO, the event was rerouted and this view should not
|
||||
// process the event.
|
||||
// We sometimes need to reroute events when there is a rollup widget and the
|
||||
// event isn't targeted at it.
|
||||
//
|
||||
// Rerouting may be needed when the user tries to navigate a context menu while
|
||||
// keeping the mouse-button down (left or right mouse button) -- the OS thinks this
|
||||
@ -2337,85 +2332,59 @@ NSEvent* gLastDragEvent = nil;
|
||||
// context menu.
|
||||
- (BOOL)ensureCorrectMouseEventTarget:(NSEvent*)anEvent
|
||||
{
|
||||
NSWindow* windowUnderMouse = nsCocoaUtils::FindWindowUnderPoint(nsCocoaUtils::ScreenLocationForEvent(anEvent));
|
||||
|
||||
if (windowUnderMouse == mWindow)
|
||||
// If there is no rollup widget we assume the OS routed the event correctly.
|
||||
if (!gRollupWidget)
|
||||
return YES;
|
||||
|
||||
if (!windowUnderMouse) {
|
||||
if ([anEvent type] == NSMouseMoved) {
|
||||
if (gRollupWidget) {
|
||||
// If a mouse moved event is not over any window and there is a rollup widget, the event
|
||||
// should go to the rollup widget.
|
||||
NSWindow* rollupWindow = (NSWindow*)gRollupWidget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
if (mWindow == rollupWindow)
|
||||
return YES;
|
||||
else
|
||||
windowUnderMouse = rollupWindow;
|
||||
}
|
||||
else {
|
||||
// If the event is not over a window and is a mouse moved event but there is no rollup widget,
|
||||
// then we don't want it to get handled. Essentially, reroute it to nowhere.
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If the event is not over a window and is not a mouse moved event, then we don't
|
||||
// want it to get handled. Essentially, reroute it to nowhere.
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
// If this is the rollup widget and the event is not a mouse move then trust the OS routing.
|
||||
// The reason for this trust is complicated.
|
||||
//
|
||||
// There are three types of mouse events that can legitimately need to be targeted at a window
|
||||
// that they are not over. Mouse moves, mouse drags, and mouse ups. Anything else our app wouldn't
|
||||
// handle (if the mouse was not over any window) or it would go to the appropriate window.
|
||||
//
|
||||
// We need to do manual event rerouting for mouse moves because we know that in some cases, like
|
||||
// when there is a submenu opened from a popup window, the OS will route mouse move events to the
|
||||
// submenu even if the mouse is over the parent. Mouse move events are never tied to a particular
|
||||
// window because of some originating action like the starting point of a drag for drag events or
|
||||
// a mouse down event for mouse up events, so it is always safe to do our own routing on them here.
|
||||
//
|
||||
// As for mouse drags and mouse ups, they have originating actions that tie them to windows they
|
||||
// may no longer be over. If there is a rollup window present when one of these events is getting
|
||||
// processed but we are not it, we are probably the window where the action originated, and that
|
||||
// action must have caused the rollup window to come into existence. In that case, we might need
|
||||
// to reroute the event if it is over the rollup window. That is why if we're not the rollup window
|
||||
// we don't return YES here.
|
||||
NSWindow* rollupWindow = (NSWindow*)gRollupWidget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
if (mWindow == rollupWindow && [anEvent type] != NSMouseMoved)
|
||||
return YES;
|
||||
|
||||
NSEventType type = [anEvent type];
|
||||
NSPoint newWindowLocation = nsCocoaUtils::EventLocationForWindow(anEvent, windowUnderMouse);
|
||||
NSEvent *newEvent = nil;
|
||||
// Find the window that the event is over.
|
||||
NSWindow* targetWindow = nsCocoaUtils::FindWindowUnderPoint(nsCocoaUtils::ScreenLocationForEvent(anEvent));
|
||||
|
||||
// If anEvent is a mouseUp event, send an extra mouseDown event before
|
||||
// sending a mouseUp event -- this is needed to support selection by
|
||||
// dragging the mouse to a menu item and then releasing it. We retain
|
||||
// the window in case it gets destroyed as a result of the extra
|
||||
// mouseDown (and release it below).
|
||||
BOOL sendSynthMouseDown = gRollupWidget && (type == NSLeftMouseUp || type == NSRightMouseUp);
|
||||
if (sendSynthMouseDown) {
|
||||
[windowUnderMouse retain];
|
||||
NSEventType extraEventType;
|
||||
switch (type) {
|
||||
case NSLeftMouseUp:
|
||||
extraEventType = NSLeftMouseDown;
|
||||
break;
|
||||
case NSRightMouseUp:
|
||||
extraEventType = NSRightMouseDown;
|
||||
break;
|
||||
default:
|
||||
extraEventType = (NSEventType) 0;
|
||||
break;
|
||||
}
|
||||
newEvent = [NSEvent mouseEventWithType:extraEventType
|
||||
location:newWindowLocation
|
||||
modifierFlags:[anEvent modifierFlags]
|
||||
timestamp:GetCurrentEventTime()
|
||||
windowNumber:[windowUnderMouse windowNumber]
|
||||
context:nil
|
||||
eventNumber:0
|
||||
clickCount:1
|
||||
pressure:0.0];
|
||||
[windowUnderMouse sendEvent:newEvent];
|
||||
}
|
||||
// If the event was not over any window, send it to the rollup window.
|
||||
if (!targetWindow)
|
||||
targetWindow = rollupWindow;
|
||||
|
||||
newEvent = [NSEvent mouseEventWithType:type
|
||||
location:newWindowLocation
|
||||
modifierFlags:[anEvent modifierFlags]
|
||||
timestamp:GetCurrentEventTime()
|
||||
windowNumber:[windowUnderMouse windowNumber]
|
||||
context:nil
|
||||
eventNumber:0
|
||||
clickCount:1
|
||||
pressure:0.0];
|
||||
[windowUnderMouse sendEvent:newEvent];
|
||||
// At this point we've resolved a target window, if we are it then just return
|
||||
// yes so we handle it. No need to redirect.
|
||||
if (targetWindow == mWindow)
|
||||
return YES;
|
||||
|
||||
if (sendSynthMouseDown)
|
||||
[windowUnderMouse release];
|
||||
// Send the event to its new destination.
|
||||
NSPoint newWindowLocation = nsCocoaUtils::EventLocationForWindow(anEvent, targetWindow);
|
||||
NSEvent *newEvent = [NSEvent mouseEventWithType:[anEvent type]
|
||||
location:newWindowLocation
|
||||
modifierFlags:[anEvent modifierFlags]
|
||||
timestamp:GetCurrentEventTime()
|
||||
windowNumber:[targetWindow windowNumber]
|
||||
context:nil
|
||||
eventNumber:0
|
||||
clickCount:1
|
||||
pressure:0.0];
|
||||
[targetWindow sendEvent:newEvent];
|
||||
|
||||
// Return NO because we just sent the event somewhere else.
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
@ -1715,7 +1715,8 @@ void patternDraw(void* aInfo, CGContextRef aContext)
|
||||
// events for a given NSWindow object go through its sendEvent: method.)
|
||||
- (void)sendEvent:(NSEvent *)anEvent
|
||||
{
|
||||
NSView *target = nil, *contentView = nil;
|
||||
NSView *target = nil;
|
||||
NSView *contentView = nil;
|
||||
NSEventType type = [anEvent type];
|
||||
NSPoint windowLocation = NSZeroPoint;
|
||||
switch (type) {
|
||||
@ -1730,10 +1731,14 @@ void patternDraw(void* aInfo, CGContextRef aContext)
|
||||
case NSLeftMouseDragged:
|
||||
case NSRightMouseDragged:
|
||||
case NSOtherMouseDragged:
|
||||
if ((contentView = [self contentView]) != nil) {
|
||||
if ((contentView = [self contentView])) {
|
||||
// Since [anEvent window] might not be us, we can't use [anEvent locationInWindow].
|
||||
windowLocation = nsCocoaUtils::EventLocationForWindow(anEvent, self);
|
||||
target = [contentView hitTest:[contentView convertPoint:windowLocation fromView:nil]];
|
||||
// If the hit test failed, the event is targeted here but is not over the window.
|
||||
// Target it at the first responder.
|
||||
if (!target)
|
||||
target = (NSView*)[self firstResponder];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1747,17 +1752,17 @@ void patternDraw(void* aInfo, CGContextRef aContext)
|
||||
case NSLeftMouseDown:
|
||||
[target mouseDown:anEvent];
|
||||
// If we're in a context menu we don't want the OS to send the coming
|
||||
// leftMouseUp event to NSApp via the window server, but we do want
|
||||
// our ChildView to receive a leftMouseUp event (and to send a Gecko
|
||||
// NSLeftMouseUp event to NSApp via the window server, but we do want
|
||||
// our ChildView to receive an NSLeftMouseUp event (and to send a Gecko
|
||||
// NS_MOUSE_BUTTON_UP event to the corresponding nsChildView object).
|
||||
// If our NSApp isn't active (i.e. if we're in a context menu raised
|
||||
// by a rightMouseDown event) when it receives the coming leftMouseUp
|
||||
// via the window server, our browser will (in effect) become partially
|
||||
// by a right mouse down event) when it receives the coming NSLeftMouseUp
|
||||
// via the window server, our app will (in effect) become partially
|
||||
// activated, which has strange side effects: For example, if another
|
||||
// app's window had the focus, that window will lose the focus and the
|
||||
// other app's main menu will be completely disabled (though it will
|
||||
// continue to be displayed).
|
||||
// A side effect of not allowing the coming leftMouseUp event to be
|
||||
// A side effect of not allowing the coming NSLeftMouseUp event to be
|
||||
// sent to NSApp via the window server is that our custom context
|
||||
// menus will roll up whenever the user left-clicks on them, whether
|
||||
// or not the left-click hit an active menu item. This is how native
|
||||
@ -1765,8 +1770,8 @@ void patternDraw(void* aInfo, CGContextRef aContext)
|
||||
// behaved previously (on the trunk or e.g. in Firefox 2.0.0.4).
|
||||
// If our ChildView's corresponding nsChildView object doesn't
|
||||
// dispatch an NS_MOUSE_BUTTON_UP event, none of our active menu items
|
||||
// will "work" on a leftMouseDown.
|
||||
if (mIsContextMenu) {
|
||||
// will "work" on an NSLeftMouseUp.
|
||||
if (mIsContextMenu && ![NSApp isActive]) {
|
||||
NSEvent *newEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
|
||||
location:windowLocation
|
||||
modifierFlags:[anEvent modifierFlags]
|
||||
@ -1812,24 +1817,6 @@ void patternDraw(void* aInfo, CGContextRef aContext)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Sometimes more than one popup window can be visible at the same time
|
||||
// (e.g. nested non-native context menus, or the test case (attachment
|
||||
// 276885) for bmo bug 392389, which displays a non-native combo-box in
|
||||
// a non-native popup window). In these cases the "active" popup window
|
||||
// (the one that corresponds to the current gRollupWidget) should receive
|
||||
// all mouse events that happen over it. So if anEvent wasn't processed
|
||||
// here, if there's a current gRollupWidget, and if its NSWindow object
|
||||
// isn't us, we send anEvent to the gRollupWidget's NSWindow object, then
|
||||
// return. Other code (in nsChildView.mm's ChildView class) will redirect
|
||||
// events that happen over us but should be redirected to the current
|
||||
// gRollupWidget.
|
||||
if (gRollupWidget) {
|
||||
NSWindow *rollupWindow = (NSWindow*)gRollupWidget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
if (rollupWindow && ![rollupWindow isEqual:self]) {
|
||||
[rollupWindow sendEvent:anEvent];
|
||||
return;
|
||||
}
|
||||
}
|
||||
[super sendEvent:anEvent];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user