diff options
-rw-r--r-- | src/backends/meta-backend-private.h | 2 | ||||
-rw-r--r-- | src/backends/meta-backend.c | 7 | ||||
-rw-r--r-- | src/backends/meta-pointer-constraint.c | 91 | ||||
-rw-r--r-- | src/backends/meta-pointer-constraint.h | 49 | ||||
-rw-r--r-- | src/backends/native/meta-backend-native.c | 60 | ||||
-rw-r--r-- | src/backends/native/meta-pointer-constraint-native.c | 693 | ||||
-rw-r--r-- | src/backends/native/meta-pointer-constraint-native.h | 46 | ||||
-rw-r--r-- | src/backends/native/meta-seat-native.c | 57 | ||||
-rw-r--r-- | src/backends/native/meta-seat-native.h | 38 | ||||
-rw-r--r-- | src/meson.build | 2 | ||||
-rw-r--r-- | src/wayland/meta-pointer-confinement-wayland.c | 755 | ||||
-rw-r--r-- | src/wayland/meta-pointer-confinement-wayland.h | 23 | ||||
-rw-r--r-- | src/wayland/meta-pointer-lock-wayland.c | 61 | ||||
-rw-r--r-- | src/wayland/meta-pointer-lock-wayland.h | 6 | ||||
-rw-r--r-- | src/wayland/meta-wayland-pointer-constraints.c | 25 |
15 files changed, 1118 insertions, 797 deletions
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h index 0b62ed4bf..afce64fd7 100644 --- a/src/backends/meta-backend-private.h +++ b/src/backends/meta-backend-private.h @@ -101,6 +101,8 @@ struct _MetaBackendClass void (* set_numlock) (MetaBackend *backend, gboolean numlock_state); + void (* set_pointer_constraint) (MetaBackend *backend, + MetaPointerConstraint *constraint); }; void meta_init_backend (GType backend_gtype); diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 1770ad795..1e4f00a75 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -1313,11 +1313,8 @@ meta_backend_set_client_pointer_constraint (MetaBackend *backend, { MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); - g_assert (!constraint || !priv->client_pointer_constraint); - - g_clear_object (&priv->client_pointer_constraint); - if (constraint) - priv->client_pointer_constraint = g_object_ref (constraint); + META_BACKEND_GET_CLASS (backend)->set_pointer_constraint (backend, constraint); + g_set_object (&priv->client_pointer_constraint, constraint); } ClutterBackend * diff --git a/src/backends/meta-pointer-constraint.c b/src/backends/meta-pointer-constraint.c index 55ca9f023..7682b14b0 100644 --- a/src/backends/meta-pointer-constraint.c +++ b/src/backends/meta-pointer-constraint.c @@ -39,10 +39,34 @@ #include "backends/meta-pointer-constraint.h" +#ifdef HAVE_NATIVE_BACKEND +#include "backends/native/meta-backend-native.h" +#include "backends/native/meta-pointer-constraint-native.h" +#endif + #include <glib-object.h> +struct _MetaPointerConstraint +{ + GObject parent_instance; + cairo_region_t *region; +}; + G_DEFINE_TYPE (MetaPointerConstraint, meta_pointer_constraint, G_TYPE_OBJECT); +G_DEFINE_TYPE (MetaPointerConstraintImpl, meta_pointer_constraint_impl, + G_TYPE_OBJECT); + +static void +meta_pointer_constraint_finalize (GObject *object) +{ + MetaPointerConstraint *constraint = META_POINTER_CONSTRAINT (object); + + g_clear_pointer (&constraint->region, cairo_region_destroy); + + G_OBJECT_CLASS (meta_pointer_constraint_parent_class)->finalize (object); +} + static void meta_pointer_constraint_init (MetaPointerConstraint *constraint) { @@ -51,11 +75,42 @@ meta_pointer_constraint_init (MetaPointerConstraint *constraint) static void meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_pointer_constraint_finalize; +} + + +MetaPointerConstraint * +meta_pointer_constraint_new (const cairo_region_t *region) +{ + MetaPointerConstraint *constraint; + + constraint = g_object_new (META_TYPE_POINTER_CONSTRAINT, NULL); + constraint->region = cairo_region_copy (region); + + return constraint; +} + +cairo_region_t * +meta_pointer_constraint_get_region (MetaPointerConstraint *constraint) +{ + return constraint->region; +} + +static void +meta_pointer_constraint_impl_init (MetaPointerConstraintImpl *constraint_impl) +{ +} + +static void +meta_pointer_constraint_impl_class_init (MetaPointerConstraintImplClass *klass) +{ } /** - * meta_pointer_constraint_constrain: - * @constraint: a #MetaPointerConstraint. + * meta_pointer_constraint_impl_constrain: + * @constraint_impl: a #MetaPointerConstraintImpl. * @device; the device of the pointer. * @time: the timestamp (in ms) of the event. * @prev_x: X-coordinate of the previous pointer position. @@ -67,17 +122,25 @@ meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass) * if needed. */ void -meta_pointer_constraint_constrain (MetaPointerConstraint *constraint, - ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y) +meta_pointer_constraint_impl_constrain (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device, + uint32_t time, + float prev_x, + float prev_y, + float *x, + float *y) +{ + META_POINTER_CONSTRAINT_IMPL_GET_CLASS (constraint_impl)->constrain (constraint_impl, + device, + time, + prev_x, prev_y, + x, y); +} + +void +meta_pointer_constraint_impl_ensure_constrained (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device) { - META_POINTER_CONSTRAINT_GET_CLASS (constraint)->constrain (constraint, - device, - time, - prev_x, prev_y, - x, y); + META_POINTER_CONSTRAINT_IMPL_GET_CLASS (constraint_impl)->ensure_constrained (constraint_impl, + device); } diff --git a/src/backends/meta-pointer-constraint.h b/src/backends/meta-pointer-constraint.h index ed0b025b5..b47eda490 100644 --- a/src/backends/meta-pointer-constraint.h +++ b/src/backends/meta-pointer-constraint.h @@ -32,34 +32,45 @@ G_BEGIN_DECLS #define META_TYPE_POINTER_CONSTRAINT (meta_pointer_constraint_get_type ()) -G_DECLARE_DERIVABLE_TYPE (MetaPointerConstraint, meta_pointer_constraint, - META, POINTER_CONSTRAINT, GObject); +G_DECLARE_FINAL_TYPE (MetaPointerConstraint, meta_pointer_constraint, + META, POINTER_CONSTRAINT, GObject); + +MetaPointerConstraint * meta_pointer_constraint_new (const cairo_region_t *region); +cairo_region_t * meta_pointer_constraint_get_region (MetaPointerConstraint *constraint); + +#define META_TYPE_POINTER_CONSTRAINT_IMPL (meta_pointer_constraint_impl_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaPointerConstraintImpl, meta_pointer_constraint_impl, + META, POINTER_CONSTRAINT_IMPL, GObject); /** - * MetaPointerConstraintClass: + * MetaPointerConstraintImplClass: * @constrain: the virtual function pointer for - * meta_pointer_constraint_constrain(). + * meta_pointer_constraint_impl_constrain(). */ -struct _MetaPointerConstraintClass +struct _MetaPointerConstraintImplClass { GObjectClass parent_class; - void (*constrain) (MetaPointerConstraint *constraint, - ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y); + void (* constrain) (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device, + uint32_t time, + float prev_x, + float prev_y, + float *x, + float *y); + void (* ensure_constrained) (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device); }; -void meta_pointer_constraint_constrain (MetaPointerConstraint *constraint, - ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y); +void meta_pointer_constraint_impl_constrain (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device, + uint32_t time, + float prev_x, + float prev_y, + float *x, + float *y); +void meta_pointer_constraint_impl_ensure_constrained (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device); G_END_DECLS diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index 73093cb03..bca79f823 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -105,38 +105,6 @@ meta_backend_native_finalize (GObject *object) G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object); } -static void -constrain_to_client_constraint (ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y) -{ - MetaBackend *backend = meta_get_backend (); - MetaPointerConstraint *constraint = - meta_backend_get_client_pointer_constraint (backend); - - if (!constraint) - return; - - meta_pointer_constraint_constrain (constraint, device, - time, prev_x, prev_y, x, y); -} - -static void -pointer_constrain_callback (ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *new_x, - float *new_y, - gpointer user_data) -{ - /* Constrain to pointer lock */ - constrain_to_client_constraint (device, time, prev_x, prev_y, new_x, new_y); -} - static ClutterBackend * meta_backend_native_create_clutter_backend (MetaBackend *backend) { @@ -181,14 +149,8 @@ maybe_disable_screen_cast_dma_bufs (MetaBackendNative *native) static void meta_backend_native_post_init (MetaBackend *backend) { - ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); - ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); MetaSettings *settings = meta_backend_get_settings (backend); - meta_seat_native_set_pointer_constrain_callback (META_SEAT_NATIVE (seat), - pointer_constrain_callback, - NULL, NULL); - META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend); if (meta_settings_is_experimental_feature_enabled (settings, @@ -350,6 +312,26 @@ meta_backend_native_set_numlock (MetaBackend *backend, } static void +meta_backend_native_set_pointer_constraint (MetaBackend *backend, + MetaPointerConstraint *constraint) +{ + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); + MetaPointerConstraintImpl *constraint_impl = NULL; + cairo_region_t *region; + + if (constraint) + { + region = meta_pointer_constraint_get_region (constraint); + constraint_impl = meta_pointer_constraint_impl_native_new (constraint, + region); + } + + meta_seat_native_set_pointer_constraint (META_SEAT_NATIVE (seat), + constraint_impl); +} + +static void meta_backend_native_update_screen_size (MetaBackend *backend, int width, int height) { @@ -562,6 +544,8 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass) backend_class->lock_layout_group = meta_backend_native_lock_layout_group; backend_class->update_screen_size = meta_backend_native_update_screen_size; backend_class->set_numlock = meta_backend_native_set_numlock; + + backend_class->set_pointer_constraint = meta_backend_native_set_pointer_constraint; } static void diff --git a/src/backends/native/meta-pointer-constraint-native.c b/src/backends/native/meta-pointer-constraint-native.c new file mode 100644 index 000000000..8ce678ae4 --- /dev/null +++ b/src/backends/native/meta-pointer-constraint-native.c @@ -0,0 +1,693 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2015-2020 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jonas Ã…dahl <jadahl@gmail.com> + */ + +#include "config.h" + +#include <glib-object.h> +#include <wayland-server.h> + +#include "core/meta-border.h" +#include "meta-pointer-constraint-native.h" + +struct _MetaPointerConstraintImplNative +{ + MetaPointerConstraintImpl parent; + MetaPointerConstraint *constraint; + cairo_region_t *region; +}; + +G_DEFINE_TYPE (MetaPointerConstraintImplNative, + meta_pointer_constraint_impl_native, + META_TYPE_POINTER_CONSTRAINT_IMPL); + +typedef struct _MetaBox +{ + int x1; + int y1; + int x2; + int y2; +} MetaBox; + +static MetaBorder * +add_border (GArray *borders, + float x1, + float y1, + float x2, + float y2, + MetaBorderMotionDirection blocking_directions) +{ + MetaBorder border; + + border = (MetaBorder) { + .line = (MetaLine2) { + .a = (MetaVector2) { + .x = x1, + .y = y1, + }, + .b = (MetaVector2) { + .x = x2, + .y = y2, + }, + }, + .blocking_directions = blocking_directions, + }; + + g_array_append_val (borders, border); + + return &g_array_index (borders, MetaBorder, borders->len - 1); +} + +static gint +compare_lines_x (gconstpointer a, + gconstpointer b) +{ + const MetaBorder *border_a = a; + const MetaBorder *border_b = b; + + if (border_a->line.a.x == border_b->line.a.x) + return border_a->line.b.x < border_b->line.b.x; + else + return border_a->line.a.x > border_b->line.a.x; +} + +static void +add_non_overlapping_edges (MetaBox *boxes, + unsigned int band_above_start, + unsigned int band_below_start, + unsigned int band_below_end, + GArray *borders) +{ + unsigned int i; + GArray *band_merge; + MetaBorder *border; + MetaBorder *prev_border; + MetaBorder *new_border; + + band_merge = g_array_new (FALSE, FALSE, sizeof *border); + + /* Add bottom band of previous row, and top band of current row, and + * sort them so lower left x coordinate comes first. If there are two + * borders with the same left x coordinate, the wider one comes first. + */ + for (i = band_above_start; i < band_below_start; i++) + { + MetaBox *box = &boxes[i]; + add_border (band_merge, box->x1, box->y2, box->x2, box->y2, + META_BORDER_MOTION_DIRECTION_POSITIVE_Y); + } + for (i = band_below_start; i < band_below_end; i++) + { + MetaBox *box= &boxes[i]; + add_border (band_merge, box->x1, box->y1, box->x2, box->y1, + META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); + } + g_array_sort (band_merge, compare_lines_x); + + /* Combine the two combined bands so that any overlapping border is + * eliminated. */ + prev_border = NULL; + for (i = 0; i < band_merge->len; i++) + { + border = &g_array_index (band_merge, MetaBorder, i); + + g_assert (border->line.a.y == border->line.b.y); + g_assert (!prev_border || + prev_border->line.a.y == border->line.a.y); + g_assert (!prev_border || + (prev_border->line.a.x != border->line.a.x || + prev_border->line.b.x != border->line.b.x)); + g_assert (!prev_border || + prev_border->line.a.x <= border->line.a.x); + + if (prev_border && + prev_border->line.a.x == border->line.a.x) + { + /* + * ------------ + + * ------- = + * [ ]----- + */ + prev_border->line.a.x = border->line.b.x; + } + else if (prev_border && + prev_border->line.b.x == border->line.b.x) + { + /* + * ------------ + + * ------ = + * ------[ ] + */ + prev_border->line.b.x = border->line.a.x; + } + else if (prev_border && + prev_border->line.b.x == border->line.a.x) + { + /* + * -------- + + * ------ = + * -------------- + */ + prev_border->line.b.x = border->line.b.x; + } + else if (prev_border && + prev_border->line.b.x >= border->line.a.x) + { + /* + * --------------- + + * ------ = + * -----[ ]---- + */ + new_border = add_border (borders, + border->line.b.x, + border->line.b.y, + prev_border->line.b.x, + prev_border->line.b.y, + prev_border->blocking_directions); + prev_border->line.b.x = border->line.a.x; + prev_border = new_border; + } + else + { + g_assert (!prev_border || + prev_border->line.b.x < border->line.a.x); + /* + * First border or non-overlapping. + * + * ----- + + * ----- = + * ----- ----- + */ + g_array_append_val (borders, *border); + prev_border = &g_array_index (borders, MetaBorder, borders->len - 1); + } + } + + g_array_free (band_merge, FALSE); +} + +static void +add_band_bottom_edges (MetaBox *boxes, + int band_start, + int band_end, + GArray *borders) +{ + int i; + + for (i = band_start; i < band_end; i++) + { + add_border (borders, + boxes[i].x1, boxes[i].y2, + boxes[i].x2, boxes[i].y2, + META_BORDER_MOTION_DIRECTION_POSITIVE_Y); + } +} + +static void +region_to_outline (cairo_region_t *region, + GArray *borders) +{ + MetaBox *boxes; + int num_boxes; + int i; + int top_most, bottom_most; + int current_roof; + int prev_top; + int band_start, prev_band_start; + + /* + * Remove any overlapping lines from the set of rectangles. Note that + * pixman regions are grouped as rows of rectangles, where rectangles + * in one row never touch or overlap and are all of the same height. + * + * -------- --- -------- --- + * | | | | | | | | + * ----------====---- --- ----------- ----- --- + * | | => | | + * ----==========--------- ----- ---------- + * | | | | + * ------------------- ------------------- + * + */ + + num_boxes = cairo_region_num_rectangles (region); + boxes = g_new (MetaBox, num_boxes); + for (i = 0; i < num_boxes; i++) + { + cairo_rectangle_int_t rect; + cairo_region_get_rectangle (region, i, &rect); + boxes[i] = (MetaBox) { + .x1 = rect.x, + .y1 = rect.y, + .x2 = rect.x + rect.width, + .y2 = rect.y + rect.height, + }; + } + prev_top = 0; + top_most = boxes[0].y1; + current_roof = top_most; + bottom_most = boxes[num_boxes - 1].y2; + band_start = 0; + prev_band_start = 0; + for (i = 0; i < num_boxes; i++) + { + /* Detect if there is a vertical empty space, and add the lower + * level of the previous band if so was the case. */ + if (i > 0 && + boxes[i].y1 != prev_top && + boxes[i].y1 != boxes[i - 1].y2) + { + current_roof = boxes[i].y1; + add_band_bottom_edges (boxes, + band_start, + i, + borders); + } + + /* Special case adding the last band, since it won't be handled + * by the band change detection below. */ + if (boxes[i].y1 != current_roof && i == num_boxes - 1) + { + if (boxes[i].y1 != prev_top) + { + /* The last band is a single box, so we don't + * have a prev_band_start to tell us when the + * previous band started. */ + add_non_overlapping_edges (boxes, + band_start, + i, + i + 1, + borders); + } + else + { + add_non_overlapping_edges (boxes, + prev_band_start, + band_start, + i + 1, + borders); + } + } + + /* Detect when passing a band and combine the top border of the + * just passed band with the bottom band of the previous band. + */ + if (boxes[i].y1 != top_most && boxes[i].y1 != prev_top) + { + /* Combine the two passed bands. */ + if (prev_top != current_roof) + { + add_non_overlapping_edges (boxes, + prev_band_start, + band_start, + i, + borders); + } + + prev_band_start = band_start; + band_start = i; + } + + /* Add the top border if the box is part of the current roof. */ + if (boxes[i].y1 == current_roof) + { + add_border (borders, + boxes[i].x1, boxes[i].y1, + boxes[i].x2, boxes[i].y1, + META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); + } + + /* Add the bottom border of the last band. */ + if (boxes[i].y2 == bottom_most) + { + add_border (borders, + boxes[i].x1, boxes[i].y2, + boxes[i].x2, boxes[i].y2, + META_BORDER_MOTION_DIRECTION_POSITIVE_Y); + } + + /* Always add the left border. */ + add_border (borders, + boxes[i].x1, boxes[i].y1, + boxes[i].x1, boxes[i].y2, + META_BORDER_MOTION_DIRECTION_NEGATIVE_X); + + /* Always add the right border. */ + add_border (borders, + boxes[i].x2, boxes[i].y1, + boxes[i].x2, boxes[i].y2, + META_BORDER_MOTION_DIRECTION_POSITIVE_X); + + prev_top = boxes[i].y1; + } + + g_free (boxes); +} + +static MetaBorder * +get_closest_border (GArray *borders, + MetaLine2 *motion, + uint32_t directions) +{ + MetaBorder *border; + MetaVector2 intersection; + MetaVector2 delta; + float distance_2; + MetaBorder *closest_border = NULL; + float closest_distance_2 = DBL_MAX; + unsigned int i; + + for (i = 0; i < borders->len; i++) + { + border = &g_array_index (borders, MetaBorder, i); + + if (!meta_border_is_blocking_directions (border, directions)) + continue; + + if (!meta_line2_intersects_with (&border->line, motion, &intersection)) + continue; + + delta = meta_vector2_subtract (intersection, motion->a); + distance_2 = delta.x*delta.x + delta.y*delta.y; + if (distance_2 < closest_distance_2) + { + closest_border = border; + closest_distance_2 = distance_2; + } + } + + return closest_border; +} + +static void +clamp_to_border (MetaBorder *border, + MetaLine2 *motion, + uint32_t *motion_dir) +{ + /* + * When clamping either rightward or downward motions, the motion needs to be + * clamped so that the destination coordinate does not end up on the border + * (see weston_pointer_clamp_event_to_region). Do this by clamping such + * motions to the border minus the smallest possible wl_fixed_t value. + * + * When clamping in either leftward or upward motion, the resulting coordinate + * needs to be clamped so that it is enough on the inside to avoid the + * inaccuracies of clutter's stage to actor transformation algorithm (the one + * used in clutter_actor_transform_stage_point) to make it end up outside the + * next motion. It also needs to be clamped so that to the wl_fixed_t + * coordinate may still be right on the border (i.e. at .0). Testing shows + * that the smallest wl_fixed_t value divided by 10 is small enough to make + * the wl_fixed_t coordinate .0 and large enough to avoid the inaccuracies of + * clutters transform algorithm. + */ + if (meta_border_is_horizontal (border)) + { + if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_Y) + motion->b.y = border->line.a.y - wl_fixed_to_double (1); + else + motion->b.y = border->line.a.y + wl_fixed_to_double (1) / 10; + *motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_Y | + META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); + } + else + { + if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_X) + motion->b.x = border->line.a.x - wl_fixed_to_double (1); + else + motion->b.x = border->line.a.x + wl_fixed_to_double (1) / 10; + *motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_X | + META_BORDER_MOTION_DIRECTION_NEGATIVE_X); + } +} + +static uint32_t +get_motion_directions (MetaLine2 *motion) +{ + uint32_t directions = 0; + + if (motion->a.x < motion->b.x) + directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_X; + else if (motion->a.x > motion->b.x) + directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_X; + if (motion->a.y < motion->b.y) + directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_Y; + else if (motion->a.y > motion->b.y) + directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_Y; + + return directions; +} + +static void +meta_pointer_constraint_impl_native_constraint (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device, + uint32_t time, + float prev_x, + float prev_y, + float *x_inout, + float *y_inout) +{ + MetaPointerConstraintImplNative *constraint_impl_native; + cairo_region_t *region; + float x, y; + GArray *borders; + MetaLine2 motion; + MetaBorder *closest_border; + uint32_t directions; + + constraint_impl_native = META_POINTER_CONSTRAINT_IMPL_NATIVE (constraint_impl); + + region = cairo_region_reference (constraint_impl_native->region); + x = *x_inout; + y = *y_inout; + + /* For motions in a positive direction on any axis, append the smallest + * possible value representable in a Wayland absolute coordinate. This is + * in order to avoid not clamping motion that as a floating point number + * won't be clamped, but will be rounded up to be outside of the range + * of wl_fixed_t. */ + if (x > prev_x) + x += (float) wl_fixed_to_double(1); + if (y > prev_y) + y += (float) wl_fixed_to_double(1); + + borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder)); + + /* + * Generate borders given the confine region we are to use. The borders + * are defined to be the outer region of the allowed area. This means + * top/left borders are "within" the allowed area, while bottom/right + * borders are outside. This needs to be considered when clamping + * confined motion vectors. + */ + region_to_outline (region, borders); + cairo_region_destroy (region); + + motion = (MetaLine2) { + .a = (MetaVector2) { + .x = prev_x, + .y = prev_y, + }, + .b = (MetaVector2) { + .x = x, + .y = y, + }, + }; + directions = get_motion_directions (&motion); + + while (directions) + { + closest_border = get_closest_border (borders, + &motion, + directions); + if (closest_border) + clamp_to_border (closest_border, &motion, &directions); + else + break; + } + + *x_inout = motion.b.x; + *y_inout = motion.b.y; + g_array_free (borders, FALSE); +} + +static float +point_to_border_distance_2 (MetaBorder *border, + float x, + float y) +{ + float orig_x, orig_y; + float dx, dy; + + if (meta_border_is_horizontal (border)) + { + if (x < border->line.a.x) + orig_x = border->line.a.x; + else if (x > border->line.b.x) + orig_x = border->line.b.x; + else + orig_x = x; + orig_y = border->line.a.y; + } + else + { + if (y < border->line.a.y) + orig_y = border->line.a.y; + else if (y > border->line.b.y) + orig_y = border->line.b.y; + else + orig_y = y; + orig_x = border->line.a.x; + } + + dx = fabsf (orig_x - x); + dy = fabsf (orig_y - y); + return dx*dx + dy*dy; +} + +static void +closest_point_behind_border (MetaBorder *border, + float *sx, + float *sy) +{ + switch (border->blocking_directions) + { + case META_BORDER_MOTION_DIRECTION_POSITIVE_X: + case META_BORDER_MOTION_DIRECTION_NEGATIVE_X: + if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_X) + *sx = border->line.a.x - wl_fixed_to_double (1); + else + *sx = border->line.a.x + wl_fixed_to_double (1); + if (*sy < border->line.a.y) + *sy = border->line.a.y + wl_fixed_to_double (1); + else if (*sy > border->line.b.y) + *sy = border->line.b.y - wl_fixed_to_double (1); + break; + case META_BORDER_MOTION_DIRECTION_POSITIVE_Y: + case META_BORDER_MOTION_DIRECTION_NEGATIVE_Y: + if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_Y) + *sy = border->line.a.y - wl_fixed_to_double (1); + else + *sy = border->line.a.y + wl_fixed_to_double (1); + if (*sx < border->line.a.x) + *sx = border->line.a.x + wl_fixed_to_double (1); + else if (*sx > (border->line.b.x)) + *sx = border->line.b.x - wl_fixed_to_double (1); + break; + } +} + +static void +meta_pointer_constraint_impl_native_ensure_constrained (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device) +{ + MetaPointerConstraintImplNative *constraint_impl_native; + graphene_point_t point; + cairo_region_t *region; + float x; + float y; + + constraint_impl_native = META_POINTER_CONSTRAINT_IMPL_NATIVE (constraint_impl); + region = cairo_region_reference (constraint_impl_native->region); + + clutter_input_device_get_coords (device, NULL, &point); + x = point.x; + y = point.y; + + if (!cairo_region_contains_point (region, (int) x, (int) y)) + { + GArray *borders; + float closest_distance_2 = FLT_MAX; + MetaBorder *closest_border = NULL; + ClutterSeat *seat; + unsigned int i; + + borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder)); + + region_to_outline (region, borders); + + for (i = 0; i < borders->len; i++) + { + MetaBorder *border = &g_array_index (borders, MetaBorder, i); + float distance_2; + + distance_2 = point_to_border_distance_2 (border, x, y); + if (distance_2 < closest_distance_2) + { + closest_border = border; + closest_distance_2 = distance_2; + } + } + + closest_point_behind_border (closest_border, &x, &y); + + seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); + clutter_seat_warp_pointer (seat, x, y); + } + + cairo_region_destroy (region); +} + +static void +meta_pointer_constraint_impl_native_finalize (GObject *object) +{ + MetaPointerConstraintImplNative *constraint_impl_native; + + constraint_impl_native = META_POINTER_CONSTRAINT_IMPL_NATIVE (object); + g_clear_pointer (&constraint_impl_native->region, cairo_region_destroy); + + G_OBJECT_CLASS (meta_pointer_constraint_impl_native_parent_class)->finalize (object); +} + +static void +meta_pointer_constraint_impl_native_init (MetaPointerConstraintImplNative *constraint_impl_native) +{ +} + +static void +meta_pointer_constraint_impl_native_class_init (MetaPointerConstraintImplNativeClass *klass) +{ + MetaPointerConstraintImplClass *constraint_impl_class; + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_pointer_constraint_impl_native_finalize; + + constraint_impl_class = META_POINTER_CONSTRAINT_IMPL_CLASS (klass); + constraint_impl_class->constrain = meta_pointer_constraint_impl_native_constraint; + constraint_impl_class->ensure_constrained = + meta_pointer_constraint_impl_native_ensure_constrained; +} + + +MetaPointerConstraintImpl * +meta_pointer_constraint_impl_native_new (MetaPointerConstraint *constraint, + const cairo_region_t *region) +{ + MetaPointerConstraintImplNative *constraint_impl; + + constraint_impl = g_object_new (META_TYPE_POINTER_CONSTRAINT_IMPL_NATIVE, + NULL); + constraint_impl->constraint = constraint; + constraint_impl->region = cairo_region_copy (region); + + return META_POINTER_CONSTRAINT_IMPL (constraint_impl); +} diff --git a/src/backends/native/meta-pointer-constraint-native.h b/src/backends/native/meta-pointer-constraint-native.h new file mode 100644 index 000000000..83a2e575d --- /dev/null +++ b/src/backends/native/meta-pointer-constraint-native.h @@ -0,0 +1,46 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2020 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Carlos Garnacho <carlosg@gnome.org> + */ + +#ifndef META_POINTER_CONSTRAINT_NATIVE_H +#define META_POINTER_CONSTRAINT_NATIVE_H + +#include <glib-object.h> + +#include "clutter/clutter.h" +#include "backends/meta-pointer-constraint.h" + +G_BEGIN_DECLS + +#define META_TYPE_POINTER_CONSTRAINT_IMPL_NATIVE (meta_pointer_constraint_impl_native_get_type ()) +G_DECLARE_FINAL_TYPE (MetaPointerConstraintImplNative, + meta_pointer_constraint_impl_native, + META, POINTER_CONSTRAINT_IMPL_NATIVE, + MetaPointerConstraintImpl) + +MetaPointerConstraintImpl * meta_pointer_constraint_impl_native_new (MetaPointerConstraint *constraint_impl, + const cairo_region_t *region); + +G_END_DECLS + +#endif /* META_POINTER_CONSTRAINT_NATIVE_H */ diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c index ea0cd0742..b27e19672 100644 --- a/src/backends/native/meta-seat-native.c +++ b/src/backends/native/meta-seat-native.c @@ -934,13 +934,14 @@ meta_seat_native_constrain_pointer (MetaSeatNative *seat, us2ms (time_us), new_x, new_y); - if (seat->constrain_callback) + /* Bar to constraints */ + if (seat->pointer_constraint) { - seat->constrain_callback (core_pointer, - us2ms (time_us), - x, y, - new_x, new_y, - seat->constrain_data); + meta_pointer_constraint_impl_constrain (seat->pointer_constraint, + core_pointer, + us2ms (time_us), + x, y, + new_x, new_y); } /* if we're moving inside a monitor, we're fine */ @@ -2642,9 +2643,6 @@ meta_seat_native_finalize (GObject *object) g_list_free (seat->free_device_ids); - if (seat->constrain_data_notify != NULL) - seat->constrain_data_notify (seat->constrain_data); - g_free (seat->seat_id); G_OBJECT_CLASS (meta_seat_native_parent_class)->finalize (object); @@ -3028,33 +3026,6 @@ meta_seat_native_set_device_callbacks (MetaOpenDeviceCallback open_callback, device_callback_data = user_data; } -/** - * meta_seat_native_set_pointer_constrain_callback: - * @seat: the #ClutterSeat created by the evdev backend - * @callback: the callback - * @user_data: data to pass to the callback - * @user_data_notify: function to be called when removing the callback - * - * Sets a callback to be invoked for every pointer motion. The callback - * can then modify the new pointer coordinates to constrain movement within - * a specific region. - */ -void -meta_seat_native_set_pointer_constrain_callback (MetaSeatNative *seat, - MetaPointerConstrainCallback callback, - gpointer user_data, - GDestroyNotify user_data_notify) -{ - g_return_if_fail (META_IS_SEAT_NATIVE (seat)); - - if (seat->constrain_data_notify) - seat->constrain_data_notify (seat->constrain_data); - - seat->constrain_callback = callback; - seat->constrain_data = user_data; - seat->constrain_data_notify = user_data_notify; -} - void meta_seat_native_update_xkb_state (MetaSeatNative *seat) { @@ -3303,3 +3274,17 @@ meta_seat_native_get_barrier_manager (MetaSeatNative *seat) { return seat->barrier_manager; } + +void +meta_seat_native_set_pointer_constraint (MetaSeatNative *seat, + MetaPointerConstraintImpl *constraint_impl) +{ + if (!g_set_object (&seat->pointer_constraint, constraint_impl)) + return; + + if (constraint_impl) + { + meta_pointer_constraint_impl_ensure_constrained (constraint_impl, + seat->core_pointer); + } +} diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h index 0cc353e7d..2a1faaee0 100644 --- a/src/backends/native/meta-seat-native.h +++ b/src/backends/native/meta-seat-native.h @@ -29,6 +29,7 @@ #include "backends/native/meta-barrier-native.h" #include "backends/native/meta-keymap-native.h" +#include "backends/native/meta-pointer-constraint-native.h" #include "backends/native/meta-xkb-utils.h" #include "clutter/clutter.h" @@ -36,30 +37,6 @@ typedef struct _MetaTouchState MetaTouchState; typedef struct _MetaSeatNative MetaSeatNative; typedef struct _MetaEventSource MetaEventSource; -/** - * MetaPointerConstrainCallback: - * @device: the core pointer device - * @time: the event time in milliseconds - * @x: (inout): the new X coordinate - * @y: (inout): the new Y coordinate - * @user_data: user data passed to this function - * - * This callback will be called for all pointer motion events, and should - * update (@x, @y) to constrain the pointer position appropriately. - * The subsequent motion event will use the updated values as the new coordinates. - * Note that the coordinates are not clamped to the stage size, and the callback - * must make sure that this happens before it returns. - * Also note that the event will be emitted even if the pointer is constrained - * to be in the same position. - */ -typedef void (* MetaPointerConstrainCallback) (ClutterInputDevice *device, - uint32_t time, - float prev_x, - float prev_y, - float *x, - float *y, - gpointer user_data); - struct _MetaTouchState { MetaSeatNative *seat; @@ -104,10 +81,7 @@ struct _MetaSeatNative GList *free_device_ids; MetaBarrierManagerNative *barrier_manager; - - MetaPointerConstrainCallback constrain_callback; - gpointer constrain_data; - GDestroyNotify constrain_data_notify; + MetaPointerConstraintImpl *pointer_constraint; MetaKeymapNative *keymap; @@ -256,11 +230,6 @@ void meta_seat_native_set_device_callbacks (MetaOpenDeviceCallback open_callba void meta_seat_native_release_devices (MetaSeatNative *seat); void meta_seat_native_reclaim_devices (MetaSeatNative *seat); -void meta_seat_native_set_pointer_constrain_callback (MetaSeatNative *seat, - MetaPointerConstrainCallback callback, - gpointer user_data, - GDestroyNotify user_data_notify); - struct xkb_state * meta_seat_native_get_xkb_state (MetaSeatNative *seat); void meta_seat_native_set_keyboard_map (MetaSeatNative *seat, @@ -286,4 +255,7 @@ void meta_seat_native_release_touch_slots (MetaSeatNative *seat, MetaBarrierManagerNative * meta_seat_native_get_barrier_manager (MetaSeatNative *seat); +void meta_seat_native_set_pointer_constraint (MetaSeatNative *seat, + MetaPointerConstraintImpl *constraint_impl); + #endif /* META_SEAT_NATIVE_H */ diff --git a/src/meson.build b/src/meson.build index cc8527bea..df8667f5c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -697,6 +697,8 @@ if have_native_backend 'backends/native/meta-kms-utils.h', 'backends/native/meta-kms.c', 'backends/native/meta-kms.h', + 'backends/native/meta-pointer-constraint-native.c', + 'backends/native/meta-pointer-constraint-native.h', 'backends/native/meta-renderer-native-gles3.c', 'backends/native/meta-renderer-native-gles3.h', 'backends/native/meta-renderer-native.h', diff --git a/src/wayland/meta-pointer-confinement-wayland.c b/src/wayland/meta-pointer-confinement-wayland.c index 7f980054c..3df6ed0ab 100644 --- a/src/wayland/meta-pointer-confinement-wayland.c +++ b/src/wayland/meta-pointer-confinement-wayland.c @@ -41,698 +41,227 @@ #include "backends/meta-backend-private.h" #include "backends/meta-pointer-constraint.h" -#include "compositor/meta-surface-actor-wayland.h" -#include "core/meta-border.h" #include "wayland/meta-wayland-pointer-constraints.h" #include "wayland/meta-wayland-pointer.h" #include "wayland/meta-wayland-seat.h" #include "wayland/meta-wayland-surface.h" -struct _MetaPointerConfinementWayland -{ - MetaPointerConstraint parent; +typedef struct _MetaPointerConfinementWaylandPrivate MetaPointerConfinementWaylandPrivate; +struct _MetaPointerConfinementWaylandPrivate +{ MetaWaylandPointerConstraint *constraint; + gboolean enabled; }; -typedef struct _MetaBox -{ - int x1; - int y1; - int x2; - int y2; -} MetaBox; - -G_DEFINE_TYPE (MetaPointerConfinementWayland, meta_pointer_confinement_wayland, - META_TYPE_POINTER_CONSTRAINT); - -static MetaBorder * -add_border (GArray *borders, - float x1, float y1, - float x2, float y2, - MetaBorderMotionDirection blocking_directions) +enum { - MetaBorder border; - - border = (MetaBorder) { - .line = (MetaLine2) { - .a = (MetaVector2) { - .x = x1, - .y = y1, - }, - .b = (MetaVector2) { - .x = x2, - .y = y2, - }, - }, - .blocking_directions = blocking_directions, - }; - - g_array_append_val (borders, border); - - return &g_array_index (borders, MetaBorder, borders->len - 1); -} + PROP_0, + PROP_WAYLAND_POINTER_CONSTRAINT, + N_PROPS, +}; -static gint -compare_lines_x (gconstpointer a, gconstpointer b) -{ - const MetaBorder *border_a = a; - const MetaBorder *border_b = b; +static GParamSpec *props[N_PROPS] = { 0 }; - if (border_a->line.a.x == border_b->line.a.x) - return border_a->line.b.x < border_b->line.b.x; - else - return border_a->line.a.x > border_b->line.a.x; -} +G_DEFINE_TYPE_WITH_PRIVATE (MetaPointerConfinementWayland, + meta_pointer_confinement_wayland, + G_TYPE_OBJECT) static void -add_non_overlapping_edges (MetaBox *boxes, - unsigned int band_above_start, - unsigned int band_below_start, - unsigned int band_below_end, - GArray *borders) +meta_pointer_confinement_wayland_update (MetaPointerConfinementWayland *self) { - unsigned int i; - GArray *band_merge; - MetaBorder *border; - MetaBorder *prev_border; - MetaBorder *new_border; - - band_merge = g_array_new (FALSE, FALSE, sizeof *border); - - /* Add bottom band of previous row, and top band of current row, and - * sort them so lower left x coordinate comes first. If there are two - * borders with the same left x coordinate, the wider one comes first. - */ - for (i = band_above_start; i < band_below_start; i++) - { - MetaBox *box = &boxes[i]; - add_border (band_merge, box->x1, box->y2, box->x2, box->y2, - META_BORDER_MOTION_DIRECTION_POSITIVE_Y); - } - for (i = band_below_start; i < band_below_end; i++) - { - MetaBox *box= &boxes[i]; - add_border (band_merge, box->x1, box->y1, box->x2, box->y1, - META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); - } - g_array_sort (band_merge, compare_lines_x); - - /* Combine the two combined bands so that any overlapping border is - * eliminated. */ - prev_border = NULL; - for (i = 0; i < band_merge->len; i++) - { - border = &g_array_index (band_merge, MetaBorder, i); - - g_assert (border->line.a.y == border->line.b.y); - g_assert (!prev_border || - prev_border->line.a.y == border->line.a.y); - g_assert (!prev_border || - (prev_border->line.a.x != border->line.a.x || - prev_border->line.b.x != border->line.b.x)); - g_assert (!prev_border || - prev_border->line.a.x <= border->line.a.x); - - if (prev_border && - prev_border->line.a.x == border->line.a.x) - { - /* - * ------------ + - * ------- = - * [ ]----- - */ - prev_border->line.a.x = border->line.b.x; - } - else if (prev_border && - prev_border->line.b.x == border->line.b.x) - { - /* - * ------------ + - * ------ = - * ------[ ] - */ - prev_border->line.b.x = border->line.a.x; - } - else if (prev_border && - prev_border->line.b.x == border->line.a.x) - { - /* - * -------- + - * ------ = - * -------------- - */ - prev_border->line.b.x = border->line.b.x; - } - else if (prev_border && - prev_border->line.b.x >= border->line.a.x) - { - /* - * --------------- + - * ------ = - * -----[ ]---- - */ - new_border = add_border (borders, - border->line.b.x, - border->line.b.y, - prev_border->line.b.x, - prev_border->line.b.y, - prev_border->blocking_directions); - prev_border->line.b.x = border->line.a.x; - prev_border = new_border; - } - else - { - g_assert (!prev_border || - prev_border->line.b.x < border->line.a.x); - /* - * First border or non-overlapping. - * - * ----- + - * ----- = - * ----- ----- - */ - g_array_append_val (borders, *border); - prev_border = &g_array_index (borders, MetaBorder, borders->len - 1); - } - } + MetaPointerConstraint *constraint; - g_array_free (band_merge, FALSE); + constraint = + META_POINTER_CONFINEMENT_WAYLAND_GET_CLASS (self)->create_constraint (self); + meta_backend_set_client_pointer_constraint (meta_get_backend (), constraint); + g_object_unref (constraint); } static void -add_band_bottom_edges (MetaBox *boxes, - int band_start, - int band_end, - GArray *borders) +surface_geometry_changed (MetaWaylandSurface *surface, + MetaPointerConfinementWayland *self) { - int i; - - for (i = band_start; i < band_end; i++) - { - add_border (borders, - boxes[i].x1, boxes[i].y2, - boxes[i].x2, boxes[i].y2, - META_BORDER_MOTION_DIRECTION_POSITIVE_Y); - } + meta_pointer_confinement_wayland_update (self); } static void -region_to_outline (cairo_region_t *region, - GArray *borders) +window_position_changed (MetaWindow *window, + MetaPointerConfinementWayland *self) { - MetaBox *boxes; - int num_boxes; - int i; - int top_most, bottom_most; - int current_roof; - int prev_top; - int band_start, prev_band_start; - - /* - * Remove any overlapping lines from the set of rectangles. Note that - * pixman regions are grouped as rows of rectangles, where rectangles - * in one row never touch or overlap and are all of the same height. - * - * -------- --- -------- --- - * | | | | | | | | - * ----------====---- --- ----------- ----- --- - * | | => | | - * ----==========--------- ----- ---------- - * | | | | - * ------------------- ------------------- - * - */ - - num_boxes = cairo_region_num_rectangles (region); - boxes = g_new (MetaBox, num_boxes); - for (i = 0; i < num_boxes; i++) - { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (region, i, &rect); - boxes[i] = (MetaBox) { - .x1 = rect.x, - .y1 = rect.y, - .x2 = rect.x + rect.width, - .y2 = rect.y + rect.height, - }; - } - prev_top = 0; - top_most = boxes[0].y1; - current_roof = top_most; - bottom_most = boxes[num_boxes - 1].y2; - band_start = 0; - prev_band_start = 0; - for (i = 0; i < num_boxes; i++) - { - /* Detect if there is a vertical empty space, and add the lower - * level of the previous band if so was the case. */ - if (i > 0 && - boxes[i].y1 != prev_top && - boxes[i].y1 != boxes[i - 1].y2) - { - current_roof = boxes[i].y1; - add_band_bottom_edges (boxes, - band_start, - i, - borders); - } - - /* Special case adding the last band, since it won't be handled - * by the band change detection below. */ - if (boxes[i].y1 != current_roof && i == num_boxes - 1) - { - if (boxes[i].y1 != prev_top) - { - /* The last band is a single box, so we don't - * have a prev_band_start to tell us when the - * previous band started. */ - add_non_overlapping_edges (boxes, - band_start, - i, - i + 1, - borders); - } - else - { - add_non_overlapping_edges (boxes, - prev_band_start, - band_start, - i + 1, - borders); - } - } - - /* Detect when passing a band and combine the top border of the - * just passed band with the bottom band of the previous band. - */ - if (boxes[i].y1 != top_most && boxes[i].y1 != prev_top) - { - /* Combine the two passed bands. */ - if (prev_top != current_roof) - { - add_non_overlapping_edges (boxes, - prev_band_start, - band_start, - i, - borders); - } - - prev_band_start = band_start; - band_start = i; - } - - /* Add the top border if the box is part of the current roof. */ - if (boxes[i].y1 == current_roof) - { - add_border (borders, - boxes[i].x1, boxes[i].y1, - boxes[i].x2, boxes[i].y1, - META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); - } - - /* Add the bottom border of the last band. */ - if (boxes[i].y2 == bottom_most) - { - add_border (borders, - boxes[i].x1, boxes[i].y2, - boxes[i].x2, boxes[i].y2, - META_BORDER_MOTION_DIRECTION_POSITIVE_Y); - } - - /* Always add the left border. */ - add_border (borders, - boxes[i].x1, boxes[i].y1, - boxes[i].x1, boxes[i].y2, - META_BORDER_MOTION_DIRECTION_NEGATIVE_X); - - /* Always add the right border. */ - add_border (borders, - boxes[i].x2, boxes[i].y1, - boxes[i].x2, boxes[i].y2, - META_BORDER_MOTION_DIRECTION_POSITIVE_X); - - prev_top = boxes[i].y1; - } - - g_free (boxes); + meta_pointer_confinement_wayland_update (self); } -static MetaBorder * -get_closest_border (GArray *borders, - MetaLine2 *motion, - uint32_t directions) +void +meta_pointer_confinement_wayland_enable (MetaPointerConfinementWayland *confinement) { - MetaBorder *border; - MetaVector2 intersection; - MetaVector2 delta; - float distance_2; - MetaBorder *closest_border = NULL; - float closest_distance_2 = DBL_MAX; - unsigned int i; - - for (i = 0; i < borders->len; i++) - { - border = &g_array_index (borders, MetaBorder, i); - - if (!meta_border_is_blocking_directions (border, directions)) - continue; + MetaPointerConfinementWaylandPrivate *priv; + MetaWaylandPointerConstraint *constraint; + MetaWaylandSurface *surface; + MetaWindow *window; - if (!meta_line2_intersects_with (&border->line, motion, &intersection)) - continue; + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + g_assert (!priv->enabled); - delta = meta_vector2_subtract (intersection, motion->a); - distance_2 = delta.x*delta.x + delta.y*delta.y; - if (distance_2 < closest_distance_2) - { - closest_border = border; - closest_distance_2 = distance_2; - } - } + priv->enabled = TRUE; + constraint = priv->constraint; - return closest_border; -} + surface = meta_wayland_pointer_constraint_get_surface (constraint); + g_signal_connect_object (surface, + "geometry-changed", + G_CALLBACK (surface_geometry_changed), + confinement, + 0); -static void -clamp_to_border (MetaBorder *border, - MetaLine2 *motion, - uint32_t *motion_dir) -{ - /* - * When clamping either rightward or downward motions, the motion needs to be - * clamped so that the destination coordinate does not end up on the border - * (see weston_pointer_clamp_event_to_region). Do this by clamping such - * motions to the border minus the smallest possible wl_fixed_t value. - * - * When clamping in either leftward or upward motion, the resulting coordinate - * needs to be clamped so that it is enough on the inside to avoid the - * inaccuracies of clutter's stage to actor transformation algorithm (the one - * used in clutter_actor_transform_stage_point) to make it end up outside the - * next motion. It also needs to be clamped so that to the wl_fixed_t - * coordinate may still be right on the border (i.e. at .0). Testing shows - * that the smallest wl_fixed_t value divided by 10 is small enough to make - * the wl_fixed_t coordinate .0 and large enough to avoid the inaccuracies of - * clutters transform algorithm. - */ - if (meta_border_is_horizontal (border)) - { - if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_Y) - motion->b.y = border->line.a.y - wl_fixed_to_double (1); - else - motion->b.y = border->line.a.y + wl_fixed_to_double (1) / 10; - *motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_Y | - META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); - } - else + window = meta_wayland_surface_get_window (surface); + if (window) { - if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_X) - motion->b.x = border->line.a.x - wl_fixed_to_double (1); - else - motion->b.x = border->line.a.x + wl_fixed_to_double (1) / 10; - *motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_X | - META_BORDER_MOTION_DIRECTION_NEGATIVE_X); + g_signal_connect_object (window, + "position-changed", + G_CALLBACK (window_position_changed), + confinement, + 0); } -} -static uint32_t -get_motion_directions (MetaLine2 *motion) -{ - uint32_t directions = 0; - - if (motion->a.x < motion->b.x) - directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_X; - else if (motion->a.x > motion->b.x) - directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_X; - if (motion->a.y < motion->b.y) - directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_Y; - else if (motion->a.y > motion->b.y) - directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_Y; - - return directions; + meta_pointer_confinement_wayland_update (confinement); } -static void -meta_pointer_confinement_wayland_constrain (MetaPointerConstraint *constraint, - ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y) +void +meta_pointer_confinement_wayland_disable (MetaPointerConfinementWayland *confinement) { - MetaPointerConfinementWayland *self = - META_POINTER_CONFINEMENT_WAYLAND (constraint); + MetaPointerConfinementWaylandPrivate *priv; + MetaWaylandPointerConstraint *constraint; MetaWaylandSurface *surface; - cairo_region_t *region; - float sx, sy; - float prev_sx, prev_sy; - GArray *borders; - MetaLine2 motion; - MetaBorder *closest_border; - uint32_t directions; - - surface = meta_wayland_pointer_constraint_get_surface (self->constraint); - - meta_wayland_surface_get_relative_coordinates (surface, *x, *y, &sx, &sy); - meta_wayland_surface_get_relative_coordinates (surface, prev_x, prev_y, - &prev_sx, &prev_sy); - - /* For motions in a positive direction on any axis, append the smallest - * possible value representable in a Wayland absolute coordinate. This is - * in order to avoid not clamping motion that as a floating point number - * won't be clamped, but will be rounded up to be outside of the range - * of wl_fixed_t. */ - if (sx > prev_sx) - sx += (float)wl_fixed_to_double(1); - if (sy > prev_sy) - sy += (float)wl_fixed_to_double(1); - - borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder)); - - /* - * Generate borders given the confine region we are to use. The borders - * are defined to be the outer region of the allowed area. This means - * top/left borders are "within" the allowed area, while bottom/right - * borders are outside. This needs to be considered when clamping - * confined motion vectors. - */ - region = - meta_wayland_pointer_constraint_calculate_effective_region (self->constraint); - region_to_outline (region, borders); - cairo_region_destroy (region); + MetaWindow *window; - motion = (MetaLine2) { - .a = (MetaVector2) { - .x = prev_sx, - .y = prev_sy, - }, - .b = (MetaVector2) { - .x = sx, - .y = sy, - }, - }; - directions = get_motion_directions (&motion); - - while (directions) + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + constraint = priv->constraint; + g_assert (priv->enabled); + + priv->enabled = FALSE; + surface = meta_wayland_pointer_constraint_get_surface (constraint); + g_signal_handlers_disconnect_by_func (surface, surface_geometry_changed, + confinement); + + window = meta_wayland_surface_get_window (surface); + if (window) { - closest_border = get_closest_border (borders, - &motion, - directions); - if (closest_border) - clamp_to_border (closest_border, &motion, &directions); - else - break; + g_signal_handlers_disconnect_by_func (window, window_position_changed, + confinement); } - meta_wayland_surface_get_absolute_coordinates (surface, - motion.b.x, motion.b.y, - x, y); + meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL); +} - g_array_free (borders, FALSE); +static void +meta_pointer_confinement_wayland_init (MetaPointerConfinementWayland *confinement_wayland) +{ } -static float -point_to_border_distance_2 (MetaBorder *border, - float x, - float y) +static void +meta_pointer_confinement_wayland_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - float orig_x, orig_y; - float dx, dy; + MetaPointerConfinementWayland *confinement; + MetaPointerConfinementWaylandPrivate *priv; - if (meta_border_is_horizontal (border)) - { - if (x < border->line.a.x) - orig_x = border->line.a.x; - else if (x > border->line.b.x) - orig_x = border->line.b.x; - else - orig_x = x; - orig_y = border->line.a.y; - } - else + confinement = META_POINTER_CONFINEMENT_WAYLAND (object); + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + + switch (prop_id) { - if (y < border->line.a.y) - orig_y = border->line.a.y; - else if (y > border->line.b.y) - orig_y = border->line.b.y; - else - orig_y = y; - orig_x = border->line.a.x; + case PROP_WAYLAND_POINTER_CONSTRAINT: + g_value_set_object (value, priv->constraint); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } - - dx = fabsf (orig_x - x); - dy = fabsf (orig_y - y); - return dx*dx + dy*dy; } static void -warp_to_behind_border (MetaBorder *border, - float *sx, - float *sy) +meta_pointer_confinement_wayland_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - switch (border->blocking_directions) + MetaPointerConfinementWayland *confinement; + MetaPointerConfinementWaylandPrivate *priv; + + confinement = META_POINTER_CONFINEMENT_WAYLAND (object); + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + + switch (prop_id) { - case META_BORDER_MOTION_DIRECTION_POSITIVE_X: - case META_BORDER_MOTION_DIRECTION_NEGATIVE_X: - if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_X) - *sx = border->line.a.x - wl_fixed_to_double (1); - else - *sx = border->line.a.x + wl_fixed_to_double (1); - if (*sy < border->line.a.y) - *sy = border->line.a.y + wl_fixed_to_double (1); - else if (*sy > border->line.b.y) - *sy = border->line.b.y - wl_fixed_to_double (1); + case PROP_WAYLAND_POINTER_CONSTRAINT: + priv->constraint = g_value_get_object (value); break; - case META_BORDER_MOTION_DIRECTION_POSITIVE_Y: - case META_BORDER_MOTION_DIRECTION_NEGATIVE_Y: - if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_Y) - *sy = border->line.a.y - wl_fixed_to_double (1); - else - *sy = border->line.a.y + wl_fixed_to_double (1); - if (*sx < border->line.a.x) - *sx = border->line.a.x + wl_fixed_to_double (1); - else if (*sx > (border->line.b.x)) - *sx = border->line.b.x - wl_fixed_to_double (1); + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } -static void -meta_pointer_confinement_wayland_maybe_warp (MetaPointerConfinementWayland *self) +static MetaPointerConstraint * +meta_pointer_confinement_wayland_create_constraint (MetaPointerConfinementWayland *confinement) { - MetaWaylandSeat *seat; + MetaPointerConfinementWaylandPrivate *priv; + MetaPointerConstraint *constraint; MetaWaylandSurface *surface; - graphene_point_t point; - float sx; - float sy; cairo_region_t *region; + float dx, dy; - seat = meta_wayland_pointer_constraint_get_seat (self->constraint); - surface = meta_wayland_pointer_constraint_get_surface (self->constraint); - - clutter_input_device_get_coords (seat->pointer->device, NULL, &point); - meta_wayland_surface_get_relative_coordinates (surface, - point.x, point.y, - &sx, &sy); + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + surface = meta_wayland_pointer_constraint_get_surface (priv->constraint); region = - meta_wayland_pointer_constraint_calculate_effective_region (self->constraint); - - if (!cairo_region_contains_point (region, (int)sx, (int)sy)) - { - GArray *borders; - float closest_distance_2 = FLT_MAX; - MetaBorder *closest_border = NULL; - ClutterSeat *seat; - unsigned int i; - float x; - float y; - - borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder)); - - region_to_outline (region, borders); - - for (i = 0; i < borders->len; i++) - { - MetaBorder *border = &g_array_index (borders, MetaBorder, i); - float distance_2; - - distance_2 = point_to_border_distance_2 (border, sx, sy); - if (distance_2 < closest_distance_2) - { - closest_border = border; - closest_distance_2 = distance_2; - } - } - - warp_to_behind_border (closest_border, &sx, &sy); + meta_wayland_pointer_constraint_calculate_effective_region (priv->constraint); - meta_wayland_surface_get_absolute_coordinates (surface, sx, sy, &x, &y); - - seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); - clutter_seat_warp_pointer (seat, (int)x, (int)y); - } + meta_wayland_surface_get_absolute_coordinates (surface, 0, 0, &dx, &dy); + cairo_region_translate (region, dx, dy); + constraint = meta_pointer_constraint_new (region); cairo_region_destroy (region); -} -static void -surface_geometry_changed (MetaWaylandSurface *surface, - MetaPointerConfinementWayland *self) -{ - meta_pointer_confinement_wayland_maybe_warp (self); + return constraint; } static void -window_position_changed (MetaWindow *window, - MetaPointerConfinementWayland *self) +meta_pointer_confinement_wayland_class_init (MetaPointerConfinementWaylandClass *klass) { - meta_pointer_confinement_wayland_maybe_warp (self); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = meta_pointer_confinement_wayland_set_property; + object_class->get_property = meta_pointer_confinement_wayland_get_property; + + klass->create_constraint = meta_pointer_confinement_wayland_create_constraint; + + props[PROP_WAYLAND_POINTER_CONSTRAINT] = + g_param_spec_object ("wayland-pointer-constraint", + "Wayland pointer constraint", + "Wayland pointer constraint", + META_TYPE_WAYLAND_POINTER_CONSTRAINT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPS, props); } -MetaPointerConstraint * +MetaPointerConfinementWayland * meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint) { - GObject *object; - MetaPointerConfinementWayland *confinement; - MetaWaylandSurface *surface; - MetaWindow *window; - - object = g_object_new (META_TYPE_POINTER_CONFINEMENT_WAYLAND, NULL); - confinement = META_POINTER_CONFINEMENT_WAYLAND (object); - - confinement->constraint = constraint; - - surface = meta_wayland_pointer_constraint_get_surface (constraint); - g_signal_connect_object (surface, - "geometry-changed", - G_CALLBACK (surface_geometry_changed), - confinement, - 0); - - window = meta_wayland_surface_get_window (surface); - if (window) - { - g_signal_connect_object (window, - "position-changed", - G_CALLBACK (window_position_changed), - confinement, - 0); - } - - return META_POINTER_CONSTRAINT (confinement); -} - -static void -meta_pointer_confinement_wayland_init (MetaPointerConfinementWayland *confinement_wayland) -{ + return g_object_new (META_TYPE_POINTER_CONFINEMENT_WAYLAND, + "wayland-pointer-constraint", constraint, + NULL); } -static void -meta_pointer_confinement_wayland_class_init (MetaPointerConfinementWaylandClass *klass) +MetaWaylandPointerConstraint * +meta_pointer_confinement_wayland_get_wayland_pointer_constraint (MetaPointerConfinementWayland *confinement) { - MetaPointerConstraintClass *pointer_constraint_class = - META_POINTER_CONSTRAINT_CLASS (klass); + MetaPointerConfinementWaylandPrivate *priv; - pointer_constraint_class->constrain = meta_pointer_confinement_wayland_constrain; + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + return priv->constraint; } diff --git a/src/wayland/meta-pointer-confinement-wayland.h b/src/wayland/meta-pointer-confinement-wayland.h index 482a25a9a..4f265779c 100644 --- a/src/wayland/meta-pointer-confinement-wayland.h +++ b/src/wayland/meta-pointer-confinement-wayland.h @@ -33,12 +33,23 @@ G_BEGIN_DECLS #define META_TYPE_POINTER_CONFINEMENT_WAYLAND (meta_pointer_confinement_wayland_get_type ()) -G_DECLARE_FINAL_TYPE (MetaPointerConfinementWayland, - meta_pointer_confinement_wayland, - META, POINTER_CONFINEMENT_WAYLAND, - MetaPointerConstraint); - -MetaPointerConstraint *meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint); +G_DECLARE_DERIVABLE_TYPE (MetaPointerConfinementWayland, + meta_pointer_confinement_wayland, + META, POINTER_CONFINEMENT_WAYLAND, + GObject) + +struct _MetaPointerConfinementWaylandClass +{ + GObjectClass parent_class; + + MetaPointerConstraint * (*create_constraint) (MetaPointerConfinementWayland *confinement); +}; + +MetaPointerConfinementWayland *meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint); +MetaWaylandPointerConstraint * + meta_pointer_confinement_wayland_get_wayland_pointer_constraint (MetaPointerConfinementWayland *confinement); +void meta_pointer_confinement_wayland_enable (MetaPointerConfinementWayland *confinement); +void meta_pointer_confinement_wayland_disable (MetaPointerConfinementWayland *confinement); G_END_DECLS diff --git a/src/wayland/meta-pointer-lock-wayland.c b/src/wayland/meta-pointer-lock-wayland.c index 08c2789bc..e87224732 100644 --- a/src/wayland/meta-pointer-lock-wayland.c +++ b/src/wayland/meta-pointer-lock-wayland.c @@ -37,33 +37,55 @@ #include <glib-object.h> -#include "backends/meta-pointer-constraint.h" +#include "backends/meta-backend-private.h" +#include "compositor/meta-surface-actor-wayland.h" struct _MetaPointerLockWayland { - MetaPointerConstraint parent; + GObject parent; + MetaWaylandPointerConstraint *constraint; }; G_DEFINE_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland, - META_TYPE_POINTER_CONSTRAINT); + META_TYPE_POINTER_CONFINEMENT_WAYLAND) -static void -meta_pointer_lock_wayland_constrain (MetaPointerConstraint *constraint, - ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y) +static MetaPointerConstraint * +meta_pointer_lock_wayland_create_constraint (MetaPointerConfinementWayland *confinement) { - *x = prev_x; - *y = prev_y; + MetaBackend *backend = meta_get_backend (); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); + ClutterInputDevice *pointer = clutter_seat_get_pointer (seat); + MetaWaylandPointerConstraint *wayland_constraint; + MetaPointerConstraint *constraint; + MetaWaylandSurface *surface; + graphene_point_t point; + cairo_region_t *region; + float sx, sy, x, y; + + clutter_input_device_get_coords (pointer, NULL, &point); + wayland_constraint = + meta_pointer_confinement_wayland_get_wayland_pointer_constraint (confinement); + surface = meta_wayland_pointer_constraint_get_surface (wayland_constraint); + meta_wayland_surface_get_relative_coordinates (surface, + point.x, point.y, + &sx, &sy); + + meta_wayland_surface_get_absolute_coordinates (surface, sx, sy, &x, &y); + region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) { (int) x, (int) y, 1 , 1 }); + + constraint = meta_pointer_constraint_new (region); + cairo_region_destroy (region); + + return constraint; } -MetaPointerConstraint * -meta_pointer_lock_wayland_new (void) +MetaPointerConfinementWayland * +meta_pointer_lock_wayland_new (MetaWaylandPointerConstraint *constraint) { - return g_object_new (META_TYPE_POINTER_LOCK_WAYLAND, NULL); + return g_object_new (META_TYPE_POINTER_LOCK_WAYLAND, + "wayland-pointer-constraint", constraint, + NULL); } static void @@ -74,8 +96,9 @@ meta_pointer_lock_wayland_init (MetaPointerLockWayland *lock_wayland) static void meta_pointer_lock_wayland_class_init (MetaPointerLockWaylandClass *klass) { - MetaPointerConstraintClass *pointer_constraint_class = - META_POINTER_CONSTRAINT_CLASS (klass); + MetaPointerConfinementWaylandClass *confinement_class = + META_POINTER_CONFINEMENT_WAYLAND_CLASS (klass); - pointer_constraint_class->constrain = meta_pointer_lock_wayland_constrain; + confinement_class->create_constraint = + meta_pointer_lock_wayland_create_constraint; } diff --git a/src/wayland/meta-pointer-lock-wayland.h b/src/wayland/meta-pointer-lock-wayland.h index 787b43269..d52aaa30d 100644 --- a/src/wayland/meta-pointer-lock-wayland.h +++ b/src/wayland/meta-pointer-lock-wayland.h @@ -27,15 +27,15 @@ #include <glib-object.h> -#include "backends/meta-pointer-constraint.h" +#include "wayland/meta-pointer-confinement-wayland.h" G_BEGIN_DECLS #define META_TYPE_POINTER_LOCK_WAYLAND (meta_pointer_lock_wayland_get_type ()) G_DECLARE_FINAL_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland, - META, POINTER_LOCK_WAYLAND, MetaPointerConstraint); + META, POINTER_LOCK_WAYLAND, MetaPointerConfinementWayland) -MetaPointerConstraint *meta_pointer_lock_wayland_new (void); +MetaPointerConfinementWayland *meta_pointer_lock_wayland_new (MetaWaylandPointerConstraint *constraint); G_END_DECLS diff --git a/src/wayland/meta-wayland-pointer-constraints.c b/src/wayland/meta-wayland-pointer-constraints.c index 7547d7e13..3a8b8e095 100644 --- a/src/wayland/meta-wayland-pointer-constraints.c +++ b/src/wayland/meta-wayland-pointer-constraints.c @@ -68,7 +68,7 @@ struct _MetaWaylandPointerConstraint wl_fixed_t x_hint; wl_fixed_t y_hint; - MetaPointerConstraint *constraint; + MetaPointerConfinementWayland *confinement; }; typedef struct _MetaWaylandSurfacePointerConstraintsData @@ -375,7 +375,7 @@ meta_wayland_pointer_constraint_notify_deactivated (MetaWaylandPointerConstraint zwp_confined_pointer_v1_send_unconfined (resource); } -static MetaPointerConstraint * +static MetaPointerConfinementWayland * meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerConstraint *constraint) { struct wl_resource *resource = constraint->resource; @@ -384,7 +384,7 @@ meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerCon &zwp_locked_pointer_v1_interface, &locked_pointer_interface)) { - return meta_pointer_lock_wayland_new (); + return meta_pointer_lock_wayland_new (constraint); } else if (wl_resource_instance_of (resource, &zwp_confined_pointer_v1_interface, @@ -399,8 +399,6 @@ meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerCon static void meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint) { - MetaBackend *backend = meta_get_backend (); - g_assert (!constraint->is_enabled); constraint->is_enabled = TRUE; @@ -408,20 +406,25 @@ meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint meta_wayland_pointer_start_grab (constraint->seat->pointer, &constraint->grab); - constraint->constraint = + constraint->confinement = meta_wayland_pointer_constraint_create_pointer_constraint (constraint); - meta_backend_set_client_pointer_constraint (backend, constraint->constraint); - g_object_add_weak_pointer (G_OBJECT (constraint->constraint), - (gpointer *) &constraint->constraint); - g_object_unref (constraint->constraint); + meta_pointer_confinement_wayland_enable (constraint->confinement); + g_object_add_weak_pointer (G_OBJECT (constraint->confinement), + (gpointer *) &constraint->confinement); } static void meta_wayland_pointer_constraint_disable (MetaWaylandPointerConstraint *constraint) { constraint->is_enabled = FALSE; + + if (constraint->confinement) + { + meta_pointer_confinement_wayland_disable (constraint->confinement); + g_object_unref (constraint->confinement); + } + meta_wayland_pointer_constraint_notify_deactivated (constraint); - meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL); meta_wayland_pointer_end_grab (constraint->grab.pointer); } |