dnd: Implement touch event support

We need to keep track of the pointer emulating touch sequence. In order
to have events properly redirected on touch devices, the
Clutter.grab_pointer and ungrab_pointer() have been replaced by the grab()
and grab_sequence() ClutterInputDevice methods, one or the other is used
depending on the device triggering DnD.

An extra "sequence" argument has been added to startDrag, passing null here
will resort to pointer grabs.

This is enough to make thumbnails in the WorkspaceBox draggable through
touch.

https://bugzilla.gnome.org/show_bug.cgi?id=756748
This commit is contained in:
Carlos Garnacho 2015-10-16 18:28:11 +02:00
parent c0b50cbdf2
commit 508a13ae72

View File

@ -79,9 +79,12 @@ const _Draggable = new Lang.Class({
dragActorOpacity: undefined }); dragActorOpacity: undefined });
this.actor = actor; this.actor = actor;
if (!params.manualMode) if (!params.manualMode) {
this.actor.connect('button-press-event', this.actor.connect('button-press-event',
Lang.bind(this, this._onButtonPress)); Lang.bind(this, this._onButtonPress));
this.actor.connect('touch-event',
Lang.bind(this, this._onTouchEvent));
}
this.actor.connect('destroy', Lang.bind(this, function() { this.actor.connect('destroy', Lang.bind(this, function() {
this._actorDestroyed = true; this._actorDestroyed = true;
@ -121,8 +124,50 @@ const _Draggable = new Lang.Class({
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
}, },
_onTouchEvent: function (actor, event) {
if (event.type() != Clutter.EventType.TOUCH_BEGIN ||
!global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
return Clutter.EVENT_PROPAGATE;
if (Tweener.getTweenCount(actor))
return Clutter.EVENT_PROPAGATE;
this._touchSequence = event.get_event_sequence();
this._buttonDown = true;
this._grabActor();
let [stageX, stageY] = event.get_coords();
this._dragStartX = stageX;
this._dragStartY = stageY;
return Clutter.EVENT_PROPAGATE;
},
_grabDevice: function(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);
else if (pointer)
pointer.grab (actor);
this._grabbedDevice = pointer;
},
_ungrabDevice: function() {
if (this._touchSequence)
this._grabbedDevice.sequence_ungrab (this._touchSequence);
else
this._grabbedDevice.ungrab();
this._touchSequence = null;
this._grabbedDevice = null;
},
_grabActor: function() { _grabActor: function() {
Clutter.grab_pointer(this.actor); this._grabDevice(this.actor);
this._onEventId = this.actor.connect('event', this._onEventId = this.actor.connect('event',
Lang.bind(this, this._onEvent)); Lang.bind(this, this._onEvent));
}, },
@ -131,7 +176,7 @@ const _Draggable = new Lang.Class({
if (!this._onEventId) if (!this._onEventId)
return; return;
Clutter.ungrab_pointer(); this._ungrabDevice();
this.actor.disconnect(this._onEventId); this.actor.disconnect(this._onEventId);
this._onEventId = null; this._onEventId = null;
}, },
@ -140,13 +185,13 @@ const _Draggable = new Lang.Class({
if (!this._eventsGrabbed) { if (!this._eventsGrabbed) {
this._eventsGrabbed = Main.pushModal(_getEventHandlerActor()); this._eventsGrabbed = Main.pushModal(_getEventHandlerActor());
if (this._eventsGrabbed) if (this._eventsGrabbed)
Clutter.grab_pointer(_getEventHandlerActor()); this._grabDevice(_getEventHandlerActor());
} }
}, },
_ungrabEvents: function() { _ungrabEvents: function() {
if (this._eventsGrabbed) { if (this._eventsGrabbed) {
Clutter.ungrab_pointer(); this._ungrabDevice();
Main.popModal(_getEventHandlerActor()); Main.popModal(_getEventHandlerActor());
this._eventsGrabbed = false; this._eventsGrabbed = false;
} }
@ -157,7 +202,9 @@ const _Draggable = new Lang.Class({
// didn't start the drag, to drop the draggable in case the drag was in progress, and // 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 // 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. // not get triggered if the drag was cancelled with Esc.
if (event.type() == Clutter.EventType.BUTTON_RELEASE) { if (event.type() == Clutter.EventType.BUTTON_RELEASE ||
(event.type() == Clutter.EventType.TOUCH_END &&
global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
this._buttonDown = false; this._buttonDown = false;
if (this._dragInProgress) { if (this._dragInProgress) {
return this._dragActorDropped(event); return this._dragActorDropped(event);
@ -172,7 +219,9 @@ const _Draggable = new Lang.Class({
} }
// We intercept MOTION event to figure out if the drag has started and to draw // We intercept MOTION event to figure out if the drag has started and to draw
// this._dragActor under the pointer when dragging is in progress // this._dragActor under the pointer when dragging is in progress
} else if (event.type() == Clutter.EventType.MOTION) { } else if (event.type() == Clutter.EventType.MOTION ||
(event.type() == Clutter.EventType.TOUCH_UPDATE &&
global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
if (this._dragInProgress) { if (this._dragInProgress) {
return this._updateDragPosition(event); return this._updateDragPosition(event);
} else if (this._dragActor == null) { } else if (this._dragActor == null) {
@ -214,7 +263,7 @@ const _Draggable = new Lang.Class({
* This function is useful to call if you've specified manualMode * This function is useful to call if you've specified manualMode
* for the draggable. * for the draggable.
*/ */
startDrag: function (stageX, stageY, time) { startDrag: function (stageX, stageY, time, sequence) {
currentDraggable = this; currentDraggable = this;
this._dragInProgress = true; this._dragInProgress = true;
@ -228,6 +277,8 @@ const _Draggable = new Lang.Class({
this.emit('drag-begin', time); this.emit('drag-begin', time);
if (this._onEventId) if (this._onEventId)
this._ungrabActor(); this._ungrabActor();
this._touchSequence = sequence;
this._grabEvents(); this._grabEvents();
global.screen.set_cursor(Meta.Cursor.DND_IN_DRAG); global.screen.set_cursor(Meta.Cursor.DND_IN_DRAG);
@ -338,7 +389,7 @@ const _Draggable = new Lang.Class({
let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold; let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
if ((Math.abs(stageX - this._dragStartX) > threshold || if ((Math.abs(stageX - this._dragStartX) > threshold ||
Math.abs(stageY - this._dragStartY) > threshold)) { Math.abs(stageY - this._dragStartY) > threshold)) {
this.startDrag(stageX, stageY, event.get_time()); this.startDrag(stageX, stageY, event.get_time(), this._touchSequence);
this._updateDragPosition(event); this._updateDragPosition(event);
} }