Bug 1476195 - Allow invoking drag sessions outside of mouseDragged. r=mstange,spohl

The parent process usually starts a native drag session during the processing
of a Gecko mouse move event while the mouse is down. Usually, these Gecko mouse
move events are processed synchronously during -[ChildView mouseDragged:]. But
in some cases, the Gecko mouse move event can be a synthetic mouse move event
that was generated in response to a reflow. Those get processed during refresh
driver ticks, which run at a time that's completely unrelated to when
mouseDragged is invoked.
So the widget should just assume that drags can be started at any time between
mouseDown and mouseUp.

Differential Revision: https://phabricator.services.mozilla.com/D36151

--HG--
extra : moz-landing-system : lando
This commit is contained in:
YUKI "Piro" Hiroshi 2019-09-12 14:13:14 +00:00
parent 785fe64f03
commit 18076b6f51
2 changed files with 15 additions and 13 deletions

View File

@ -3078,9 +3078,10 @@ NSPasteboard* globalDragPboard = nil;
// gLastDragView and gLastDragMouseDownEvent are used to communicate information
// to the drag service during drag invocation (starting a drag in from the view).
// gLastDragView is only non-null while mouseDragged is on the call stack.
NSView* gLastDragView = nil;
NSEvent* gLastDragMouseDownEvent = nil;
// gLastDragView is only non-null while a mouse button is pressed, so between
// mouseDown and mouseUp.
NSView* gLastDragView = nil; // [weak]
NSEvent* gLastDragMouseDownEvent = nil; // [strong]
+ (void)initialize {
static BOOL initialized = NO;
@ -3321,6 +3322,10 @@ NSEvent* gLastDragMouseDownEvent = nil;
[mPixelHostingView removeFromSuperview];
[mPixelHostingView release];
if (gLastDragView == self) {
gLastDragView = nil;
}
[super dealloc];
NS_OBJC_END_TRY_ABORT_BLOCK;
@ -4235,6 +4240,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
[gLastDragMouseDownEvent release];
gLastDragMouseDownEvent = [theEvent retain];
gLastDragView = self;
// We need isClickThrough because at this point the window we're in might
// already have become main, so the check for isMainWindow in
@ -4287,6 +4293,8 @@ NSEvent* gLastDragMouseDownEvent = nil;
- (void)mouseUp:(NSEvent*)theEvent {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
gLastDragView = nil;
if (!mGeckoChild || mBlockedLastMouseDown) return;
if (mTextInputHandler->OnHandleEvent(theEvent)) {
return;
@ -4369,8 +4377,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
return;
}
gLastDragView = self;
WidgetMouseEvent geckoEvent(true, eMouseMove, mGeckoChild, WidgetMouseEvent::eReal);
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
@ -4378,7 +4384,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
// Note, sending the above event might have destroyed our widget since we didn't retain.
// Fine so long as we don't access any local variables from here on.
gLastDragView = nil;
// XXX maybe call markedTextSelectionChanged:client: here?

View File

@ -252,13 +252,10 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
if (!gLastDragView) {
// gLastDragView is only set during -[ChildView mouseDragged:].
// InvokeDragSessionImpl is only called while Gecko processes a mouse move
// event. So if we get here with gLastDragView being null, that means that
// the mouse button has already been released, and mouseMoved is on the
// stack instead of mouseDragged. In that case we need to abort the drag
// because the OS won't know where to drop whatever's being dragged, and we
// might end up with a stuck drag & drop session.
// gLastDragView is non-null between -[ChildView mouseDown:] and -[ChildView mouseUp:].
// If we get here with gLastDragView being null, that means that the mouse button has already
// been released. In that case we need to abort the drag because the OS won't know where to drop
// whatever's being dragged, and we might end up with a stuck drag & drop session.
return NS_ERROR_FAILURE;
}