Skip to content

Commit 6c1b00e

Browse files
committed
DragDropAction: Don't consume events before drag started
We don't want to consume events let alone grab the actor before we actually are sure that we will handle this drag. This will improve situations where multiple gestures can be started from the same position most notably in the multitasking view drag and drop of window clones and (once the new touchbackend is merged) swipe left and right for switching workspaces. This will also allow to use a separate click action instead of having to implement clicking in the dnd action as well.
1 parent 1a3ce93 commit 6c1b00e

File tree

1 file changed

+113
-97
lines changed

1 file changed

+113
-97
lines changed

lib/DragDropAction.vala

Lines changed: 113 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ namespace Gala {
201201
return Clutter.EVENT_PROPAGATE;
202202
}
203203

204-
grab_actor (actor, event.get_device ());
205204
clicked = true;
206205

207206
float x, y;
@@ -210,8 +209,78 @@ namespace Gala {
210209
last_x = x;
211210
last_y = y;
212211

212+
// We didn't start dragging yet, so allow propagation (maybe somebody else wants
213+
// to handle this as well)
214+
return Clutter.EVENT_PROPAGATE;
215+
216+
case Clutter.EventType.MOTION:
217+
case Clutter.EventType.TOUCH_UPDATE:
218+
if (!is_valid_touch_event (event)) {
219+
return Clutter.EVENT_PROPAGATE;
220+
}
221+
222+
if (!clicked) {
223+
return Clutter.EVENT_PROPAGATE;
224+
}
225+
226+
float x, y;
227+
event.get_coords (out x, out y);
228+
229+
#if HAS_MUTTER47
230+
var drag_threshold = actor.context.get_settings ().dnd_drag_threshold;
231+
#else
232+
var drag_threshold = Clutter.Settings.get_default ().dnd_drag_threshold;
233+
#endif
234+
if (Math.fabsf (last_x - x) < drag_threshold && Math.fabsf (last_y - y) < drag_threshold) {
235+
// Not moved far enough yet, continue waiting and allowing propagation
236+
return Clutter.EVENT_PROPAGATE;
237+
}
238+
239+
// We have moved enough, start the drag
240+
handle = drag_begin (last_x, last_y);
241+
if (handle == null) {
242+
critical ("No handle has been returned by the started signal, aborting drag.");
243+
return Clutter.EVENT_PROPAGATE;
244+
}
245+
246+
clicked = false;
247+
dragging = true;
248+
249+
grab_actor (handle, event.get_device ());
250+
251+
var source_list = sources.@get (drag_id);
252+
if (source_list != null) {
253+
var dest_list = destinations[drag_id];
254+
foreach (var actor in source_list) {
255+
// Do not unset reactivity on destinations
256+
if (dest_list == null || actor in dest_list) {
257+
continue;
258+
}
259+
260+
actor.reactive = false;
261+
}
262+
}
263+
213264
return Clutter.EVENT_STOP;
214265

266+
case Clutter.EventType.BUTTON_RELEASE:
267+
case Clutter.EventType.TOUCH_END:
268+
float x, y, ex, ey;
269+
event.get_coords (out ex, out ey);
270+
actor.get_transformed_position (out x, out y);
271+
272+
// release has happened within bounds of actor
273+
if (clicked && x < ex && x + actor.width > ex && y < ey && y + actor.height > ey) {
274+
actor_clicked (
275+
event.get_type () == BUTTON_RELEASE ? event.get_button () : Clutter.Button.PRIMARY,
276+
event.get_source_device ().get_device_type ()
277+
);
278+
}
279+
280+
clicked = false;
281+
282+
return Clutter.EVENT_PROPAGATE;
283+
215284
default:
216285
break;
217286
}
@@ -247,6 +316,8 @@ namespace Gala {
247316
}
248317

249318
private bool on_event (Clutter.Event event) {
319+
assert (dragging);
320+
250321
var device = event.get_device ();
251322

252323
if (grabbed_device != null &&
@@ -269,32 +340,11 @@ namespace Gala {
269340
return Clutter.EVENT_PROPAGATE;
270341
}
271342

272-
if (dragging) {
273-
if (hovered != null) {
274-
finish ();
275-
hovered = null;
276-
} else {
277-
cancel ();
278-
}
279-
280-
return Clutter.EVENT_STOP;
281-
}
282-
283-
float x, y, ex, ey;
284-
event.get_coords (out ex, out ey);
285-
actor.get_transformed_position (out x, out y);
286-
287-
// release has happened within bounds of actor
288-
if (clicked && x < ex && x + actor.width > ex && y < ey && y + actor.height > ey) {
289-
actor_clicked (
290-
event.get_type () == BUTTON_RELEASE ? event.get_button () : Clutter.Button.PRIMARY,
291-
event.get_source_device ().get_device_type ()
292-
);
293-
}
294-
295-
if (clicked) {
296-
ungrab_actor ();
297-
clicked = false;
343+
if (hovered != null) {
344+
finish ();
345+
hovered = null;
346+
} else {
347+
cancel ();
298348
}
299349

300350
return Clutter.EVENT_STOP;
@@ -308,89 +358,55 @@ namespace Gala {
308358
float x, y;
309359
event.get_coords (out x, out y);
310360

311-
if (!dragging && clicked) {
312-
#if HAS_MUTTER47
313-
var drag_threshold = actor.context.get_settings ().dnd_drag_threshold;
314-
#else
315-
var drag_threshold = Clutter.Settings.get_default ().dnd_drag_threshold;
316-
#endif
317-
if (Math.fabsf (last_x - x) > drag_threshold || Math.fabsf (last_y - y) > drag_threshold) {
318-
handle = drag_begin (last_x, last_y);
319-
if (handle == null) {
320-
ungrab_actor ();
321-
critical ("No handle has been returned by the started signal, aborting drag.");
322-
return Clutter.EVENT_PROPAGATE;
323-
}
324-
325-
clicked = false;
326-
dragging = true;
327-
328-
ungrab_actor ();
329-
grab_actor (handle, event.get_device ());
330-
331-
var source_list = sources.@get (drag_id);
332-
if (source_list != null) {
333-
var dest_list = destinations[drag_id];
334-
foreach (var actor in source_list) {
335-
// Do not unset reactivity on destinations
336-
if (dest_list == null || actor in dest_list) {
337-
continue;
338-
}
339-
340-
actor.reactive = false;
341-
}
342-
}
343-
}
344-
return Clutter.EVENT_STOP;
361+
if (!dragging) {
362+
return Clutter.EVENT_PROPAGATE;
363+
}
345364

346-
} else if (dragging) {
347-
handle.x -= last_x - x;
348-
handle.y -= last_y - y;
349-
last_x = x;
350-
last_y = y;
351-
352-
var stage = actor.get_stage ();
353-
var actor = stage.get_actor_at_pos (NONE, (int) x, (int) y);
354-
DragDropAction action = null;
355-
// if we're allowed to bubble and this actor is not a destination, check its parents
356-
if (actor != null && (action = get_drag_drop_action (actor)) == null && allow_bubbling) {
357-
while ((actor = actor.get_parent ()) != stage) {
358-
if ((action = get_drag_drop_action (actor)) != null)
359-
break;
360-
}
361-
}
365+
handle.x -= last_x - x;
366+
handle.y -= last_y - y;
367+
last_x = x;
368+
last_y = y;
362369

363-
// didn't change, no need to do anything
364-
if (actor == hovered) {
365-
if (hovered != null) {
366-
destination_motion (hovered, x - hovered.x, y - hovered.y);
367-
}
368-
return Clutter.EVENT_STOP;
370+
var stage = actor.get_stage ();
371+
var actor = stage.get_actor_at_pos (NONE, (int) x, (int) y);
372+
DragDropAction action = null;
373+
// if we're allowed to bubble and this actor is not a destination, check its parents
374+
if (actor != null && (action = get_drag_drop_action (actor)) == null && allow_bubbling) {
375+
while ((actor = actor.get_parent ()) != stage) {
376+
if ((action = get_drag_drop_action (actor)) != null)
377+
break;
369378
}
379+
}
370380

371-
if (action == null) {
372-
// apparently we left ours if we had one before
373-
if (hovered != null) {
374-
emit_crossed (hovered, false);
375-
hovered = null;
376-
}
377-
378-
return Clutter.EVENT_STOP;
381+
// didn't change, no need to do anything
382+
if (actor == hovered) {
383+
if (hovered != null) {
384+
destination_motion (hovered, x - hovered.x, y - hovered.y);
379385
}
386+
return Clutter.EVENT_STOP;
387+
}
380388

381-
// signal the previous one that we left it
389+
if (action == null) {
390+
// apparently we left ours if we had one before
382391
if (hovered != null) {
383392
emit_crossed (hovered, false);
393+
hovered = null;
384394
}
385395

386-
// tell the new one that it is hovered
387-
hovered = actor;
388-
emit_crossed (hovered, true);
389-
390396
return Clutter.EVENT_STOP;
391397
}
392398

393-
break;
399+
// signal the previous one that we left it
400+
if (hovered != null) {
401+
emit_crossed (hovered, false);
402+
}
403+
404+
// tell the new one that it is hovered
405+
hovered = actor;
406+
emit_crossed (hovered, true);
407+
408+
return Clutter.EVENT_STOP;
409+
394410
default:
395411
break;
396412
}

0 commit comments

Comments
 (0)