From c2961f2152fd20afc0ce453e87772f5bee545ed3 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 7 Sep 2018 15:13:18 +0200 Subject: [PATCH] dnd: Get dragging device from the triggering events Instead of fetching the CLUTTER_POINTER_DEVICE device. It will be wrong if drags get initiated from tablet pointers. This allows for DnD operations to be started, moved, and more importantly finished through tablet devices. Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/540 --- js/ui/dnd.js | 64 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/js/ui/dnd.js b/js/ui/dnd.js index 4aca7c341..0562c7cbd 100644 --- a/js/ui/dnd.js +++ b/js/ui/dnd.js @@ -119,7 +119,7 @@ var _Draggable = class _Draggable { return Clutter.EVENT_PROPAGATE; this._buttonDown = true; - this._grabActor(); + this._grabActor(event.get_device()); let [stageX, stageY] = event.get_coords(); this._dragStartX = stageX; @@ -136,10 +136,8 @@ var _Draggable = class _Draggable { if (Tweener.getTweenCount(actor)) return Clutter.EVENT_PROPAGATE; - this._touchSequence = event.get_event_sequence(); - this._buttonDown = true; - this._grabActor(); + this._grabActor(event.get_device(), event.get_event_sequence()); let [stageX, stageY] = event.get_coords(); this._dragStartX = stageX; @@ -148,16 +146,14 @@ var _Draggable = class _Draggable { return Clutter.EVENT_PROPAGATE; } - _grabDevice(actor) { - let manager = Clutter.DeviceManager.get_default(); - let pointer = manager.get_core_device(Clutter.InputDeviceType.POINTER_DEVICE); - - if (pointer && this._touchSequence) - pointer.sequence_grab(this._touchSequence, actor); + _grabDevice(actor, pointer, touchSequence) { + if (touchSequence) + pointer.sequence_grab(touchSequence, actor); else if (pointer) pointer.grab (actor); this._grabbedDevice = pointer; + this._touchSequence = touchSequence; } _ungrabDevice() { @@ -170,8 +166,8 @@ var _Draggable = class _Draggable { this._grabbedDevice = null; } - _grabActor() { - this._grabDevice(this.actor); + _grabActor(device, touchSequence) { + this._grabDevice(this.actor, device, touchSequence); this._onEventId = this.actor.connect('event', this._onEvent.bind(this)); } @@ -185,11 +181,11 @@ var _Draggable = class _Draggable { this._onEventId = null; } - _grabEvents() { + _grabEvents(device, touchSequence) { if (!this._eventsGrabbed) { this._eventsGrabbed = Main.pushModal(_getEventHandlerActor()); if (this._eventsGrabbed) - this._grabDevice(_getEventHandlerActor()); + this._grabDevice(_getEventHandlerActor(), device, touchSequence); } } @@ -201,14 +197,29 @@ var _Draggable = class _Draggable { } } + _eventIsRelease(event) { + if (event.type() == Clutter.EventType.BUTTON_RELEASE) { + let buttonMask = (Clutter.ModifierType.BUTTON1_MASK | + Clutter.ModifierType.BUTTON2_MASK | + Clutter.ModifierType.BUTTON3_MASK); + /* We only obey the last button release from the device, + * other buttons may get pressed/released during the DnD op. + */ + return (event.get_state() & buttonMask) == 0; + } else if (event.type() == Clutter.EventType.TOUCH_END) { + /* For touch, we only obey the pointer emulating sequence */ + return global.display.is_pointer_emulating_sequence(event.get_event_sequence()); + } + + return false; + }, + _onEvent(actor, event) { // We intercept BUTTON_RELEASE event to know that the button was released in case we // didn't start the drag, to drop the draggable in case the drag was in progress, and // to complete the drag and ensure that whatever happens to be under the pointer does // not get triggered if the drag was cancelled with Esc. - if (event.type() == Clutter.EventType.BUTTON_RELEASE || - (event.type() == Clutter.EventType.TOUCH_END && - global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) { + if (this._eventIsRelease(event)) { this._buttonDown = false; if (this._dragState == DragState.DRAGGING) { return this._dragActorDropped(event); @@ -268,7 +279,19 @@ var _Draggable = class _Draggable { * This function is useful to call if you've specified manualMode * for the draggable. */ - startDrag(stageX, stageY, time, sequence) { + startDrag(stageX, stageY, time, sequence, device) { + if (device == undefined) { + let event = Clutter.get_current_event(); + + if (event) + device = event.get_device(); + + if (device == undefined) { + let manager = Clutter.DeviceManager.get_default(); + device = manager.get_core_device(Clutter.InputDeviceType.POINTER_DEVICE); + } + } + currentDraggable = this; this._dragState = DragState.DRAGGING; @@ -283,8 +306,7 @@ var _Draggable = class _Draggable { if (this._onEventId) this._ungrabActor(); - this._touchSequence = sequence; - this._grabEvents(); + this._grabEvents(device, sequence); global.display.set_cursor(Meta.Cursor.DND_IN_DRAG); this._dragX = this._dragStartX = stageX; @@ -401,7 +423,7 @@ var _Draggable = class _Draggable { let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold; if ((Math.abs(stageX - this._dragStartX) > threshold || Math.abs(stageY - this._dragStartY) > threshold)) { - this.startDrag(stageX, stageY, event.get_time(), this._touchSequence); + this.startDrag(stageX, stageY, event.get_time(), this._touchSequence, event.get_device()); this._updateDragPosition(event); }