summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backends/meta-backend-private.h2
-rw-r--r--src/backends/meta-backend.c7
-rw-r--r--src/backends/meta-pointer-constraint.c91
-rw-r--r--src/backends/meta-pointer-constraint.h49
-rw-r--r--src/backends/native/meta-backend-native.c60
-rw-r--r--src/backends/native/meta-pointer-constraint-native.c693
-rw-r--r--src/backends/native/meta-pointer-constraint-native.h46
-rw-r--r--src/backends/native/meta-seat-native.c57
-rw-r--r--src/backends/native/meta-seat-native.h38
-rw-r--r--src/meson.build2
-rw-r--r--src/wayland/meta-pointer-confinement-wayland.c755
-rw-r--r--src/wayland/meta-pointer-confinement-wayland.h23
-rw-r--r--src/wayland/meta-pointer-lock-wayland.c61
-rw-r--r--src/wayland/meta-pointer-lock-wayland.h6
-rw-r--r--src/wayland/meta-wayland-pointer-constraints.c25
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);
}