Implement support for the wp_pointer_constraints protocol

The wp_pointer_constraints protocol is a protocol which enables clients
to manipulate the behavior of the pointer cursor associated with a seat.

Currently available constraints are locking the pointer to a static
position, and confining the pointer to a given region.

Currently locking is fully implemented, and confining is implemented for
rectangular confinement regions.

What else is lacking is less troublesome semantics for enabling the lock
or confinement; currently the only requirement implemented is that the
window that appears focused is the one that may aquire the lock.

This means that a pointer could be 'stolen' by creating a new window that
receives active focus, or when using focus-follows-mouse, a pointer
passes a window that has requested a lock. This semantics can be changed
and the protocol itself allows any semantics as seems fit.

https://bugzilla.gnome.org/show_bug.cgi?id=744104
This commit is contained in:
Jonas Ådahl 2015-06-17 12:10:52 +08:00
parent e2efc85b08
commit 495c89401a
19 changed files with 1523 additions and 1 deletions

2
.gitignore vendored
View File

@ -70,6 +70,8 @@ src/pointer-gestures-unstable-v*-protocol.c
src/pointer-gestures-unstable-v*-server-protocol.h src/pointer-gestures-unstable-v*-server-protocol.h
src/relative-pointer-unstable-v*-protocol.c src/relative-pointer-unstable-v*-protocol.c
src/relative-pointer-unstable-v*-server-protocol.h src/relative-pointer-unstable-v*-server-protocol.h
src/pointer-constraints-unstable-v*-protocol.c
src/pointer-constraints-unstable-v*-server-protocol.h
src/meta/meta-version.h src/meta/meta-version.h
doc/reference/*.args doc/reference/*.args
doc/reference/*.bak doc/reference/*.bak

View File

@ -53,6 +53,8 @@ mutter_built_sources += \
xdg-shell-unstable-v5-server-protocol.h \ xdg-shell-unstable-v5-server-protocol.h \
relative-pointer-unstable-v1-protocol.c \ relative-pointer-unstable-v1-protocol.c \
relative-pointer-unstable-v1-server-protocol.h \ relative-pointer-unstable-v1-server-protocol.h \
pointer-constraints-unstable-v1-protocol.c \
pointer-constraints-unstable-v1-server-protocol.h \
$(NULL) $(NULL)
endif endif
@ -86,6 +88,8 @@ libmutter_la_SOURCES = \
backends/meta-monitor-manager-private.h \ backends/meta-monitor-manager-private.h \
backends/meta-monitor-manager-dummy.c \ backends/meta-monitor-manager-dummy.c \
backends/meta-monitor-manager-dummy.h \ backends/meta-monitor-manager-dummy.h \
backends/meta-pointer-constraint.c \
backends/meta-pointer-constraint.h \
backends/meta-stage.h \ backends/meta-stage.h \
backends/meta-stage.c \ backends/meta-stage.c \
backends/edid-parse.c \ backends/edid-parse.c \
@ -268,6 +272,12 @@ libmutter_la_SOURCES += \
wayland/meta-wayland-keyboard.h \ wayland/meta-wayland-keyboard.h \
wayland/meta-wayland-pointer.c \ wayland/meta-wayland-pointer.c \
wayland/meta-wayland-pointer.h \ wayland/meta-wayland-pointer.h \
wayland/meta-wayland-pointer-constraints.c \
wayland/meta-wayland-pointer-constraints.h \
wayland/meta-pointer-lock-wayland.c \
wayland/meta-pointer-lock-wayland.h \
wayland/meta-pointer-confinement-wayland.c \
wayland/meta-pointer-confinement-wayland.h \
wayland/meta-wayland-popup.c \ wayland/meta-wayland-popup.c \
wayland/meta-wayland-popup.h \ wayland/meta-wayland-popup.h \
wayland/meta-wayland-seat.c \ wayland/meta-wayland-seat.c \

View File

@ -34,6 +34,7 @@
#include <meta/meta-idle-monitor.h> #include <meta/meta-idle-monitor.h>
#include "meta-cursor-renderer.h" #include "meta-cursor-renderer.h"
#include "meta-monitor-manager-private.h" #include "meta-monitor-manager-private.h"
#include "backends/meta-pointer-constraint.h"
#define DEFAULT_XKB_RULES_FILE "evdev" #define DEFAULT_XKB_RULES_FILE "evdev"
#define DEFAULT_XKB_MODEL "pc105+inet" #define DEFAULT_XKB_MODEL "pc105+inet"
@ -51,6 +52,8 @@ struct _MetaBackend
GHashTable *device_monitors; GHashTable *device_monitors;
gint current_device_id; gint current_device_id;
MetaPointerConstraint *client_pointer_constraint;
}; };
struct _MetaBackendClass struct _MetaBackendClass
@ -124,4 +127,7 @@ gboolean meta_backend_get_relative_motion_deltas (MetaBackend *backend,
double *dx_unaccel, double *dx_unaccel,
double *dy_unaccel); double *dy_unaccel);
void meta_backend_set_client_pointer_constraint (MetaBackend *backend,
MetaPointerConstraint *constraint);
#endif /* META_BACKEND_PRIVATE_H */ #endif /* META_BACKEND_PRIVATE_H */

View File

@ -571,6 +571,17 @@ meta_backend_get_relative_motion_deltas (MetaBackend *backend,
dx_unaccel, dy_unaccel); dx_unaccel, dy_unaccel);
} }
void
meta_backend_set_client_pointer_constraint (MetaBackend *backend,
MetaPointerConstraint *constraint)
{
g_assert (!constraint || (constraint && !backend->client_pointer_constraint));
g_clear_object (&backend->client_pointer_constraint);
if (constraint)
backend->client_pointer_constraint = g_object_ref (constraint);
}
static GType static GType
get_backend_type (void) get_backend_type (void)
{ {

View File

@ -0,0 +1,57 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 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 "backends/meta-pointer-constraint.h"
#include <glib-object.h>
G_DEFINE_TYPE (MetaPointerConstraint, meta_pointer_constraint, G_TYPE_OBJECT);
static void
meta_pointer_constraint_init (MetaPointerConstraint *constraint)
{
}
static void
meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass)
{
}
void
meta_pointer_constraint_constrain (MetaPointerConstraint *constraint,
ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y)
{
META_POINTER_CONSTRAINT_GET_CLASS (constraint)->constrain (constraint,
device,
time,
prev_x, prev_y,
x, y);
}

View File

@ -0,0 +1,60 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 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>
*/
#ifndef META_POINTER_CONSTRAINT_H
#define META_POINTER_CONSTRAINT_H
#include <glib-object.h>
#include <clutter/clutter.h>
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);
struct _MetaPointerConstraintClass
{
GObjectClass parent_class;
void (*constrain) (MetaPointerConstraint *constraint,
ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y);
};
void meta_pointer_constraint_constrain (MetaPointerConstraint *constraint,
ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y);
G_END_DECLS
#endif /* META_POINTER_CONSTRAINT_H */

View File

@ -36,6 +36,7 @@
#include "meta-monitor-manager-kms.h" #include "meta-monitor-manager-kms.h"
#include "meta-cursor-renderer-native.h" #include "meta-cursor-renderer-native.h"
#include "meta-launcher.h" #include "meta-launcher.h"
#include "backends/meta-pointer-constraint.h"
#include <stdlib.h> #include <stdlib.h>
@ -139,6 +140,24 @@ constrain_to_barriers (ClutterInputDevice *device,
new_x, new_y); new_x, new_y);
} }
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 = backend->client_pointer_constraint;
if (!constraint)
return;
meta_pointer_constraint_constrain (constraint, device,
time, prev_x, prev_y, x, y);
}
/* /*
* The pointer constrain code is mostly a rip-off of the XRandR code from Xorg. * The pointer constrain code is mostly a rip-off of the XRandR code from Xorg.
* (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder) * (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder)
@ -207,6 +226,9 @@ pointer_constrain_callback (ClutterInputDevice *device,
/* Constrain to barriers */ /* Constrain to barriers */
constrain_to_barriers (device, time, new_x, new_y); constrain_to_barriers (device, time, new_x, new_y);
/* Constrain to pointer lock */
constrain_to_client_constraint (device, time, prev_x, prev_y, new_x, new_y);
monitor_manager = meta_monitor_manager_get (); monitor_manager = meta_monitor_manager_get ();
monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors); monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors);

View File

@ -0,0 +1,200 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 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 "wayland/meta-pointer-confinement-wayland.h"
#include <glib-object.h>
#include <cairo.h>
#include "backends/meta-backend-private.h"
#include "wayland/meta-wayland-seat.h"
#include "wayland/meta-wayland-pointer.h"
#include "wayland/meta-wayland-pointer-constraints.h"
#include "wayland/meta-wayland-surface.h"
#include "backends/meta-pointer-constraint.h"
#include "compositor/meta-surface-actor-wayland.h"
struct _MetaPointerConfinementWayland
{
MetaPointerConstraint parent;
MetaWaylandPointerConstraint *constraint;
};
G_DEFINE_TYPE (MetaPointerConfinementWayland, meta_pointer_confinement_wayland,
META_TYPE_POINTER_CONSTRAINT);
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;
cairo_rectangle_int_t extents;
float sx, sy;
float min_sx, max_sx;
float min_sy, max_sy;
region =
meta_wayland_pointer_constraint_calculate_effective_region (self->constraint);
cairo_region_get_extents (region, &extents);
cairo_region_destroy (region);
min_sx = extents.x;
max_sx = extents.x + extents.width - 1;
max_sy = extents.y + extents.height - 1;
min_sy = extents.y;
surface = meta_wayland_pointer_constraint_get_surface (self->constraint);
meta_wayland_surface_get_relative_coordinates (surface, *x, *y, &sx, &sy);
if (sx < min_sx)
sx = min_sx;
else if (sx > max_sx)
sx = max_sx;
if (sy < min_sy)
sy = min_sy;
else if (sy > max_sy)
sy = max_sy;
meta_wayland_surface_get_absolute_coordinates (surface, sx, sy, x, y);
}
static void
meta_pointer_confinement_wayland_maybe_warp (MetaPointerConfinementWayland *self)
{
MetaWaylandSeat *seat;
MetaWaylandSurface *surface;
wl_fixed_t sx;
wl_fixed_t sy;
cairo_region_t *region;
seat = meta_wayland_pointer_constraint_get_seat (self->constraint);
surface = meta_wayland_pointer_constraint_get_surface (self->constraint);
meta_wayland_pointer_get_relative_coordinates (&seat->pointer,
surface,
&sx, &sy);
region =
meta_wayland_pointer_constraint_calculate_effective_region (self->constraint);
if (!cairo_region_contains_point (region,
wl_fixed_to_int (sx),
wl_fixed_to_int (sy)))
{
cairo_rectangle_int_t extents;
wl_fixed_t min_sx;
wl_fixed_t max_sx;
wl_fixed_t max_sy;
wl_fixed_t min_sy;
gboolean x_changed = TRUE, y_changed = TRUE;
cairo_region_get_extents (region, &extents);
min_sx = wl_fixed_from_int (extents.x);
max_sx = wl_fixed_from_int (extents.x + extents.width - 1);
max_sy = wl_fixed_from_int (extents.y + extents.height - 1);
min_sy = wl_fixed_from_int (extents.y);
if (sx < min_sx)
sx = min_sx;
else if (sx > max_sx)
sx = max_sx;
else
x_changed = FALSE;
if (sy < min_sy)
sy = min_sy;
else if (sy > max_sy)
sy = max_sy;
else
y_changed = FALSE;
if (x_changed || y_changed)
{
float x, y;
meta_wayland_surface_get_absolute_coordinates (surface,
wl_fixed_to_double (sx),
wl_fixed_to_double (sy),
&x, &y);
meta_backend_warp_pointer (meta_get_backend (), (int)x, (int)y);
}
}
cairo_region_destroy (region);
}
static void
surface_actor_painting (MetaSurfaceActorWayland *surface_actor,
MetaPointerConfinementWayland *self)
{
meta_pointer_confinement_wayland_maybe_warp (self);
}
MetaPointerConstraint *
meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint)
{
GObject *object;
MetaPointerConfinementWayland *confinement;
MetaWaylandSurface *surface;
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->surface_actor,
"painting",
G_CALLBACK (surface_actor_painting),
confinement,
0);
return META_POINTER_CONSTRAINT (confinement);
}
static void
meta_pointer_confinement_wayland_init (MetaPointerConfinementWayland *confinement_wayland)
{
}
static void
meta_pointer_confinement_wayland_class_init (MetaPointerConfinementWaylandClass *klass)
{
MetaPointerConstraintClass *pointer_constraint_class =
META_POINTER_CONSTRAINT_CLASS (klass);
pointer_constraint_class->constrain = meta_pointer_confinement_wayland_constrain;
}

View File

@ -0,0 +1,45 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 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>
*/
#ifndef META_POINTER_CONFINEMENT_WAYLAND_H
#define META_POINTER_CONFINEMENT_WAYLAND_H
#include <glib-object.h>
#include "backends/meta-pointer-constraint.h"
#include "wayland/meta-wayland-pointer-constraints.h"
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_END_DECLS
#endif /* META_CONFINEMENT_WAYLAND_H */

View File

@ -0,0 +1,72 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 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 "wayland/meta-pointer-lock-wayland.h"
#include <glib-object.h>
#include "backends/meta-pointer-constraint.h"
struct _MetaPointerLockWayland
{
MetaPointerConstraint parent;
};
G_DEFINE_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland,
META_TYPE_POINTER_CONSTRAINT);
static void
meta_pointer_lock_wayland_constrain (MetaPointerConstraint *constraint,
ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y)
{
*x = prev_x;
*y = prev_y;
}
MetaPointerConstraint *
meta_pointer_lock_wayland_new (void)
{
return g_object_new (META_TYPE_POINTER_LOCK_WAYLAND, NULL);
}
static void
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);
pointer_constraint_class->constrain = meta_pointer_lock_wayland_constrain;
}

View File

@ -0,0 +1,42 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 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>
*/
#ifndef META_POINTER_LOCK_WAYLAND_H
#define META_POINTER_LOCK_WAYLAND_H
#include <glib-object.h>
#include "backends/meta-pointer-constraint.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);
MetaPointerConstraint *meta_pointer_lock_wayland_new (void);
G_END_DECLS
#endif /* META_LOCK_WAYLAND_H */

View File

@ -0,0 +1,818 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 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 "meta-wayland-pointer-constraints.h"
#include <glib.h>
#include "meta/meta-backend.h"
#include "meta-wayland-private.h"
#include "meta-wayland-seat.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-surface.h"
#include "meta-wayland-region.h"
#include "meta-pointer-lock-wayland.h"
#include "meta-pointer-confinement-wayland.h"
#include "window-private.h"
#include "backends/meta-backend-private.h"
#include "backends/native/meta-backend-native.h"
#include "backends/meta-pointer-constraint.h"
#include "pointer-constraints-unstable-v1-server-protocol.h"
static GQuark quark_pending_constraint_state = 0;
struct _MetaWaylandPointerConstraint
{
GObject parent;
MetaWaylandSurface *surface;
gboolean is_enabled;
cairo_region_t *region;
struct wl_resource *resource;
MetaWaylandPointerGrab grab;
MetaWaylandSeat *seat;
enum zwp_pointer_constraints_v1_lifetime lifetime;
gboolean hint_set;
wl_fixed_t x_hint;
wl_fixed_t y_hint;
MetaPointerConstraint *constraint;
};
typedef struct
{
MetaWaylandPointerConstraint *constraint;
cairo_region_t *region;
gulong applied_handler_id;
} MetaWaylandPendingConstraintState;
typedef struct
{
GList *pending_constraint_states;
} MetaWaylandPendingConstraintStateContainer;
G_DEFINE_TYPE (MetaWaylandPointerConstraint, meta_wayland_pointer_constraint,
G_TYPE_OBJECT);
static const struct zwp_locked_pointer_v1_interface locked_pointer_interface;
static const struct zwp_confined_pointer_v1_interface confined_pointer_interface;
static const MetaWaylandPointerGrabInterface locked_pointer_grab_interface;
static const MetaWaylandPointerGrabInterface confined_pointer_grab_interface;
static cairo_region_t *
create_infinite_constraint_region (void)
{
return cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
.x = INT_MIN / 2,
.y = INT_MIN / 2,
.width = INT_MAX,
.height = INT_MAX,
});
}
static MetaWaylandPointerConstraint *
meta_wayland_pointer_constraint_new (MetaWaylandSurface *surface,
MetaWaylandSeat *seat,
MetaWaylandRegion *region,
enum zwp_pointer_constraints_v1_lifetime lifetime,
struct wl_resource *resource,
const MetaWaylandPointerGrabInterface *grab_interface)
{
MetaWaylandPointerConstraint *constraint;
constraint = g_object_new (META_TYPE_WAYLAND_POINTER_CONSTRAINT, NULL);
if (!constraint)
return NULL;
constraint->surface = surface;
constraint->seat = seat;
constraint->lifetime = lifetime;
constraint->resource = resource;
constraint->grab.interface = grab_interface;
if (region)
{
constraint->region =
cairo_region_copy (meta_wayland_region_peek_cairo_region (region));
}
else
{
constraint->region = create_infinite_constraint_region ();
}
return constraint;
}
static gboolean
meta_wayland_pointer_constraint_is_enabled (MetaWaylandPointerConstraint *constraint)
{
return constraint->is_enabled;
}
static void
meta_wayland_pointer_constraint_notify_activated (MetaWaylandPointerConstraint *constraint)
{
struct wl_resource *resource = constraint->resource;
if (wl_resource_instance_of (resource,
&zwp_locked_pointer_v1_interface,
&locked_pointer_interface))
{
zwp_locked_pointer_v1_send_locked (resource);
}
else if (wl_resource_instance_of (resource,
&zwp_confined_pointer_v1_interface,
&confined_pointer_interface))
{
zwp_confined_pointer_v1_send_confined (resource);
}
}
static void
meta_wayland_pointer_constraint_notify_deactivated (MetaWaylandPointerConstraint *constraint)
{
struct wl_resource *resource = constraint->resource;
if (wl_resource_instance_of (resource,
&zwp_locked_pointer_v1_interface,
&locked_pointer_interface))
zwp_locked_pointer_v1_send_unlocked (resource);
else if (wl_resource_instance_of (resource,
&zwp_confined_pointer_v1_interface,
&confined_pointer_interface))
zwp_confined_pointer_v1_send_unconfined (resource);
}
static MetaPointerConstraint *
meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerConstraint *constraint)
{
struct wl_resource *resource = constraint->resource;
if (wl_resource_instance_of (resource,
&zwp_locked_pointer_v1_interface,
&locked_pointer_interface))
{
return meta_pointer_lock_wayland_new ();
}
else if (wl_resource_instance_of (resource,
&zwp_confined_pointer_v1_interface,
&confined_pointer_interface))
{
return meta_pointer_confinement_wayland_new (constraint);
}
g_assert_not_reached ();
return NULL;
}
static void
meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint)
{
MetaBackend *backend = meta_get_backend ();
g_assert (!constraint->is_enabled);
constraint->is_enabled = TRUE;
meta_wayland_pointer_constraint_notify_activated (constraint);
meta_wayland_pointer_start_grab (&constraint->seat->pointer,
&constraint->grab);
constraint->constraint =
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);
}
static void
meta_wayland_pointer_constraint_disable (MetaWaylandPointerConstraint *constraint)
{
meta_wayland_pointer_constraint_notify_deactivated (constraint);
meta_wayland_pointer_end_grab (constraint->grab.pointer);
meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL);
}
void
meta_wayland_pointer_constraint_destroy (MetaWaylandPointerConstraint *constraint)
{
if (meta_wayland_pointer_constraint_is_enabled (constraint))
meta_wayland_pointer_constraint_disable (constraint);
wl_resource_set_user_data (constraint->resource, NULL);
cairo_region_destroy (constraint->region);
g_object_unref (constraint);
}
static gboolean
is_within_constraint_region (MetaWaylandPointerConstraint *constraint,
wl_fixed_t sx,
wl_fixed_t sy)
{
cairo_region_t *region;
gboolean is_within;
region = meta_wayland_pointer_constraint_calculate_effective_region (constraint);
is_within = cairo_region_contains_point (constraint->region,
wl_fixed_to_int (sx),
wl_fixed_to_int (sy));
cairo_region_destroy (region);
return is_within;
}
void
meta_wayland_pointer_constraint_maybe_enable (MetaWaylandPointerConstraint *constraint)
{
MetaWaylandSeat *seat = constraint->seat;
wl_fixed_t sx, sy;
if (constraint->is_enabled)
return;
if (seat->keyboard.focus_surface != constraint->surface)
return;
meta_wayland_pointer_get_relative_coordinates (&constraint->seat->pointer,
constraint->surface,
&sx, &sy);
if (!is_within_constraint_region (constraint, sx, sy))
return;
meta_wayland_pointer_constraint_enable (constraint);
}
static void
meta_wayland_pointer_constraint_remove (MetaWaylandPointerConstraint *constraint)
{
MetaWaylandSurface *surface = constraint->surface;
meta_wayland_surface_remove_pointer_constraint (surface, constraint);
meta_wayland_pointer_constraint_destroy (constraint);
}
void
meta_wayland_pointer_constraint_maybe_remove_for_seat (MetaWaylandSeat *seat,
MetaWindow *focus_window)
{
MetaWaylandPointer *pointer = &seat->pointer;
if ((pointer->grab->interface == &confined_pointer_grab_interface ||
pointer->grab->interface == &locked_pointer_grab_interface) &&
pointer->focus_surface &&
pointer->focus_surface->window != focus_window)
{
MetaWaylandPointerConstraint *constraint =
wl_container_of (pointer->grab, constraint, grab);
switch (constraint->lifetime)
{
case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT:
meta_wayland_pointer_constraint_remove (constraint);
break;
case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT:
meta_wayland_pointer_constraint_disable (constraint);
break;
default:
g_assert_not_reached ();
}
}
}
void
meta_wayland_pointer_constraint_maybe_enable_for_window (MetaWindow *window)
{
MetaWaylandSurface *surface = window->surface;
GList *it;
for (it = surface->pointer_constraints; it; it = it->next)
{
MetaWaylandPointerConstraint *constraint = it->data;
meta_wayland_pointer_constraint_maybe_enable (constraint);
}
}
MetaWaylandSeat *
meta_wayland_pointer_constraint_get_seat (MetaWaylandPointerConstraint *constraint)
{
return constraint->seat;
}
cairo_region_t *
meta_wayland_pointer_constraint_calculate_effective_region (MetaWaylandPointerConstraint *constraint)
{
cairo_region_t *region;
region = cairo_region_copy (constraint->surface->input_region);
cairo_region_intersect (region, constraint->region);
return region;
}
cairo_region_t *
meta_wayland_pointer_constraint_get_region (MetaWaylandPointerConstraint *constraint)
{
return constraint->region;
}
MetaWaylandSurface *
meta_wayland_pointer_constraint_get_surface (MetaWaylandPointerConstraint *constraint)
{
return constraint->surface;
}
static void
pointer_constraint_resource_destroyed (struct wl_resource *resource)
{
MetaWaylandPointerConstraint *constraint =
wl_resource_get_user_data (resource);
if (!constraint)
return;
meta_wayland_pointer_constraint_remove (constraint);
}
static void
pending_constraint_state_free (MetaWaylandPendingConstraintState *constraint_pending)
{
g_clear_pointer (&constraint_pending->region, cairo_region_destroy);
if (constraint_pending->constraint)
g_object_remove_weak_pointer (G_OBJECT (constraint_pending->constraint),
(gpointer *) &constraint_pending->constraint);
}
static MetaWaylandPendingConstraintStateContainer *
get_pending_constraint_state_container (MetaWaylandPendingState *pending)
{
return g_object_get_qdata (G_OBJECT (pending),
quark_pending_constraint_state);
}
static MetaWaylandPendingConstraintState *
get_pending_constraint_state (MetaWaylandPointerConstraint *constraint)
{
MetaWaylandPendingState *pending = constraint->surface->pending;
MetaWaylandPendingConstraintStateContainer *container;
GList *l;
container = get_pending_constraint_state_container (pending);
for (l = container->pending_constraint_states; l; l = l->next)
{
MetaWaylandPendingConstraintState *constraint_pending = l->data;
if (constraint_pending->constraint == constraint)
return constraint_pending;
}
return NULL;
}
static void
pending_constraint_state_container_free (MetaWaylandPendingConstraintStateContainer *container)
{
g_list_free_full (container->pending_constraint_states,
(GDestroyNotify) pending_constraint_state_free);
g_free (container);
}
static MetaWaylandPendingConstraintStateContainer *
ensure_pending_constraint_state_container (MetaWaylandPendingState *pending)
{
MetaWaylandPendingConstraintStateContainer *container;
container = get_pending_constraint_state_container (pending);
if (!container)
{
container = g_new0 (MetaWaylandPendingConstraintStateContainer, 1);
g_object_set_qdata_full (G_OBJECT (pending),
quark_pending_constraint_state,
container,
(GDestroyNotify) pending_constraint_state_container_free);
}
return container;
}
static void
remove_pending_constraint_state (MetaWaylandPointerConstraint *constraint,
MetaWaylandPendingState *pending)
{
MetaWaylandPendingConstraintStateContainer *container;
GList *l;
container = get_pending_constraint_state_container (pending);
for (l = container->pending_constraint_states; l; l = l->next)
{
MetaWaylandPendingConstraintState *constraint_pending = l->data;
if (constraint_pending->constraint != constraint)
continue;
pending_constraint_state_free (l->data);
container->pending_constraint_states =
g_list_remove_link (container->pending_constraint_states, l);
break;
}
}
static void
pending_constraint_state_applied (MetaWaylandPendingState *pending,
MetaWaylandPendingConstraintState *constraint_pending)
{
MetaWaylandPointerConstraint *constraint = constraint_pending->constraint;
if (!constraint)
return;
g_clear_pointer (&constraint->region, cairo_region_destroy);
if (constraint_pending->region)
{
constraint->region = constraint_pending->region;
constraint_pending->region = NULL;
}
else
{
constraint->region = create_infinite_constraint_region ();
}
g_signal_handler_disconnect (pending,
constraint_pending->applied_handler_id);
remove_pending_constraint_state (constraint, pending);
/* The pointer is potentially warped by the actor paint signal callback if
* the new region proved it necessary.
*/
}
static MetaWaylandPendingConstraintState *
ensure_pending_constraint_state (MetaWaylandPointerConstraint *constraint)
{
MetaWaylandPendingState *pending = constraint->surface->pending;
MetaWaylandPendingConstraintStateContainer *container;
MetaWaylandPendingConstraintState *constraint_pending;
container = ensure_pending_constraint_state_container (pending);
constraint_pending = get_pending_constraint_state (constraint);
if (!constraint_pending)
{
constraint_pending = g_new0 (MetaWaylandPendingConstraintState, 1);
constraint_pending->constraint = constraint;
constraint_pending->applied_handler_id =
g_signal_connect (pending, "applied",
G_CALLBACK (pending_constraint_state_applied),
constraint_pending);
g_object_add_weak_pointer (G_OBJECT (constraint),
(gpointer *) &constraint_pending->constraint);
container->pending_constraint_states =
g_list_append (container->pending_constraint_states,
constraint_pending);
}
return constraint_pending;
}
static void
meta_wayland_pointer_constraint_set_pending_region (MetaWaylandPointerConstraint *constraint,
MetaWaylandRegion *region)
{
MetaWaylandPendingConstraintState *constraint_pending;
constraint_pending = ensure_pending_constraint_state (constraint);
g_clear_pointer (&constraint_pending->region, cairo_region_destroy);
if (region)
{
constraint_pending->region =
cairo_region_copy (meta_wayland_region_peek_cairo_region (region));
}
}
static void
init_pointer_constraint (struct wl_resource *resource,
uint32_t id,
MetaWaylandSurface *surface,
MetaWaylandSeat *seat,
MetaWaylandRegion *region,
enum zwp_pointer_constraints_v1_lifetime lifetime,
const struct wl_interface *interface,
const void *implementation,
const MetaWaylandPointerGrabInterface *grab_interface)
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_resource *cr;
MetaWaylandPointerConstraint *constraint;
if (meta_wayland_surface_get_pointer_constraint_for_seat (surface, seat))
{
wl_resource_post_error (resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"the pointer as already requested to be "
"locked or confined on that surface");
return;
}
cr = wl_resource_create (client, interface,
wl_resource_get_version (resource),
id);
if (cr == NULL)
{
wl_client_post_no_memory (client);
return;
}
constraint = meta_wayland_pointer_constraint_new (surface, seat,
region,
lifetime,
cr, grab_interface);
if (constraint == NULL)
{
wl_client_post_no_memory (client);
return;
}
meta_wayland_surface_add_pointer_constraint (surface, constraint);
wl_resource_set_implementation (cr, implementation, constraint,
pointer_constraint_resource_destroyed);
meta_wayland_pointer_constraint_maybe_enable (constraint);
}
static void
locked_pointer_destroy (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandPointerConstraint *constraint =
wl_resource_get_user_data (resource);
gboolean warp_pointer = FALSE;
int warp_x, warp_y;
if (constraint && constraint->is_enabled && constraint->hint_set &&
is_within_constraint_region (constraint,
constraint->x_hint,
constraint->y_hint))
{
float sx, sy;
float x, y;
sx = (float)wl_fixed_to_double (constraint->x_hint);
sy = (float)wl_fixed_to_double (constraint->y_hint);
meta_wayland_surface_get_absolute_coordinates (constraint->surface,
sx, sy,
&x, &y);
warp_pointer = TRUE;
warp_x = (int) x;
warp_y = (int) y;
}
wl_resource_destroy (resource);
if (warp_pointer)
meta_backend_warp_pointer (meta_get_backend (), warp_x, warp_y);
}
static void
locked_pointer_set_cursor_position_hint (struct wl_client *client,
struct wl_resource *resource,
wl_fixed_t surface_x,
wl_fixed_t surface_y)
{
MetaWaylandPointerConstraint *constraint =
wl_resource_get_user_data (resource);
/* Ignore a set cursor hint that was already sent after the constraint
* was cancelled. */
if (!constraint->resource || constraint->resource != resource)
return;
constraint->hint_set = TRUE;
constraint->x_hint = surface_x;
constraint->y_hint = surface_y;
}
static void
locked_pointer_set_region (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *region_resource)
{
MetaWaylandPointerConstraint *constraint =
wl_resource_get_user_data (resource);
MetaWaylandRegion *region =
region_resource ? wl_resource_get_user_data (region_resource) : NULL;
meta_wayland_pointer_constraint_set_pending_region (constraint, region);
}
static const struct zwp_locked_pointer_v1_interface locked_pointer_interface = {
locked_pointer_destroy,
locked_pointer_set_cursor_position_hint,
locked_pointer_set_region,
};
static void
locked_pointer_grab_pointer_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface)
{
}
static void
locked_pointer_grab_pointer_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
meta_wayland_pointer_send_relative_motion (grab->pointer, event);
}
static void
locked_pointer_grab_pointer_button (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
meta_wayland_pointer_send_button (grab->pointer, event);
}
static const MetaWaylandPointerGrabInterface locked_pointer_grab_interface = {
locked_pointer_grab_pointer_focus,
locked_pointer_grab_pointer_motion,
locked_pointer_grab_pointer_button,
};
static void
pointer_constraints_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
pointer_constraints_lock_pointer (struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource,
struct wl_resource *pointer_resource,
struct wl_resource *region_resource,
uint32_t lifetime)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandPointer *pointer = wl_resource_get_user_data (pointer_resource);
MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
MetaWaylandRegion *region =
region_resource ? wl_resource_get_user_data (region_resource) : NULL;
init_pointer_constraint (resource, id, surface, seat, region, lifetime,
&zwp_locked_pointer_v1_interface,
&locked_pointer_interface,
&locked_pointer_grab_interface);
}
static void
confined_pointer_grab_pointer_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface)
{
}
static void
confined_pointer_grab_pointer_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
MetaWaylandPointerConstraint *constraint =
wl_container_of (grab, constraint, grab);
MetaWaylandPointer *pointer = grab->pointer;
g_assert (pointer->focus_surface);
g_assert (pointer->focus_surface == constraint->surface);
meta_wayland_pointer_send_motion (pointer, event);
}
static void
confined_pointer_grab_pointer_button (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
meta_wayland_pointer_send_button (grab->pointer, event);
}
static const MetaWaylandPointerGrabInterface confined_pointer_grab_interface = {
confined_pointer_grab_pointer_focus,
confined_pointer_grab_pointer_motion,
confined_pointer_grab_pointer_button,
};
static void
confined_pointer_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
confined_pointer_set_region (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *region_resource)
{
MetaWaylandPointerConstraint *constraint =
wl_resource_get_user_data (resource);
MetaWaylandRegion *region =
region_resource ? wl_resource_get_user_data (region_resource) : NULL;
meta_wayland_pointer_constraint_set_pending_region (constraint, region);
}
static const struct zwp_confined_pointer_v1_interface confined_pointer_interface = {
confined_pointer_destroy,
confined_pointer_set_region,
};
static void
pointer_constraints_confine_pointer (struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource,
struct wl_resource *pointer_resource,
struct wl_resource *region_resource,
uint32_t lifetime)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandPointer *pointer = wl_resource_get_user_data (pointer_resource);
MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
MetaWaylandRegion *region =
region_resource ? wl_resource_get_user_data (region_resource) : NULL;
init_pointer_constraint (resource, id, surface, seat, region, lifetime,
&zwp_confined_pointer_v1_interface,
&confined_pointer_interface,
&confined_pointer_grab_interface);
}
static const struct zwp_pointer_constraints_v1_interface pointer_constraints = {
pointer_constraints_destroy,
pointer_constraints_lock_pointer,
pointer_constraints_confine_pointer,
};
static void
bind_pointer_constraints (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
MetaWaylandCompositor *compositor = data;
struct wl_resource *resource;
resource = wl_resource_create (client,
&zwp_pointer_constraints_v1_interface,
1, id);
wl_resource_set_implementation (resource,
&pointer_constraints,
compositor,
NULL);
}
void
meta_wayland_pointer_constraints_init (MetaWaylandCompositor *compositor)
{
if (!wl_global_create (compositor->wayland_display,
&zwp_pointer_constraints_v1_interface, 1,
compositor, bind_pointer_constraints))
g_error ("Could not create wp_pointer_constraints global");
}
static void
meta_wayland_pointer_constraint_init (MetaWaylandPointerConstraint *constraint)
{
}
static void
meta_wayland_pointer_constraint_class_init (MetaWaylandPointerConstraintClass *klass)
{
quark_pending_constraint_state =
g_quark_from_static_string ("-meta-wayland-pointer-constraint-pending_state");
}

View File

@ -0,0 +1,60 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 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>
*/
#ifndef META_WAYLAND_POINTER_CONSTRAINTS_H
#define META_WAYLAND_POINTER_CONSTRAINTS_H
#include "meta-wayland-types.h"
#include "meta/window.h"
#include <wayland-server.h>
#define META_TYPE_WAYLAND_POINTER_CONSTRAINT (meta_wayland_pointer_constraint_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandPointerConstraint,
meta_wayland_pointer_constraint,
META, WAYLAND_POINTER_CONSTRAINT,
GObject);
typedef struct _MetaWaylandPointerConstraint MetaWaylandPointerConstraint;
void meta_wayland_pointer_constraints_init (MetaWaylandCompositor *compositor);
void meta_wayland_pointer_constraint_maybe_enable (MetaWaylandPointerConstraint *constraint);
void meta_wayland_pointer_constraint_destroy (MetaWaylandPointerConstraint *constraint);
MetaWaylandSeat * meta_wayland_pointer_constraint_get_seat (MetaWaylandPointerConstraint *constraint);
cairo_region_t * meta_wayland_pointer_constraint_calculate_effective_region (MetaWaylandPointerConstraint *constraint);
cairo_region_t * meta_wayland_pointer_constraint_get_region (MetaWaylandPointerConstraint *constraint);
MetaWaylandSurface * meta_wayland_pointer_constraint_get_surface (MetaWaylandPointerConstraint *constraint);
void meta_wayland_pointer_constraint_maybe_remove_for_seat (MetaWaylandSeat *seat,
MetaWindow *focus_window);
void meta_wayland_pointer_constraint_maybe_enable_for_window (MetaWindow *window);
#endif /* META_WAYLAND_POINTER_CONSTRAINTS_H */

View File

@ -273,7 +273,7 @@ meta_wayland_pointer_broadcast_frame (MetaWaylandPointer *pointer)
} }
} }
static void void
meta_wayland_pointer_send_relative_motion (MetaWaylandPointer *pointer, meta_wayland_pointer_send_relative_motion (MetaWaylandPointer *pointer,
const ClutterEvent *event) const ClutterEvent *event)
{ {
@ -1249,6 +1249,13 @@ meta_wayland_relative_pointer_init (MetaWaylandCompositor *compositor)
g_error ("Could not create relative pointer manager global"); g_error ("Could not create relative pointer manager global");
} }
MetaWaylandSeat *
meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
{
MetaWaylandSeat *seat = wl_container_of (pointer, seat, pointer);
return seat;
}
static void static void
cursor_surface_role_assigned (MetaWaylandSurfaceRole *surface_role) cursor_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
{ {

View File

@ -28,6 +28,7 @@
#include "meta-wayland-pointer-gesture-swipe.h" #include "meta-wayland-pointer-gesture-swipe.h"
#include "meta-wayland-pointer-gesture-pinch.h" #include "meta-wayland-pointer-gesture-pinch.h"
#include "meta-wayland-surface.h" #include "meta-wayland-surface.h"
#include "meta-wayland-pointer-constraints.h"
#include <meta/meta-cursor-tracker.h> #include <meta/meta-cursor-tracker.h>
@ -102,6 +103,9 @@ gboolean meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
void meta_wayland_pointer_send_motion (MetaWaylandPointer *pointer, void meta_wayland_pointer_send_motion (MetaWaylandPointer *pointer,
const ClutterEvent *event); const ClutterEvent *event);
void meta_wayland_pointer_send_relative_motion (MetaWaylandPointer *pointer,
const ClutterEvent *event);
void meta_wayland_pointer_send_button (MetaWaylandPointer *pointer, void meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
const ClutterEvent *event); const ClutterEvent *event);
@ -145,4 +149,6 @@ void meta_wayland_pointer_unbind_pointer_client_resource (struct wl_resource *re
void meta_wayland_relative_pointer_init (MetaWaylandCompositor *compositor); void meta_wayland_relative_pointer_init (MetaWaylandCompositor *compositor);
MetaWaylandSeat *meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer);
#endif /* META_WAYLAND_POINTER_H */ #endif /* META_WAYLAND_POINTER_H */

View File

@ -55,6 +55,14 @@
#include "meta-surface-actor-wayland.h" #include "meta-surface-actor-wayland.h"
#include "meta-xwayland-private.h" #include "meta-xwayland-private.h"
enum {
PENDING_STATE_SIGNAL_APPLIED,
PENDING_STATE_SIGNAL_LAST_SIGNAL
};
static guint pending_state_signals[PENDING_STATE_SIGNAL_LAST_SIGNAL];
typedef struct _MetaWaylandSurfaceRolePrivate typedef struct _MetaWaylandSurfaceRolePrivate
{ {
MetaWaylandSurface *surface; MetaWaylandSurface *surface;
@ -516,6 +524,14 @@ meta_wayland_pending_state_class_init (MetaWaylandPendingStateClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_wayland_pending_state_finalize; object_class->finalize = meta_wayland_pending_state_finalize;
pending_state_signals[PENDING_STATE_SIGNAL_APPLIED] =
g_signal_new ("applied",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
} }
static void static void
@ -689,6 +705,10 @@ apply_pending_state (MetaWaylandSurface *surface,
wl_list_init (&pending->frame_callback_list); wl_list_init (&pending->frame_callback_list);
} }
g_signal_emit (pending,
pending_state_signals[PENDING_STATE_SIGNAL_APPLIED],
0);
meta_surface_actor_wayland_sync_state ( meta_surface_actor_wayland_sync_state (
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor)); META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
@ -1072,6 +1092,9 @@ wl_surface_destructor (struct wl_resource *resource)
if (surface->window) if (surface->window)
destroy_window (surface); destroy_window (surface);
g_list_free_full (surface->pointer_constraints,
(GDestroyNotify) meta_wayland_pointer_constraint_destroy);
surface_set_buffer (surface, NULL); surface_set_buffer (surface, NULL);
g_clear_object (&surface->pending); g_clear_object (&surface->pending);
@ -2468,6 +2491,39 @@ meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface)
return NULL; return NULL;
} }
void
meta_wayland_surface_add_pointer_constraint (MetaWaylandSurface *surface,
MetaWaylandPointerConstraint *constraint)
{
surface->pointer_constraints = g_list_append (surface->pointer_constraints,
constraint);
}
void
meta_wayland_surface_remove_pointer_constraint (MetaWaylandSurface *surface,
MetaWaylandPointerConstraint *constraint)
{
surface->pointer_constraints = g_list_remove (surface->pointer_constraints,
constraint);
}
MetaWaylandPointerConstraint *
meta_wayland_surface_get_pointer_constraint_for_seat (MetaWaylandSurface *surface,
MetaWaylandSeat *seat)
{
GList *iter;
for (iter = surface->pointer_constraints; iter; iter = iter->next)
{
MetaWaylandPointerConstraint *constraint = iter->data;
if (seat == meta_wayland_pointer_constraint_get_seat (constraint))
return constraint;
}
return NULL;
}
void void
meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface, meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface,
float abs_x, float abs_x,
@ -2483,6 +2539,27 @@ meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface,
*sy /= surface->scale; *sy /= surface->scale;
} }
void
meta_wayland_surface_get_absolute_coordinates (MetaWaylandSurface *surface,
float sx,
float sy,
float *x,
float *y)
{
ClutterActor *actor =
CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor));
ClutterVertex sv = {
.x = sx * surface->scale,
.y = sy * surface->scale,
};
ClutterVertex v = { 0 };
clutter_actor_apply_relative_transform_to_point (actor, NULL, &sv, &v);
*x = v.x;
*y = v.y;
}
static void static void
meta_wayland_surface_init (MetaWaylandSurface *surface) meta_wayland_surface_init (MetaWaylandSurface *surface)
{ {

View File

@ -31,6 +31,7 @@
#include "meta-wayland-types.h" #include "meta-wayland-types.h"
#include "meta-surface-actor.h" #include "meta-surface-actor.h"
#include "backends/meta-monitor-manager-private.h" #include "backends/meta-monitor-manager-private.h"
#include "meta-wayland-pointer-constraints.h"
typedef struct _MetaWaylandPendingState MetaWaylandPendingState; typedef struct _MetaWaylandPendingState MetaWaylandPendingState;
@ -217,6 +218,8 @@ struct _MetaWaylandSurface
gboolean pending_pos; gboolean pending_pos;
GSList *pending_placement_ops; GSList *pending_placement_ops;
} sub; } sub;
GList *pointer_constraints;
}; };
void meta_wayland_shell_init (MetaWaylandCompositor *compositor); void meta_wayland_shell_init (MetaWaylandCompositor *compositor);
@ -261,12 +264,27 @@ void meta_wayland_surface_queue_pending_frame_callbacks (MetaWayl
void meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface *surface, void meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending); MetaWaylandPendingState *pending);
void meta_wayland_surface_add_pointer_constraint (MetaWaylandSurface *surface,
MetaWaylandPointerConstraint *constraint);
void meta_wayland_surface_remove_pointer_constraint (MetaWaylandSurface *surface,
MetaWaylandPointerConstraint *constraint);
MetaWaylandPointerConstraint *
meta_wayland_surface_get_pointer_constraint_for_seat (MetaWaylandSurface *surface,
MetaWaylandSeat *seat);
void meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface, void meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface,
float abs_x, float abs_x,
float abs_y, float abs_y,
float *sx, float *sx,
float *sy); float *sy);
void meta_wayland_surface_get_absolute_coordinates (MetaWaylandSurface *surface,
float sx,
float sy,
float *x,
float *y);
MetaWaylandSurface * meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role); MetaWaylandSurface * meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role);
#endif #endif

View File

@ -329,6 +329,7 @@ meta_wayland_init (void)
meta_wayland_pointer_gestures_init (compositor); meta_wayland_pointer_gestures_init (compositor);
meta_wayland_seat_init (compositor); meta_wayland_seat_init (compositor);
meta_wayland_relative_pointer_init (compositor); meta_wayland_relative_pointer_init (compositor);
meta_wayland_pointer_constraints_init (compositor);
if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display)) if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
g_error ("Failed to start X Wayland"); g_error ("Failed to start X Wayland");

View File

@ -30,6 +30,7 @@
#include "window-private.h" #include "window-private.h"
#include "boxes-private.h" #include "boxes-private.h"
#include "stack-tracker.h" #include "stack-tracker.h"
#include "meta-wayland-private.h"
#include "meta-wayland-surface.h" #include "meta-wayland-surface.h"
#include "compositor/meta-surface-actor-wayland.h" #include "compositor/meta-surface-actor-wayland.h"
@ -402,6 +403,11 @@ appears_focused_changed (GObject *object,
gpointer user_data) gpointer user_data)
{ {
MetaWindow *window = META_WINDOW (object); MetaWindow *window = META_WINDOW (object);
MetaWaylandCompositor *wayland_compositor;
wayland_compositor = meta_wayland_compositor_get_default ();
meta_wayland_pointer_constraint_maybe_remove_for_seat (wayland_compositor->seat,
window);
/* When we're unmanaging, we remove focus from the window, /* When we're unmanaging, we remove focus from the window,
* causing this to fire. Don't do anything in that case. */ * causing this to fire. Don't do anything in that case. */
@ -409,6 +415,8 @@ appears_focused_changed (GObject *object,
return; return;
surface_state_changed (window); surface_state_changed (window);
meta_wayland_pointer_constraint_maybe_enable_for_window (window);
} }
static void static void