clutter/stage: When compressing relative motion, append the axes

When using a tablet tool in relative mode motion compression may
apply. Doing so drops the axes from the event, leading to a segfault
later when we're trying to broadcast_axis() an event without axes.

Fix this by making sure we copy the axes over during motion compression.
All but the wheel are absolute so we can just take them from the new
event but if we do have wheel data add them together and where the wheel
changes direction skip motion compression.

We can take a few shortcuts here because the clutter implementation
guarantees exactly CLUTTER_INPUT_AXIS_LAST axes so we only need to
put in warning checks in case that ever changes.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3766
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4117>
This commit is contained in:
Peter Hutterer 2024-11-05 15:33:48 +10:00 committed by Marge Bot
parent 423f17a982
commit 4de65bd836

View File

@ -711,6 +711,8 @@ clutter_stage_compress_motion (ClutterStage *stage,
double dst_dx = 0.0, dst_dy = 0.0; double dst_dx = 0.0, dst_dy = 0.0;
double dst_dx_unaccel = 0.0, dst_dy_unaccel = 0.0; double dst_dx_unaccel = 0.0, dst_dy_unaccel = 0.0;
double dst_dx_constrained = 0.0, dst_dy_constrained = 0.0; double dst_dx_constrained = 0.0, dst_dy_constrained = 0.0;
double *current_axes, *last_axes;
guint n_current_axes, n_last_axes;
graphene_point_t coords; graphene_point_t coords;
if (!clutter_event_get_relative_motion (to_discard, if (!clutter_event_get_relative_motion (to_discard,
@ -726,6 +728,35 @@ clutter_stage_compress_motion (ClutterStage *stage,
clutter_event_get_position (event, &coords); clutter_event_get_position (event, &coords);
/* All tablet axes but the wheel are absolute so we can use those
* as-is. But for wheels we only compress if the current value goes in the
* same direction.
*/
current_axes = clutter_event_get_axes (to_discard, &n_current_axes);
last_axes = clutter_event_get_axes (event, &n_last_axes);
g_return_val_if_fail (!last_axes == !current_axes, NULL);
if (current_axes)
{
double current_val = 0.0;
double last_val = 0.0;
g_return_val_if_fail (n_current_axes == CLUTTER_INPUT_AXIS_LAST, NULL);
g_return_val_if_fail (n_last_axes == CLUTTER_INPUT_AXIS_LAST, NULL);
g_return_val_if_fail (n_current_axes == n_last_axes, NULL);
current_val = current_axes[CLUTTER_INPUT_AXIS_WHEEL];
last_val = last_axes[CLUTTER_INPUT_AXIS_WHEEL];
if ((current_val < 0.0 && last_val > 0.0) ||
(current_val > 0.0 && last_val < 0.0))
return NULL;
current_axes = g_memdup2 (current_axes, sizeof (double) * n_current_axes);
current_axes[CLUTTER_INPUT_AXIS_WHEEL] += last_axes[CLUTTER_INPUT_AXIS_WHEEL];
}
return clutter_event_motion_new (CLUTTER_EVENT_FLAG_RELATIVE_MOTION, return clutter_event_motion_new (CLUTTER_EVENT_FLAG_RELATIVE_MOTION,
clutter_event_get_time_us (event), clutter_event_get_time_us (event),
clutter_event_get_source_device (event), clutter_event_get_source_device (event),
@ -738,7 +769,7 @@ clutter_stage_compress_motion (ClutterStage *stage,
(float) (dy_unaccel + dst_dy_unaccel)), (float) (dy_unaccel + dst_dy_unaccel)),
GRAPHENE_POINT_INIT ((float) (dx_constrained + dst_dx_constrained), GRAPHENE_POINT_INIT ((float) (dx_constrained + dst_dx_constrained),
(float) (dy_constrained + dst_dy_constrained)), (float) (dy_constrained + dst_dy_constrained)),
NULL); current_axes);
} }
CLUTTER_EXPORT void CLUTTER_EXPORT void