mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
backends: Delegate pointer confinements to an impl object
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
This commit is contained in:
parent
a3825f2085
commit
03f2bade19
@ -105,6 +105,8 @@ struct _MetaBackendClass
|
|||||||
void (* set_numlock) (MetaBackend *backend,
|
void (* set_numlock) (MetaBackend *backend,
|
||||||
gboolean numlock_state);
|
gboolean numlock_state);
|
||||||
|
|
||||||
|
void (* set_pointer_constraint) (MetaBackend *backend,
|
||||||
|
MetaPointerConstraint *constraint);
|
||||||
};
|
};
|
||||||
|
|
||||||
void meta_init_backend (GType backend_gtype);
|
void meta_init_backend (GType backend_gtype);
|
||||||
|
@ -1340,11 +1340,8 @@ meta_backend_set_client_pointer_constraint (MetaBackend *backend,
|
|||||||
{
|
{
|
||||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||||
|
|
||||||
g_assert (!constraint || !priv->client_pointer_constraint);
|
META_BACKEND_GET_CLASS (backend)->set_pointer_constraint (backend, constraint);
|
||||||
|
g_set_object (&priv->client_pointer_constraint, constraint);
|
||||||
g_clear_object (&priv->client_pointer_constraint);
|
|
||||||
if (constraint)
|
|
||||||
priv->client_pointer_constraint = g_object_ref (constraint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClutterBackend *
|
ClutterBackend *
|
||||||
|
@ -39,8 +39,19 @@
|
|||||||
|
|
||||||
#include "backends/meta-pointer-constraint.h"
|
#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>
|
#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 (MetaPointerConstraint, meta_pointer_constraint, G_TYPE_OBJECT);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -53,9 +64,40 @@ meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (MetaPointerConstraintImpl, meta_pointer_constraint_impl,
|
||||||
|
G_TYPE_OBJECT);
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_pointer_constraint_impl_init (MetaPointerConstraintImpl *impl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_pointer_constraint_impl_class_init (MetaPointerConstraintImplClass *klass)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_pointer_constraint_constrain:
|
* meta_pointer_constraint_impl_constrain:
|
||||||
* @constraint: a #MetaPointerConstraint.
|
* @impl: a #MetaPointerConstraintImpl.
|
||||||
* @device; the device of the pointer.
|
* @device; the device of the pointer.
|
||||||
* @time: the timestamp (in ms) of the event.
|
* @time: the timestamp (in ms) of the event.
|
||||||
* @prev_x: X-coordinate of the previous pointer position.
|
* @prev_x: X-coordinate of the previous pointer position.
|
||||||
@ -67,17 +109,25 @@ meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass)
|
|||||||
* if needed.
|
* if needed.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
meta_pointer_constraint_constrain (MetaPointerConstraint *constraint,
|
meta_pointer_constraint_impl_constrain (MetaPointerConstraintImpl *impl,
|
||||||
ClutterInputDevice *device,
|
ClutterInputDevice *device,
|
||||||
guint32 time,
|
uint32_t time,
|
||||||
float prev_x,
|
float prev_x,
|
||||||
float prev_y,
|
float prev_y,
|
||||||
float *x,
|
float *x,
|
||||||
float *y)
|
float *y)
|
||||||
{
|
{
|
||||||
META_POINTER_CONSTRAINT_GET_CLASS (constraint)->constrain (constraint,
|
META_POINTER_CONSTRAINT_IMPL_GET_CLASS (impl)->constrain (impl,
|
||||||
device,
|
device,
|
||||||
time,
|
time,
|
||||||
prev_x, prev_y,
|
prev_x, prev_y,
|
||||||
x, y);
|
x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_pointer_constraint_impl_ensure_constrained (MetaPointerConstraintImpl *impl,
|
||||||
|
ClutterInputDevice *device)
|
||||||
|
{
|
||||||
|
META_POINTER_CONSTRAINT_IMPL_GET_CLASS (impl)->ensure_constrained (impl,
|
||||||
|
device);
|
||||||
}
|
}
|
||||||
|
@ -32,34 +32,45 @@
|
|||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define META_TYPE_POINTER_CONSTRAINT (meta_pointer_constraint_get_type ())
|
#define META_TYPE_POINTER_CONSTRAINT (meta_pointer_constraint_get_type ())
|
||||||
G_DECLARE_DERIVABLE_TYPE (MetaPointerConstraint, meta_pointer_constraint,
|
G_DECLARE_FINAL_TYPE (MetaPointerConstraint, meta_pointer_constraint,
|
||||||
META, POINTER_CONSTRAINT, GObject);
|
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
|
* @constrain: the virtual function pointer for
|
||||||
* meta_pointer_constraint_constrain().
|
* meta_pointer_constraint_impl_constrain().
|
||||||
*/
|
*/
|
||||||
struct _MetaPointerConstraintClass
|
struct _MetaPointerConstraintImplClass
|
||||||
{
|
{
|
||||||
GObjectClass parent_class;
|
GObjectClass parent_class;
|
||||||
|
|
||||||
void (*constrain) (MetaPointerConstraint *constraint,
|
void (* constrain) (MetaPointerConstraintImpl *impl,
|
||||||
ClutterInputDevice *device,
|
ClutterInputDevice *device,
|
||||||
guint32 time,
|
uint32_t time,
|
||||||
float prev_x,
|
float prev_x,
|
||||||
float prev_y,
|
float prev_y,
|
||||||
float *x,
|
float *x,
|
||||||
float *y);
|
float *y);
|
||||||
|
void (* ensure_constrained) (MetaPointerConstraintImpl *impl,
|
||||||
|
ClutterInputDevice *device);
|
||||||
};
|
};
|
||||||
|
|
||||||
void meta_pointer_constraint_constrain (MetaPointerConstraint *constraint,
|
void meta_pointer_constraint_impl_constrain (MetaPointerConstraintImpl *impl,
|
||||||
ClutterInputDevice *device,
|
ClutterInputDevice *device,
|
||||||
guint32 time,
|
uint32_t time,
|
||||||
float prev_x,
|
float prev_x,
|
||||||
float prev_y,
|
float prev_y,
|
||||||
float *x,
|
float *x,
|
||||||
float *y);
|
float *y);
|
||||||
|
void meta_pointer_constraint_impl_ensure_constrained (MetaPointerConstraintImpl *impl,
|
||||||
|
ClutterInputDevice *device);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
@ -101,38 +101,6 @@ meta_backend_native_finalize (GObject *object)
|
|||||||
G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (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 *
|
static ClutterBackend *
|
||||||
meta_backend_native_create_clutter_backend (MetaBackend *backend)
|
meta_backend_native_create_clutter_backend (MetaBackend *backend)
|
||||||
{
|
{
|
||||||
@ -142,14 +110,8 @@ meta_backend_native_create_clutter_backend (MetaBackend *backend)
|
|||||||
static void
|
static void
|
||||||
meta_backend_native_post_init (MetaBackend *backend)
|
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);
|
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);
|
META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend);
|
||||||
|
|
||||||
if (meta_settings_is_experimental_feature_enabled (settings,
|
if (meta_settings_is_experimental_feature_enabled (settings,
|
||||||
@ -297,6 +259,25 @@ meta_backend_native_set_numlock (MetaBackend *backend,
|
|||||||
numlock_state);
|
numlock_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
meta_backend_native_update_screen_size (MetaBackend *backend,
|
meta_backend_native_update_screen_size (MetaBackend *backend,
|
||||||
int width, int height)
|
int width, int height)
|
||||||
@ -504,6 +485,8 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
|
|||||||
backend_class->lock_layout_group = meta_backend_native_lock_layout_group;
|
backend_class->lock_layout_group = meta_backend_native_lock_layout_group;
|
||||||
backend_class->update_screen_size = meta_backend_native_update_screen_size;
|
backend_class->update_screen_size = meta_backend_native_update_screen_size;
|
||||||
backend_class->set_numlock = meta_backend_native_set_numlock;
|
backend_class->set_numlock = meta_backend_native_set_numlock;
|
||||||
|
|
||||||
|
backend_class->set_pointer_constraint = meta_backend_native_set_pointer_constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
676
src/backends/native/meta-pointer-constraint-native.c
Normal file
676
src/backends/native/meta-pointer-constraint-native.c
Normal file
@ -0,0 +1,676 @@
|
|||||||
|
/* -*- 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 *impl,
|
||||||
|
ClutterInputDevice *device,
|
||||||
|
uint32_t time,
|
||||||
|
float prev_x,
|
||||||
|
float prev_y,
|
||||||
|
float *x_inout,
|
||||||
|
float *y_inout)
|
||||||
|
{
|
||||||
|
MetaPointerConstraintImplNative *native = META_POINTER_CONSTRAINT_IMPL_NATIVE (impl);
|
||||||
|
cairo_region_t *region;
|
||||||
|
float x, y;
|
||||||
|
GArray *borders;
|
||||||
|
MetaLine2 motion;
|
||||||
|
MetaBorder *closest_border;
|
||||||
|
uint32_t directions;
|
||||||
|
|
||||||
|
region = cairo_region_reference (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 *impl,
|
||||||
|
ClutterInputDevice *device)
|
||||||
|
{
|
||||||
|
MetaPointerConstraintImplNative *impl_native;
|
||||||
|
graphene_point_t point;
|
||||||
|
cairo_region_t *region;
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
|
||||||
|
impl_native = META_POINTER_CONSTRAINT_IMPL_NATIVE (impl);
|
||||||
|
region = cairo_region_reference (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_init (MetaPointerConstraintImplNative *constraint)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_pointer_constraint_impl_native_class_init (MetaPointerConstraintImplNativeClass *klass)
|
||||||
|
{
|
||||||
|
MetaPointerConstraintImplClass *constraint_impl;
|
||||||
|
|
||||||
|
constraint_impl = META_POINTER_CONSTRAINT_IMPL_CLASS (klass);
|
||||||
|
constraint_impl->constrain = meta_pointer_constraint_impl_native_constraint;
|
||||||
|
constraint_impl->ensure_constrained =
|
||||||
|
meta_pointer_constraint_impl_native_ensure_constrained;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MetaPointerConstraintImpl *
|
||||||
|
meta_pointer_constraint_impl_native_new (MetaPointerConstraint *constraint,
|
||||||
|
const cairo_region_t *region)
|
||||||
|
{
|
||||||
|
MetaPointerConstraintImplNative *impl;
|
||||||
|
|
||||||
|
impl = g_object_new (META_TYPE_POINTER_CONSTRAINT_IMPL_NATIVE, NULL);
|
||||||
|
impl->constraint = constraint;
|
||||||
|
impl->region = cairo_region_copy (region);
|
||||||
|
|
||||||
|
return META_POINTER_CONSTRAINT_IMPL (impl);
|
||||||
|
}
|
46
src/backends/native/meta-pointer-constraint-native.h
Normal file
46
src/backends/native/meta-pointer-constraint-native.h
Normal file
@ -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,
|
||||||
|
const cairo_region_t *region);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* META_POINTER_CONSTRAINT_NATIVE_H */
|
@ -936,13 +936,14 @@ meta_seat_native_constrain_pointer (MetaSeatNative *seat,
|
|||||||
us2ms (time_us),
|
us2ms (time_us),
|
||||||
new_x, new_y);
|
new_x, new_y);
|
||||||
|
|
||||||
if (seat->constrain_callback)
|
/* Bar to constraints */
|
||||||
|
if (seat->pointer_constraint)
|
||||||
{
|
{
|
||||||
seat->constrain_callback (core_pointer,
|
meta_pointer_constraint_impl_constrain (seat->pointer_constraint,
|
||||||
us2ms (time_us),
|
core_pointer,
|
||||||
x, y,
|
us2ms (time_us),
|
||||||
new_x, new_y,
|
x, y,
|
||||||
seat->constrain_data);
|
new_x, new_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we're moving inside a monitor, we're fine */
|
/* if we're moving inside a monitor, we're fine */
|
||||||
@ -2612,9 +2613,6 @@ meta_seat_native_finalize (GObject *object)
|
|||||||
|
|
||||||
g_list_free (seat->free_device_ids);
|
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_free (seat->seat_id);
|
||||||
|
|
||||||
G_OBJECT_CLASS (meta_seat_native_parent_class)->finalize (object);
|
G_OBJECT_CLASS (meta_seat_native_parent_class)->finalize (object);
|
||||||
@ -2959,33 +2957,6 @@ meta_seat_native_set_device_callbacks (MetaOpenDeviceCallback open_callback,
|
|||||||
device_callback_data = user_data;
|
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
|
void
|
||||||
meta_seat_native_update_xkb_state (MetaSeatNative *seat)
|
meta_seat_native_update_xkb_state (MetaSeatNative *seat)
|
||||||
{
|
{
|
||||||
@ -3276,3 +3247,14 @@ meta_seat_native_get_barrier_manager (MetaSeatNative *seat)
|
|||||||
{
|
{
|
||||||
return seat->barrier_manager;
|
return seat->barrier_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_seat_native_set_pointer_constraint (MetaSeatNative *seat,
|
||||||
|
MetaPointerConstraintImpl *impl)
|
||||||
|
{
|
||||||
|
if (g_set_object (&seat->pointer_constraint, impl))
|
||||||
|
{
|
||||||
|
if (impl)
|
||||||
|
meta_pointer_constraint_impl_ensure_constrained (impl, seat->core_pointer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "backends/native/meta-barrier-native.h"
|
#include "backends/native/meta-barrier-native.h"
|
||||||
#include "backends/native/meta-keymap-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 "backends/native/meta-xkb-utils.h"
|
||||||
#include "clutter/clutter.h"
|
#include "clutter/clutter.h"
|
||||||
|
|
||||||
@ -36,30 +37,6 @@ typedef struct _MetaTouchState MetaTouchState;
|
|||||||
typedef struct _MetaSeatNative MetaSeatNative;
|
typedef struct _MetaSeatNative MetaSeatNative;
|
||||||
typedef struct _MetaEventSource MetaEventSource;
|
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
|
struct _MetaTouchState
|
||||||
{
|
{
|
||||||
MetaSeatNative *seat;
|
MetaSeatNative *seat;
|
||||||
@ -102,10 +79,7 @@ struct _MetaSeatNative
|
|||||||
GList *free_device_ids;
|
GList *free_device_ids;
|
||||||
|
|
||||||
MetaBarrierManagerNative *barrier_manager;
|
MetaBarrierManagerNative *barrier_manager;
|
||||||
|
MetaPointerConstraintImpl *pointer_constraint;
|
||||||
MetaPointerConstrainCallback constrain_callback;
|
|
||||||
gpointer constrain_data;
|
|
||||||
GDestroyNotify constrain_data_notify;
|
|
||||||
|
|
||||||
MetaKeymapNative *keymap;
|
MetaKeymapNative *keymap;
|
||||||
|
|
||||||
@ -257,11 +231,6 @@ void meta_seat_native_set_device_callbacks (MetaOpenDeviceCallback open_callba
|
|||||||
void meta_seat_native_release_devices (MetaSeatNative *seat);
|
void meta_seat_native_release_devices (MetaSeatNative *seat);
|
||||||
void meta_seat_native_reclaim_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);
|
struct xkb_state * meta_seat_native_get_xkb_state (MetaSeatNative *seat);
|
||||||
|
|
||||||
void meta_seat_native_set_keyboard_map (MetaSeatNative *seat,
|
void meta_seat_native_set_keyboard_map (MetaSeatNative *seat,
|
||||||
@ -284,4 +253,7 @@ void meta_seat_native_set_keyboard_repeat (MetaSeatNative *seat,
|
|||||||
|
|
||||||
MetaBarrierManagerNative * meta_seat_native_get_barrier_manager (MetaSeatNative *seat);
|
MetaBarrierManagerNative * meta_seat_native_get_barrier_manager (MetaSeatNative *seat);
|
||||||
|
|
||||||
|
void meta_seat_native_set_pointer_constraint (MetaSeatNative *seat,
|
||||||
|
MetaPointerConstraintImpl *impl);
|
||||||
|
|
||||||
#endif /* META_SEAT_NATIVE_H */
|
#endif /* META_SEAT_NATIVE_H */
|
||||||
|
@ -695,6 +695,8 @@ if have_native_backend
|
|||||||
'backends/native/meta-kms-utils.h',
|
'backends/native/meta-kms-utils.h',
|
||||||
'backends/native/meta-kms.c',
|
'backends/native/meta-kms.c',
|
||||||
'backends/native/meta-kms.h',
|
'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.c',
|
||||||
'backends/native/meta-renderer-native-gles3.h',
|
'backends/native/meta-renderer-native-gles3.h',
|
||||||
'backends/native/meta-renderer-native.h',
|
'backends/native/meta-renderer-native.h',
|
||||||
|
@ -41,667 +41,70 @@
|
|||||||
|
|
||||||
#include "backends/meta-backend-private.h"
|
#include "backends/meta-backend-private.h"
|
||||||
#include "backends/meta-pointer-constraint.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-constraints.h"
|
||||||
#include "wayland/meta-wayland-pointer.h"
|
#include "wayland/meta-wayland-pointer.h"
|
||||||
#include "wayland/meta-wayland-seat.h"
|
#include "wayland/meta-wayland-seat.h"
|
||||||
#include "wayland/meta-wayland-surface.h"
|
#include "wayland/meta-wayland-surface.h"
|
||||||
|
|
||||||
struct _MetaPointerConfinementWayland
|
typedef struct _MetaPointerConfinementWaylandPrivate MetaPointerConfinementWaylandPrivate;
|
||||||
{
|
|
||||||
MetaPointerConstraint parent;
|
|
||||||
|
|
||||||
|
struct _MetaPointerConfinementWaylandPrivate
|
||||||
|
{
|
||||||
MetaWaylandPointerConstraint *constraint;
|
MetaWaylandPointerConstraint *constraint;
|
||||||
|
gboolean enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _MetaBox
|
enum
|
||||||
{
|
{
|
||||||
int x1;
|
PROP_0,
|
||||||
int y1;
|
PROP_WAYLAND_POINTER_CONSTRAINT,
|
||||||
int x2;
|
N_PROPS,
|
||||||
int y2;
|
};
|
||||||
} MetaBox;
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (MetaPointerConfinementWayland, meta_pointer_confinement_wayland,
|
static GParamSpec *props[N_PROPS] = { 0 };
|
||||||
META_TYPE_POINTER_CONSTRAINT);
|
|
||||||
|
|
||||||
static MetaBorder *
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaPointerConfinementWayland,
|
||||||
add_border (GArray *borders,
|
meta_pointer_confinement_wayland,
|
||||||
float x1, float y1,
|
G_TYPE_OBJECT)
|
||||||
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
|
static void
|
||||||
add_non_overlapping_edges (MetaBox *boxes,
|
meta_pointer_confinement_wayland_update (MetaPointerConfinementWayland *self)
|
||||||
unsigned int band_above_start,
|
|
||||||
unsigned int band_below_start,
|
|
||||||
unsigned int band_below_end,
|
|
||||||
GArray *borders)
|
|
||||||
{
|
{
|
||||||
unsigned int i;
|
MetaPointerConstraint *constraint;
|
||||||
GArray *band_merge;
|
|
||||||
MetaBorder *border;
|
|
||||||
MetaBorder *prev_border;
|
|
||||||
MetaBorder *new_border;
|
|
||||||
|
|
||||||
band_merge = g_array_new (FALSE, FALSE, sizeof *border);
|
constraint =
|
||||||
|
META_POINTER_CONFINEMENT_WAYLAND_GET_CLASS (self)->create_constraint (self);
|
||||||
/* Add bottom band of previous row, and top band of current row, and
|
meta_backend_set_client_pointer_constraint (meta_get_backend (), constraint);
|
||||||
* sort them so lower left x coordinate comes first. If there are two
|
g_object_unref (constraint);
|
||||||
* 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_confinement_wayland_constrain (MetaPointerConstraint *constraint,
|
|
||||||
ClutterInputDevice *device,
|
|
||||||
guint32 time,
|
|
||||||
float prev_x,
|
|
||||||
float prev_y,
|
|
||||||
float *x,
|
|
||||||
float *y)
|
|
||||||
{
|
|
||||||
MetaPointerConfinementWayland *self =
|
|
||||||
META_POINTER_CONFINEMENT_WAYLAND (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);
|
|
||||||
|
|
||||||
motion = (MetaLine2) {
|
|
||||||
.a = (MetaVector2) {
|
|
||||||
.x = prev_sx,
|
|
||||||
.y = prev_sy,
|
|
||||||
},
|
|
||||||
.b = (MetaVector2) {
|
|
||||||
.x = sx,
|
|
||||||
.y = sy,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_wayland_surface_get_absolute_coordinates (surface,
|
|
||||||
motion.b.x, motion.b.y,
|
|
||||||
x, 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
|
|
||||||
warp_to_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_confinement_wayland_maybe_warp (MetaPointerConfinementWayland *self)
|
|
||||||
{
|
|
||||||
MetaWaylandSeat *seat;
|
|
||||||
MetaWaylandSurface *surface;
|
|
||||||
graphene_point_t point;
|
|
||||||
float sx;
|
|
||||||
float sy;
|
|
||||||
cairo_region_t *region;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_region_destroy (region);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
surface_geometry_changed (MetaWaylandSurface *surface,
|
surface_geometry_changed (MetaWaylandSurface *surface,
|
||||||
MetaPointerConfinementWayland *self)
|
MetaPointerConfinementWayland *self)
|
||||||
{
|
{
|
||||||
meta_pointer_confinement_wayland_maybe_warp (self);
|
meta_pointer_confinement_wayland_update (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
window_position_changed (MetaWindow *window,
|
window_position_changed (MetaWindow *window,
|
||||||
MetaPointerConfinementWayland *self)
|
MetaPointerConfinementWayland *self)
|
||||||
{
|
{
|
||||||
meta_pointer_confinement_wayland_maybe_warp (self);
|
meta_pointer_confinement_wayland_update (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaPointerConstraint *
|
void
|
||||||
meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint)
|
meta_pointer_confinement_wayland_enable (MetaPointerConfinementWayland *confinement)
|
||||||
{
|
{
|
||||||
GObject *object;
|
MetaPointerConfinementWaylandPrivate *priv;
|
||||||
MetaPointerConfinementWayland *confinement;
|
MetaWaylandPointerConstraint *constraint;
|
||||||
MetaWaylandSurface *surface;
|
MetaWaylandSurface *surface;
|
||||||
MetaWindow *window;
|
MetaWindow *window;
|
||||||
|
|
||||||
object = g_object_new (META_TYPE_POINTER_CONFINEMENT_WAYLAND, NULL);
|
priv = meta_pointer_confinement_wayland_get_instance_private (confinement);
|
||||||
confinement = META_POINTER_CONFINEMENT_WAYLAND (object);
|
g_assert (!priv->enabled);
|
||||||
|
|
||||||
confinement->constraint = constraint;
|
priv->enabled = TRUE;
|
||||||
|
constraint = priv->constraint;
|
||||||
|
|
||||||
surface = meta_wayland_pointer_constraint_get_surface (constraint);
|
surface = meta_wayland_pointer_constraint_get_surface (constraint);
|
||||||
g_signal_connect_object (surface,
|
g_signal_connect_object (surface,
|
||||||
@ -720,7 +123,34 @@ meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint)
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return META_POINTER_CONSTRAINT (confinement);
|
meta_pointer_confinement_wayland_update (confinement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_pointer_confinement_wayland_disable (MetaPointerConfinementWayland *confinement)
|
||||||
|
{
|
||||||
|
MetaPointerConfinementWaylandPrivate *priv;
|
||||||
|
MetaWaylandPointerConstraint *constraint;
|
||||||
|
MetaWaylandSurface *surface;
|
||||||
|
MetaWindow *window;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
g_signal_handlers_disconnect_by_func (window, window_position_changed,
|
||||||
|
confinement);
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -728,11 +158,110 @@ meta_pointer_confinement_wayland_init (MetaPointerConfinementWayland *confinemen
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_pointer_confinement_wayland_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
MetaPointerConfinementWayland *confinement;
|
||||||
|
MetaPointerConfinementWaylandPrivate *priv;
|
||||||
|
|
||||||
|
confinement = META_POINTER_CONFINEMENT_WAYLAND (object);
|
||||||
|
priv = meta_pointer_confinement_wayland_get_instance_private (confinement);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_pointer_confinement_wayland_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
MetaPointerConfinementWayland *confinement;
|
||||||
|
MetaPointerConfinementWaylandPrivate *priv;
|
||||||
|
|
||||||
|
confinement = META_POINTER_CONFINEMENT_WAYLAND (object);
|
||||||
|
priv = meta_pointer_confinement_wayland_get_instance_private (confinement);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_WAYLAND_POINTER_CONSTRAINT:
|
||||||
|
priv->constraint = g_value_get_object (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetaPointerConstraint *
|
||||||
|
meta_pointer_confinement_wayland_create_constraint (MetaPointerConfinementWayland *confinement)
|
||||||
|
{
|
||||||
|
MetaPointerConfinementWaylandPrivate *priv;
|
||||||
|
MetaPointerConstraint *constraint;
|
||||||
|
MetaWaylandSurface *surface;
|
||||||
|
cairo_region_t *region;
|
||||||
|
float dx, dy;
|
||||||
|
|
||||||
|
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 (priv->constraint);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return constraint;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_pointer_confinement_wayland_class_init (MetaPointerConfinementWaylandClass *klass)
|
meta_pointer_confinement_wayland_class_init (MetaPointerConfinementWaylandClass *klass)
|
||||||
{
|
{
|
||||||
MetaPointerConstraintClass *pointer_constraint_class =
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
META_POINTER_CONSTRAINT_CLASS (klass);
|
|
||||||
|
|
||||||
pointer_constraint_class->constrain = meta_pointer_confinement_wayland_constrain;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaPointerConfinementWayland *
|
||||||
|
meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint)
|
||||||
|
{
|
||||||
|
return g_object_new (META_TYPE_POINTER_CONFINEMENT_WAYLAND,
|
||||||
|
"wayland-pointer-constraint", constraint,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaWaylandPointerConstraint *
|
||||||
|
meta_pointer_confinement_wayland_get_wayland_pointer_constraint (MetaPointerConfinementWayland *confinement)
|
||||||
|
{
|
||||||
|
MetaPointerConfinementWaylandPrivate *priv;
|
||||||
|
|
||||||
|
priv = meta_pointer_confinement_wayland_get_instance_private (confinement);
|
||||||
|
return priv->constraint;
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,23 @@
|
|||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define META_TYPE_POINTER_CONFINEMENT_WAYLAND (meta_pointer_confinement_wayland_get_type ())
|
#define META_TYPE_POINTER_CONFINEMENT_WAYLAND (meta_pointer_confinement_wayland_get_type ())
|
||||||
G_DECLARE_FINAL_TYPE (MetaPointerConfinementWayland,
|
G_DECLARE_DERIVABLE_TYPE (MetaPointerConfinementWayland,
|
||||||
meta_pointer_confinement_wayland,
|
meta_pointer_confinement_wayland,
|
||||||
META, POINTER_CONFINEMENT_WAYLAND,
|
META, POINTER_CONFINEMENT_WAYLAND,
|
||||||
MetaPointerConstraint);
|
GObject)
|
||||||
|
|
||||||
MetaPointerConstraint *meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
|
@ -37,33 +37,55 @@
|
|||||||
|
|
||||||
#include <glib-object.h>
|
#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
|
struct _MetaPointerLockWayland
|
||||||
{
|
{
|
||||||
MetaPointerConstraint parent;
|
GObject parent;
|
||||||
|
MetaWaylandPointerConstraint *constraint;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland,
|
G_DEFINE_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland,
|
||||||
META_TYPE_POINTER_CONSTRAINT);
|
META_TYPE_POINTER_CONFINEMENT_WAYLAND)
|
||||||
|
|
||||||
static void
|
static MetaPointerConstraint *
|
||||||
meta_pointer_lock_wayland_constrain (MetaPointerConstraint *constraint,
|
meta_pointer_lock_wayland_create_constraint (MetaPointerConfinementWayland *confinement)
|
||||||
ClutterInputDevice *device,
|
|
||||||
guint32 time,
|
|
||||||
float prev_x,
|
|
||||||
float prev_y,
|
|
||||||
float *x,
|
|
||||||
float *y)
|
|
||||||
{
|
{
|
||||||
*x = prev_x;
|
MetaBackend *backend = meta_get_backend ();
|
||||||
*y = prev_y;
|
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 *
|
MetaPointerConfinementWayland *
|
||||||
meta_pointer_lock_wayland_new (void)
|
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
|
static void
|
||||||
@ -74,8 +96,9 @@ meta_pointer_lock_wayland_init (MetaPointerLockWayland *lock_wayland)
|
|||||||
static void
|
static void
|
||||||
meta_pointer_lock_wayland_class_init (MetaPointerLockWaylandClass *klass)
|
meta_pointer_lock_wayland_class_init (MetaPointerLockWaylandClass *klass)
|
||||||
{
|
{
|
||||||
MetaPointerConstraintClass *pointer_constraint_class =
|
MetaPointerConfinementWaylandClass *confinement_class =
|
||||||
META_POINTER_CONSTRAINT_CLASS (klass);
|
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;
|
||||||
}
|
}
|
||||||
|
@ -27,15 +27,15 @@
|
|||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
|
||||||
#include "backends/meta-pointer-constraint.h"
|
#include "wayland/meta-pointer-confinement-wayland.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define META_TYPE_POINTER_LOCK_WAYLAND (meta_pointer_lock_wayland_get_type ())
|
#define META_TYPE_POINTER_LOCK_WAYLAND (meta_pointer_lock_wayland_get_type ())
|
||||||
G_DECLARE_FINAL_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland,
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ struct _MetaWaylandPointerConstraint
|
|||||||
wl_fixed_t x_hint;
|
wl_fixed_t x_hint;
|
||||||
wl_fixed_t y_hint;
|
wl_fixed_t y_hint;
|
||||||
|
|
||||||
MetaPointerConstraint *constraint;
|
MetaPointerConfinementWayland *confinement;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _MetaWaylandSurfacePointerConstraintsData
|
typedef struct _MetaWaylandSurfacePointerConstraintsData
|
||||||
@ -375,7 +375,7 @@ meta_wayland_pointer_constraint_notify_deactivated (MetaWaylandPointerConstraint
|
|||||||
zwp_confined_pointer_v1_send_unconfined (resource);
|
zwp_confined_pointer_v1_send_unconfined (resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MetaPointerConstraint *
|
static MetaPointerConfinementWayland *
|
||||||
meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerConstraint *constraint)
|
meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerConstraint *constraint)
|
||||||
{
|
{
|
||||||
struct wl_resource *resource = constraint->resource;
|
struct wl_resource *resource = constraint->resource;
|
||||||
@ -384,7 +384,7 @@ meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerCon
|
|||||||
&zwp_locked_pointer_v1_interface,
|
&zwp_locked_pointer_v1_interface,
|
||||||
&locked_pointer_interface))
|
&locked_pointer_interface))
|
||||||
{
|
{
|
||||||
return meta_pointer_lock_wayland_new ();
|
return meta_pointer_lock_wayland_new (constraint);
|
||||||
}
|
}
|
||||||
else if (wl_resource_instance_of (resource,
|
else if (wl_resource_instance_of (resource,
|
||||||
&zwp_confined_pointer_v1_interface,
|
&zwp_confined_pointer_v1_interface,
|
||||||
@ -399,8 +399,6 @@ meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerCon
|
|||||||
static void
|
static void
|
||||||
meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint)
|
meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint)
|
||||||
{
|
{
|
||||||
MetaBackend *backend = meta_get_backend ();
|
|
||||||
|
|
||||||
g_assert (!constraint->is_enabled);
|
g_assert (!constraint->is_enabled);
|
||||||
|
|
||||||
constraint->is_enabled = TRUE;
|
constraint->is_enabled = TRUE;
|
||||||
@ -408,20 +406,25 @@ meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint
|
|||||||
meta_wayland_pointer_start_grab (constraint->seat->pointer,
|
meta_wayland_pointer_start_grab (constraint->seat->pointer,
|
||||||
&constraint->grab);
|
&constraint->grab);
|
||||||
|
|
||||||
constraint->constraint =
|
constraint->confinement =
|
||||||
meta_wayland_pointer_constraint_create_pointer_constraint (constraint);
|
meta_wayland_pointer_constraint_create_pointer_constraint (constraint);
|
||||||
meta_backend_set_client_pointer_constraint (backend, constraint->constraint);
|
meta_pointer_confinement_wayland_enable (constraint->confinement);
|
||||||
g_object_add_weak_pointer (G_OBJECT (constraint->constraint),
|
g_object_add_weak_pointer (G_OBJECT (constraint->confinement),
|
||||||
(gpointer *) &constraint->constraint);
|
(gpointer *) &constraint->confinement);
|
||||||
g_object_unref (constraint->constraint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_wayland_pointer_constraint_disable (MetaWaylandPointerConstraint *constraint)
|
meta_wayland_pointer_constraint_disable (MetaWaylandPointerConstraint *constraint)
|
||||||
{
|
{
|
||||||
constraint->is_enabled = FALSE;
|
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_wayland_pointer_constraint_notify_deactivated (constraint);
|
||||||
meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL);
|
|
||||||
meta_wayland_pointer_end_grab (constraint->grab.pointer);
|
meta_wayland_pointer_end_grab (constraint->grab.pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user