Compare commits
29 Commits
3.19.4
...
wip/primar
Author | SHA1 | Date | |
---|---|---|---|
![]() |
297d11b323 | ||
![]() |
3f60a2e48a | ||
![]() |
3729e592a6 | ||
![]() |
56beedf9f2 | ||
![]() |
bed82427c6 | ||
![]() |
e097bc8353 | ||
![]() |
4e82a751fb | ||
![]() |
acd50508dc | ||
![]() |
9611661154 | ||
![]() |
a70a2c3744 | ||
![]() |
bc47b19c3f | ||
![]() |
bc1dd1cee4 | ||
![]() |
495c89401a | ||
![]() |
e2efc85b08 | ||
![]() |
020ae58fe4 | ||
![]() |
525644059d | ||
![]() |
f0f638d2bd | ||
![]() |
bc8ec2d90d | ||
![]() |
5b0eabec51 | ||
![]() |
50099c4c10 | ||
![]() |
55eef2deb3 | ||
![]() |
f9db65f47f | ||
![]() |
a809055470 | ||
![]() |
247909e161 | ||
![]() |
e5ce6192f4 | ||
![]() |
7adbb58736 | ||
![]() |
0165cb6974 | ||
![]() |
3cdcd3e9c1 | ||
![]() |
6fc51e3723 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -68,6 +68,10 @@ src/xdg-shell-unstable-v*-protocol.c
|
||||
src/xdg-shell-unstable-v*-server-protocol.h
|
||||
src/pointer-gestures-unstable-v*-protocol.c
|
||||
src/pointer-gestures-unstable-v*-server-protocol.h
|
||||
src/relative-pointer-unstable-v*-protocol.c
|
||||
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
|
||||
doc/reference/*.args
|
||||
doc/reference/*.bak
|
||||
|
@@ -59,7 +59,7 @@ CANBERRA_GTK_VERSION=0.26
|
||||
CLUTTER_PACKAGE=clutter-1.0
|
||||
|
||||
MUTTER_PC_MODULES="
|
||||
gtk+-3.0 >= 3.19.7
|
||||
gtk+-3.0 >= 3.19.8
|
||||
gio-unix-2.0 >= 2.35.1
|
||||
pango >= 1.2.0
|
||||
cairo >= 1.10.0
|
||||
@@ -221,7 +221,7 @@ AS_IF([test "$have_wayland" = "yes"], [
|
||||
AC_SUBST([WAYLAND_SCANNER])
|
||||
AC_DEFINE([HAVE_WAYLAND],[1],[Define if you want to enable Wayland support])
|
||||
|
||||
PKG_CHECK_MODULES(WAYLAND_PROTOCOLS, [wayland-protocols >= 1.0],
|
||||
PKG_CHECK_MODULES(WAYLAND_PROTOCOLS, [wayland-protocols >= 1.1],
|
||||
[ac_wayland_protocols_pkgdatadir=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`])
|
||||
AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, $ac_wayland_protocols_pkgdatadir)
|
||||
])
|
||||
|
@@ -45,12 +45,18 @@ mutter_built_sources = \
|
||||
|
||||
if HAVE_WAYLAND
|
||||
mutter_built_sources += \
|
||||
primary-selection-unstable-v1-protocol.c \
|
||||
primary-selection-unstable-v1-server-protocol.h \
|
||||
pointer-gestures-unstable-v1-protocol.c \
|
||||
pointer-gestures-unstable-v1-server-protocol.h \
|
||||
gtk-shell-protocol.c \
|
||||
gtk-shell-server-protocol.h \
|
||||
xdg-shell-unstable-v5-protocol.c \
|
||||
xdg-shell-unstable-v5-server-protocol.h \
|
||||
relative-pointer-unstable-v1-protocol.c \
|
||||
relative-pointer-unstable-v1-server-protocol.h \
|
||||
pointer-constraints-unstable-v1-protocol.c \
|
||||
pointer-constraints-unstable-v1-server-protocol.h \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
@@ -84,6 +90,8 @@ libmutter_la_SOURCES = \
|
||||
backends/meta-monitor-manager-private.h \
|
||||
backends/meta-monitor-manager-dummy.c \
|
||||
backends/meta-monitor-manager-dummy.h \
|
||||
backends/meta-pointer-constraint.c \
|
||||
backends/meta-pointer-constraint.h \
|
||||
backends/meta-stage.h \
|
||||
backends/meta-stage.c \
|
||||
backends/edid-parse.c \
|
||||
@@ -110,6 +118,8 @@ libmutter_la_SOURCES = \
|
||||
core/boxes.c \
|
||||
core/boxes-private.h \
|
||||
meta/boxes.h \
|
||||
core/meta-border.c \
|
||||
core/meta-border.h \
|
||||
compositor/clutter-utils.c \
|
||||
compositor/clutter-utils.h \
|
||||
compositor/cogl-utils.c \
|
||||
@@ -190,6 +200,8 @@ libmutter_la_SOURCES = \
|
||||
core/screen.c \
|
||||
core/screen-private.h \
|
||||
meta/screen.h \
|
||||
core/startup-notification.c \
|
||||
core/startup-notification-private.h \
|
||||
meta/types.h \
|
||||
core/restart.c \
|
||||
core/stack.c \
|
||||
@@ -264,6 +276,12 @@ libmutter_la_SOURCES += \
|
||||
wayland/meta-wayland-keyboard.h \
|
||||
wayland/meta-wayland-pointer.c \
|
||||
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.h \
|
||||
wayland/meta-wayland-seat.c \
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include "meta-cursor-renderer.h"
|
||||
#include "meta-monitor-manager-private.h"
|
||||
#include "backends/meta-pointer-constraint.h"
|
||||
|
||||
#define DEFAULT_XKB_RULES_FILE "evdev"
|
||||
#define DEFAULT_XKB_MODEL "pc105+inet"
|
||||
@@ -51,6 +52,8 @@ struct _MetaBackend
|
||||
|
||||
GHashTable *device_monitors;
|
||||
gint current_device_id;
|
||||
|
||||
MetaPointerConstraint *client_pointer_constraint;
|
||||
};
|
||||
|
||||
struct _MetaBackendClass
|
||||
@@ -87,6 +90,13 @@ struct _MetaBackendClass
|
||||
|
||||
void (* update_screen_size) (MetaBackend *backend, int width, int height);
|
||||
void (* select_stage_events) (MetaBackend *backend);
|
||||
|
||||
gboolean (* get_relative_motion_deltas) (MetaBackend *backend,
|
||||
const ClutterEvent *event,
|
||||
double *dx,
|
||||
double *dy,
|
||||
double *dx_unaccel,
|
||||
double *dy_unaccel);
|
||||
};
|
||||
|
||||
MetaIdleMonitor * meta_backend_get_idle_monitor (MetaBackend *backend,
|
||||
@@ -110,4 +120,14 @@ struct xkb_keymap * meta_backend_get_keymap (MetaBackend *backend);
|
||||
void meta_backend_update_last_device (MetaBackend *backend,
|
||||
int device_id);
|
||||
|
||||
gboolean meta_backend_get_relative_motion_deltas (MetaBackend *backend,
|
||||
const ClutterEvent *event,
|
||||
double *dx,
|
||||
double *dy,
|
||||
double *dx_unaccel,
|
||||
double *dy_unaccel);
|
||||
|
||||
void meta_backend_set_client_pointer_constraint (MetaBackend *backend,
|
||||
MetaPointerConstraint *constraint);
|
||||
|
||||
#endif /* META_BACKEND_PRIVATE_H */
|
||||
|
@@ -353,6 +353,17 @@ meta_backend_real_select_stage_events (MetaBackend *backend)
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_backend_real_get_relative_motion_deltas (MetaBackend *backend,
|
||||
const ClutterEvent *event,
|
||||
double *dx,
|
||||
double *dy,
|
||||
double *dx_unaccel,
|
||||
double *dy_unaccel)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_class_init (MetaBackendClass *klass)
|
||||
{
|
||||
@@ -366,6 +377,7 @@ meta_backend_class_init (MetaBackendClass *klass)
|
||||
klass->ungrab_device = meta_backend_real_ungrab_device;
|
||||
klass->update_screen_size = meta_backend_real_update_screen_size;
|
||||
klass->select_stage_events = meta_backend_real_select_stage_events;
|
||||
klass->get_relative_motion_deltas = meta_backend_real_get_relative_motion_deltas;
|
||||
|
||||
g_signal_new ("keymap-changed",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
@@ -544,6 +556,32 @@ meta_backend_update_last_device (MetaBackend *backend,
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_backend_get_relative_motion_deltas (MetaBackend *backend,
|
||||
const ClutterEvent *event,
|
||||
double *dx,
|
||||
double *dy,
|
||||
double *dx_unaccel,
|
||||
double *dy_unaccel)
|
||||
{
|
||||
MetaBackendClass *klass = META_BACKEND_GET_CLASS (backend);
|
||||
return klass->get_relative_motion_deltas (backend,
|
||||
event,
|
||||
dx, dy,
|
||||
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
|
||||
get_backend_type (void)
|
||||
{
|
||||
|
@@ -26,6 +26,8 @@
|
||||
#ifndef META_BARRIER_PRIVATE_H
|
||||
#define META_BARRIER_PRIVATE_H
|
||||
|
||||
#include "core/meta-border.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_BARRIER_IMPL (meta_barrier_impl_get_type ())
|
||||
@@ -67,14 +69,7 @@ G_END_DECLS
|
||||
struct _MetaBarrierPrivate
|
||||
{
|
||||
MetaDisplay *display;
|
||||
|
||||
int x1;
|
||||
int y1;
|
||||
int x2;
|
||||
int y2;
|
||||
|
||||
MetaBarrierDirection directions;
|
||||
|
||||
MetaBorder border;
|
||||
MetaBarrierImpl *impl;
|
||||
};
|
||||
|
||||
|
@@ -61,19 +61,20 @@ meta_barrier_get_property (GObject *object,
|
||||
g_value_set_object (value, priv->display);
|
||||
break;
|
||||
case PROP_X1:
|
||||
g_value_set_int (value, priv->x1);
|
||||
g_value_set_int (value, priv->border.line.a.x);
|
||||
break;
|
||||
case PROP_Y1:
|
||||
g_value_set_int (value, priv->y1);
|
||||
g_value_set_int (value, priv->border.line.a.y);
|
||||
break;
|
||||
case PROP_X2:
|
||||
g_value_set_int (value, priv->x2);
|
||||
g_value_set_int (value, priv->border.line.b.x);
|
||||
break;
|
||||
case PROP_Y2:
|
||||
g_value_set_int (value, priv->y2);
|
||||
g_value_set_int (value, priv->border.line.b.y);
|
||||
break;
|
||||
case PROP_DIRECTIONS:
|
||||
g_value_set_flags (value, priv->directions);
|
||||
g_value_set_flags (value,
|
||||
meta_border_get_allows_directions (&priv->border));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
@@ -95,19 +96,20 @@ meta_barrier_set_property (GObject *object,
|
||||
priv->display = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_X1:
|
||||
priv->x1 = g_value_get_int (value);
|
||||
priv->border.line.a.x = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_Y1:
|
||||
priv->y1 = g_value_get_int (value);
|
||||
priv->border.line.a.y = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_X2:
|
||||
priv->x2 = g_value_get_int (value);
|
||||
priv->border.line.b.x = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_Y2:
|
||||
priv->y2 = g_value_get_int (value);
|
||||
priv->border.line.b.y = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_DIRECTIONS:
|
||||
priv->directions = g_value_get_flags (value);
|
||||
meta_border_set_allows_directions (&priv->border,
|
||||
g_value_get_flags (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
@@ -166,7 +168,8 @@ meta_barrier_constructed (GObject *object)
|
||||
MetaBarrier *barrier = META_BARRIER (object);
|
||||
MetaBarrierPrivate *priv = barrier->priv;
|
||||
|
||||
g_return_if_fail (priv->x1 == priv->x2 || priv->y1 == priv->y2);
|
||||
g_return_if_fail (priv->border.line.a.x == priv->border.line.b.x ||
|
||||
priv->border.line.a.y == priv->border.line.b.y);
|
||||
|
||||
#if defined(HAVE_NATIVE_BACKEND)
|
||||
if (META_IS_BACKEND_NATIVE (meta_get_backend ()))
|
||||
|
57
src/backends/meta-pointer-constraint.c
Normal file
57
src/backends/meta-pointer-constraint.c
Normal 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);
|
||||
}
|
60
src/backends/meta-pointer-constraint.h
Normal file
60
src/backends/meta-pointer-constraint.h
Normal 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 */
|
@@ -36,6 +36,8 @@
|
||||
#include "meta-monitor-manager-kms.h"
|
||||
#include "meta-cursor-renderer-native.h"
|
||||
#include "meta-launcher.h"
|
||||
#include "backends/meta-cursor-tracker-private.h"
|
||||
#include "backends/meta-pointer-constraint.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -139,6 +141,24 @@ constrain_to_barriers (ClutterInputDevice *device,
|
||||
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.
|
||||
* (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder)
|
||||
@@ -193,10 +213,12 @@ constrain_all_screen_monitors (ClutterInputDevice *device,
|
||||
|
||||
static void
|
||||
pointer_constrain_callback (ClutterInputDevice *device,
|
||||
guint32 time,
|
||||
float *new_x,
|
||||
float *new_y,
|
||||
gpointer user_data)
|
||||
guint32 time,
|
||||
float prev_x,
|
||||
float prev_y,
|
||||
float *new_x,
|
||||
float *new_y,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaMonitorManager *monitor_manager;
|
||||
MetaMonitorInfo *monitors;
|
||||
@@ -205,6 +227,9 @@ pointer_constrain_callback (ClutterInputDevice *device,
|
||||
/* Constrain to barriers */
|
||||
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 ();
|
||||
monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors);
|
||||
|
||||
@@ -255,11 +280,16 @@ meta_backend_native_warp_pointer (MetaBackend *backend,
|
||||
{
|
||||
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
|
||||
ClutterInputDevice *device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
|
||||
MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (NULL);
|
||||
|
||||
/* XXX */
|
||||
guint32 time_ = 0;
|
||||
|
||||
/* Warp the input device pointer state. */
|
||||
clutter_evdev_warp_pointer (device, time_, x, y);
|
||||
|
||||
/* Warp displayed pointer cursor. */
|
||||
meta_cursor_tracker_update_position (tracker, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -306,6 +336,19 @@ meta_backend_native_lock_layout_group (MetaBackend *backend,
|
||||
g_signal_emit_by_name (backend, "keymap-layout-group-changed", idx, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_backend_native_get_relative_motion_deltas (MetaBackend *backend,
|
||||
const ClutterEvent *event,
|
||||
double *dx,
|
||||
double *dy,
|
||||
double *dx_unaccel,
|
||||
double *dy_unaccel)
|
||||
{
|
||||
return clutter_evdev_event_get_relative_motion (event,
|
||||
dx, dy,
|
||||
dx_unaccel, dy_unaccel);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_native_class_init (MetaBackendNativeClass *klass)
|
||||
{
|
||||
@@ -323,6 +366,7 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
|
||||
backend_class->set_keymap = meta_backend_native_set_keymap;
|
||||
backend_class->get_keymap = meta_backend_native_get_keymap;
|
||||
backend_class->lock_layout_group = meta_backend_native_lock_layout_group;
|
||||
backend_class->get_relative_motion_deltas = meta_backend_native_get_relative_motion_deltas;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -93,126 +93,18 @@ next_serial (void)
|
||||
return barrier_serial;
|
||||
}
|
||||
|
||||
typedef struct _Vector2
|
||||
{
|
||||
float x, y;
|
||||
} Vector2;
|
||||
|
||||
static float
|
||||
vector2_cross_product (Vector2 a, Vector2 b)
|
||||
{
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
static Vector2
|
||||
vector2_add (Vector2 a, Vector2 b)
|
||||
{
|
||||
return (Vector2) {
|
||||
.x = a.x + b.x,
|
||||
.y = a.y + b.y,
|
||||
};
|
||||
}
|
||||
|
||||
static Vector2
|
||||
vector2_subtract (Vector2 a, Vector2 b)
|
||||
{
|
||||
return (Vector2) {
|
||||
.x = a.x - b.x,
|
||||
.y = a.y - b.y,
|
||||
};
|
||||
}
|
||||
|
||||
static Vector2
|
||||
vector2_multiply_constant (float c, Vector2 a)
|
||||
{
|
||||
return (Vector2) {
|
||||
.x = c * a.x,
|
||||
.y = c * a.y,
|
||||
};
|
||||
}
|
||||
|
||||
typedef struct _Line2
|
||||
{
|
||||
Vector2 a;
|
||||
Vector2 b;
|
||||
} Line2;
|
||||
|
||||
static gboolean
|
||||
lines_intersect (Line2 *line1, Line2 *line2, Vector2 *intersection)
|
||||
{
|
||||
Vector2 p = line1->a;
|
||||
Vector2 r = vector2_subtract (line1->b, line1->a);
|
||||
Vector2 q = line2->a;
|
||||
Vector2 s = vector2_subtract (line2->b, line2->a);
|
||||
float rxs;
|
||||
float sxr;
|
||||
float t;
|
||||
float u;
|
||||
|
||||
/*
|
||||
* The line (p, r) and (q, s) intersects where
|
||||
*
|
||||
* p + t r = q + u s
|
||||
*
|
||||
* Calculate t:
|
||||
*
|
||||
* (p + t r) × s = (q + u s) × s
|
||||
* p × s + t (r × s) = q × s + u (s × s)
|
||||
* p × s + t (r × s) = q × s
|
||||
* t (r × s) = q × s - p × s
|
||||
* t (r × s) = (q - p) × s
|
||||
* t = ((q - p) × s) / (r × s)
|
||||
*
|
||||
* Using the same method, for u we get:
|
||||
*
|
||||
* u = ((p - q) × r) / (s × r)
|
||||
*/
|
||||
|
||||
rxs = vector2_cross_product (r, s);
|
||||
sxr = vector2_cross_product (s, r);
|
||||
|
||||
/* If r × s = 0 then the lines are either parallel or collinear. */
|
||||
if (fabs ( rxs) < DBL_MIN)
|
||||
return FALSE;
|
||||
|
||||
t = vector2_cross_product (vector2_subtract (q, p), s) / rxs;
|
||||
u = vector2_cross_product (vector2_subtract (p, q), r) / sxr;
|
||||
|
||||
|
||||
/* The lines only intersect if 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1. */
|
||||
if (t < 0.0 || t > 1.0 || u < 0.0 || u > 1.0)
|
||||
return FALSE;
|
||||
|
||||
*intersection = vector2_add (p, vector2_multiply_constant (t, r));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_barrier_horizontal (MetaBarrier *barrier)
|
||||
{
|
||||
return barrier->priv->y1 == barrier->priv->y2;
|
||||
return meta_border_is_horizontal (&barrier->priv->border);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_barrier_blocking_directions (MetaBarrier *barrier,
|
||||
MetaBarrierDirection directions)
|
||||
{
|
||||
/* Barriers doesn't block parallel motions. */
|
||||
if (is_barrier_horizontal (barrier))
|
||||
{
|
||||
if ((directions & (META_BARRIER_DIRECTION_POSITIVE_Y |
|
||||
META_BARRIER_DIRECTION_NEGATIVE_Y)) == 0)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((directions & (META_BARRIER_DIRECTION_POSITIVE_X |
|
||||
META_BARRIER_DIRECTION_NEGATIVE_X)) == 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (barrier->priv->directions & directions) != directions;
|
||||
return meta_border_is_blocking_directions (&barrier->priv->border,
|
||||
directions);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -224,31 +116,16 @@ dismiss_pointer (MetaBarrierImplNative *self)
|
||||
priv->state = META_BARRIER_STATE_LEFT;
|
||||
}
|
||||
|
||||
static Line2
|
||||
barrier_to_line (MetaBarrier *barrier)
|
||||
{
|
||||
return (Line2) {
|
||||
.a = (Vector2) {
|
||||
.x = MIN (barrier->priv->x1, barrier->priv->x2),
|
||||
.y = MIN (barrier->priv->y1, barrier->priv->y2),
|
||||
},
|
||||
.b = (Vector2) {
|
||||
.x = MAX (barrier->priv->x1, barrier->priv->x2),
|
||||
.y = MAX (barrier->priv->y1, barrier->priv->y2),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the hit box for a held motion. The hit box is a 2 px wide region
|
||||
* in the opposite direction of every direction the barrier blocks. The purpose
|
||||
* of this is to allow small movements without receiving a "left" signal. This
|
||||
* heuristic comes from the X.org pointer barrier implementation.
|
||||
*/
|
||||
static Line2
|
||||
static MetaLine2
|
||||
calculate_barrier_hit_box (MetaBarrier *barrier)
|
||||
{
|
||||
Line2 hit_box = barrier_to_line (barrier);
|
||||
MetaLine2 hit_box = barrier->priv->border.line;
|
||||
|
||||
if (is_barrier_horizontal (barrier))
|
||||
{
|
||||
@@ -273,7 +150,8 @@ calculate_barrier_hit_box (MetaBarrier *barrier)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_within_box (Line2 box, Vector2 point)
|
||||
is_within_box (MetaLine2 box,
|
||||
MetaVector2 point)
|
||||
{
|
||||
return (point.x >= box.a.x && point.x < box.b.x &&
|
||||
point.y >= box.a.y && point.y < box.b.y);
|
||||
@@ -288,8 +166,8 @@ maybe_release_barrier (gpointer key,
|
||||
MetaBarrierImplNativePrivate *priv =
|
||||
meta_barrier_impl_native_get_instance_private (self);
|
||||
MetaBarrier *barrier = priv->barrier;
|
||||
Line2 *motion = user_data;
|
||||
Line2 hit_box;
|
||||
MetaLine2 *motion = user_data;
|
||||
MetaLine2 hit_box;
|
||||
|
||||
if (priv->state != META_BARRIER_STATE_HELD)
|
||||
return;
|
||||
@@ -297,8 +175,10 @@ maybe_release_barrier (gpointer key,
|
||||
/* Release if we end up outside barrier end points. */
|
||||
if (is_barrier_horizontal (barrier))
|
||||
{
|
||||
if (motion->b.x > MAX (barrier->priv->x1, barrier->priv->x2) ||
|
||||
motion->b.x < MIN (barrier->priv->x1, barrier->priv->x2))
|
||||
if (motion->b.x > MAX (barrier->priv->border.line.a.x,
|
||||
barrier->priv->border.line.b.x) ||
|
||||
motion->b.x < MIN (barrier->priv->border.line.a.x,
|
||||
barrier->priv->border.line.b.x))
|
||||
{
|
||||
dismiss_pointer (self);
|
||||
return;
|
||||
@@ -306,8 +186,10 @@ maybe_release_barrier (gpointer key,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (motion->b.y > MAX (barrier->priv->y1, barrier->priv->y2) ||
|
||||
motion->b.y < MIN (barrier->priv->y1, barrier->priv->y2))
|
||||
if (motion->b.y > MAX (barrier->priv->border.line.a.y,
|
||||
barrier->priv->border.line.b.y) ||
|
||||
motion->b.y < MIN (barrier->priv->border.line.a.y,
|
||||
barrier->priv->border.line.b.y))
|
||||
{
|
||||
dismiss_pointer (self);
|
||||
return;
|
||||
@@ -330,7 +212,7 @@ maybe_release_barriers (MetaBarrierManagerNative *manager,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
Line2 motion = {
|
||||
MetaLine2 motion = {
|
||||
.a = {
|
||||
.x = prev_x,
|
||||
.y = prev_y,
|
||||
@@ -350,7 +232,7 @@ typedef struct _MetaClosestBarrierData
|
||||
{
|
||||
struct
|
||||
{
|
||||
Line2 motion;
|
||||
MetaLine2 motion;
|
||||
MetaBarrierDirection directions;
|
||||
} in;
|
||||
|
||||
@@ -371,8 +253,7 @@ update_closest_barrier (gpointer key,
|
||||
meta_barrier_impl_native_get_instance_private (self);
|
||||
MetaBarrier *barrier = priv->barrier;
|
||||
MetaClosestBarrierData *data = user_data;
|
||||
Line2 barrier_line;
|
||||
Vector2 intersection;
|
||||
MetaVector2 intersection;
|
||||
float dx, dy;
|
||||
float distance_2;
|
||||
|
||||
@@ -391,17 +272,9 @@ update_closest_barrier (gpointer key,
|
||||
|
||||
/* Check if the motion intersects with the barrier, and retrieve the
|
||||
* intersection point if any. */
|
||||
barrier_line = (Line2) {
|
||||
.a = {
|
||||
.x = barrier->priv->x1,
|
||||
.y = barrier->priv->y1
|
||||
},
|
||||
.b = {
|
||||
.x = barrier->priv->x2,
|
||||
.y = barrier->priv->y2
|
||||
},
|
||||
};
|
||||
if (!lines_intersect (&barrier_line, &data->in.motion, &intersection))
|
||||
if (!meta_line2_intersects_with (&barrier->priv->border.line,
|
||||
&data->in.motion,
|
||||
&intersection))
|
||||
return;
|
||||
|
||||
/* Calculate the distance to the barrier and keep track of the closest
|
||||
@@ -570,9 +443,9 @@ clamp_to_barrier (MetaBarrierImplNative *self,
|
||||
if (is_barrier_horizontal (barrier))
|
||||
{
|
||||
if (*motion_dir & META_BARRIER_DIRECTION_POSITIVE_Y)
|
||||
*y = barrier->priv->y1;
|
||||
*y = barrier->priv->border.line.a.y;
|
||||
else if (*motion_dir & META_BARRIER_DIRECTION_NEGATIVE_Y)
|
||||
*y = barrier->priv->y1;
|
||||
*y = barrier->priv->border.line.a.y;
|
||||
|
||||
priv->blocked_dir = *motion_dir & (META_BARRIER_DIRECTION_POSITIVE_Y |
|
||||
META_BARRIER_DIRECTION_NEGATIVE_Y);
|
||||
@@ -582,9 +455,9 @@ clamp_to_barrier (MetaBarrierImplNative *self,
|
||||
else
|
||||
{
|
||||
if (*motion_dir & META_BARRIER_DIRECTION_POSITIVE_X)
|
||||
*x = barrier->priv->x1;
|
||||
*x = barrier->priv->border.line.a.x;
|
||||
else if (*motion_dir & META_BARRIER_DIRECTION_NEGATIVE_X)
|
||||
*x = barrier->priv->x1;
|
||||
*x = barrier->priv->border.line.a.x;
|
||||
|
||||
priv->blocked_dir = *motion_dir & (META_BARRIER_DIRECTION_POSITIVE_X |
|
||||
META_BARRIER_DIRECTION_NEGATIVE_X);
|
||||
|
@@ -102,9 +102,6 @@ meta_cursor_renderer_native_finalize (GObject *object)
|
||||
if (priv->animation_timeout_id)
|
||||
g_source_remove (priv->animation_timeout_id);
|
||||
|
||||
if (priv->gbm)
|
||||
gbm_device_destroy (priv->gbm);
|
||||
|
||||
G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -672,7 +669,7 @@ meta_cursor_renderer_native_init (MetaCursorRendererNative *native)
|
||||
{
|
||||
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx));
|
||||
priv->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
|
||||
priv->gbm = gbm_create_device (priv->drm_fd);
|
||||
priv->gbm = cogl_kms_renderer_get_gbm (cogl_renderer);
|
||||
|
||||
uint64_t width, height;
|
||||
if (drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
|
||||
|
@@ -46,6 +46,12 @@
|
||||
#include "meta-cursor-renderer-native.h"
|
||||
#include "meta-idle-monitor-native.h"
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevEnumerator, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(Login1Session, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(Login1Seat, g_object_unref)
|
||||
|
||||
struct _MetaLauncher
|
||||
{
|
||||
Login1Session *session_proxy;
|
||||
@@ -58,8 +64,8 @@ static Login1Session *
|
||||
get_session_proxy (GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
char *proxy_path;
|
||||
char *session_id;
|
||||
g_autofree char *proxy_path = NULL;
|
||||
g_autofree char *session_id = NULL;
|
||||
Login1Session *session_proxy;
|
||||
|
||||
if (sd_pid_get_session (getpid (), &session_id) < 0)
|
||||
@@ -81,8 +87,6 @@ get_session_proxy (GCancellable *cancellable,
|
||||
if (!session_proxy)
|
||||
g_prefix_error(error, "Could not get session proxy: ");
|
||||
|
||||
free (proxy_path);
|
||||
|
||||
return session_proxy;
|
||||
}
|
||||
|
||||
@@ -285,8 +289,8 @@ get_primary_gpu_path (const gchar *seat_name)
|
||||
gchar *path = NULL;
|
||||
GList *devices, *tmp;
|
||||
|
||||
GUdevClient *gudev_client = g_udev_client_new (subsystems);
|
||||
GUdevEnumerator *enumerator = g_udev_enumerator_new (gudev_client);
|
||||
g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems);
|
||||
g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client);
|
||||
|
||||
g_udev_enumerator_add_match_name (enumerator, "card*");
|
||||
g_udev_enumerator_add_match_tag (enumerator, "seat");
|
||||
@@ -297,7 +301,8 @@ get_primary_gpu_path (const gchar *seat_name)
|
||||
|
||||
for (tmp = devices; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
GUdevDevice *platform_device = NULL, *pci_device = NULL;
|
||||
g_autoptr (GUdevDevice) platform_device = NULL;
|
||||
g_autoptr (GUdevDevice) pci_device = NULL;
|
||||
GUdevDevice *dev = tmp->data;
|
||||
gint boot_vga;
|
||||
const gchar *device_seat;
|
||||
@@ -328,7 +333,6 @@ get_primary_gpu_path (const gchar *seat_name)
|
||||
if (platform_device != NULL)
|
||||
{
|
||||
path = g_strdup (g_udev_device_get_device_file (dev));
|
||||
g_object_unref (platform_device);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -343,17 +347,12 @@ get_primary_gpu_path (const gchar *seat_name)
|
||||
path = g_strdup (g_udev_device_get_device_file (dev));
|
||||
break;
|
||||
}
|
||||
|
||||
g_object_unref (pci_device);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free_full (devices, g_object_unref);
|
||||
|
||||
out:
|
||||
g_object_unref (enumerator);
|
||||
g_object_unref (gudev_client);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -399,7 +398,8 @@ get_kms_fd (Login1Session *session_proxy,
|
||||
static gchar *
|
||||
get_seat_id (GError **error)
|
||||
{
|
||||
char *session_id, *seat_id;
|
||||
g_autofree char *session_id = NULL;
|
||||
char *seat_id = NULL;
|
||||
int r;
|
||||
|
||||
r = sd_pid_get_session (0, &session_id);
|
||||
@@ -413,8 +413,6 @@ get_seat_id (GError **error)
|
||||
}
|
||||
|
||||
r = sd_session_get_seat (session_id, &seat_id);
|
||||
free (session_id);
|
||||
|
||||
if (r < 0)
|
||||
{
|
||||
g_set_error (error,
|
||||
@@ -431,9 +429,9 @@ MetaLauncher *
|
||||
meta_launcher_new (GError **error)
|
||||
{
|
||||
MetaLauncher *self = NULL;
|
||||
Login1Session *session_proxy = NULL;
|
||||
Login1Seat *seat_proxy = NULL;
|
||||
char *seat_id = NULL;
|
||||
g_autoptr (Login1Session) session_proxy = NULL;
|
||||
g_autoptr (Login1Seat) seat_proxy = NULL;
|
||||
g_autofree char *seat_id = NULL;
|
||||
gboolean have_control = FALSE;
|
||||
int kms_fd;
|
||||
|
||||
@@ -460,11 +458,9 @@ meta_launcher_new (GError **error)
|
||||
if (!get_kms_fd (session_proxy, seat_id, &kms_fd, error))
|
||||
goto fail;
|
||||
|
||||
free (seat_id);
|
||||
|
||||
self = g_slice_new0 (MetaLauncher);
|
||||
self->session_proxy = session_proxy;
|
||||
self->seat_proxy = seat_proxy;
|
||||
self->session_proxy = g_object_ref (session_proxy);
|
||||
self->seat_proxy = g_object_ref (seat_proxy);
|
||||
|
||||
self->session_active = TRUE;
|
||||
|
||||
@@ -479,10 +475,6 @@ meta_launcher_new (GError **error)
|
||||
fail:
|
||||
if (have_control)
|
||||
login1_session_call_release_control_sync (session_proxy, NULL, NULL);
|
||||
g_clear_object (&session_proxy);
|
||||
g_clear_object (&seat_proxy);
|
||||
free (seat_id);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -107,6 +107,7 @@ meta_barrier_impl_x11_new (MetaBarrier *barrier)
|
||||
MetaDisplay *display = barrier->priv->display;
|
||||
Display *dpy;
|
||||
Window root;
|
||||
unsigned int allowed_motion_dirs;
|
||||
|
||||
if (display == NULL)
|
||||
{
|
||||
@@ -121,12 +122,14 @@ meta_barrier_impl_x11_new (MetaBarrier *barrier)
|
||||
dpy = display->xdisplay;
|
||||
root = DefaultRootWindow (dpy);
|
||||
|
||||
allowed_motion_dirs =
|
||||
meta_border_get_allows_directions (&barrier->priv->border);
|
||||
priv->xbarrier = XFixesCreatePointerBarrier (dpy, root,
|
||||
barrier->priv->x1,
|
||||
barrier->priv->y1,
|
||||
barrier->priv->x2,
|
||||
barrier->priv->y2,
|
||||
barrier->priv->directions,
|
||||
barrier->priv->border.line.a.x,
|
||||
barrier->priv->border.line.a.y,
|
||||
barrier->priv->border.line.b.x,
|
||||
barrier->priv->border.line.b.y,
|
||||
allowed_motion_dirs,
|
||||
0, NULL);
|
||||
|
||||
g_hash_table_insert (display->xids, &priv->xbarrier, barrier);
|
||||
|
@@ -36,6 +36,14 @@
|
||||
|
||||
#include "compositor/region-utils.h"
|
||||
|
||||
enum {
|
||||
PAINTING,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
struct _MetaSurfaceActorWaylandPrivate
|
||||
{
|
||||
MetaWaylandSurface *surface;
|
||||
@@ -347,12 +355,13 @@ meta_surface_actor_wayland_paint (ClutterActor *actor)
|
||||
if (priv->surface)
|
||||
{
|
||||
MetaWaylandCompositor *compositor = priv->surface->compositor;
|
||||
meta_wayland_surface_update_outputs (priv->surface);
|
||||
|
||||
wl_list_insert_list (&compositor->frame_callbacks, &priv->frame_callback_list);
|
||||
wl_list_init (&priv->frame_callback_list);
|
||||
}
|
||||
|
||||
g_signal_emit (actor, signals[PAINTING], 0);
|
||||
|
||||
CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class)->paint (actor);
|
||||
}
|
||||
|
||||
@@ -388,6 +397,13 @@ meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
|
||||
surface_actor_class->get_window = meta_surface_actor_wayland_get_window;
|
||||
|
||||
object_class->dispose = meta_surface_actor_wayland_dispose;
|
||||
|
||||
signals[PAINTING] = g_signal_new ("painting",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include <meta/boxes.h>
|
||||
#include <meta/display.h>
|
||||
#include "keybindings-private.h"
|
||||
#include "startup-notification-private.h"
|
||||
#include "meta-gesture-tracker-private.h"
|
||||
#include <meta/prefs.h>
|
||||
#include <meta/barrier.h>
|
||||
@@ -276,9 +277,8 @@ struct _MetaDisplay
|
||||
int xinput_event_base;
|
||||
int xinput_opcode;
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
SnDisplay *sn_display;
|
||||
#endif
|
||||
MetaStartupNotification *startup_notification;
|
||||
|
||||
int xsync_event_base;
|
||||
int xsync_error_base;
|
||||
int shape_event_base;
|
||||
|
@@ -400,28 +400,6 @@ meta_display_remove_pending_pings_for_window (MetaDisplay *display,
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
static void
|
||||
sn_error_trap_push (SnDisplay *sn_display,
|
||||
Display *xdisplay)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
if (display != NULL)
|
||||
meta_error_trap_push (display);
|
||||
}
|
||||
|
||||
static void
|
||||
sn_error_trap_pop (SnDisplay *sn_display,
|
||||
Display *xdisplay)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
if (display != NULL)
|
||||
meta_error_trap_pop (display);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
enable_compositor (MetaDisplay *display)
|
||||
{
|
||||
@@ -527,6 +505,20 @@ gesture_tracker_state_changed (MetaGestureTracker *tracker,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_startup_notification_changed (MetaStartupNotification *sn,
|
||||
gpointer sequence,
|
||||
MetaDisplay *display)
|
||||
{
|
||||
if (!display->screen)
|
||||
return;
|
||||
|
||||
g_slist_free (display->screen->startup_sequences);
|
||||
display->screen->startup_sequences =
|
||||
meta_startup_notification_get_sequences (display->startup_notification);
|
||||
g_signal_emit_by_name (display->screen, "startup-sequence-changed", sequence);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_display_open:
|
||||
*
|
||||
@@ -630,12 +622,6 @@ meta_display_open (void)
|
||||
|
||||
display->screen = NULL;
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
display->sn_display = sn_display_new (display->xdisplay,
|
||||
sn_error_trap_push,
|
||||
sn_error_trap_pop);
|
||||
#endif
|
||||
|
||||
/* Get events */
|
||||
meta_display_init_events (display);
|
||||
meta_display_init_events_x11 (display);
|
||||
@@ -916,6 +902,10 @@ meta_display_open (void)
|
||||
|
||||
display->screen = screen;
|
||||
|
||||
display->startup_notification = meta_startup_notification_get (display);
|
||||
g_signal_connect (display->startup_notification, "changed",
|
||||
G_CALLBACK (on_startup_notification_changed), display);
|
||||
|
||||
meta_screen_init_workspaces (screen);
|
||||
|
||||
enable_compositor (display);
|
||||
@@ -1100,6 +1090,7 @@ meta_display_close (MetaDisplay *display,
|
||||
|
||||
meta_display_remove_autoraise_callback (display);
|
||||
|
||||
g_clear_object (&display->startup_notification);
|
||||
g_clear_object (&display->gesture_tracker);
|
||||
|
||||
if (display->focus_timeout_id)
|
||||
@@ -1112,14 +1103,6 @@ meta_display_close (MetaDisplay *display,
|
||||
|
||||
meta_screen_free (display->screen, timestamp);
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
if (display->sn_display)
|
||||
{
|
||||
sn_display_unref (display->sn_display);
|
||||
display->sn_display = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Must be after all calls to meta_window_unmanage() since they
|
||||
* unregister windows
|
||||
*/
|
||||
|
154
src/core/meta-border.c
Normal file
154
src/core/meta-border.c
Normal file
@@ -0,0 +1,154 @@
|
||||
/* -*- 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 "core/meta-border.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
static inline float
|
||||
meta_vector2_cross_product (const MetaVector2 a,
|
||||
const MetaVector2 b)
|
||||
{
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
static inline MetaVector2
|
||||
meta_vector2_add (const MetaVector2 a,
|
||||
const MetaVector2 b)
|
||||
{
|
||||
return (MetaVector2) {
|
||||
.x = a.x + b.x,
|
||||
.y = a.y + b.y,
|
||||
};
|
||||
}
|
||||
|
||||
static inline MetaVector2
|
||||
meta_vector2_multiply_constant (const float c,
|
||||
const MetaVector2 a)
|
||||
{
|
||||
return (MetaVector2) {
|
||||
.x = c * a.x,
|
||||
.y = c * a.y,
|
||||
};
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_line2_intersects_with (const MetaLine2 *line1,
|
||||
const MetaLine2 *line2,
|
||||
MetaVector2 *intersection)
|
||||
{
|
||||
MetaVector2 p = line1->a;
|
||||
MetaVector2 r = meta_vector2_subtract (line1->b, line1->a);
|
||||
MetaVector2 q = line2->a;
|
||||
MetaVector2 s = meta_vector2_subtract (line2->b, line2->a);
|
||||
float rxs;
|
||||
float sxr;
|
||||
float t;
|
||||
float u;
|
||||
|
||||
/*
|
||||
* The line (p, r) and (q, s) intersects where
|
||||
*
|
||||
* p + t r = q + u s
|
||||
*
|
||||
* Calculate t:
|
||||
*
|
||||
* (p + t r) × s = (q + u s) × s
|
||||
* p × s + t (r × s) = q × s + u (s × s)
|
||||
* p × s + t (r × s) = q × s
|
||||
* t (r × s) = q × s - p × s
|
||||
* t (r × s) = (q - p) × s
|
||||
* t = ((q - p) × s) / (r × s)
|
||||
*
|
||||
* Using the same method, for u we get:
|
||||
*
|
||||
* u = ((p - q) × r) / (s × r)
|
||||
*/
|
||||
|
||||
rxs = meta_vector2_cross_product (r, s);
|
||||
sxr = meta_vector2_cross_product (s, r);
|
||||
|
||||
/* If r × s = 0 then the lines are either parallel or collinear. */
|
||||
if (fabsf (rxs) < FLT_MIN)
|
||||
return FALSE;
|
||||
|
||||
t = meta_vector2_cross_product (meta_vector2_subtract (q, p), s) / rxs;
|
||||
u = meta_vector2_cross_product (meta_vector2_subtract (p, q), r) / sxr;
|
||||
|
||||
/* The lines only intersect if 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1. */
|
||||
if (t < 0.0 || t > 1.0 || u < 0.0 || u > 1.0)
|
||||
return FALSE;
|
||||
|
||||
*intersection = meta_vector2_add (p, meta_vector2_multiply_constant (t, r));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_border_is_horizontal (MetaBorder *border)
|
||||
{
|
||||
return border->line.a.y == border->line.b.y;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_border_is_blocking_directions (MetaBorder *border,
|
||||
MetaBorderMotionDirection directions)
|
||||
{
|
||||
if (meta_border_is_horizontal (border))
|
||||
{
|
||||
if ((directions & (META_BORDER_MOTION_DIRECTION_POSITIVE_Y |
|
||||
META_BORDER_MOTION_DIRECTION_NEGATIVE_Y)) == 0)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((directions & (META_BORDER_MOTION_DIRECTION_POSITIVE_X |
|
||||
META_BORDER_MOTION_DIRECTION_NEGATIVE_X)) == 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (~border->blocking_directions & directions) != directions;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
meta_border_get_allows_directions (MetaBorder *border)
|
||||
{
|
||||
return ~border->blocking_directions &
|
||||
(META_BORDER_MOTION_DIRECTION_POSITIVE_X |
|
||||
META_BORDER_MOTION_DIRECTION_POSITIVE_Y |
|
||||
META_BORDER_MOTION_DIRECTION_NEGATIVE_X |
|
||||
META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
|
||||
}
|
||||
|
||||
void
|
||||
meta_border_set_allows_directions (MetaBorder *border, unsigned int directions)
|
||||
{
|
||||
border->blocking_directions =
|
||||
~directions & (META_BORDER_MOTION_DIRECTION_POSITIVE_X |
|
||||
META_BORDER_MOTION_DIRECTION_POSITIVE_Y |
|
||||
META_BORDER_MOTION_DIRECTION_NEGATIVE_X |
|
||||
META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
|
||||
}
|
84
src/core/meta-border.h
Normal file
84
src/core/meta-border.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* -*- 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_BORDER_H
|
||||
#define META_BORDER_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_BORDER_MOTION_DIRECTION_POSITIVE_X = 1 << 0,
|
||||
META_BORDER_MOTION_DIRECTION_POSITIVE_Y = 1 << 1,
|
||||
META_BORDER_MOTION_DIRECTION_NEGATIVE_X = 1 << 2,
|
||||
META_BORDER_MOTION_DIRECTION_NEGATIVE_Y = 1 << 3,
|
||||
} MetaBorderMotionDirection;
|
||||
|
||||
typedef struct _MetaVector2
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
} MetaVector2;
|
||||
|
||||
typedef struct _MetaLine2
|
||||
{
|
||||
MetaVector2 a;
|
||||
MetaVector2 b;
|
||||
} MetaLine2;
|
||||
|
||||
typedef struct _MetaBorder
|
||||
{
|
||||
MetaLine2 line;
|
||||
MetaBorderMotionDirection blocking_directions;
|
||||
} MetaBorder;
|
||||
|
||||
static inline MetaVector2
|
||||
meta_vector2_subtract (const MetaVector2 a,
|
||||
const MetaVector2 b)
|
||||
{
|
||||
return (MetaVector2) {
|
||||
.x = a.x - b.x,
|
||||
.y = a.y - b.y,
|
||||
};
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_line2_intersects_with (const MetaLine2 *line1,
|
||||
const MetaLine2 *line2,
|
||||
MetaVector2 *intersection);
|
||||
|
||||
gboolean
|
||||
meta_border_is_horizontal (MetaBorder *border);
|
||||
|
||||
gboolean
|
||||
meta_border_is_blocking_directions (MetaBorder *border,
|
||||
MetaBorderMotionDirection directions);
|
||||
|
||||
unsigned int
|
||||
meta_border_get_allows_directions (MetaBorder *border);
|
||||
|
||||
void
|
||||
meta_border_set_allows_directions (MetaBorder *border, unsigned int directions);
|
||||
|
||||
#endif /* META_BORDER_H */
|
@@ -85,11 +85,7 @@ struct _MetaScreen
|
||||
/* Cache the current monitor */
|
||||
int last_monitor_index;
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
SnMonitorContext *sn_context;
|
||||
GSList *startup_sequences;
|
||||
guint startup_sequence_timeout;
|
||||
#endif
|
||||
|
||||
Window wm_cm_selection_window;
|
||||
guint work_area_later;
|
||||
|
@@ -71,11 +71,6 @@ static void prefs_changed_callback (MetaPreference pref,
|
||||
static void set_desktop_geometry_hint (MetaScreen *screen);
|
||||
static void set_desktop_viewport_hint (MetaScreen *screen);
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
static void meta_screen_sn_event (SnMonitorEvent *event,
|
||||
void *user_data);
|
||||
#endif
|
||||
|
||||
static void on_monitors_changed (MetaMonitorManager *manager,
|
||||
MetaScreen *screen);
|
||||
|
||||
@@ -730,17 +725,6 @@ meta_screen_new (MetaDisplay *display,
|
||||
|
||||
meta_prefs_add_listener (prefs_changed_callback, screen);
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
screen->sn_context =
|
||||
sn_monitor_context_new (screen->display->sn_display,
|
||||
screen->number,
|
||||
meta_screen_sn_event,
|
||||
screen,
|
||||
NULL);
|
||||
screen->startup_sequences = NULL;
|
||||
screen->startup_sequence_timeout = 0;
|
||||
#endif
|
||||
|
||||
meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
|
||||
screen->number, screen->screen_name, screen->xroot);
|
||||
|
||||
@@ -800,24 +784,6 @@ meta_screen_free (MetaScreen *screen,
|
||||
|
||||
meta_screen_ungrab_keys (screen);
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
g_slist_foreach (screen->startup_sequences,
|
||||
(GFunc) sn_startup_sequence_unref, NULL);
|
||||
g_slist_free (screen->startup_sequences);
|
||||
screen->startup_sequences = NULL;
|
||||
|
||||
if (screen->startup_sequence_timeout != 0)
|
||||
{
|
||||
g_source_remove (screen->startup_sequence_timeout);
|
||||
screen->startup_sequence_timeout = 0;
|
||||
}
|
||||
if (screen->sn_context)
|
||||
{
|
||||
sn_monitor_context_unref (screen->sn_context);
|
||||
screen->sn_context = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
meta_ui_free (screen->ui);
|
||||
|
||||
meta_stack_free (screen->stack);
|
||||
@@ -2538,208 +2504,6 @@ meta_screen_unshow_desktop (MetaScreen *screen)
|
||||
meta_screen_update_showing_desktop_hint (screen);
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
static gboolean startup_sequence_timeout (void *data);
|
||||
|
||||
static void
|
||||
update_startup_feedback (MetaScreen *screen)
|
||||
{
|
||||
if (screen->startup_sequences != NULL)
|
||||
{
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Setting busy cursor\n");
|
||||
meta_screen_set_cursor (screen, META_CURSOR_BUSY);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Setting default cursor\n");
|
||||
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_sequence (MetaScreen *screen,
|
||||
SnStartupSequence *sequence)
|
||||
{
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Adding sequence %s\n",
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
sn_startup_sequence_ref (sequence);
|
||||
screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
|
||||
sequence);
|
||||
|
||||
/* our timeout just polls every second, instead of bothering
|
||||
* to compute exactly when we may next time out
|
||||
*/
|
||||
if (screen->startup_sequence_timeout == 0)
|
||||
{
|
||||
screen->startup_sequence_timeout = g_timeout_add_seconds (1,
|
||||
startup_sequence_timeout,
|
||||
screen);
|
||||
g_source_set_name_by_id (screen->startup_sequence_timeout,
|
||||
"[mutter] startup_sequence_timeout");
|
||||
}
|
||||
|
||||
update_startup_feedback (screen);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_sequence (MetaScreen *screen,
|
||||
SnStartupSequence *sequence)
|
||||
{
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Removing sequence %s\n",
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
|
||||
screen->startup_sequences = g_slist_remove (screen->startup_sequences,
|
||||
sequence);
|
||||
|
||||
if (screen->startup_sequences == NULL &&
|
||||
screen->startup_sequence_timeout != 0)
|
||||
{
|
||||
g_source_remove (screen->startup_sequence_timeout);
|
||||
screen->startup_sequence_timeout = 0;
|
||||
}
|
||||
|
||||
update_startup_feedback (screen);
|
||||
|
||||
sn_startup_sequence_unref (sequence);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSList *list;
|
||||
GTimeVal now;
|
||||
} CollectTimedOutData;
|
||||
|
||||
/* This should be fairly long, as it should never be required unless
|
||||
* apps or .desktop files are buggy, and it's confusing if
|
||||
* OpenOffice or whatever seems to stop launching - people
|
||||
* might decide they need to launch it again.
|
||||
*/
|
||||
#define STARTUP_TIMEOUT 15000
|
||||
|
||||
static void
|
||||
collect_timed_out_foreach (void *element,
|
||||
void *data)
|
||||
{
|
||||
CollectTimedOutData *ctod = data;
|
||||
SnStartupSequence *sequence = element;
|
||||
long tv_sec, tv_usec;
|
||||
double elapsed;
|
||||
|
||||
sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
|
||||
|
||||
elapsed =
|
||||
((((double)ctod->now.tv_sec - tv_sec) * G_USEC_PER_SEC +
|
||||
(ctod->now.tv_usec - tv_usec))) / 1000.0;
|
||||
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Sequence used %g seconds vs. %g max: %s\n",
|
||||
elapsed, (double) STARTUP_TIMEOUT,
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
|
||||
if (elapsed > STARTUP_TIMEOUT)
|
||||
ctod->list = g_slist_prepend (ctod->list, sequence);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
startup_sequence_timeout (void *data)
|
||||
{
|
||||
MetaScreen *screen = data;
|
||||
CollectTimedOutData ctod;
|
||||
GSList *l;
|
||||
|
||||
ctod.list = NULL;
|
||||
g_get_current_time (&ctod.now);
|
||||
g_slist_foreach (screen->startup_sequences,
|
||||
collect_timed_out_foreach,
|
||||
&ctod);
|
||||
|
||||
for (l = ctod.list; l != NULL; l = l->next)
|
||||
{
|
||||
SnStartupSequence *sequence = l->data;
|
||||
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Timed out sequence %s\n",
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
|
||||
sn_startup_sequence_complete (sequence);
|
||||
}
|
||||
|
||||
g_slist_free (ctod.list);
|
||||
|
||||
if (screen->startup_sequences != NULL)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* remove */
|
||||
screen->startup_sequence_timeout = 0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_sn_event (SnMonitorEvent *event,
|
||||
void *user_data)
|
||||
{
|
||||
MetaScreen *screen;
|
||||
SnStartupSequence *sequence;
|
||||
|
||||
screen = user_data;
|
||||
|
||||
sequence = sn_monitor_event_get_startup_sequence (event);
|
||||
|
||||
sn_startup_sequence_ref (sequence);
|
||||
|
||||
switch (sn_monitor_event_get_type (event))
|
||||
{
|
||||
case SN_MONITOR_EVENT_INITIATED:
|
||||
{
|
||||
const char *wmclass;
|
||||
|
||||
wmclass = sn_startup_sequence_get_wmclass (sequence);
|
||||
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Received startup initiated for %s wmclass %s\n",
|
||||
sn_startup_sequence_get_id (sequence),
|
||||
wmclass ? wmclass : "(unset)");
|
||||
add_sequence (screen, sequence);
|
||||
}
|
||||
break;
|
||||
|
||||
case SN_MONITOR_EVENT_COMPLETED:
|
||||
{
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Received startup completed for %s\n",
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
remove_sequence (screen,
|
||||
sn_monitor_event_get_startup_sequence (event));
|
||||
}
|
||||
break;
|
||||
|
||||
case SN_MONITOR_EVENT_CHANGED:
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Received startup changed for %s\n",
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
break;
|
||||
|
||||
case SN_MONITOR_EVENT_CANCELED:
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Received startup canceled for %s\n",
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
break;
|
||||
}
|
||||
|
||||
g_signal_emit (G_OBJECT (screen), screen_signals[STARTUP_SEQUENCE_CHANGED], 0, sequence);
|
||||
|
||||
sn_startup_sequence_unref (sequence);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_screen_get_startup_sequences: (skip)
|
||||
* @screen:
|
||||
@@ -2751,7 +2515,6 @@ meta_screen_get_startup_sequences (MetaScreen *screen)
|
||||
{
|
||||
return screen->startup_sequences;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sets the initial_timestamp and initial_workspace properties
|
||||
* of a window according to information given us by the
|
||||
|
48
src/core/startup-notification-private.h
Normal file
48
src/core/startup-notification-private.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001, 2002 Havoc Pennington
|
||||
* Copyright (C) 2002, 2003 Red Hat Inc.
|
||||
* Some ICCCM manager selection code derived from fvwm2,
|
||||
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
|
||||
* Copyright (C) 2003 Rob Adams
|
||||
* Copyright (C) 2004-2006 Elijah Newren
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef META_STARTUP_NOTIFICATION_PRIVATE_H
|
||||
#define META_STARTUP_NOTIFICATION_PRIVATE_H
|
||||
|
||||
#include "display-private.h"
|
||||
|
||||
#define META_TYPE_STARTUP_NOTIFICATION (meta_startup_notification_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (MetaStartupNotification,
|
||||
meta_startup_notification,
|
||||
META, STARTUP_NOTIFICATION,
|
||||
GObject)
|
||||
|
||||
MetaStartupNotification *
|
||||
meta_startup_notification_get (MetaDisplay *display);
|
||||
|
||||
gboolean meta_startup_notification_handle_xevent (MetaStartupNotification *sn,
|
||||
XEvent *xevent);
|
||||
|
||||
void meta_startup_notification_remove_sequence (MetaStartupNotification *sn,
|
||||
const gchar *id);
|
||||
|
||||
GSList * meta_startup_notification_get_sequences (MetaStartupNotification *sn);
|
||||
|
||||
#endif /* META_STARTUP_NOTIFICATION_PRIVATE_H */
|
767
src/core/startup-notification.c
Normal file
767
src/core/startup-notification.c
Normal file
@@ -0,0 +1,767 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001, 2002 Havoc Pennington
|
||||
* Copyright (C) 2002, 2003 Red Hat Inc.
|
||||
* Some ICCCM manager selection code derived from fvwm2,
|
||||
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
|
||||
* Copyright (C) 2003 Rob Adams
|
||||
* Copyright (C) 2004-2006 Elijah Newren
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <meta/errors.h>
|
||||
#include "display-private.h"
|
||||
#include "screen-private.h"
|
||||
#include "startup-notification-private.h"
|
||||
|
||||
/* This should be fairly long, as it should never be required unless
|
||||
* apps or .desktop files are buggy, and it's confusing if
|
||||
* OpenOffice or whatever seems to stop launching - people
|
||||
* might decide they need to launch it again.
|
||||
*/
|
||||
#define STARTUP_TIMEOUT 15000000
|
||||
|
||||
typedef struct _MetaStartupNotificationSequence MetaStartupNotificationSequence;
|
||||
typedef struct _MetaStartupNotificationSequenceClass MetaStartupNotificationSequenceClass;
|
||||
|
||||
enum {
|
||||
PROP_SN_0,
|
||||
PROP_SN_DISPLAY,
|
||||
N_SN_PROPS
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_SEQ_0,
|
||||
PROP_SEQ_ID,
|
||||
PROP_SEQ_TIMESTAMP,
|
||||
N_SEQ_PROPS
|
||||
};
|
||||
|
||||
enum {
|
||||
SN_CHANGED,
|
||||
N_SN_SIGNALS
|
||||
};
|
||||
|
||||
static guint sn_signals[N_SN_SIGNALS];
|
||||
static GParamSpec *sn_props[N_SN_PROPS];
|
||||
static GParamSpec *seq_props[N_SEQ_PROPS];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSList *list;
|
||||
gint64 now;
|
||||
} CollectTimedOutData;
|
||||
|
||||
struct _MetaStartupNotification
|
||||
{
|
||||
GObject parent_instance;
|
||||
MetaDisplay *display;
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
SnDisplay *sn_display;
|
||||
SnMonitorContext *sn_context;
|
||||
#endif
|
||||
|
||||
GSList *startup_sequences;
|
||||
guint startup_sequence_timeout;
|
||||
};
|
||||
|
||||
#define META_TYPE_STARTUP_NOTIFICATION_SEQUENCE \
|
||||
(meta_startup_notification_sequence_get_type ())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (MetaStartupNotificationSequence,
|
||||
meta_startup_notification_sequence,
|
||||
META, STARTUP_NOTIFICATION_SEQUENCE,
|
||||
GObject)
|
||||
|
||||
typedef struct {
|
||||
gchar *id;
|
||||
time_t timestamp;
|
||||
} MetaStartupNotificationSequencePrivate;
|
||||
|
||||
struct _MetaStartupNotificationSequenceClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* complete) (MetaStartupNotificationSequence *sequence);
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaStartupNotification,
|
||||
meta_startup_notification,
|
||||
G_TYPE_OBJECT)
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaStartupNotificationSequence,
|
||||
meta_startup_notification_sequence,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
|
||||
enum {
|
||||
PROP_SEQ_X11_0,
|
||||
PROP_SEQ_X11_SEQ,
|
||||
N_SEQ_X11_PROPS
|
||||
};
|
||||
|
||||
struct _MetaStartupNotificationSequenceX11 {
|
||||
MetaStartupNotificationSequence parent_instance;
|
||||
SnStartupSequence *seq;
|
||||
};
|
||||
|
||||
static GParamSpec *seq_x11_props[N_SEQ_X11_PROPS];
|
||||
|
||||
#define META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11 \
|
||||
(meta_startup_notification_sequence_x11_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (MetaStartupNotificationSequenceX11,
|
||||
meta_startup_notification_sequence_x11,
|
||||
META, STARTUP_NOTIFICATION_SEQUENCE_X11,
|
||||
MetaStartupNotificationSequence)
|
||||
|
||||
G_DEFINE_TYPE (MetaStartupNotificationSequenceX11,
|
||||
meta_startup_notification_sequence_x11,
|
||||
META_TYPE_STARTUP_NOTIFICATION_SEQUENCE)
|
||||
|
||||
static void meta_startup_notification_ensure_timeout (MetaStartupNotification *sn);
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
meta_startup_notification_update_feedback (MetaStartupNotification *sn)
|
||||
{
|
||||
MetaScreen *screen = sn->display->screen;
|
||||
|
||||
if (sn->startup_sequences != NULL)
|
||||
{
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Setting busy cursor\n");
|
||||
meta_screen_set_cursor (screen, META_CURSOR_BUSY);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Setting default cursor\n");
|
||||
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_init (MetaStartupNotificationSequence *seq)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_finalize (GObject *object)
|
||||
{
|
||||
MetaStartupNotificationSequence *seq;
|
||||
MetaStartupNotificationSequencePrivate *priv;
|
||||
|
||||
seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
|
||||
priv = meta_startup_notification_sequence_get_instance_private (seq);
|
||||
g_free (priv->id);
|
||||
|
||||
G_OBJECT_CLASS (meta_startup_notification_sequence_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaStartupNotificationSequence *seq;
|
||||
MetaStartupNotificationSequencePrivate *priv;
|
||||
|
||||
seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
|
||||
priv = meta_startup_notification_sequence_get_instance_private (seq);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SEQ_ID:
|
||||
priv->id = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_SEQ_TIMESTAMP:
|
||||
priv->timestamp = g_value_get_int64 (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaStartupNotificationSequence *seq;
|
||||
MetaStartupNotificationSequencePrivate *priv;
|
||||
|
||||
seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
|
||||
priv = meta_startup_notification_sequence_get_instance_private (seq);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SEQ_ID:
|
||||
g_value_set_string (value, priv->id);
|
||||
break;
|
||||
case PROP_SEQ_TIMESTAMP:
|
||||
g_value_set_int64 (value, priv->timestamp);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_class_init (MetaStartupNotificationSequenceClass *klass)
|
||||
{
|
||||
GObjectClass *object_class;
|
||||
|
||||
object_class = G_OBJECT_CLASS (klass);
|
||||
object_class->finalize = meta_startup_notification_sequence_finalize;
|
||||
object_class->set_property = meta_startup_notification_sequence_set_property;
|
||||
object_class->get_property = meta_startup_notification_sequence_get_property;
|
||||
|
||||
seq_props[PROP_SEQ_ID] =
|
||||
g_param_spec_string ("id",
|
||||
"ID",
|
||||
"ID",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
seq_props[PROP_SEQ_TIMESTAMP] =
|
||||
g_param_spec_int64 ("timestamp",
|
||||
"Timestamp",
|
||||
"Timestamp",
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (object_class, N_SEQ_PROPS, seq_props);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
meta_startup_notification_sequence_get_id (MetaStartupNotificationSequence *seq)
|
||||
{
|
||||
MetaStartupNotificationSequencePrivate *priv;
|
||||
|
||||
priv = meta_startup_notification_sequence_get_instance_private (seq);
|
||||
return priv->id;
|
||||
}
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
static gint64
|
||||
meta_startup_notification_sequence_get_timestamp (MetaStartupNotificationSequence *seq)
|
||||
{
|
||||
MetaStartupNotificationSequencePrivate *priv;
|
||||
|
||||
priv = meta_startup_notification_sequence_get_instance_private (seq);
|
||||
return priv->timestamp;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_complete (MetaStartupNotificationSequence *seq)
|
||||
{
|
||||
MetaStartupNotificationSequenceClass *klass;
|
||||
|
||||
klass = META_STARTUP_NOTIFICATION_SEQUENCE_GET_CLASS (seq);
|
||||
|
||||
if (klass->complete)
|
||||
klass->complete (seq);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
static void
|
||||
meta_startup_notification_sequence_x11_complete (MetaStartupNotificationSequence *seq)
|
||||
{
|
||||
MetaStartupNotificationSequenceX11 *seq_x11;
|
||||
|
||||
seq_x11 = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (seq);
|
||||
sn_startup_sequence_complete (seq_x11->seq);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_x11_finalize (GObject *object)
|
||||
{
|
||||
MetaStartupNotificationSequenceX11 *seq;
|
||||
|
||||
seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
|
||||
sn_startup_sequence_unref (seq->seq);
|
||||
|
||||
G_OBJECT_CLASS (meta_startup_notification_sequence_x11_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_x11_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaStartupNotificationSequenceX11 *seq;
|
||||
|
||||
seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SEQ_X11_SEQ:
|
||||
seq->seq = g_value_get_pointer (value);
|
||||
sn_startup_sequence_ref (seq->seq);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_x11_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaStartupNotificationSequenceX11 *seq;
|
||||
|
||||
seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SEQ_X11_SEQ:
|
||||
g_value_set_pointer (value, seq->seq);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_x11_init (MetaStartupNotificationSequenceX11 *seq)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sequence_x11_class_init (MetaStartupNotificationSequenceX11Class *klass)
|
||||
{
|
||||
MetaStartupNotificationSequenceClass *seq_class;
|
||||
GObjectClass *object_class;
|
||||
|
||||
seq_class = META_STARTUP_NOTIFICATION_SEQUENCE_CLASS (klass);
|
||||
seq_class->complete = meta_startup_notification_sequence_x11_complete;
|
||||
|
||||
object_class = G_OBJECT_CLASS (klass);
|
||||
object_class->finalize = meta_startup_notification_sequence_x11_finalize;
|
||||
object_class->set_property = meta_startup_notification_sequence_x11_set_property;
|
||||
object_class->get_property = meta_startup_notification_sequence_x11_get_property;
|
||||
|
||||
seq_x11_props[PROP_SEQ_X11_SEQ] =
|
||||
g_param_spec_pointer ("seq",
|
||||
"Sequence",
|
||||
"Sequence",
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (object_class, N_SEQ_X11_PROPS,
|
||||
seq_x11_props);
|
||||
}
|
||||
|
||||
static MetaStartupNotificationSequence *
|
||||
meta_startup_notification_sequence_x11_new (SnStartupSequence *seq)
|
||||
{
|
||||
return g_object_new (META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11,
|
||||
"id", sn_startup_sequence_get_id (seq),
|
||||
"timestamp", sn_startup_sequence_get_timestamp (seq) * 1000,
|
||||
"seq", seq,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_add_sequence_internal (MetaStartupNotification *sn,
|
||||
MetaStartupNotificationSequence *seq)
|
||||
{
|
||||
sn->startup_sequences = g_slist_prepend (sn->startup_sequences,
|
||||
g_object_ref (seq));
|
||||
|
||||
meta_startup_notification_ensure_timeout (sn);
|
||||
meta_startup_notification_update_feedback (sn);
|
||||
}
|
||||
|
||||
static void
|
||||
collect_timed_out_foreach (void *element,
|
||||
void *data)
|
||||
{
|
||||
MetaStartupNotificationSequence *sequence = element;
|
||||
CollectTimedOutData *ctod = data;
|
||||
gint64 elapsed, timestamp;
|
||||
|
||||
timestamp = meta_startup_notification_sequence_get_timestamp (sequence);
|
||||
elapsed = ctod->now - timestamp;
|
||||
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Sequence used %ld ms vs. %d max: %s\n",
|
||||
elapsed, STARTUP_TIMEOUT,
|
||||
meta_startup_notification_sequence_get_id (sequence));
|
||||
|
||||
if (elapsed > STARTUP_TIMEOUT)
|
||||
ctod->list = g_slist_prepend (ctod->list, sequence);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
startup_sequence_timeout (void *data)
|
||||
{
|
||||
MetaStartupNotification *sn = data;
|
||||
CollectTimedOutData ctod;
|
||||
GSList *l;
|
||||
|
||||
ctod.list = NULL;
|
||||
ctod.now = g_get_monotonic_time ();
|
||||
g_slist_foreach (sn->startup_sequences,
|
||||
collect_timed_out_foreach,
|
||||
&ctod);
|
||||
|
||||
for (l = ctod.list; l != NULL; l = l->next)
|
||||
{
|
||||
MetaStartupNotificationSequence *sequence = l->data;
|
||||
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Timed out sequence %s\n",
|
||||
meta_startup_notification_sequence_get_id (sequence));
|
||||
|
||||
meta_startup_notification_sequence_complete (sequence);
|
||||
}
|
||||
|
||||
g_slist_free (ctod.list);
|
||||
|
||||
if (sn->startup_sequences != NULL)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* remove */
|
||||
sn->startup_sequence_timeout = 0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_ensure_timeout (MetaStartupNotification *sn)
|
||||
{
|
||||
if (sn->startup_sequence_timeout != 0)
|
||||
return;
|
||||
|
||||
/* our timeout just polls every second, instead of bothering
|
||||
* to compute exactly when we may next time out
|
||||
*/
|
||||
sn->startup_sequence_timeout = g_timeout_add_seconds (1,
|
||||
startup_sequence_timeout,
|
||||
sn);
|
||||
g_source_set_name_by_id (sn->startup_sequence_timeout,
|
||||
"[mutter] startup_sequence_timeout");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
meta_startup_notification_remove_sequence_internal (MetaStartupNotification *sn,
|
||||
MetaStartupNotificationSequence *seq)
|
||||
{
|
||||
sn->startup_sequences = g_slist_remove (sn->startup_sequences, seq);
|
||||
meta_startup_notification_update_feedback (sn);
|
||||
|
||||
if (sn->startup_sequences == NULL &&
|
||||
sn->startup_sequence_timeout != 0)
|
||||
{
|
||||
g_source_remove (sn->startup_sequence_timeout);
|
||||
sn->startup_sequence_timeout = 0;
|
||||
}
|
||||
|
||||
g_object_unref (seq);
|
||||
}
|
||||
|
||||
static MetaStartupNotificationSequence *
|
||||
meta_startup_notification_lookup_sequence (MetaStartupNotification *sn,
|
||||
const gchar *id)
|
||||
{
|
||||
MetaStartupNotificationSequence *seq;
|
||||
const gchar *seq_id;
|
||||
GSList *l;
|
||||
|
||||
for (l = sn->startup_sequences; l; l = l->next)
|
||||
{
|
||||
seq = l->data;
|
||||
seq_id = meta_startup_notification_sequence_get_id (seq);
|
||||
|
||||
if (g_str_equal (seq_id, id))
|
||||
return l->data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_init (MetaStartupNotification *sn)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_finalize (GObject *object)
|
||||
{
|
||||
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
sn_monitor_context_unref (sn->sn_context);
|
||||
sn_display_unref (sn->sn_display);
|
||||
#endif
|
||||
|
||||
if (sn->startup_sequence_timeout)
|
||||
g_source_remove (sn->startup_sequence_timeout);
|
||||
|
||||
g_slist_foreach (sn->startup_sequences, (GFunc) g_object_unref, NULL);
|
||||
g_slist_free (sn->startup_sequences);
|
||||
sn->startup_sequences = NULL;
|
||||
|
||||
G_OBJECT_CLASS (meta_startup_notification_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SN_DISPLAY:
|
||||
sn->display = g_value_get_object (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SN_DISPLAY:
|
||||
g_value_set_object (value, sn->display);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
static void
|
||||
sn_error_trap_push (SnDisplay *sn_display,
|
||||
Display *xdisplay)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
if (display != NULL)
|
||||
meta_error_trap_push (display);
|
||||
}
|
||||
|
||||
static void
|
||||
sn_error_trap_pop (SnDisplay *sn_display,
|
||||
Display *xdisplay)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
if (display != NULL)
|
||||
meta_error_trap_pop (display);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_sn_event (SnMonitorEvent *event,
|
||||
void *user_data)
|
||||
{
|
||||
MetaStartupNotification *sn = user_data;
|
||||
MetaStartupNotificationSequence *seq;
|
||||
SnStartupSequence *sequence;
|
||||
|
||||
sequence = sn_monitor_event_get_startup_sequence (event);
|
||||
|
||||
sn_startup_sequence_ref (sequence);
|
||||
|
||||
switch (sn_monitor_event_get_type (event))
|
||||
{
|
||||
case SN_MONITOR_EVENT_INITIATED:
|
||||
{
|
||||
const char *wmclass;
|
||||
|
||||
wmclass = sn_startup_sequence_get_wmclass (sequence);
|
||||
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Received startup initiated for %s wmclass %s\n",
|
||||
sn_startup_sequence_get_id (sequence),
|
||||
wmclass ? wmclass : "(unset)");
|
||||
|
||||
seq = meta_startup_notification_sequence_x11_new (sequence);
|
||||
meta_startup_notification_add_sequence_internal (sn, seq);
|
||||
g_object_unref (seq);
|
||||
}
|
||||
break;
|
||||
|
||||
case SN_MONITOR_EVENT_COMPLETED:
|
||||
{
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Received startup completed for %s\n",
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
|
||||
meta_startup_notification_remove_sequence (sn, sn_startup_sequence_get_id (sequence));
|
||||
}
|
||||
break;
|
||||
|
||||
case SN_MONITOR_EVENT_CHANGED:
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Received startup changed for %s\n",
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
break;
|
||||
|
||||
case SN_MONITOR_EVENT_CANCELED:
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Received startup canceled for %s\n",
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
break;
|
||||
}
|
||||
|
||||
g_signal_emit (sn, sn_signals[SN_CHANGED], 0, sequence);
|
||||
|
||||
sn_startup_sequence_unref (sequence);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
meta_startup_notification_constructed (GObject *object)
|
||||
{
|
||||
MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
|
||||
|
||||
g_assert (sn->display != NULL);
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
sn->sn_display = sn_display_new (sn->display->xdisplay,
|
||||
sn_error_trap_push,
|
||||
sn_error_trap_pop);
|
||||
sn->sn_context =
|
||||
sn_monitor_context_new (sn->sn_display,
|
||||
sn->display->screen->number,
|
||||
meta_startup_notification_sn_event,
|
||||
sn,
|
||||
NULL);
|
||||
#endif
|
||||
sn->startup_sequences = NULL;
|
||||
sn->startup_sequence_timeout = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_startup_notification_class_init (MetaStartupNotificationClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = meta_startup_notification_constructed;
|
||||
object_class->finalize = meta_startup_notification_finalize;
|
||||
object_class->set_property = meta_startup_notification_set_property;
|
||||
object_class->get_property = meta_startup_notification_get_property;
|
||||
|
||||
sn_props[PROP_SN_DISPLAY] =
|
||||
g_param_spec_object ("display",
|
||||
"Display",
|
||||
"Display",
|
||||
META_TYPE_DISPLAY,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
sn_signals[SN_CHANGED] =
|
||||
g_signal_new ("changed",
|
||||
META_TYPE_STARTUP_NOTIFICATION,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, G_TYPE_POINTER);
|
||||
|
||||
g_object_class_install_properties (object_class, N_SN_PROPS, sn_props);
|
||||
}
|
||||
|
||||
MetaStartupNotification *
|
||||
meta_startup_notification_get (MetaDisplay *display)
|
||||
{
|
||||
static MetaStartupNotification *notification = NULL;
|
||||
|
||||
if (!notification)
|
||||
notification = g_object_new (META_TYPE_STARTUP_NOTIFICATION,
|
||||
"display", display,
|
||||
NULL);
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
void
|
||||
meta_startup_notification_remove_sequence (MetaStartupNotification *sn,
|
||||
const gchar *id)
|
||||
{
|
||||
MetaStartupNotificationSequence *seq;
|
||||
|
||||
seq = meta_startup_notification_lookup_sequence (sn, id);
|
||||
if (seq)
|
||||
meta_startup_notification_remove_sequence_internal (sn, seq);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_startup_notification_handle_xevent (MetaStartupNotification *sn,
|
||||
XEvent *xevent)
|
||||
{
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
return sn_display_process_event (sn->sn_display, xevent);
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GSList *
|
||||
meta_startup_notification_get_sequences (MetaStartupNotification *sn)
|
||||
{
|
||||
GSList *sequences = NULL;
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
GSList *l;
|
||||
|
||||
/* We return a list of SnStartupSequences here */
|
||||
for (l = sn->startup_sequences; l; l = l->next)
|
||||
{
|
||||
MetaStartupNotificationSequenceX11 *seq_x11;
|
||||
|
||||
if (!META_IS_STARTUP_NOTIFICATION_SEQUENCE_X11 (l->data))
|
||||
continue;
|
||||
|
||||
seq_x11 = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (l->data);
|
||||
sequences = g_slist_prepend (sequences, seq_x11->seq);
|
||||
}
|
||||
#endif
|
||||
|
||||
return sequences;
|
||||
}
|
@@ -7388,10 +7388,31 @@ meta_window_set_gtk_dbus_properties (MetaWindow *window,
|
||||
g_object_thaw_notify (G_OBJECT (window));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_transient_for_loop (MetaWindow *window,
|
||||
MetaWindow *parent)
|
||||
{
|
||||
while (parent)
|
||||
{
|
||||
if (parent->transient_for == window)
|
||||
return TRUE;
|
||||
parent = parent->transient_for;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_set_transient_for (MetaWindow *window,
|
||||
MetaWindow *parent)
|
||||
{
|
||||
if (check_transient_for_loop (window, parent))
|
||||
{
|
||||
meta_warning ("Setting %s transient for %s would create a loop.\n",
|
||||
window->desc, parent->desc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (meta_window_appears_focused (window) && window->transient_for != NULL)
|
||||
meta_window_propagate_focus_appearance (window, FALSE);
|
||||
|
||||
|
@@ -447,7 +447,7 @@ meta_frames_new (int screen_number)
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_theme_variant_override (MetaFrames *frames)
|
||||
get_global_theme_variant (MetaFrames *frames)
|
||||
{
|
||||
GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (frames));
|
||||
GtkSettings *settings = gtk_settings_get_for_screen (screen);
|
||||
@@ -474,19 +474,15 @@ meta_ui_frame_attach_style (MetaUIFrame *frame)
|
||||
{
|
||||
MetaFrames *frames = frame->frames;
|
||||
const char *variant;
|
||||
const char *variant_override;
|
||||
|
||||
if (frame->style_info != NULL)
|
||||
meta_style_info_unref (frame->style_info);
|
||||
|
||||
variant_override = get_theme_variant_override (frame->frames);
|
||||
variant = frame->meta_window->gtk_theme_variant;
|
||||
if (variant == NULL)
|
||||
variant = get_global_theme_variant (frame->frames);;
|
||||
|
||||
if (variant_override)
|
||||
variant = variant_override;
|
||||
else
|
||||
variant = frame->meta_window->gtk_theme_variant;
|
||||
|
||||
if (variant == NULL || strcmp(variant, "normal") == 0)
|
||||
if (variant == NULL || *variant == '\0')
|
||||
frame->style_info = meta_style_info_ref (frames->normal_style);
|
||||
else
|
||||
frame->style_info = meta_style_info_ref (meta_frames_get_theme_variant (frames,
|
||||
@@ -1366,6 +1362,10 @@ meta_ui_frame_get_mask (MetaUIFrame *frame,
|
||||
borders.invisible.left / scale,
|
||||
borders.invisible.top / scale,
|
||||
frame_rect.width / scale, frame_rect.height / scale);
|
||||
gtk_render_background (frame->style_info->styles[META_STYLE_ELEMENT_TITLEBAR], cr,
|
||||
borders.invisible.left / scale,
|
||||
borders.invisible.top / scale,
|
||||
frame_rect.width / scale, borders.total.top / scale);
|
||||
}
|
||||
|
||||
/* XXX -- this is disgusting. Find a better approach here.
|
||||
|
@@ -53,6 +53,8 @@ typedef struct _MetaFrameGeometry MetaFrameGeometry;
|
||||
**/
|
||||
struct _MetaFrameLayout
|
||||
{
|
||||
/** Invisible border required by the theme */
|
||||
GtkBorder invisible_border;
|
||||
/** Border/padding of the entire frame */
|
||||
GtkBorder frame_border;
|
||||
/** Border/padding of the titlebar region */
|
||||
@@ -167,6 +169,7 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_STYLE_ELEMENT_WINDOW,
|
||||
META_STYLE_ELEMENT_FRAME,
|
||||
META_STYLE_ELEMENT_TITLEBAR,
|
||||
META_STYLE_ELEMENT_TITLE,
|
||||
|
@@ -94,23 +94,28 @@ meta_frame_layout_get_borders (const MetaFrameLayout *layout,
|
||||
borders->visible.right = layout->frame_border.right;
|
||||
borders->visible.bottom = layout->frame_border.bottom;
|
||||
|
||||
borders->invisible = layout->invisible_border;
|
||||
|
||||
draggable_borders = meta_prefs_get_draggable_border_width ();
|
||||
|
||||
if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
|
||||
{
|
||||
borders->invisible.left = MAX (0, draggable_borders - borders->visible.left);
|
||||
borders->invisible.right = MAX (0, draggable_borders - borders->visible.right);
|
||||
borders->invisible.left = MAX (borders->invisible.left,
|
||||
draggable_borders - borders->visible.left);
|
||||
borders->invisible.right = MAX (borders->invisible.right,
|
||||
draggable_borders - borders->visible.right);
|
||||
}
|
||||
|
||||
if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
|
||||
{
|
||||
borders->invisible.bottom = MAX (0, draggable_borders - borders->visible.bottom);
|
||||
borders->invisible.bottom = MAX (borders->invisible.bottom,
|
||||
draggable_borders - borders->visible.bottom);
|
||||
|
||||
/* borders.visible.top is the height of the *title bar*. We can't do the same
|
||||
* algorithm here, titlebars are expectedly much bigger. Just subtract a couple
|
||||
* pixels to get a proper feel. */
|
||||
if (type != META_FRAME_TYPE_ATTACHED)
|
||||
borders->invisible.top = MAX (0, draggable_borders - 2);
|
||||
borders->invisible.top = MAX (borders->invisible.top, draggable_borders - 2);
|
||||
}
|
||||
|
||||
borders->total.left = borders->invisible.left + borders->visible.left;
|
||||
@@ -266,6 +271,7 @@ meta_frame_layout_sync_with_style (MetaFrameLayout *layout,
|
||||
GtkStyleContext *style;
|
||||
GtkBorder border;
|
||||
GtkRequisition requisition;
|
||||
GdkRectangle clip_rect;
|
||||
int border_radius, max_radius;
|
||||
|
||||
meta_style_info_set_flags (style_info, flags);
|
||||
@@ -274,6 +280,12 @@ meta_frame_layout_sync_with_style (MetaFrameLayout *layout,
|
||||
get_padding_and_border (style, &layout->frame_border);
|
||||
scale_border (&layout->frame_border, layout->title_scale);
|
||||
|
||||
gtk_render_background_get_clip (style, 0, 0, 0, 0, &clip_rect);
|
||||
layout->invisible_border.left = -clip_rect.x;
|
||||
layout->invisible_border.right = clip_rect.width + clip_rect.x;
|
||||
layout->invisible_border.top = -clip_rect.y;
|
||||
layout->invisible_border.bottom = clip_rect.height + clip_rect.y;
|
||||
|
||||
if (layout->hide_buttons)
|
||||
layout->icon_size = 0;
|
||||
|
||||
@@ -1033,15 +1045,20 @@ meta_theme_create_style_info (GdkScreen *screen,
|
||||
style_info = g_new0 (MetaStyleInfo, 1);
|
||||
style_info->refcount = 1;
|
||||
|
||||
style_info->styles[META_STYLE_ELEMENT_FRAME] =
|
||||
style_info->styles[META_STYLE_ELEMENT_WINDOW] =
|
||||
create_style_context (META_TYPE_FRAMES,
|
||||
NULL,
|
||||
provider,
|
||||
"decoration",
|
||||
"window",
|
||||
GTK_STYLE_CLASS_BACKGROUND,
|
||||
"window-frame",
|
||||
"ssd",
|
||||
NULL);
|
||||
style_info->styles[META_STYLE_ELEMENT_FRAME] =
|
||||
create_style_context (META_TYPE_FRAMES,
|
||||
style_info->styles[META_STYLE_ELEMENT_WINDOW],
|
||||
provider,
|
||||
"decoration",
|
||||
NULL);
|
||||
style_info->styles[META_STYLE_ELEMENT_TITLEBAR] =
|
||||
create_style_context (GTK_TYPE_HEADER_BAR,
|
||||
style_info->styles[META_STYLE_ELEMENT_FRAME],
|
||||
|
707
src/wayland/meta-pointer-confinement-wayland.c
Normal file
707
src/wayland/meta-pointer-confinement-wayland.c
Normal file
@@ -0,0 +1,707 @@
|
||||
/* -*- 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 "core/meta-border.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;
|
||||
};
|
||||
|
||||
typedef struct _MetaBox
|
||||
{
|
||||
int x1;
|
||||
int y1;
|
||||
int x2;
|
||||
int y2;
|
||||
} MetaBox;
|
||||
|
||||
G_DEFINE_TYPE (MetaPointerConfinementWayland, meta_pointer_confinement_wayland,
|
||||
META_TYPE_POINTER_CONSTRAINT);
|
||||
|
||||
static MetaBorder *
|
||||
add_border (GArray *borders,
|
||||
float x1, float y1,
|
||||
float x2, float y2,
|
||||
MetaBorderMotionDirection blocking_directions)
|
||||
{
|
||||
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_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;
|
||||
ClutterPoint 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;
|
||||
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);
|
||||
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;
|
||||
}
|
45
src/wayland/meta-pointer-confinement-wayland.h
Normal file
45
src/wayland/meta-pointer-confinement-wayland.h
Normal 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 */
|
72
src/wayland/meta-pointer-lock-wayland.c
Normal file
72
src/wayland/meta-pointer-lock-wayland.c
Normal 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;
|
||||
}
|
42
src/wayland/meta-pointer-lock-wayland.h
Normal file
42
src/wayland/meta-pointer-lock-wayland.h
Normal 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 */
|
@@ -51,13 +51,32 @@ void
|
||||
meta_wayland_buffer_unref (MetaWaylandBuffer *buffer)
|
||||
{
|
||||
buffer->ref_count--;
|
||||
|
||||
if (buffer->ref_count == 0)
|
||||
{
|
||||
g_warn_if_fail (buffer->use_count == 0);
|
||||
|
||||
g_clear_pointer (&buffer->texture, cogl_object_unref);
|
||||
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_buffer_ref_use_count (MetaWaylandBuffer *buffer)
|
||||
{
|
||||
buffer->use_count++;
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_buffer_unref_use_count (MetaWaylandBuffer *buffer)
|
||||
{
|
||||
g_return_if_fail (buffer->use_count != 0);
|
||||
|
||||
buffer->use_count--;
|
||||
|
||||
if (buffer->use_count == 0)
|
||||
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
|
||||
}
|
||||
|
||||
MetaWaylandBuffer *
|
||||
meta_wayland_buffer_from_resource (struct wl_resource *resource)
|
||||
{
|
||||
@@ -93,6 +112,8 @@ meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer)
|
||||
CoglTexture *texture;
|
||||
struct wl_shm_buffer *shm_buffer;
|
||||
|
||||
g_return_val_if_fail (buffer->use_count != 0, NULL);
|
||||
|
||||
if (buffer->texture)
|
||||
goto out;
|
||||
|
||||
@@ -126,6 +147,8 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
|
||||
{
|
||||
struct wl_shm_buffer *shm_buffer;
|
||||
|
||||
g_return_if_fail (buffer->use_count != 0);
|
||||
|
||||
shm_buffer = wl_shm_buffer_get (buffer->resource);
|
||||
|
||||
if (shm_buffer)
|
||||
|
@@ -39,11 +39,14 @@ struct _MetaWaylandBuffer
|
||||
|
||||
CoglTexture *texture;
|
||||
uint32_t ref_count;
|
||||
uint32_t use_count;
|
||||
};
|
||||
|
||||
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
|
||||
void meta_wayland_buffer_ref (MetaWaylandBuffer *buffer);
|
||||
void meta_wayland_buffer_unref (MetaWaylandBuffer *buffer);
|
||||
void meta_wayland_buffer_ref_use_count (MetaWaylandBuffer *buffer);
|
||||
void meta_wayland_buffer_unref_use_count (MetaWaylandBuffer *buffer);
|
||||
CoglTexture * meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer);
|
||||
void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
|
||||
cairo_region_t *region);
|
||||
|
@@ -31,4 +31,10 @@ G_DECLARE_FINAL_TYPE (MetaWaylandDataSourceWayland,
|
||||
META, WAYLAND_DATA_SOURCE_WAYLAND,
|
||||
MetaWaylandDataSource);
|
||||
|
||||
#define META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY (meta_wayland_data_source_primary_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaWaylandDataSourcePrimary,
|
||||
meta_wayland_data_source_primary,
|
||||
META, WAYLAND_DATA_SOURCE_PRIMARY,
|
||||
MetaWaylandDataSourceWayland);
|
||||
|
||||
#endif /* META_WAYLAND_DATA_DEVICE_PRIVATE_H */
|
||||
|
@@ -37,6 +37,8 @@
|
||||
#include "meta-wayland-private.h"
|
||||
#include "meta-dnd-actor-private.h"
|
||||
|
||||
#include "primary-selection-unstable-v1-server-protocol.h"
|
||||
|
||||
#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
|
||||
@@ -70,13 +72,22 @@ typedef struct _MetaWaylandDataSourceWayland
|
||||
struct wl_resource *resource;
|
||||
} MetaWaylandDataSourceWayland;
|
||||
|
||||
typedef struct _MetaWaylandDataSourcePrimary
|
||||
{
|
||||
MetaWaylandDataSourceWayland parent;
|
||||
} MetaWaylandDataSourcePrimary;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandDataSource, meta_wayland_data_source,
|
||||
G_TYPE_OBJECT);
|
||||
G_DEFINE_TYPE (MetaWaylandDataSourceWayland, meta_wayland_data_source_wayland,
|
||||
META_TYPE_WAYLAND_DATA_SOURCE);
|
||||
G_DEFINE_TYPE (MetaWaylandDataSourcePrimary, meta_wayland_data_source_primary,
|
||||
META_TYPE_WAYLAND_DATA_SOURCE_WAYLAND);
|
||||
|
||||
static MetaWaylandDataSource *
|
||||
meta_wayland_data_source_wayland_new (struct wl_resource *resource);
|
||||
static MetaWaylandDataSource *
|
||||
meta_wayland_data_source_primary_new (struct wl_resource *resource);
|
||||
|
||||
static void
|
||||
drag_grab_data_source_destroyed (gpointer data, GObject *where_the_object_was);
|
||||
@@ -160,7 +171,8 @@ static void
|
||||
meta_wayland_data_source_target (MetaWaylandDataSource *source,
|
||||
const char *mime_type)
|
||||
{
|
||||
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target (source, mime_type);
|
||||
if (META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target)
|
||||
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target (source, mime_type);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -430,6 +442,32 @@ static const struct wl_data_offer_interface data_offer_interface = {
|
||||
data_offer_set_actions,
|
||||
};
|
||||
|
||||
static void
|
||||
primary_offer_receive (struct wl_client *client, struct wl_resource *resource,
|
||||
const char *mime_type, int32_t fd, uint32_t serial)
|
||||
{
|
||||
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
|
||||
MetaWaylandDataSource *source = offer->source;
|
||||
MetaWaylandSeat *seat;
|
||||
|
||||
if (!source)
|
||||
{
|
||||
close (fd);
|
||||
return;
|
||||
}
|
||||
|
||||
seat = meta_wayland_data_source_get_seat (source);
|
||||
|
||||
if (serial == seat->keyboard.key_serial ||
|
||||
serial == seat->pointer.click_serial)
|
||||
meta_wayland_data_source_send (source, mime_type, fd);
|
||||
}
|
||||
|
||||
static const struct zwp_primary_selection_offer_v1_interface primary_offer_interface = {
|
||||
primary_offer_receive,
|
||||
data_offer_destroy,
|
||||
};
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source)
|
||||
{
|
||||
@@ -500,6 +538,35 @@ meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
|
||||
return offer->resource;
|
||||
}
|
||||
|
||||
static struct wl_resource *
|
||||
meta_wayland_data_source_send_primary_offer (MetaWaylandDataSource *source,
|
||||
struct wl_resource *target)
|
||||
{
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
MetaWaylandDataOffer *offer = g_slice_new0 (MetaWaylandDataOffer);
|
||||
char **p;
|
||||
|
||||
offer->source = source;
|
||||
g_object_add_weak_pointer (G_OBJECT (source), (gpointer *)&offer->source);
|
||||
offer->resource = wl_resource_create (wl_resource_get_client (target),
|
||||
&zwp_primary_selection_offer_v1_interface,
|
||||
wl_resource_get_version (target), 0);
|
||||
wl_resource_set_implementation (offer->resource,
|
||||
&primary_offer_interface,
|
||||
offer,
|
||||
destroy_data_offer);
|
||||
|
||||
zwp_primary_selection_device_v1_send_data_offer (target, offer->resource);
|
||||
|
||||
wl_array_for_each (p, &priv->mime_types)
|
||||
zwp_primary_selection_offer_v1_send_offer (offer->resource, *p);
|
||||
|
||||
meta_wayland_data_source_set_current_offer (source, offer);
|
||||
|
||||
return offer->resource;
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_offer (struct wl_client *client,
|
||||
struct wl_resource *resource, const char *type)
|
||||
@@ -561,6 +628,11 @@ static struct wl_data_source_interface data_source_interface = {
|
||||
data_source_set_actions
|
||||
};
|
||||
|
||||
static struct zwp_primary_selection_source_v1_interface primary_source_interface = {
|
||||
data_source_offer,
|
||||
data_source_destroy,
|
||||
};
|
||||
|
||||
struct _MetaWaylandDragGrab {
|
||||
MetaWaylandPointerGrab generic;
|
||||
|
||||
@@ -1108,6 +1180,43 @@ meta_wayland_data_source_wayland_class_init (MetaWaylandDataSourceWaylandClass *
|
||||
data_source_class->drag_finished = meta_wayland_source_drag_finished;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_primary_send (MetaWaylandDataSource *source,
|
||||
const gchar *mime_type,
|
||||
gint fd)
|
||||
{
|
||||
MetaWaylandDataSourceWayland *source_wayland;
|
||||
|
||||
source_wayland = (MetaWaylandDataSourceWayland *) source;
|
||||
zwp_primary_selection_source_v1_send_send (source_wayland->resource,
|
||||
mime_type, fd);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_primary_cancel (MetaWaylandDataSource *source)
|
||||
{
|
||||
MetaWaylandDataSourceWayland *source_wayland;
|
||||
|
||||
source_wayland = (MetaWaylandDataSourceWayland *) source;
|
||||
zwp_primary_selection_source_v1_send_cancelled (source_wayland->resource);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_primary_init (MetaWaylandDataSourcePrimary *source_primary)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_primary_class_init (MetaWaylandDataSourcePrimaryClass *klass)
|
||||
{
|
||||
MetaWaylandDataSourceClass *data_source_class =
|
||||
META_WAYLAND_DATA_SOURCE_CLASS (klass);
|
||||
|
||||
data_source_class->send = meta_wayland_data_source_primary_send;
|
||||
data_source_class->cancel = meta_wayland_data_source_primary_cancel;
|
||||
data_source_class->target = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_finalize (GObject *object)
|
||||
{
|
||||
@@ -1299,6 +1408,7 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
|
||||
|
||||
if (source)
|
||||
{
|
||||
meta_wayland_data_source_set_seat (source, seat);
|
||||
g_object_weak_ref (G_OBJECT (source),
|
||||
selection_data_source_destroyed,
|
||||
data_device);
|
||||
@@ -1351,6 +1461,93 @@ static const struct wl_data_device_interface data_device_interface = {
|
||||
data_device_release,
|
||||
};
|
||||
|
||||
static void
|
||||
primary_source_destroyed (gpointer data,
|
||||
GObject *object_was_here)
|
||||
{
|
||||
MetaWaylandDataDevice *data_device = data;
|
||||
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
|
||||
struct wl_client *focus_client = NULL;
|
||||
|
||||
data_device->primary_data_source = NULL;
|
||||
|
||||
focus_client = meta_wayland_keyboard_get_focus_client (&seat->keyboard);
|
||||
if (focus_client)
|
||||
{
|
||||
struct wl_resource *data_device_resource;
|
||||
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
|
||||
if (data_device_resource)
|
||||
zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
|
||||
MetaWaylandDataSource *source)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
|
||||
struct wl_resource *data_device_resource, *offer;
|
||||
struct wl_client *focus_client;
|
||||
|
||||
if (data_device->primary_data_source)
|
||||
{
|
||||
meta_wayland_data_source_cancel (data_device->primary_data_source);
|
||||
g_object_weak_unref (G_OBJECT (data_device->primary_data_source),
|
||||
primary_source_destroyed,
|
||||
data_device);
|
||||
data_device->primary_data_source = NULL;
|
||||
}
|
||||
|
||||
data_device->primary_data_source = source;
|
||||
|
||||
focus_client = meta_wayland_keyboard_get_focus_client (&seat->keyboard);
|
||||
if (focus_client)
|
||||
{
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
|
||||
if (data_device_resource)
|
||||
{
|
||||
if (data_device->primary_data_source)
|
||||
{
|
||||
offer = meta_wayland_data_source_send_primary_offer (data_device->primary_data_source,
|
||||
data_device_resource);
|
||||
zwp_primary_selection_device_v1_send_selection (data_device_resource, offer);
|
||||
}
|
||||
else
|
||||
{
|
||||
zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (source)
|
||||
{
|
||||
meta_wayland_data_source_set_seat (source, seat);
|
||||
g_object_weak_ref (G_OBJECT (source),
|
||||
primary_source_destroyed,
|
||||
data_device);
|
||||
}
|
||||
|
||||
wl_signal_emit (&data_device->primary_ownership_signal, source);
|
||||
}
|
||||
|
||||
static void
|
||||
primary_device_set_selection (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
struct wl_resource *source_resource)
|
||||
{
|
||||
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
|
||||
MetaWaylandDataSource *source;
|
||||
|
||||
source = wl_resource_get_user_data (source_resource);
|
||||
meta_wayland_data_device_set_primary (data_device, source);
|
||||
}
|
||||
|
||||
static const struct zwp_primary_selection_device_v1_interface primary_device_interface = {
|
||||
primary_device_set_selection,
|
||||
data_device_release,
|
||||
};
|
||||
|
||||
static void
|
||||
destroy_data_source (struct wl_resource *resource)
|
||||
{
|
||||
@@ -1389,6 +1586,48 @@ static const struct wl_data_device_manager_interface manager_interface = {
|
||||
get_data_device
|
||||
};
|
||||
|
||||
static void
|
||||
primary_device_manager_create_source (struct wl_client *client,
|
||||
struct wl_resource *manager_resource,
|
||||
guint32 id)
|
||||
{
|
||||
struct wl_resource *source_resource;
|
||||
|
||||
source_resource =
|
||||
wl_resource_create (client, &zwp_primary_selection_source_v1_interface,
|
||||
wl_resource_get_version (manager_resource),
|
||||
id);
|
||||
meta_wayland_data_source_primary_new (source_resource);
|
||||
}
|
||||
|
||||
static void
|
||||
primary_device_manager_get_device (struct wl_client *client,
|
||||
struct wl_resource *manager_resource,
|
||||
guint32 id,
|
||||
struct wl_resource *seat_resource)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
||||
struct wl_resource *cr;
|
||||
|
||||
cr = wl_resource_create (client, &zwp_primary_selection_device_v1_interface,
|
||||
wl_resource_get_version (manager_resource), id);
|
||||
wl_resource_set_implementation (cr, &primary_device_interface,
|
||||
&seat->data_device, unbind_resource);
|
||||
wl_list_insert (&seat->data_device.primary_resource_list, wl_resource_get_link (cr));
|
||||
}
|
||||
|
||||
static void
|
||||
primary_device_manager_destroy (struct wl_client *client,
|
||||
struct wl_resource *manager_resource)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct zwp_primary_selection_device_manager_v1_interface primary_manager_interface = {
|
||||
primary_device_manager_create_source,
|
||||
primary_device_manager_get_device,
|
||||
primary_device_manager_destroy
|
||||
};
|
||||
|
||||
static void
|
||||
bind_manager (struct wl_client *client,
|
||||
void *data, guint32 version, guint32 id)
|
||||
@@ -1398,6 +1637,19 @@ bind_manager (struct wl_client *client,
|
||||
wl_resource_set_implementation (resource, &manager_interface, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_primary_manager (struct wl_client *client,
|
||||
void *data,
|
||||
uint32_t version,
|
||||
uint32_t id)
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
|
||||
resource = wl_resource_create (client, &zwp_primary_selection_device_manager_v1_interface,
|
||||
version, id);
|
||||
wl_resource_set_implementation (resource, &primary_manager_interface, NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor)
|
||||
{
|
||||
@@ -1406,13 +1658,20 @@ meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor)
|
||||
META_WL_DATA_DEVICE_MANAGER_VERSION,
|
||||
NULL, bind_manager) == NULL)
|
||||
g_error ("Could not create data_device");
|
||||
|
||||
if (wl_global_create (compositor->wayland_display,
|
||||
&zwp_primary_selection_device_manager_v1_interface,
|
||||
1, NULL, bind_primary_manager) == NULL)
|
||||
g_error ("Could not create data_device");
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_data_device_init (MetaWaylandDataDevice *data_device)
|
||||
{
|
||||
wl_list_init (&data_device->resource_list);
|
||||
wl_list_init (&data_device->primary_resource_list);
|
||||
wl_signal_init (&data_device->selection_ownership_signal);
|
||||
wl_signal_init (&data_device->primary_ownership_signal);
|
||||
wl_signal_init (&data_device->dnd_ownership_signal);
|
||||
}
|
||||
|
||||
@@ -1435,17 +1694,32 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
|
||||
return;
|
||||
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
|
||||
if (!data_device_resource)
|
||||
return;
|
||||
|
||||
source = data_device->selection_data_source;
|
||||
if (source)
|
||||
if (data_device_resource)
|
||||
{
|
||||
offer = meta_wayland_data_source_send_offer (source, data_device_resource);
|
||||
wl_data_device_send_selection (data_device_resource, offer);
|
||||
source = data_device->selection_data_source;
|
||||
if (source)
|
||||
{
|
||||
offer = meta_wayland_data_source_send_offer (source, data_device_resource);
|
||||
wl_data_device_send_selection (data_device_resource, offer);
|
||||
}
|
||||
else
|
||||
wl_data_device_send_selection (data_device_resource, NULL);
|
||||
}
|
||||
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
|
||||
if (data_device_resource)
|
||||
{
|
||||
source = data_device->primary_data_source;
|
||||
if (source)
|
||||
{
|
||||
offer = meta_wayland_data_source_send_primary_offer (source, data_device_resource);
|
||||
zwp_primary_selection_device_v1_send_selection (data_device_resource, offer);
|
||||
}
|
||||
else
|
||||
{
|
||||
zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
wl_data_device_send_selection (data_device_resource, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -1486,6 +1760,19 @@ meta_wayland_data_source_wayland_new (struct wl_resource *resource)
|
||||
return META_WAYLAND_DATA_SOURCE (source_wayland);
|
||||
}
|
||||
|
||||
static MetaWaylandDataSource *
|
||||
meta_wayland_data_source_primary_new (struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandDataSourceWayland *source_wayland =
|
||||
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY, NULL);
|
||||
|
||||
source_wayland->resource = resource;
|
||||
wl_resource_set_implementation (resource, &primary_source_interface,
|
||||
source_wayland, destroy_data_source);
|
||||
|
||||
return META_WAYLAND_DATA_SOURCE (source_wayland);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
|
||||
const gchar *mime_type)
|
||||
|
@@ -57,13 +57,16 @@ struct _MetaWaylandDataDevice
|
||||
uint32_t selection_serial;
|
||||
MetaWaylandDataSource *selection_data_source;
|
||||
MetaWaylandDataSource *dnd_data_source;
|
||||
MetaWaylandDataSource *primary_data_source;
|
||||
struct wl_listener selection_data_source_listener;
|
||||
struct wl_list resource_list;
|
||||
struct wl_list primary_resource_list;
|
||||
MetaWaylandDragGrab *current_grab;
|
||||
struct wl_client *focus_client;
|
||||
|
||||
struct wl_signal selection_ownership_signal;
|
||||
struct wl_signal dnd_ownership_signal;
|
||||
struct wl_signal primary_ownership_signal;
|
||||
};
|
||||
|
||||
void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor);
|
||||
@@ -80,6 +83,8 @@ void meta_wayland_data_device_set_dnd_source (MetaWaylandDataDevice *data_de
|
||||
void meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
|
||||
MetaWaylandDataSource *source,
|
||||
guint32 serial);
|
||||
void meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
|
||||
MetaWaylandDataSource *source);
|
||||
|
||||
gboolean meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
|
||||
const gchar *mime_type);
|
||||
|
818
src/wayland/meta-wayland-pointer-constraints.c
Normal file
818
src/wayland/meta-wayland-pointer-constraints.c
Normal 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");
|
||||
}
|
60
src/wayland/meta-wayland-pointer-constraints.h
Normal file
60
src/wayland/meta-wayland-pointer-constraints.h
Normal 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 */
|
@@ -63,6 +63,8 @@
|
||||
#include "backends/meta-cursor-tracker-private.h"
|
||||
#include "backends/meta-cursor-renderer.h"
|
||||
|
||||
#include "relative-pointer-unstable-v1-server-protocol.h"
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
#include "backends/native/meta-backend-native.h"
|
||||
#endif
|
||||
@@ -96,6 +98,7 @@ meta_wayland_pointer_client_new (void)
|
||||
wl_list_init (&pointer_client->pointer_resources);
|
||||
wl_list_init (&pointer_client->swipe_gesture_resources);
|
||||
wl_list_init (&pointer_client->pinch_gesture_resources);
|
||||
wl_list_init (&pointer_client->relative_pointer_resources);
|
||||
|
||||
return pointer_client;
|
||||
}
|
||||
@@ -124,6 +127,11 @@ meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
|
||||
wl_list_remove (wl_resource_get_link (resource));
|
||||
wl_list_init (wl_resource_get_link (resource));
|
||||
}
|
||||
wl_resource_for_each_safe (resource, next, &pointer_client->relative_pointer_resources)
|
||||
{
|
||||
wl_list_remove (wl_resource_get_link (resource));
|
||||
wl_list_init (wl_resource_get_link (resource));
|
||||
}
|
||||
|
||||
g_slice_free (MetaWaylandPointerClient, pointer_client);
|
||||
}
|
||||
@@ -133,7 +141,8 @@ meta_wayland_pointer_client_is_empty (MetaWaylandPointerClient *pointer_client)
|
||||
{
|
||||
return (wl_list_empty (&pointer_client->pointer_resources) &&
|
||||
wl_list_empty (&pointer_client->swipe_gesture_resources) &&
|
||||
wl_list_empty (&pointer_client->pinch_gesture_resources));
|
||||
wl_list_empty (&pointer_client->pinch_gesture_resources) &&
|
||||
wl_list_empty (&pointer_client->relative_pointer_resources));
|
||||
}
|
||||
|
||||
MetaWaylandPointerClient *
|
||||
@@ -264,27 +273,79 @@ meta_wayland_pointer_broadcast_frame (MetaWaylandPointer *pointer)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_pointer_send_relative_motion (MetaWaylandPointer *pointer,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
double dx, dy;
|
||||
double dx_unaccel, dy_unaccel;
|
||||
uint64_t time_us;
|
||||
uint32_t time_us_hi;
|
||||
uint32_t time_us_lo;
|
||||
wl_fixed_t dxf, dyf;
|
||||
wl_fixed_t dx_unaccelf, dy_unaccelf;
|
||||
|
||||
if (!pointer->focus_client)
|
||||
return;
|
||||
|
||||
if (!meta_backend_get_relative_motion_deltas (meta_get_backend (),
|
||||
event,
|
||||
&dx, &dy,
|
||||
&dx_unaccel, &dy_unaccel))
|
||||
return;
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
time_us = clutter_evdev_event_get_time_usec (event);
|
||||
if (time_us == 0)
|
||||
#endif
|
||||
time_us = clutter_event_get_time (event) * 1000ULL;
|
||||
time_us_hi = (uint32_t) (time_us >> 32);
|
||||
time_us_lo = (uint32_t) time_us;
|
||||
dxf = wl_fixed_from_double (dx);
|
||||
dyf = wl_fixed_from_double (dy);
|
||||
dx_unaccelf = wl_fixed_from_double (dx_unaccel);
|
||||
dy_unaccelf = wl_fixed_from_double (dy_unaccel);
|
||||
|
||||
wl_resource_for_each (resource,
|
||||
&pointer->focus_client->relative_pointer_resources)
|
||||
{
|
||||
zwp_relative_pointer_v1_send_relative_motion (resource,
|
||||
time_us_hi,
|
||||
time_us_lo,
|
||||
dxf,
|
||||
dyf,
|
||||
dx_unaccelf,
|
||||
dy_unaccelf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_pointer_send_motion (MetaWaylandPointer *pointer,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
uint32_t time;
|
||||
wl_fixed_t sx, sy;
|
||||
float sx, sy;
|
||||
|
||||
if (!pointer->focus_client)
|
||||
return;
|
||||
|
||||
time = clutter_event_get_time (event);
|
||||
meta_wayland_pointer_get_relative_coordinates (pointer,
|
||||
pointer->focus_surface,
|
||||
meta_wayland_surface_get_relative_coordinates (pointer->focus_surface,
|
||||
event->motion.x,
|
||||
event->motion.y,
|
||||
&sx, &sy);
|
||||
|
||||
wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
|
||||
{
|
||||
wl_pointer_send_motion (resource, time, sx, sy);
|
||||
wl_pointer_send_motion (resource, time,
|
||||
wl_fixed_from_double (sx),
|
||||
wl_fixed_from_double (sy));
|
||||
}
|
||||
|
||||
meta_wayland_pointer_send_relative_motion (pointer, event);
|
||||
|
||||
meta_wayland_pointer_broadcast_frame (pointer);
|
||||
}
|
||||
|
||||
@@ -339,6 +400,9 @@ meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
|
||||
time = clutter_event_get_time (event);
|
||||
serial = wl_display_next_serial (display);
|
||||
|
||||
if (event->type == CLUTTER_BUTTON_PRESS)
|
||||
pointer->click_serial = serial;
|
||||
|
||||
wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
|
||||
{
|
||||
wl_pointer_send_button (resource, serial,
|
||||
@@ -866,11 +930,10 @@ meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
|
||||
ClutterPoint pos;
|
||||
|
||||
clutter_input_device_get_coords (pointer->device, NULL, &pos);
|
||||
clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
|
||||
pos.x, pos.y, &xf, &yf);
|
||||
meta_wayland_surface_get_relative_coordinates (surface, pos.x, pos.y, &xf, &yf);
|
||||
|
||||
*sx = wl_fixed_from_double (xf) / surface->scale;
|
||||
*sy = wl_fixed_from_double (yf) / surface->scale;
|
||||
*sx = wl_fixed_from_double (xf);
|
||||
*sy = wl_fixed_from_double (yf);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1097,6 +1160,108 @@ meta_wayland_pointer_get_top_popup (MetaWaylandPointer *pointer)
|
||||
return meta_wayland_popup_grab_get_top_popup(grab);
|
||||
}
|
||||
|
||||
static void
|
||||
relative_pointer_destroy (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static const struct zwp_relative_pointer_v1_interface relative_pointer_interface = {
|
||||
relative_pointer_destroy
|
||||
};
|
||||
|
||||
static void
|
||||
relative_pointer_manager_destroy (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static void
|
||||
relative_pointer_manager_get_relative_pointer (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t id,
|
||||
struct wl_resource *pointer_resource)
|
||||
{
|
||||
MetaWaylandPointer *pointer = wl_resource_get_user_data (pointer_resource);
|
||||
struct wl_resource *cr;
|
||||
MetaWaylandPointerClient *pointer_client;
|
||||
|
||||
cr = wl_resource_create (client, &zwp_relative_pointer_v1_interface,
|
||||
wl_resource_get_version (resource), id);
|
||||
if (cr == NULL)
|
||||
{
|
||||
wl_client_post_no_memory (client);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_implementation (cr, &relative_pointer_interface,
|
||||
pointer,
|
||||
meta_wayland_pointer_unbind_pointer_client_resource);
|
||||
|
||||
pointer_client = meta_wayland_pointer_ensure_pointer_client (pointer, client);
|
||||
|
||||
wl_list_insert (&pointer_client->relative_pointer_resources,
|
||||
wl_resource_get_link (cr));
|
||||
}
|
||||
|
||||
static const struct zwp_relative_pointer_manager_v1_interface relative_pointer_manager = {
|
||||
relative_pointer_manager_destroy,
|
||||
relative_pointer_manager_get_relative_pointer,
|
||||
};
|
||||
|
||||
static void
|
||||
bind_relative_pointer_manager (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_relative_pointer_manager_v1_interface,
|
||||
1, id);
|
||||
|
||||
if (version != 1)
|
||||
wl_resource_post_error (resource,
|
||||
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
||||
"bound invalid version %u of "
|
||||
"wp_relative_pointer_manager",
|
||||
version);
|
||||
|
||||
wl_resource_set_implementation (resource, &relative_pointer_manager,
|
||||
compositor,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_relative_pointer_init (MetaWaylandCompositor *compositor)
|
||||
{
|
||||
/* Relative pointer events are currently only supported by the native backend
|
||||
* so lets just advertise the extension when the native backend is used.
|
||||
*/
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
if (!META_IS_BACKEND_NATIVE (meta_get_backend ()))
|
||||
return;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!wl_global_create (compositor->wayland_display,
|
||||
&zwp_relative_pointer_manager_v1_interface, 1,
|
||||
compositor, bind_relative_pointer_manager))
|
||||
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
|
||||
cursor_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
|
||||
{
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "meta-wayland-pointer-gesture-swipe.h"
|
||||
#include "meta-wayland-pointer-gesture-pinch.h"
|
||||
#include "meta-wayland-surface.h"
|
||||
#include "meta-wayland-pointer-constraints.h"
|
||||
|
||||
#include <meta/meta-cursor-tracker.h>
|
||||
|
||||
@@ -58,6 +59,7 @@ struct _MetaWaylandPointerClient
|
||||
struct wl_list pointer_resources;
|
||||
struct wl_list swipe_gesture_resources;
|
||||
struct wl_list pinch_gesture_resources;
|
||||
struct wl_list relative_pointer_resources;
|
||||
};
|
||||
|
||||
struct _MetaWaylandPointer
|
||||
@@ -101,6 +103,9 @@ gboolean meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
|
||||
void meta_wayland_pointer_send_motion (MetaWaylandPointer *pointer,
|
||||
const ClutterEvent *event);
|
||||
|
||||
void meta_wayland_pointer_send_relative_motion (MetaWaylandPointer *pointer,
|
||||
const ClutterEvent *event);
|
||||
|
||||
void meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
|
||||
const ClutterEvent *event);
|
||||
|
||||
@@ -142,4 +147,8 @@ MetaWaylandPointerClient * meta_wayland_pointer_get_pointer_client (MetaWaylandP
|
||||
struct wl_client *client);
|
||||
void meta_wayland_pointer_unbind_pointer_client_resource (struct wl_resource *resource);
|
||||
|
||||
void meta_wayland_relative_pointer_init (MetaWaylandCompositor *compositor);
|
||||
|
||||
MetaWaylandSeat *meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer);
|
||||
|
||||
#endif /* META_WAYLAND_POINTER_H */
|
||||
|
@@ -55,6 +55,14 @@
|
||||
#include "meta-surface-actor-wayland.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
|
||||
{
|
||||
MetaWaylandSurface *surface;
|
||||
@@ -79,6 +87,10 @@ G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandSurfaceRole,
|
||||
meta_wayland_surface_role,
|
||||
G_TYPE_OBJECT);
|
||||
|
||||
G_DEFINE_TYPE (MetaWaylandPendingState,
|
||||
meta_wayland_pending_state,
|
||||
G_TYPE_OBJECT);
|
||||
|
||||
struct _MetaWaylandSurfaceRoleSubsurface
|
||||
{
|
||||
MetaWaylandSurfaceRole parent;
|
||||
@@ -162,6 +174,25 @@ meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
surface_use_buffer (MetaWaylandSurface *surface)
|
||||
{
|
||||
g_return_if_fail (!surface->using_buffer);
|
||||
|
||||
meta_wayland_buffer_ref_use_count (surface->buffer);
|
||||
surface->using_buffer = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
surface_stop_using_buffer (MetaWaylandSurface *surface)
|
||||
{
|
||||
if (!surface->using_buffer)
|
||||
return;
|
||||
|
||||
meta_wayland_buffer_unref_use_count (surface->buffer);
|
||||
surface->using_buffer = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
surface_set_buffer (MetaWaylandSurface *surface,
|
||||
MetaWaylandBuffer *buffer)
|
||||
@@ -172,6 +203,8 @@ surface_set_buffer (MetaWaylandSurface *surface,
|
||||
if (surface->buffer)
|
||||
{
|
||||
wl_list_remove (&surface->buffer_destroy_listener.link);
|
||||
|
||||
surface_stop_using_buffer (surface);
|
||||
meta_wayland_buffer_unref (surface->buffer);
|
||||
}
|
||||
|
||||
@@ -333,6 +366,12 @@ toplevel_surface_commit (MetaWaylandSurfaceRole *surface_role,
|
||||
|
||||
queue_surface_actor_frame_callbacks (surface, pending);
|
||||
|
||||
/* If there's no new buffer pending, then there's nothing else to
|
||||
* do
|
||||
*/
|
||||
if (!pending->newly_attached)
|
||||
return;
|
||||
|
||||
if (META_IS_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE (surface->role))
|
||||
{
|
||||
/* For wl_shell, it's equivalent to an unmap. Semantics
|
||||
@@ -468,7 +507,18 @@ move_pending_state (MetaWaylandPendingState *from,
|
||||
if (from->buffer)
|
||||
wl_list_remove (&from->buffer_destroy_listener.link);
|
||||
|
||||
*to = *from;
|
||||
to->newly_attached = from->newly_attached;
|
||||
to->buffer = from->buffer;
|
||||
to->dx = from->dx;
|
||||
to->dy = from->dy;
|
||||
to->scale = from->scale;
|
||||
to->damage = from->damage;
|
||||
to->input_region = from->input_region;
|
||||
to->input_region_set = from->input_region_set;
|
||||
to->opaque_region = from->opaque_region;
|
||||
to->opaque_region_set = from->opaque_region_set;
|
||||
to->new_geometry = from->new_geometry;
|
||||
to->has_new_geometry = from->has_new_geometry;
|
||||
|
||||
wl_list_init (&to->frame_callback_list);
|
||||
wl_list_insert_list (&to->frame_callback_list, &from->frame_callback_list);
|
||||
@@ -479,6 +529,38 @@ move_pending_state (MetaWaylandPendingState *from,
|
||||
pending_state_init (from);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_pending_state_finalize (GObject *object)
|
||||
{
|
||||
MetaWaylandPendingState *state = META_WAYLAND_PENDING_STATE (object);
|
||||
|
||||
pending_state_destroy (state);
|
||||
|
||||
G_OBJECT_CLASS (meta_wayland_pending_state_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_pending_state_init (MetaWaylandPendingState *state)
|
||||
{
|
||||
pending_state_init (state);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_pending_state_class_init (MetaWaylandPendingStateClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
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
|
||||
subsurface_surface_commit (MetaWaylandSurfaceRole *surface_role,
|
||||
MetaWaylandPendingState *pending)
|
||||
@@ -577,7 +659,7 @@ parent_surface_state_applied (gpointer data, gpointer user_data)
|
||||
}
|
||||
|
||||
if (is_surface_effectively_synchronized (surface))
|
||||
apply_pending_state (surface, &surface->sub.pending);
|
||||
apply_pending_state (surface, surface->sub.pending);
|
||||
|
||||
meta_surface_actor_wayland_sync_subsurface_state (
|
||||
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
|
||||
@@ -587,6 +669,8 @@ static void
|
||||
apply_pending_state (MetaWaylandSurface *surface,
|
||||
MetaWaylandPendingState *pending)
|
||||
{
|
||||
gboolean release_new_buffer = FALSE;
|
||||
|
||||
if (pending->newly_attached)
|
||||
{
|
||||
if (!surface->buffer && surface->window)
|
||||
@@ -594,10 +678,18 @@ apply_pending_state (MetaWaylandSurface *surface,
|
||||
|
||||
surface_set_buffer (surface, pending->buffer);
|
||||
|
||||
if (pending->buffer)
|
||||
if (pending->buffer && !surface->using_buffer)
|
||||
{
|
||||
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (pending->buffer->resource);
|
||||
|
||||
surface_use_buffer (surface);
|
||||
CoglTexture *texture = meta_wayland_buffer_ensure_texture (pending->buffer);
|
||||
meta_surface_actor_wayland_set_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), texture);
|
||||
|
||||
/* Release the buffer as soon as possible, so the client can reuse it
|
||||
*/
|
||||
if (shm_buffer)
|
||||
release_new_buffer = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,6 +699,9 @@ apply_pending_state (MetaWaylandSurface *surface,
|
||||
if (!cairo_region_is_empty (pending->damage))
|
||||
surface_process_damage (surface, pending->damage);
|
||||
|
||||
if (release_new_buffer)
|
||||
surface_stop_using_buffer (surface);
|
||||
|
||||
surface->offset_x += pending->dx;
|
||||
surface->offset_y += pending->dy;
|
||||
|
||||
@@ -646,6 +741,10 @@ apply_pending_state (MetaWaylandSurface *surface,
|
||||
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 (surface->surface_actor));
|
||||
|
||||
@@ -666,9 +765,9 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface)
|
||||
* surface is in effective desynchronized mode.
|
||||
*/
|
||||
if (is_surface_effectively_synchronized (surface))
|
||||
move_pending_state (&surface->pending, &surface->sub.pending);
|
||||
move_pending_state (surface->pending, surface->sub.pending);
|
||||
else
|
||||
apply_pending_state (surface, &surface->pending);
|
||||
apply_pending_state (surface, surface->pending);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -697,17 +796,17 @@ wl_surface_attach (struct wl_client *client,
|
||||
else
|
||||
buffer = NULL;
|
||||
|
||||
if (surface->pending.buffer)
|
||||
wl_list_remove (&surface->pending.buffer_destroy_listener.link);
|
||||
if (surface->pending->buffer)
|
||||
wl_list_remove (&surface->pending->buffer_destroy_listener.link);
|
||||
|
||||
surface->pending.newly_attached = TRUE;
|
||||
surface->pending.buffer = buffer;
|
||||
surface->pending.dx = dx;
|
||||
surface->pending.dy = dy;
|
||||
surface->pending->newly_attached = TRUE;
|
||||
surface->pending->buffer = buffer;
|
||||
surface->pending->dx = dx;
|
||||
surface->pending->dy = dy;
|
||||
|
||||
if (buffer)
|
||||
wl_signal_add (&buffer->destroy_signal,
|
||||
&surface->pending.buffer_destroy_listener);
|
||||
&surface->pending->buffer_destroy_listener);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -725,7 +824,7 @@ wl_surface_damage (struct wl_client *client,
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
cairo_region_union_rectangle (surface->pending.damage, &rectangle);
|
||||
cairo_region_union_rectangle (surface->pending->damage, &rectangle);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -755,7 +854,7 @@ wl_surface_frame (struct wl_client *client,
|
||||
callback->resource = wl_resource_create (client, &wl_callback_interface, META_WL_CALLBACK_VERSION, callback_id);
|
||||
wl_resource_set_implementation (callback->resource, NULL, callback, destroy_frame_callback);
|
||||
|
||||
wl_list_insert (surface->pending.frame_callback_list.prev, &callback->link);
|
||||
wl_list_insert (surface->pending->frame_callback_list.prev, &callback->link);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -769,14 +868,14 @@ wl_surface_set_opaque_region (struct wl_client *client,
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
|
||||
g_clear_pointer (&surface->pending->opaque_region, cairo_region_destroy);
|
||||
if (region_resource)
|
||||
{
|
||||
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
|
||||
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
|
||||
surface->pending.opaque_region = cairo_region_copy (cr_region);
|
||||
surface->pending->opaque_region = cairo_region_copy (cr_region);
|
||||
}
|
||||
surface->pending.opaque_region_set = TRUE;
|
||||
surface->pending->opaque_region_set = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -790,14 +889,14 @@ wl_surface_set_input_region (struct wl_client *client,
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
|
||||
g_clear_pointer (&surface->pending->input_region, cairo_region_destroy);
|
||||
if (region_resource)
|
||||
{
|
||||
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
|
||||
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
|
||||
surface->pending.input_region = cairo_region_copy (cr_region);
|
||||
surface->pending->input_region = cairo_region_copy (cr_region);
|
||||
}
|
||||
surface->pending.input_region_set = TRUE;
|
||||
surface->pending->input_region_set = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -828,7 +927,7 @@ wl_surface_set_buffer_scale (struct wl_client *client,
|
||||
{
|
||||
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
||||
if (scale > 0)
|
||||
surface->pending.scale = scale;
|
||||
surface->pending->scale = scale;
|
||||
else
|
||||
g_warning ("Trying to set invalid buffer_scale of %d\n", scale);
|
||||
}
|
||||
@@ -1029,8 +1128,11 @@ wl_surface_destructor (struct wl_resource *resource)
|
||||
if (surface->window)
|
||||
destroy_window (surface);
|
||||
|
||||
g_list_free_full (surface->pointer_constraints,
|
||||
(GDestroyNotify) meta_wayland_pointer_constraint_destroy);
|
||||
|
||||
surface_set_buffer (surface, NULL);
|
||||
pending_state_destroy (&surface->pending);
|
||||
g_clear_object (&surface->pending);
|
||||
|
||||
if (surface->opaque_region)
|
||||
cairo_region_destroy (surface->opaque_region);
|
||||
@@ -1069,6 +1171,13 @@ wl_surface_destructor (struct wl_resource *resource)
|
||||
meta_wayland_compositor_repick (compositor);
|
||||
}
|
||||
|
||||
static void
|
||||
surface_actor_painting (MetaSurfaceActorWayland *surface_actor,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
meta_wayland_surface_update_outputs (surface);
|
||||
}
|
||||
|
||||
MetaWaylandSurface *
|
||||
meta_wayland_surface_create (MetaWaylandCompositor *compositor,
|
||||
struct wl_client *client,
|
||||
@@ -1088,11 +1197,16 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
|
||||
|
||||
wl_list_init (&surface->pending_frame_callback_list);
|
||||
|
||||
g_signal_connect_object (surface->surface_actor,
|
||||
"painting",
|
||||
G_CALLBACK (surface_actor_painting),
|
||||
surface,
|
||||
0);
|
||||
|
||||
sync_drag_dest_funcs (surface);
|
||||
|
||||
surface->outputs_to_destroy_notify_id = g_hash_table_new (NULL, NULL);
|
||||
|
||||
pending_state_init (&surface->pending);
|
||||
return surface;
|
||||
}
|
||||
|
||||
@@ -1295,11 +1409,11 @@ xdg_surface_set_window_geometry (struct wl_client *client,
|
||||
{
|
||||
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
||||
|
||||
surface->pending.has_new_geometry = TRUE;
|
||||
surface->pending.new_geometry.x = x;
|
||||
surface->pending.new_geometry.y = y;
|
||||
surface->pending.new_geometry.width = width;
|
||||
surface->pending.new_geometry.height = height;
|
||||
surface->pending->has_new_geometry = TRUE;
|
||||
surface->pending->new_geometry.x = x;
|
||||
surface->pending->new_geometry.y = y;
|
||||
surface->pending->new_geometry.width = width;
|
||||
surface->pending->new_geometry.height = height;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1951,8 +2065,21 @@ get_gtk_surface (struct wl_client *client,
|
||||
wl_resource_set_implementation (surface->gtk_surface, &meta_wayland_gtk_surface_interface, surface, gtk_surface_destructor);
|
||||
}
|
||||
|
||||
static void
|
||||
set_startup_id (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
const char *startup_id)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
|
||||
display = meta_get_display ();
|
||||
meta_startup_notification_remove_sequence (display->startup_notification,
|
||||
startup_id);
|
||||
}
|
||||
|
||||
static const struct gtk_shell_interface meta_wayland_gtk_shell_interface = {
|
||||
get_gtk_surface
|
||||
get_gtk_surface,
|
||||
set_startup_id
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -1966,7 +2093,7 @@ bind_gtk_shell (struct wl_client *client,
|
||||
|
||||
resource = wl_resource_create (client, >k_shell_interface, version, id);
|
||||
|
||||
if (version != META_GTK_SHELL_VERSION)
|
||||
if (version < 2)
|
||||
{
|
||||
wl_resource_post_error (resource,
|
||||
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
||||
@@ -2008,7 +2135,7 @@ wl_subsurface_destructor (struct wl_resource *resource)
|
||||
surface->sub.parent = NULL;
|
||||
}
|
||||
|
||||
pending_state_destroy (&surface->sub.pending);
|
||||
g_clear_object (&surface->sub.pending);
|
||||
surface->wl_subsurface = NULL;
|
||||
}
|
||||
|
||||
@@ -2134,7 +2261,7 @@ wl_subsurface_set_desync (struct wl_client *client,
|
||||
surface->sub.synchronous = FALSE;
|
||||
if (was_effectively_synchronized &&
|
||||
!is_surface_effectively_synchronized (surface))
|
||||
apply_pending_state (surface, &surface->sub.pending);
|
||||
apply_pending_state (surface, surface->sub.pending);
|
||||
}
|
||||
|
||||
static const struct wl_subsurface_interface meta_wayland_wl_subsurface_interface = {
|
||||
@@ -2198,7 +2325,7 @@ wl_subcompositor_get_subsurface (struct wl_client *client,
|
||||
surface->wl_subsurface = wl_resource_create (client, &wl_subsurface_interface, wl_resource_get_version (resource), id);
|
||||
wl_resource_set_implementation (surface->wl_subsurface, &meta_wayland_wl_subsurface_interface, surface, wl_subsurface_destructor);
|
||||
|
||||
pending_state_init (&surface->sub.pending);
|
||||
surface->sub.pending = g_object_new (META_TYPE_WAYLAND_PENDING_STATE, NULL);
|
||||
surface->sub.synchronous = TRUE;
|
||||
surface->sub.parent = parent;
|
||||
surface->sub.parent_destroy_listener.notify = surface_handle_parent_surface_destroyed;
|
||||
@@ -2413,9 +2540,79 @@ meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface)
|
||||
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
|
||||
meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface,
|
||||
float abs_x,
|
||||
float abs_y,
|
||||
float *sx,
|
||||
float *sy)
|
||||
{
|
||||
ClutterActor *actor =
|
||||
CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor));
|
||||
|
||||
clutter_actor_transform_stage_point (actor, abs_x, abs_y, sx, sy);
|
||||
*sx /= 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
|
||||
meta_wayland_surface_init (MetaWaylandSurface *surface)
|
||||
{
|
||||
surface->pending = g_object_new (META_TYPE_WAYLAND_PENDING_STATE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "meta-wayland-types.h"
|
||||
#include "meta-surface-actor.h"
|
||||
#include "backends/meta-monitor-manager-private.h"
|
||||
#include "meta-wayland-pointer-constraints.h"
|
||||
|
||||
typedef struct _MetaWaylandPendingState MetaWaylandPendingState;
|
||||
|
||||
@@ -44,6 +45,12 @@ G_DECLARE_FINAL_TYPE (MetaWaylandSurface,
|
||||
G_DECLARE_DERIVABLE_TYPE (MetaWaylandSurfaceRole, meta_wayland_surface_role,
|
||||
META, WAYLAND_SURFACE_ROLE, GObject);
|
||||
|
||||
#define META_TYPE_WAYLAND_PENDING_STATE (meta_wayland_pending_state_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaWaylandPendingState,
|
||||
meta_wayland_pending_state,
|
||||
META, WAYLAND_PENDING_STATE,
|
||||
GObject);
|
||||
|
||||
struct _MetaWaylandSurfaceRoleClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
@@ -92,6 +99,8 @@ G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleDND,
|
||||
|
||||
struct _MetaWaylandPendingState
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
/* wl_surface.attach */
|
||||
gboolean newly_attached;
|
||||
MetaWaylandBuffer *buffer;
|
||||
@@ -143,6 +152,7 @@ struct _MetaWaylandSurface
|
||||
MetaWaylandSurfaceRole *role;
|
||||
MetaWindow *window;
|
||||
MetaWaylandBuffer *buffer;
|
||||
gboolean using_buffer;
|
||||
struct wl_listener buffer_destroy_listener;
|
||||
cairo_region_t *input_region;
|
||||
cairo_region_t *opaque_region;
|
||||
@@ -161,7 +171,7 @@ struct _MetaWaylandSurface
|
||||
} dnd;
|
||||
|
||||
/* All the pending state that wl_surface.commit will apply. */
|
||||
MetaWaylandPendingState pending;
|
||||
MetaWaylandPendingState *pending;
|
||||
|
||||
/* Extension resources. */
|
||||
struct wl_resource *xdg_surface;
|
||||
@@ -202,13 +212,15 @@ struct _MetaWaylandSurface
|
||||
* state here.
|
||||
*/
|
||||
gboolean synchronous;
|
||||
MetaWaylandPendingState pending;
|
||||
MetaWaylandPendingState *pending;
|
||||
|
||||
int32_t pending_x;
|
||||
int32_t pending_y;
|
||||
gboolean pending_pos;
|
||||
GSList *pending_placement_ops;
|
||||
} sub;
|
||||
|
||||
GList *pointer_constraints;
|
||||
};
|
||||
|
||||
void meta_wayland_shell_init (MetaWaylandCompositor *compositor);
|
||||
@@ -253,6 +265,27 @@ void meta_wayland_surface_queue_pending_frame_callbacks (MetaWayl
|
||||
void meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface *surface,
|
||||
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,
|
||||
float abs_x,
|
||||
float abs_y,
|
||||
float *sx,
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
@@ -42,7 +42,7 @@
|
||||
#define META_WL_SEAT_VERSION 5
|
||||
#define META_WL_OUTPUT_VERSION 2
|
||||
#define META_XSERVER_VERSION 1
|
||||
#define META_GTK_SHELL_VERSION 2
|
||||
#define META_GTK_SHELL_VERSION 3
|
||||
#define META_WL_SUBCOMPOSITOR_VERSION 1
|
||||
#define META_ZWP_POINTER_GESTURES_V1_VERSION 1
|
||||
|
||||
|
@@ -48,14 +48,6 @@ meta_wayland_compositor_get_default (void)
|
||||
return &_meta_wayland_compositor;
|
||||
}
|
||||
|
||||
static guint32
|
||||
get_time (void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday (&tv, NULL);
|
||||
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSource source;
|
||||
@@ -186,7 +178,7 @@ meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor)
|
||||
MetaWaylandFrameCallback *callback =
|
||||
wl_container_of (compositor->frame_callbacks.next, callback, link);
|
||||
|
||||
wl_callback_send_done (callback->resource, get_time ());
|
||||
wl_callback_send_done (callback->resource, g_get_monotonic_time () / 1000);
|
||||
wl_resource_destroy (callback->resource);
|
||||
}
|
||||
}
|
||||
@@ -336,6 +328,8 @@ meta_wayland_init (void)
|
||||
meta_wayland_shell_init (compositor);
|
||||
meta_wayland_pointer_gestures_init (compositor);
|
||||
meta_wayland_seat_init (compositor);
|
||||
meta_wayland_relative_pointer_init (compositor);
|
||||
meta_wayland_pointer_constraints_init (compositor);
|
||||
|
||||
if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
|
||||
g_error ("Failed to start X Wayland");
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "window-private.h"
|
||||
#include "boxes-private.h"
|
||||
#include "stack-tracker.h"
|
||||
#include "meta-wayland-private.h"
|
||||
#include "meta-wayland-surface.h"
|
||||
#include "compositor/meta-surface-actor-wayland.h"
|
||||
|
||||
@@ -402,6 +403,11 @@ appears_focused_changed (GObject *object,
|
||||
gpointer user_data)
|
||||
{
|
||||
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,
|
||||
* causing this to fire. Don't do anything in that case. */
|
||||
@@ -409,6 +415,8 @@ appears_focused_changed (GObject *object,
|
||||
return;
|
||||
|
||||
surface_state_changed (window);
|
||||
|
||||
meta_wayland_pointer_constraint_maybe_enable_for_window (window);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -91,6 +91,7 @@ struct _MetaWaylandDataSourceXWayland
|
||||
|
||||
struct _MetaXWaylandSelection {
|
||||
MetaSelectionBridge clipboard;
|
||||
MetaSelectionBridge primary;
|
||||
MetaDndBridge dnd;
|
||||
};
|
||||
|
||||
@@ -396,6 +397,8 @@ atom_to_selection_bridge (MetaWaylandCompositor *compositor,
|
||||
|
||||
if (selection_atom == selection_data->clipboard.selection_atom)
|
||||
return &selection_data->clipboard;
|
||||
else if (selection_atom == selection_data->primary.selection_atom)
|
||||
return &selection_data->primary;
|
||||
else if (selection_atom == selection_data->dnd.selection.selection_atom)
|
||||
return &selection_data->dnd.selection;
|
||||
else
|
||||
@@ -530,6 +533,8 @@ data_device_get_active_source_for_atom (MetaWaylandDataDevice *data_device,
|
||||
{
|
||||
if (selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
|
||||
return data_device->selection_data_source;
|
||||
else if (selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
|
||||
return data_device->primary_data_source;
|
||||
else if (selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
|
||||
return data_device->dnd_data_source;
|
||||
else
|
||||
@@ -1058,6 +1063,10 @@ meta_xwayland_selection_get_x11_targets (MetaWaylandCompositor *compositor,
|
||||
meta_wayland_data_device_set_selection (&compositor->seat->data_device, data_source,
|
||||
wl_display_next_serial (compositor->wayland_display));
|
||||
}
|
||||
else if (selection->selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
|
||||
{
|
||||
meta_wayland_data_device_set_primary (&compositor->seat->data_device, data_source);
|
||||
}
|
||||
}
|
||||
else
|
||||
g_object_unref (data_source);
|
||||
@@ -1529,7 +1538,8 @@ meta_xwayland_selection_handle_xfixes_selection_notify (MetaWaylandCompositor *c
|
||||
if (!selection)
|
||||
return FALSE;
|
||||
|
||||
if (selection->selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
|
||||
if (selection->selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD") ||
|
||||
selection->selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
|
||||
{
|
||||
if (event->owner == None)
|
||||
{
|
||||
@@ -1712,6 +1722,9 @@ meta_xwayland_init_selection (void)
|
||||
init_selection_bridge (&manager->selection_data->clipboard,
|
||||
gdk_x11_get_xatom_by_name ("CLIPBOARD"),
|
||||
&compositor->seat->data_device.selection_ownership_signal);
|
||||
init_selection_bridge (&manager->selection_data->primary,
|
||||
gdk_x11_get_xatom_by_name ("PRIMARY"),
|
||||
&compositor->seat->data_device.primary_ownership_signal);
|
||||
init_selection_bridge (&manager->selection_data->dnd.selection,
|
||||
xdnd_atoms[ATOM_DND_SELECTION],
|
||||
&compositor->seat->data_device.dnd_ownership_signal);
|
||||
@@ -1730,6 +1743,7 @@ meta_xwayland_shutdown_selection (void)
|
||||
|
||||
meta_xwayland_shutdown_dnd (manager);
|
||||
shutdown_selection_bridge (&selection->clipboard);
|
||||
shutdown_selection_bridge (&selection->primary);
|
||||
shutdown_selection_bridge (&selection->dnd.selection);
|
||||
|
||||
g_slice_free (MetaXWaylandSelection, selection);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<protocol name="gtk">
|
||||
|
||||
<interface name="gtk_shell" version="2">
|
||||
<interface name="gtk_shell" version="3">
|
||||
<description summary="gtk specific extensions">
|
||||
gtk_shell is a protocol extension providing additional features for
|
||||
clients implementing it. It is not backward compatible, and a client must
|
||||
@@ -23,9 +23,13 @@
|
||||
<arg name="gtk_surface" type="new_id" interface="gtk_surface"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
|
||||
<request name="set_startup_id" since="3">
|
||||
<arg name="startup_id" type="string" allow-null="true"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="gtk_surface" version="2">
|
||||
<interface name="gtk_surface" version="3">
|
||||
<request name="set_dbus_properties">
|
||||
<arg name="application_id" type="string" allow-null="true"/>
|
||||
<arg name="app_menu_path" type="string" allow-null="true"/>
|
||||
|
@@ -1671,13 +1671,12 @@ meta_display_handle_xevent (MetaDisplay *display,
|
||||
meta_spew_event_print (display, event);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
if (sn_display_process_event (display->sn_display, event))
|
||||
if (meta_startup_notification_handle_xevent (display->startup_notification,
|
||||
event))
|
||||
{
|
||||
bypass_gtk = bypass_compositor = TRUE;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (meta_is_wayland_compositor () &&
|
||||
|
@@ -1732,9 +1732,9 @@ meta_window_x11_update_input_region (MetaWindow *window)
|
||||
region = cairo_region_create ();
|
||||
}
|
||||
else if (n_rects == 1 &&
|
||||
(rects[0].x == 0 ||
|
||||
rects[0].y == 0 ||
|
||||
rects[0].width == priv->client_rect.width ||
|
||||
(rects[0].x == 0 &&
|
||||
rects[0].y == 0 &&
|
||||
rects[0].width == priv->client_rect.width &&
|
||||
rects[0].height == priv->client_rect.height))
|
||||
{
|
||||
/* This is the bounding region case. Keep the
|
||||
|
Reference in New Issue
Block a user