clutter: Move event filter handling to happen before throttling
As event handling goes: 1) Events get generated and queued by the seat (from another thread in native, in the same thread in X11) 2) The MetaBackend gets those events and forwards them to Clutter via clutter_do_event() 3) The events get queued in the ClutterStage 4) At the time of processing a frame, the input events are processed, 5) Motion events are throttled, only the last is effectively handled 6) Events are filtered, wayland and WM handling happens here 7) Events maybe reach to clutter This commit moves 6 to happen between 2 and 3. The end result is that: - Throttling only applies to Clutter event handling, The wayland event forwarding bits will handle the event stream as soon as it comes, as timely as possible. - WM event handling is also unthrottled, but that's more of a side effect. - This all still happens on the main thread, so there's the possibility that other busy areas (e.g. relayout) temporarily block this event forwarding. - Sending events unthrottled inherently means more CPU, probably dependent on input devices' frequency. The impact is not measured. This should bring the best of both worlds with e.g. 1000Hz mice, wayland clients get unthrottled events, while GNOME Shell UI still behaves like it used to do. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
This commit is contained in:
parent
35b8346a33
commit
b8f92a6ce4
@ -136,6 +136,10 @@ static const GDebugKey clutter_paint_debug_keys[] = {
|
||||
{ "max-render-time", CLUTTER_DEBUG_PAINT_MAX_RENDER_TIME },
|
||||
};
|
||||
|
||||
static ClutterActor * update_device_for_event (ClutterStage *stage,
|
||||
ClutterEvent *event,
|
||||
gboolean emit_crossing);
|
||||
|
||||
gboolean
|
||||
_clutter_context_get_show_fps (void)
|
||||
{
|
||||
@ -695,9 +699,6 @@ static inline void
|
||||
emit_pointer_event (ClutterEvent *event,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
if (_clutter_event_process_filters (event))
|
||||
return;
|
||||
|
||||
if (device != NULL && device->pointer_grab_actor != NULL)
|
||||
clutter_actor_event (device->pointer_grab_actor, event, FALSE);
|
||||
else
|
||||
@ -711,9 +712,6 @@ emit_crossing_event (ClutterEvent *event,
|
||||
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
|
||||
ClutterActor *grab_actor = NULL;
|
||||
|
||||
if (_clutter_event_process_filters (event))
|
||||
return;
|
||||
|
||||
if (sequence)
|
||||
{
|
||||
if (device->sequence_grab_actors != NULL)
|
||||
@ -737,9 +735,6 @@ emit_touch_event (ClutterEvent *event,
|
||||
{
|
||||
ClutterActor *grab_actor = NULL;
|
||||
|
||||
if (_clutter_event_process_filters (event))
|
||||
return;
|
||||
|
||||
if (device->sequence_grab_actors != NULL)
|
||||
{
|
||||
grab_actor = g_hash_table_lookup (device->sequence_grab_actors,
|
||||
@ -764,30 +759,12 @@ process_key_event (ClutterEvent *event,
|
||||
{
|
||||
cally_snoop_key_event ((ClutterKeyEvent *) event);
|
||||
|
||||
if (_clutter_event_process_filters (event))
|
||||
return;
|
||||
|
||||
if (device != NULL && device->keyboard_grab_actor != NULL)
|
||||
clutter_actor_event (device->keyboard_grab_actor, event, FALSE);
|
||||
else
|
||||
emit_event_chain (event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_off_stage (ClutterActor *stage,
|
||||
gfloat x,
|
||||
gfloat y)
|
||||
{
|
||||
gfloat width, height;
|
||||
|
||||
clutter_actor_get_size (stage, &width, &height);
|
||||
|
||||
return (x < 0 ||
|
||||
y < 0 ||
|
||||
x >= width ||
|
||||
y >= height);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_do_event:
|
||||
* @event: a #ClutterEvent.
|
||||
@ -805,6 +782,9 @@ is_off_stage (ClutterActor *stage,
|
||||
void
|
||||
clutter_do_event (ClutterEvent *event)
|
||||
{
|
||||
ClutterInputDevice *device;
|
||||
ClutterEventSequence *sequence;
|
||||
|
||||
/* we need the stage for the event */
|
||||
if (event->any.stage == NULL)
|
||||
{
|
||||
@ -816,6 +796,62 @@ clutter_do_event (ClutterEvent *event)
|
||||
if (CLUTTER_ACTOR_IN_DESTRUCTION (event->any.stage))
|
||||
return;
|
||||
|
||||
device = clutter_event_get_device (event);
|
||||
sequence = clutter_event_get_event_sequence (event);
|
||||
|
||||
if (device)
|
||||
{
|
||||
ClutterActor *actor = NULL;
|
||||
|
||||
switch (event->any.type)
|
||||
{
|
||||
case CLUTTER_ENTER:
|
||||
case CLUTTER_MOTION:
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_TOUCH_BEGIN:
|
||||
case CLUTTER_TOUCH_UPDATE:
|
||||
actor = update_device_for_event (event->any.stage, event, TRUE);
|
||||
break;
|
||||
case CLUTTER_KEY_PRESS:
|
||||
case CLUTTER_KEY_RELEASE:
|
||||
case CLUTTER_PAD_BUTTON_PRESS:
|
||||
case CLUTTER_PAD_BUTTON_RELEASE:
|
||||
case CLUTTER_PAD_STRIP:
|
||||
case CLUTTER_PAD_RING:
|
||||
case CLUTTER_IM_COMMIT:
|
||||
case CLUTTER_IM_DELETE:
|
||||
case CLUTTER_IM_PREEDIT:
|
||||
actor = clutter_stage_get_key_focus (event->any.stage);
|
||||
break;
|
||||
case CLUTTER_DEVICE_ADDED:
|
||||
case CLUTTER_DEVICE_REMOVED:
|
||||
actor = CLUTTER_ACTOR (event->any.stage);
|
||||
break;
|
||||
case CLUTTER_LEAVE:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
case CLUTTER_TOUCH_END:
|
||||
case CLUTTER_TOUCH_CANCEL:
|
||||
case CLUTTER_SCROLL:
|
||||
case CLUTTER_TOUCHPAD_PINCH:
|
||||
case CLUTTER_TOUCHPAD_SWIPE:
|
||||
case CLUTTER_TOUCHPAD_HOLD:
|
||||
case CLUTTER_PROXIMITY_IN:
|
||||
case CLUTTER_PROXIMITY_OUT:
|
||||
actor = clutter_stage_get_device_actor (event->any.stage,
|
||||
device, sequence);
|
||||
break;
|
||||
case CLUTTER_NOTHING:
|
||||
case CLUTTER_EVENT_LAST:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
clutter_event_set_source (event, actor);
|
||||
}
|
||||
|
||||
if (_clutter_event_process_filters (event))
|
||||
return;
|
||||
|
||||
/* Instead of processing events when received, we queue them up to
|
||||
* handle per-frame before animations, layout, and drawing.
|
||||
*
|
||||
@ -1035,32 +1071,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
break;
|
||||
|
||||
case CLUTTER_ENTER:
|
||||
/* if we're entering from outside the stage we need
|
||||
* to check whether the pointer is actually on another
|
||||
* actor, and emit an additional pointer event
|
||||
*/
|
||||
if (event->any.source == stage &&
|
||||
event->crossing.related == NULL)
|
||||
{
|
||||
ClutterActor *actor = NULL;
|
||||
|
||||
emit_crossing_event (event, device);
|
||||
|
||||
actor = update_device_for_event (CLUTTER_STAGE (stage), event, FALSE);
|
||||
if (actor != stage)
|
||||
{
|
||||
ClutterEvent *crossing;
|
||||
|
||||
/* we emit the exact same event on the actor */
|
||||
crossing = clutter_event_copy (event);
|
||||
crossing->crossing.related = stage;
|
||||
crossing->crossing.source = actor;
|
||||
|
||||
emit_crossing_event (crossing, device);
|
||||
clutter_event_free (crossing);
|
||||
}
|
||||
}
|
||||
else
|
||||
emit_crossing_event (event, device);
|
||||
break;
|
||||
|
||||
@ -1106,9 +1116,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
/* Only stage gets motion events */
|
||||
event->any.source = stage;
|
||||
|
||||
if (_clutter_event_process_filters (event))
|
||||
break;
|
||||
|
||||
if (device != NULL && device->pointer_grab_actor != NULL)
|
||||
{
|
||||
clutter_actor_event (device->pointer_grab_actor,
|
||||
@ -1147,66 +1154,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
|
||||
/* Only do a pick to find the source if source is not already set
|
||||
* (as it could be in a synthetic event)
|
||||
*/
|
||||
if (event->any.source == NULL)
|
||||
{
|
||||
/* emulate X11 the implicit soft grab; the implicit soft grab
|
||||
* keeps relaying motion events when the stage is left with a
|
||||
* pointer button pressed. since this is what happens when we
|
||||
* disable per-actor motion events we need to maintain the same
|
||||
* behaviour when the per-actor motion events are enabled as
|
||||
* well
|
||||
*/
|
||||
if (is_off_stage (stage, x, y))
|
||||
{
|
||||
if (event->type == CLUTTER_BUTTON_RELEASE)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"Release off stage received at %.2f, %.2f",
|
||||
x, y);
|
||||
|
||||
event->button.source = stage;
|
||||
|
||||
emit_pointer_event (event, device);
|
||||
}
|
||||
else if (event->type == CLUTTER_MOTION)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"Motion off stage received at %.2f, %2.f",
|
||||
x, y);
|
||||
|
||||
event->motion.source = stage;
|
||||
|
||||
emit_pointer_event (event, device);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* We need to repick on both motion and button press events, the
|
||||
* latter is only needed for X11 (there the device actor might be
|
||||
* stale because we don't always receive motion events).
|
||||
*/
|
||||
if (event->type == CLUTTER_BUTTON_PRESS ||
|
||||
event->type == CLUTTER_MOTION)
|
||||
{
|
||||
event->any.source =
|
||||
update_device_for_event (CLUTTER_STAGE (stage), event, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
event->any.source =
|
||||
clutter_stage_get_device_actor (CLUTTER_STAGE (stage),
|
||||
device,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (event->any.source == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"Reactive event received at %.2f, %.2f - actor: %p",
|
||||
x, y,
|
||||
@ -1226,9 +1173,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
/* Only stage gets motion events */
|
||||
event->any.source = stage;
|
||||
|
||||
if (_clutter_event_process_filters (event))
|
||||
break;
|
||||
|
||||
/* global grabs */
|
||||
if (device->sequence_grab_actors != NULL)
|
||||
{
|
||||
@ -1260,51 +1204,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
|
||||
/* Only do a pick to find the source if source is not already set
|
||||
* (as it could be in a synthetic event)
|
||||
*/
|
||||
if (event->any.source == NULL)
|
||||
{
|
||||
/* same as the mouse events above, emulate the X11 implicit
|
||||
* soft grab */
|
||||
if (is_off_stage (stage, x, y))
|
||||
{
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"Touch %s off stage received at %.2f, %.2f",
|
||||
event->type == CLUTTER_TOUCH_UPDATE ? "update" :
|
||||
event->type == CLUTTER_TOUCH_END ? "end" :
|
||||
event->type == CLUTTER_TOUCH_CANCEL ? "cancel" :
|
||||
"?", x, y);
|
||||
|
||||
event->touch.source = stage;
|
||||
|
||||
emit_touch_event (event, device);
|
||||
|
||||
if (event->type == CLUTTER_TOUCH_END ||
|
||||
event->type == CLUTTER_TOUCH_CANCEL)
|
||||
remove_device_for_event (CLUTTER_STAGE (stage), event, TRUE);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (event->type == CLUTTER_TOUCH_BEGIN ||
|
||||
event->type == CLUTTER_TOUCH_UPDATE)
|
||||
{
|
||||
event->any.source =
|
||||
update_device_for_event (CLUTTER_STAGE (stage), event, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
event->any.source =
|
||||
clutter_stage_get_device_actor (CLUTTER_STAGE (stage),
|
||||
device,
|
||||
event->touch.sequence);
|
||||
}
|
||||
|
||||
if (event->any.source == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"Reactive event received at %.2f, %.2f - actor: %p",
|
||||
x, y,
|
||||
@ -1321,9 +1220,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
|
||||
case CLUTTER_PROXIMITY_IN:
|
||||
case CLUTTER_PROXIMITY_OUT:
|
||||
if (_clutter_event_process_filters (event))
|
||||
break;
|
||||
|
||||
if (!clutter_actor_event (stage, event, TRUE))
|
||||
{
|
||||
/* and bubbling phase */
|
||||
@ -1332,16 +1228,10 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
|
||||
break;
|
||||
|
||||
case CLUTTER_DEVICE_ADDED:
|
||||
_clutter_event_process_filters (event);
|
||||
break;
|
||||
|
||||
case CLUTTER_DEVICE_REMOVED:
|
||||
{
|
||||
ClutterInputDeviceType device_type;
|
||||
|
||||
_clutter_event_process_filters (event);
|
||||
|
||||
device_type = clutter_input_device_get_device_type (device);
|
||||
if (device_type == CLUTTER_POINTER_DEVICE ||
|
||||
device_type == CLUTTER_TABLET_DEVICE ||
|
||||
@ -1353,6 +1243,7 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
break;
|
||||
}
|
||||
|
||||
case CLUTTER_DEVICE_ADDED:
|
||||
case CLUTTER_EVENT_LAST:
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user