summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2023-01-24 13:34:29 +0100
committerJonas Ã…dahl <jadahl@gmail.com>2023-02-01 09:33:44 +0100
commit844ce1776df1ac9e396c39e488904991fd32919e (patch)
treed3c3bd21827ceec653c5e7e1529fd97d5f3bafa4
parent45d83b49a8090e882939beea5d70aa89b5c73d38 (diff)
downloadmutter-844ce1776df1ac9e396c39e488904991fd32919e.tar.gz
backends/native: Keep general direction when crossing monitors
When the pointer crosses monitors, we account for a single motion event resulting in the pointer moving across more than 2 monitors, in order to correctly account each monitor scale and the distance traversed across each monitor in the resulting relative motion vector. However, memory on the direction is kept short, each iteration to find the target view just remembers the direction it came from. This brings a pathological case with 4 monitors with the same resolution in a 2x2 grid, and a motion vector that crosses monitors at the intersection of all 4 in a perfect diagonal. (Say, monitors are all 1920x1080 and pointer moves from 1920,1080 to 1919,1079). In that case, the intersection point at the crossing between 4 monitors (say, 1920,1080) will be considered to intersect with 2 edges of each view. Since there is always at least 2 directions to try, the loop will always find the direction other than the one it came from, and as a result endlessly jump across all 4 possible choices. In order to fix this, consider only the global v/h directions, we already know if the pointer moves left/right or up/down, so only consider those directions to jump across monitors. For the case at hand, this will result in three monitors visited, (either bottomright/bottomleft/topleft, or bottomright/topright/topleft) with a total distance of 0,0 in the middle one, effectively resulting in a correct diagonal motion. Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2598 Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2803> (cherry picked from commit 8f268f2930b15bdf974395e0c27085c69d35b99e)
-rw-r--r--src/backends/native/meta-seat-impl.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index cec2060f7..62bf9fc1b 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -1158,12 +1158,22 @@ relative_motion_across_outputs (MetaViewportInfo *viewports,
float x = cur_x, y = cur_y;
float target_x = cur_x, target_y = cur_y;
float dx = *dx_inout, dy = *dy_inout;
- MetaDisplayDirection direction = -1;
+ MetaDisplayDirection direction_h, direction_v;
+
+#define META_DISPLAY_NONE -1
+ direction_h = dx > 0.0 ? META_DISPLAY_RIGHT :
+ dx < 0.0 ? META_DISPLAY_LEFT :
+ META_DISPLAY_NONE;
+ direction_v = dy > 0.0 ? META_DISPLAY_DOWN :
+ dy < 0.0 ? META_DISPLAY_UP :
+ META_DISPLAY_NONE;
+#undef META_DISPLAY_NONE
while (cur_view >= 0)
{
MetaLine2 left, right, top, bottom, motion;
MetaVector2 intersection;
+ MetaDisplayDirection direction;
cairo_rectangle_int_t rect;
float scale;
@@ -1193,16 +1203,16 @@ relative_motion_across_outputs (MetaViewportInfo *viewports,
{ rect.x + rect.width, rect.y + rect.height }
};
- if (direction != META_DISPLAY_RIGHT &&
+ if (direction_h == META_DISPLAY_LEFT &&
meta_line2_intersects_with (&motion, &left, &intersection))
direction = META_DISPLAY_LEFT;
- else if (direction != META_DISPLAY_LEFT &&
+ else if (direction_h == META_DISPLAY_RIGHT &&
meta_line2_intersects_with (&motion, &right, &intersection))
direction = META_DISPLAY_RIGHT;
- else if (direction != META_DISPLAY_DOWN &&
+ else if (direction_v == META_DISPLAY_UP &&
meta_line2_intersects_with (&motion, &top, &intersection))
direction = META_DISPLAY_UP;
- else if (direction != META_DISPLAY_UP &&
+ else if (direction_v == META_DISPLAY_DOWN &&
meta_line2_intersects_with (&motion, &bottom, &intersection))
direction = META_DISPLAY_DOWN;
else