Compare commits

...

29 Commits

Author SHA1 Message Date
Carlos Garnacho
297d11b323 WIP: Implement the primary selection protocol 2016-02-20 01:37:01 +01:00
Carlos Garnacho
3f60a2e48a wayland: Implement gtk-shell v3
Implement the gtk_shell.set_startup_id request, so that the ID is
removed from the sequences list, and feedback updated accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=762268
2016-02-19 17:41:03 +01:00
Carlos Garnacho
3729e592a6 wayland: Update gtk-shell protocol file to v3
Add a gtk_shell.set_startup_id request, so the application can communicate
to the compositor the startup id that it received through the
DESKTOP_STARTUP_ID envvar, or other means.

https://bugzilla.gnome.org/show_bug.cgi?id=762268
2016-02-19 17:41:03 +01:00
Carlos Garnacho
56beedf9f2 core: Refactor startup notification into a separate object
This is kind of in a middle ground at the moment. Even though it
handles sequences not coming from libsn, they're added nowhere at
the moment, we'll rely on the app launch context being in the x11
side at the moment.

Also, even though we do create internal sequence objects, we keep
exposing SnStartupSequences to make gnome-shell happy, we could
consider making this object "public" (and the sequence objects with
it), things stay private at the moment.

https://bugzilla.gnome.org/show_bug.cgi?id=762268
2016-02-19 17:41:03 +01:00
Ray Strode
bed82427c6 wayland: change accessible boolean to use_count counter
Since a buffer can be used by multiple surfaces at once,
we need to release the buffer only after all surfaces
are finished with it.  Currently we track whether or
not to release the buffer based on the accessible boolean.
This commit changes it to a counter to accomodate multiple
users.

Also, each surface needs to know whether not it is done with
the buffer, so this commit adds a buffer_used boolean to the
surface state.

https://bugzilla.gnome.org/show_bug.cgi?id=761613
2016-02-19 08:57:56 -05:00
Ray Strode
e097bc8353 wayland: get rid of buffer->copied_data boolean
We currently track whether or not a buffer can be released early
by looking at the copied_data boolean on the buffer.  This boolean
is, practically speaking, always set to TRUE for shm buffers and is
always false otherwise.

We can just as easily check if the buffer is a shm buffer to decide
whether or not to do an early release.  That's better from a
theoretical point of view since copied_data assumes a 1-to-1
relationship between surface and buffer, which may not actually hold.

This commit drops copied_data and changes the check to instead see
if the buffer is shm.

https://bugzilla.gnome.org/show_bug.cgi?id=761613
2016-02-19 08:57:56 -05:00
Olivier Fourdan
4e82a751fb window: check for possible loop in transients
If a broken or naughty application tries set up its windows to create
a loop in the transient relationship, mutter will hang, looping forever
in meta_window_foreach_ancestor()

To avoid looping infinitely at various point in the code, check for a
possible loop when setting the transient relationship and deny the
request to set a window transient for another if that would create a
loop.

Bugzilla: https://bugzilla.gnome.org/show_bug.cgi?id=759299
2016-02-18 09:03:56 +01:00
Ray Strode
acd50508dc wayland: return from toplevel commit early if no new buffer
meta_wayland_surface_toplevel_commit has a lot of logic to handle
a new buffer getting attached as part of the commit.  None of
that code needs to run if there is no new buffer attached.

This commit short-circuits that case.

https://bugzilla.gnome.org/show_bug.cgi?id=761613
2016-02-17 16:16:07 -05:00
Jonas Ådahl
9611661154 native: Don't wait for a new input event to wrap the pointer
If we rely on getting back an input event with the warped pointer
coordinates, we might draw a frame with the old coordinates if we warp
during the paint phase. Avoid that by moving the cursor immediately.

https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:48 +08:00
Jonas Ådahl
a70a2c3744 MetaPointerConfinementWayland: Support non-rectangular confinement regions
This patch adds support for confinement regions that are more complex
than a single rectangle. It relies on details about cairo regions not
explicitly in the API in order to generate the outer border of the
region.

https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:48 +08:00
Jonas Ådahl
bc47b19c3f wayland: Use the event coordinates when sending pointer motion events
The x/y coordinates of the ClutterInputDevice were not the ones which was
the result of this event but whatever event was queued the last. The
correct coordinates can, however, be found in the event itself, so lets
use those.

https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:48 +08:00
Jonas Ådahl
bc1dd1cee4 MetaBorder: Use float constants and functions instead of double variants
We calculate with floats, so lets use that type throughout.

https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:48 +08:00
Jonas Ådahl
495c89401a Implement support for the wp_pointer_constraints protocol
The wp_pointer_constraints protocol is a protocol which enables clients
to manipulate the behavior of the pointer cursor associated with a seat.

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

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

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

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

https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:48 +08:00
Jonas Ådahl
e2efc85b08 wayland: Make the pending surface state a GObject
Making the pending state an GObject makes it easier to extend it with
additional optional state without putting everything inside one big
struct.

https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:48 +08:00
Jonas Ådahl
020ae58fe4 wayland: Add "painting" signal to surface actor
Make MetaWaylandSurface a listener and move output state updating to
the handler function.

https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:48 +08:00
Jonas Ådahl
525644059d native: Update to new constrain callback API
https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:48 +08:00
Jonas Ådahl
f0f638d2bd Move out generic math parts out of the native barrier implementation
In order to reuse some vector math for pointer confinement, move out
those parts to its own file, introducing the types old types
"MetaVector2" and "MetaLine2" outside of meta-barrier-native.c, as well
as introducing MetaBorder which is a line, with a blocking direction.

https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:48 +08:00
Jonas Ådahl
bc8ec2d90d wayland: Add global to surface coordinate helper
https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:47 +08:00
Jonas Ådahl
5b0eabec51 wayland: Implement support for wp_relative_pointer
Add support for sending relative pointer motion deltas to clients who
request such events by creating wp_relative_pointer objects via
wp_relative_pointer_manager.

This currently implements the unstable version 1 from wayland-protocols.

https://bugzilla.gnome.org/show_bug.cgi?id=744104
2016-02-16 19:02:47 +08:00
Ray Strode
50099c4c10 wayland: use glib function for fetching timestamp
The code currently implements a function, get_time, that
fetches a timestamp.  That duplicates code already in glib,
and the glib implementation is better, anyway, since it doesn't
skew backward when the system clock is changed.

This commit changes the code to use g_get_monotonic_time and
drop the get_time function.

https://bugzilla.gnome.org/show_bug.cgi?id=761613
2016-02-08 17:01:58 -05:00
Rui Matos
55eef2deb3 cursor-renderer-native: Re-use cogl's gbm device
Instancing a gbm device without initializing EGL with it means that it
won't be able to import wl_drm buffers. Instead, let's re-use cogl's
gbm device which is already properly initialized.

https://bugzilla.gnome.org/show_bug.cgi?id=761557
2016-02-04 18:22:05 +01:00
Florian Müllner
f9db65f47f theme: Take invisible borders required by the theme into account
GTK+ paints some elements like box shadows (which Adwaita likes to (ab)use
for borders) outside the rectangle passed to gtk_render_*. This is not
an issue if our own invisible frame border is big enough, but in case
of non-resizable windows we end up clipping away part of the decoration.
Use the newly added gtk_render_background_get_clip() to make sure we
always use a mask that is large enough to contain all decorations.

https://bugzilla.gnome.org/show_bug.cgi?id=752794
2016-02-04 15:16:26 +01:00
Florian Müllner
a809055470 theme: Update style context hierarchy (again)
GtkWindow actually uses two CSS nodes, 'window' and 'decoration'.
Simulate that by using two separate style contexts for the frame.
2016-02-04 15:13:23 +01:00
Alberts Muktupāvels
247909e161 frames: don't force dark theme to all windows
Use global theme variant only if window does not have _GTK_THEME_VARIANT
property. This allows applications to request default theme variant when
global dark theme is enabled.

https://bugzilla.gnome.org/show_bug.cgi?id=761543
2016-02-04 16:02:21 +02:00
Alberts Muktupāvels
e5ce6192f4 frames: default theme variant now is set as empty string
Related change in GTK+:
https://git.gnome.org/browse/gtk+/commit/?id=8eb261988869608604c78ed90de5579beb4ef2b0

https://bugzilla.gnome.org/show_bug.cgi?id=761543
2016-02-04 15:54:26 +02:00
Ray Strode
7adbb58736 wayland: don't prematurely release EGL buffers
commit 0165cb6974 changed
mutter to release committed shm buffers as soon as they were
uploaded to the GPU.

It also inadvertently changed mutter to prematurely
release EGL buffers (which never get copied, but get used
directly).

This commit corrects that mistake.

https://bugzilla.gnome.org/show_bug.cgi?id=761312
2016-02-02 11:15:43 -05:00
Ray Strode
0165cb6974 wayland: release buffer after processing commit
When a client is ready for the compositor to read a surface's
shared memory buffer, it tells the compositor via
wl_surface_commit.

From that point forward, the baton is given to the compositor:
it knows it can read the buffer without worring about the client
making changes out from under it.

After the compositor has uploaded the pixel contents to the video
card it is supposed to release the buffer back to the client so that
the client can reuse it for future use.

At the moment, mutter only releases the buffer when a new buffer
is attached.  This is problematic, since it means the client has
to have a second buffer prepared before the compositor gives the
first one back.  Preparing the second buffer potentially involves
copying megabytes of pixel data, so that's suboptimal, and there's
no reason mutter couldn't release the buffer earlier.

This commit changes mutter to release a surface's buffer as soon
as it's done processing the commit request.

https://bugzilla.gnome.org/show_bug.cgi?id=761312
2016-02-01 14:16:17 -05:00
Rui Matos
3cdcd3e9c1 meta-launcher: Use g_auto* macros
This fixes a couple of minor memory leaks.

https://bugzilla.gnome.org/show_bug.cgi?id=760670
2016-01-25 13:59:53 +01:00
Jasper St. Pierre
6fc51e3723 window-x11: Fix checks for a bounding region input region
When cleaning up the logic in commit c408cf7, I forgot to properly apply
de Morgan's laws to an inverse.

Reported by ricotz on IRC.
2016-01-22 18:28:47 -08:00
49 changed files with 4033 additions and 586 deletions

4
.gitignore vendored
View File

@@ -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

View File

@@ -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)
])

View File

@@ -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 \

View File

@@ -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 */

View File

@@ -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)
{

View File

@@ -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;
};

View File

@@ -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 ()))

View File

@@ -0,0 +1,57 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jonas Ådahl <jadahl@gmail.com>
*/
#include "config.h"
#include "backends/meta-pointer-constraint.h"
#include <glib-object.h>
G_DEFINE_TYPE (MetaPointerConstraint, meta_pointer_constraint, G_TYPE_OBJECT);
static void
meta_pointer_constraint_init (MetaPointerConstraint *constraint)
{
}
static void
meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass)
{
}
void
meta_pointer_constraint_constrain (MetaPointerConstraint *constraint,
ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y)
{
META_POINTER_CONSTRAINT_GET_CLASS (constraint)->constrain (constraint,
device,
time,
prev_x, prev_y,
x, y);
}

View File

@@ -0,0 +1,60 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jonas Ådahl <jadahl@gmail.com>
*/
#ifndef META_POINTER_CONSTRAINT_H
#define META_POINTER_CONSTRAINT_H
#include <glib-object.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define META_TYPE_POINTER_CONSTRAINT (meta_pointer_constraint_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaPointerConstraint, meta_pointer_constraint,
META, POINTER_CONSTRAINT, GObject);
struct _MetaPointerConstraintClass
{
GObjectClass parent_class;
void (*constrain) (MetaPointerConstraint *constraint,
ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y);
};
void meta_pointer_constraint_constrain (MetaPointerConstraint *constraint,
ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y);
G_END_DECLS
#endif /* META_POINTER_CONSTRAINT_H */

View File

@@ -36,6 +36,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

View File

@@ -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);

View File

@@ -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 &&

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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
View 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
View 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 */

View File

@@ -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;

View File

@@ -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

View 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 */

View 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;
}

View File

@@ -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);

View File

@@ -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.

View File

@@ -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,

View File

@@ -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],

View 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;
}

View File

@@ -0,0 +1,45 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jonas Ådahl <jadahl@gmail.com>
*/
#ifndef META_POINTER_CONFINEMENT_WAYLAND_H
#define META_POINTER_CONFINEMENT_WAYLAND_H
#include <glib-object.h>
#include "backends/meta-pointer-constraint.h"
#include "wayland/meta-wayland-pointer-constraints.h"
G_BEGIN_DECLS
#define META_TYPE_POINTER_CONFINEMENT_WAYLAND (meta_pointer_confinement_wayland_get_type ())
G_DECLARE_FINAL_TYPE (MetaPointerConfinementWayland,
meta_pointer_confinement_wayland,
META, POINTER_CONFINEMENT_WAYLAND,
MetaPointerConstraint);
MetaPointerConstraint *meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint);
G_END_DECLS
#endif /* META_CONFINEMENT_WAYLAND_H */

View File

@@ -0,0 +1,72 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jonas Ådahl <jadahl@gmail.com>
*/
#include "config.h"
#include "wayland/meta-pointer-lock-wayland.h"
#include <glib-object.h>
#include "backends/meta-pointer-constraint.h"
struct _MetaPointerLockWayland
{
MetaPointerConstraint parent;
};
G_DEFINE_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland,
META_TYPE_POINTER_CONSTRAINT);
static void
meta_pointer_lock_wayland_constrain (MetaPointerConstraint *constraint,
ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y)
{
*x = prev_x;
*y = prev_y;
}
MetaPointerConstraint *
meta_pointer_lock_wayland_new (void)
{
return g_object_new (META_TYPE_POINTER_LOCK_WAYLAND, NULL);
}
static void
meta_pointer_lock_wayland_init (MetaPointerLockWayland *lock_wayland)
{
}
static void
meta_pointer_lock_wayland_class_init (MetaPointerLockWaylandClass *klass)
{
MetaPointerConstraintClass *pointer_constraint_class =
META_POINTER_CONSTRAINT_CLASS (klass);
pointer_constraint_class->constrain = meta_pointer_lock_wayland_constrain;
}

View File

@@ -0,0 +1,42 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jonas Ådahl <jadahl@gmail.com>
*/
#ifndef META_POINTER_LOCK_WAYLAND_H
#define META_POINTER_LOCK_WAYLAND_H
#include <glib-object.h>
#include "backends/meta-pointer-constraint.h"
G_BEGIN_DECLS
#define META_TYPE_POINTER_LOCK_WAYLAND (meta_pointer_lock_wayland_get_type ())
G_DECLARE_FINAL_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland,
META, POINTER_LOCK_WAYLAND, MetaPointerConstraint);
MetaPointerConstraint *meta_pointer_lock_wayland_new (void);
G_END_DECLS
#endif /* META_LOCK_WAYLAND_H */

View File

@@ -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)

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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);

View File

@@ -0,0 +1,818 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jonas Ådahl <jadahl@gmail.com>
*/
#include "config.h"
#include "meta-wayland-pointer-constraints.h"
#include <glib.h>
#include "meta/meta-backend.h"
#include "meta-wayland-private.h"
#include "meta-wayland-seat.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-surface.h"
#include "meta-wayland-region.h"
#include "meta-pointer-lock-wayland.h"
#include "meta-pointer-confinement-wayland.h"
#include "window-private.h"
#include "backends/meta-backend-private.h"
#include "backends/native/meta-backend-native.h"
#include "backends/meta-pointer-constraint.h"
#include "pointer-constraints-unstable-v1-server-protocol.h"
static GQuark quark_pending_constraint_state = 0;
struct _MetaWaylandPointerConstraint
{
GObject parent;
MetaWaylandSurface *surface;
gboolean is_enabled;
cairo_region_t *region;
struct wl_resource *resource;
MetaWaylandPointerGrab grab;
MetaWaylandSeat *seat;
enum zwp_pointer_constraints_v1_lifetime lifetime;
gboolean hint_set;
wl_fixed_t x_hint;
wl_fixed_t y_hint;
MetaPointerConstraint *constraint;
};
typedef struct
{
MetaWaylandPointerConstraint *constraint;
cairo_region_t *region;
gulong applied_handler_id;
} MetaWaylandPendingConstraintState;
typedef struct
{
GList *pending_constraint_states;
} MetaWaylandPendingConstraintStateContainer;
G_DEFINE_TYPE (MetaWaylandPointerConstraint, meta_wayland_pointer_constraint,
G_TYPE_OBJECT);
static const struct zwp_locked_pointer_v1_interface locked_pointer_interface;
static const struct zwp_confined_pointer_v1_interface confined_pointer_interface;
static const MetaWaylandPointerGrabInterface locked_pointer_grab_interface;
static const MetaWaylandPointerGrabInterface confined_pointer_grab_interface;
static cairo_region_t *
create_infinite_constraint_region (void)
{
return cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
.x = INT_MIN / 2,
.y = INT_MIN / 2,
.width = INT_MAX,
.height = INT_MAX,
});
}
static MetaWaylandPointerConstraint *
meta_wayland_pointer_constraint_new (MetaWaylandSurface *surface,
MetaWaylandSeat *seat,
MetaWaylandRegion *region,
enum zwp_pointer_constraints_v1_lifetime lifetime,
struct wl_resource *resource,
const MetaWaylandPointerGrabInterface *grab_interface)
{
MetaWaylandPointerConstraint *constraint;
constraint = g_object_new (META_TYPE_WAYLAND_POINTER_CONSTRAINT, NULL);
if (!constraint)
return NULL;
constraint->surface = surface;
constraint->seat = seat;
constraint->lifetime = lifetime;
constraint->resource = resource;
constraint->grab.interface = grab_interface;
if (region)
{
constraint->region =
cairo_region_copy (meta_wayland_region_peek_cairo_region (region));
}
else
{
constraint->region = create_infinite_constraint_region ();
}
return constraint;
}
static gboolean
meta_wayland_pointer_constraint_is_enabled (MetaWaylandPointerConstraint *constraint)
{
return constraint->is_enabled;
}
static void
meta_wayland_pointer_constraint_notify_activated (MetaWaylandPointerConstraint *constraint)
{
struct wl_resource *resource = constraint->resource;
if (wl_resource_instance_of (resource,
&zwp_locked_pointer_v1_interface,
&locked_pointer_interface))
{
zwp_locked_pointer_v1_send_locked (resource);
}
else if (wl_resource_instance_of (resource,
&zwp_confined_pointer_v1_interface,
&confined_pointer_interface))
{
zwp_confined_pointer_v1_send_confined (resource);
}
}
static void
meta_wayland_pointer_constraint_notify_deactivated (MetaWaylandPointerConstraint *constraint)
{
struct wl_resource *resource = constraint->resource;
if (wl_resource_instance_of (resource,
&zwp_locked_pointer_v1_interface,
&locked_pointer_interface))
zwp_locked_pointer_v1_send_unlocked (resource);
else if (wl_resource_instance_of (resource,
&zwp_confined_pointer_v1_interface,
&confined_pointer_interface))
zwp_confined_pointer_v1_send_unconfined (resource);
}
static MetaPointerConstraint *
meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerConstraint *constraint)
{
struct wl_resource *resource = constraint->resource;
if (wl_resource_instance_of (resource,
&zwp_locked_pointer_v1_interface,
&locked_pointer_interface))
{
return meta_pointer_lock_wayland_new ();
}
else if (wl_resource_instance_of (resource,
&zwp_confined_pointer_v1_interface,
&confined_pointer_interface))
{
return meta_pointer_confinement_wayland_new (constraint);
}
g_assert_not_reached ();
return NULL;
}
static void
meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint)
{
MetaBackend *backend = meta_get_backend ();
g_assert (!constraint->is_enabled);
constraint->is_enabled = TRUE;
meta_wayland_pointer_constraint_notify_activated (constraint);
meta_wayland_pointer_start_grab (&constraint->seat->pointer,
&constraint->grab);
constraint->constraint =
meta_wayland_pointer_constraint_create_pointer_constraint (constraint);
meta_backend_set_client_pointer_constraint (backend, constraint->constraint);
g_object_add_weak_pointer (G_OBJECT (constraint->constraint),
(gpointer *) &constraint->constraint);
g_object_unref (constraint->constraint);
}
static void
meta_wayland_pointer_constraint_disable (MetaWaylandPointerConstraint *constraint)
{
meta_wayland_pointer_constraint_notify_deactivated (constraint);
meta_wayland_pointer_end_grab (constraint->grab.pointer);
meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL);
}
void
meta_wayland_pointer_constraint_destroy (MetaWaylandPointerConstraint *constraint)
{
if (meta_wayland_pointer_constraint_is_enabled (constraint))
meta_wayland_pointer_constraint_disable (constraint);
wl_resource_set_user_data (constraint->resource, NULL);
cairo_region_destroy (constraint->region);
g_object_unref (constraint);
}
static gboolean
is_within_constraint_region (MetaWaylandPointerConstraint *constraint,
wl_fixed_t sx,
wl_fixed_t sy)
{
cairo_region_t *region;
gboolean is_within;
region = meta_wayland_pointer_constraint_calculate_effective_region (constraint);
is_within = cairo_region_contains_point (constraint->region,
wl_fixed_to_int (sx),
wl_fixed_to_int (sy));
cairo_region_destroy (region);
return is_within;
}
void
meta_wayland_pointer_constraint_maybe_enable (MetaWaylandPointerConstraint *constraint)
{
MetaWaylandSeat *seat = constraint->seat;
wl_fixed_t sx, sy;
if (constraint->is_enabled)
return;
if (seat->keyboard.focus_surface != constraint->surface)
return;
meta_wayland_pointer_get_relative_coordinates (&constraint->seat->pointer,
constraint->surface,
&sx, &sy);
if (!is_within_constraint_region (constraint, sx, sy))
return;
meta_wayland_pointer_constraint_enable (constraint);
}
static void
meta_wayland_pointer_constraint_remove (MetaWaylandPointerConstraint *constraint)
{
MetaWaylandSurface *surface = constraint->surface;
meta_wayland_surface_remove_pointer_constraint (surface, constraint);
meta_wayland_pointer_constraint_destroy (constraint);
}
void
meta_wayland_pointer_constraint_maybe_remove_for_seat (MetaWaylandSeat *seat,
MetaWindow *focus_window)
{
MetaWaylandPointer *pointer = &seat->pointer;
if ((pointer->grab->interface == &confined_pointer_grab_interface ||
pointer->grab->interface == &locked_pointer_grab_interface) &&
pointer->focus_surface &&
pointer->focus_surface->window != focus_window)
{
MetaWaylandPointerConstraint *constraint =
wl_container_of (pointer->grab, constraint, grab);
switch (constraint->lifetime)
{
case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT:
meta_wayland_pointer_constraint_remove (constraint);
break;
case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT:
meta_wayland_pointer_constraint_disable (constraint);
break;
default:
g_assert_not_reached ();
}
}
}
void
meta_wayland_pointer_constraint_maybe_enable_for_window (MetaWindow *window)
{
MetaWaylandSurface *surface = window->surface;
GList *it;
for (it = surface->pointer_constraints; it; it = it->next)
{
MetaWaylandPointerConstraint *constraint = it->data;
meta_wayland_pointer_constraint_maybe_enable (constraint);
}
}
MetaWaylandSeat *
meta_wayland_pointer_constraint_get_seat (MetaWaylandPointerConstraint *constraint)
{
return constraint->seat;
}
cairo_region_t *
meta_wayland_pointer_constraint_calculate_effective_region (MetaWaylandPointerConstraint *constraint)
{
cairo_region_t *region;
region = cairo_region_copy (constraint->surface->input_region);
cairo_region_intersect (region, constraint->region);
return region;
}
cairo_region_t *
meta_wayland_pointer_constraint_get_region (MetaWaylandPointerConstraint *constraint)
{
return constraint->region;
}
MetaWaylandSurface *
meta_wayland_pointer_constraint_get_surface (MetaWaylandPointerConstraint *constraint)
{
return constraint->surface;
}
static void
pointer_constraint_resource_destroyed (struct wl_resource *resource)
{
MetaWaylandPointerConstraint *constraint =
wl_resource_get_user_data (resource);
if (!constraint)
return;
meta_wayland_pointer_constraint_remove (constraint);
}
static void
pending_constraint_state_free (MetaWaylandPendingConstraintState *constraint_pending)
{
g_clear_pointer (&constraint_pending->region, cairo_region_destroy);
if (constraint_pending->constraint)
g_object_remove_weak_pointer (G_OBJECT (constraint_pending->constraint),
(gpointer *) &constraint_pending->constraint);
}
static MetaWaylandPendingConstraintStateContainer *
get_pending_constraint_state_container (MetaWaylandPendingState *pending)
{
return g_object_get_qdata (G_OBJECT (pending),
quark_pending_constraint_state);
}
static MetaWaylandPendingConstraintState *
get_pending_constraint_state (MetaWaylandPointerConstraint *constraint)
{
MetaWaylandPendingState *pending = constraint->surface->pending;
MetaWaylandPendingConstraintStateContainer *container;
GList *l;
container = get_pending_constraint_state_container (pending);
for (l = container->pending_constraint_states; l; l = l->next)
{
MetaWaylandPendingConstraintState *constraint_pending = l->data;
if (constraint_pending->constraint == constraint)
return constraint_pending;
}
return NULL;
}
static void
pending_constraint_state_container_free (MetaWaylandPendingConstraintStateContainer *container)
{
g_list_free_full (container->pending_constraint_states,
(GDestroyNotify) pending_constraint_state_free);
g_free (container);
}
static MetaWaylandPendingConstraintStateContainer *
ensure_pending_constraint_state_container (MetaWaylandPendingState *pending)
{
MetaWaylandPendingConstraintStateContainer *container;
container = get_pending_constraint_state_container (pending);
if (!container)
{
container = g_new0 (MetaWaylandPendingConstraintStateContainer, 1);
g_object_set_qdata_full (G_OBJECT (pending),
quark_pending_constraint_state,
container,
(GDestroyNotify) pending_constraint_state_container_free);
}
return container;
}
static void
remove_pending_constraint_state (MetaWaylandPointerConstraint *constraint,
MetaWaylandPendingState *pending)
{
MetaWaylandPendingConstraintStateContainer *container;
GList *l;
container = get_pending_constraint_state_container (pending);
for (l = container->pending_constraint_states; l; l = l->next)
{
MetaWaylandPendingConstraintState *constraint_pending = l->data;
if (constraint_pending->constraint != constraint)
continue;
pending_constraint_state_free (l->data);
container->pending_constraint_states =
g_list_remove_link (container->pending_constraint_states, l);
break;
}
}
static void
pending_constraint_state_applied (MetaWaylandPendingState *pending,
MetaWaylandPendingConstraintState *constraint_pending)
{
MetaWaylandPointerConstraint *constraint = constraint_pending->constraint;
if (!constraint)
return;
g_clear_pointer (&constraint->region, cairo_region_destroy);
if (constraint_pending->region)
{
constraint->region = constraint_pending->region;
constraint_pending->region = NULL;
}
else
{
constraint->region = create_infinite_constraint_region ();
}
g_signal_handler_disconnect (pending,
constraint_pending->applied_handler_id);
remove_pending_constraint_state (constraint, pending);
/* The pointer is potentially warped by the actor paint signal callback if
* the new region proved it necessary.
*/
}
static MetaWaylandPendingConstraintState *
ensure_pending_constraint_state (MetaWaylandPointerConstraint *constraint)
{
MetaWaylandPendingState *pending = constraint->surface->pending;
MetaWaylandPendingConstraintStateContainer *container;
MetaWaylandPendingConstraintState *constraint_pending;
container = ensure_pending_constraint_state_container (pending);
constraint_pending = get_pending_constraint_state (constraint);
if (!constraint_pending)
{
constraint_pending = g_new0 (MetaWaylandPendingConstraintState, 1);
constraint_pending->constraint = constraint;
constraint_pending->applied_handler_id =
g_signal_connect (pending, "applied",
G_CALLBACK (pending_constraint_state_applied),
constraint_pending);
g_object_add_weak_pointer (G_OBJECT (constraint),
(gpointer *) &constraint_pending->constraint);
container->pending_constraint_states =
g_list_append (container->pending_constraint_states,
constraint_pending);
}
return constraint_pending;
}
static void
meta_wayland_pointer_constraint_set_pending_region (MetaWaylandPointerConstraint *constraint,
MetaWaylandRegion *region)
{
MetaWaylandPendingConstraintState *constraint_pending;
constraint_pending = ensure_pending_constraint_state (constraint);
g_clear_pointer (&constraint_pending->region, cairo_region_destroy);
if (region)
{
constraint_pending->region =
cairo_region_copy (meta_wayland_region_peek_cairo_region (region));
}
}
static void
init_pointer_constraint (struct wl_resource *resource,
uint32_t id,
MetaWaylandSurface *surface,
MetaWaylandSeat *seat,
MetaWaylandRegion *region,
enum zwp_pointer_constraints_v1_lifetime lifetime,
const struct wl_interface *interface,
const void *implementation,
const MetaWaylandPointerGrabInterface *grab_interface)
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_resource *cr;
MetaWaylandPointerConstraint *constraint;
if (meta_wayland_surface_get_pointer_constraint_for_seat (surface, seat))
{
wl_resource_post_error (resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"the pointer as already requested to be "
"locked or confined on that surface");
return;
}
cr = wl_resource_create (client, interface,
wl_resource_get_version (resource),
id);
if (cr == NULL)
{
wl_client_post_no_memory (client);
return;
}
constraint = meta_wayland_pointer_constraint_new (surface, seat,
region,
lifetime,
cr, grab_interface);
if (constraint == NULL)
{
wl_client_post_no_memory (client);
return;
}
meta_wayland_surface_add_pointer_constraint (surface, constraint);
wl_resource_set_implementation (cr, implementation, constraint,
pointer_constraint_resource_destroyed);
meta_wayland_pointer_constraint_maybe_enable (constraint);
}
static void
locked_pointer_destroy (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandPointerConstraint *constraint =
wl_resource_get_user_data (resource);
gboolean warp_pointer = FALSE;
int warp_x, warp_y;
if (constraint && constraint->is_enabled && constraint->hint_set &&
is_within_constraint_region (constraint,
constraint->x_hint,
constraint->y_hint))
{
float sx, sy;
float x, y;
sx = (float)wl_fixed_to_double (constraint->x_hint);
sy = (float)wl_fixed_to_double (constraint->y_hint);
meta_wayland_surface_get_absolute_coordinates (constraint->surface,
sx, sy,
&x, &y);
warp_pointer = TRUE;
warp_x = (int) x;
warp_y = (int) y;
}
wl_resource_destroy (resource);
if (warp_pointer)
meta_backend_warp_pointer (meta_get_backend (), warp_x, warp_y);
}
static void
locked_pointer_set_cursor_position_hint (struct wl_client *client,
struct wl_resource *resource,
wl_fixed_t surface_x,
wl_fixed_t surface_y)
{
MetaWaylandPointerConstraint *constraint =
wl_resource_get_user_data (resource);
/* Ignore a set cursor hint that was already sent after the constraint
* was cancelled. */
if (!constraint->resource || constraint->resource != resource)
return;
constraint->hint_set = TRUE;
constraint->x_hint = surface_x;
constraint->y_hint = surface_y;
}
static void
locked_pointer_set_region (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *region_resource)
{
MetaWaylandPointerConstraint *constraint =
wl_resource_get_user_data (resource);
MetaWaylandRegion *region =
region_resource ? wl_resource_get_user_data (region_resource) : NULL;
meta_wayland_pointer_constraint_set_pending_region (constraint, region);
}
static const struct zwp_locked_pointer_v1_interface locked_pointer_interface = {
locked_pointer_destroy,
locked_pointer_set_cursor_position_hint,
locked_pointer_set_region,
};
static void
locked_pointer_grab_pointer_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface)
{
}
static void
locked_pointer_grab_pointer_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
meta_wayland_pointer_send_relative_motion (grab->pointer, event);
}
static void
locked_pointer_grab_pointer_button (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
meta_wayland_pointer_send_button (grab->pointer, event);
}
static const MetaWaylandPointerGrabInterface locked_pointer_grab_interface = {
locked_pointer_grab_pointer_focus,
locked_pointer_grab_pointer_motion,
locked_pointer_grab_pointer_button,
};
static void
pointer_constraints_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
pointer_constraints_lock_pointer (struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource,
struct wl_resource *pointer_resource,
struct wl_resource *region_resource,
uint32_t lifetime)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandPointer *pointer = wl_resource_get_user_data (pointer_resource);
MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
MetaWaylandRegion *region =
region_resource ? wl_resource_get_user_data (region_resource) : NULL;
init_pointer_constraint (resource, id, surface, seat, region, lifetime,
&zwp_locked_pointer_v1_interface,
&locked_pointer_interface,
&locked_pointer_grab_interface);
}
static void
confined_pointer_grab_pointer_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface)
{
}
static void
confined_pointer_grab_pointer_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
MetaWaylandPointerConstraint *constraint =
wl_container_of (grab, constraint, grab);
MetaWaylandPointer *pointer = grab->pointer;
g_assert (pointer->focus_surface);
g_assert (pointer->focus_surface == constraint->surface);
meta_wayland_pointer_send_motion (pointer, event);
}
static void
confined_pointer_grab_pointer_button (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
meta_wayland_pointer_send_button (grab->pointer, event);
}
static const MetaWaylandPointerGrabInterface confined_pointer_grab_interface = {
confined_pointer_grab_pointer_focus,
confined_pointer_grab_pointer_motion,
confined_pointer_grab_pointer_button,
};
static void
confined_pointer_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
confined_pointer_set_region (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *region_resource)
{
MetaWaylandPointerConstraint *constraint =
wl_resource_get_user_data (resource);
MetaWaylandRegion *region =
region_resource ? wl_resource_get_user_data (region_resource) : NULL;
meta_wayland_pointer_constraint_set_pending_region (constraint, region);
}
static const struct zwp_confined_pointer_v1_interface confined_pointer_interface = {
confined_pointer_destroy,
confined_pointer_set_region,
};
static void
pointer_constraints_confine_pointer (struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource,
struct wl_resource *pointer_resource,
struct wl_resource *region_resource,
uint32_t lifetime)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandPointer *pointer = wl_resource_get_user_data (pointer_resource);
MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
MetaWaylandRegion *region =
region_resource ? wl_resource_get_user_data (region_resource) : NULL;
init_pointer_constraint (resource, id, surface, seat, region, lifetime,
&zwp_confined_pointer_v1_interface,
&confined_pointer_interface,
&confined_pointer_grab_interface);
}
static const struct zwp_pointer_constraints_v1_interface pointer_constraints = {
pointer_constraints_destroy,
pointer_constraints_lock_pointer,
pointer_constraints_confine_pointer,
};
static void
bind_pointer_constraints (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
MetaWaylandCompositor *compositor = data;
struct wl_resource *resource;
resource = wl_resource_create (client,
&zwp_pointer_constraints_v1_interface,
1, id);
wl_resource_set_implementation (resource,
&pointer_constraints,
compositor,
NULL);
}
void
meta_wayland_pointer_constraints_init (MetaWaylandCompositor *compositor)
{
if (!wl_global_create (compositor->wayland_display,
&zwp_pointer_constraints_v1_interface, 1,
compositor, bind_pointer_constraints))
g_error ("Could not create wp_pointer_constraints global");
}
static void
meta_wayland_pointer_constraint_init (MetaWaylandPointerConstraint *constraint)
{
}
static void
meta_wayland_pointer_constraint_class_init (MetaWaylandPointerConstraintClass *klass)
{
quark_pending_constraint_state =
g_quark_from_static_string ("-meta-wayland-pointer-constraint-pending_state");
}

View File

@@ -0,0 +1,60 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jonas Ådahl <jadahl@gmail.com>
*/
#ifndef META_WAYLAND_POINTER_CONSTRAINTS_H
#define META_WAYLAND_POINTER_CONSTRAINTS_H
#include "meta-wayland-types.h"
#include "meta/window.h"
#include <wayland-server.h>
#define META_TYPE_WAYLAND_POINTER_CONSTRAINT (meta_wayland_pointer_constraint_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandPointerConstraint,
meta_wayland_pointer_constraint,
META, WAYLAND_POINTER_CONSTRAINT,
GObject);
typedef struct _MetaWaylandPointerConstraint MetaWaylandPointerConstraint;
void meta_wayland_pointer_constraints_init (MetaWaylandCompositor *compositor);
void meta_wayland_pointer_constraint_maybe_enable (MetaWaylandPointerConstraint *constraint);
void meta_wayland_pointer_constraint_destroy (MetaWaylandPointerConstraint *constraint);
MetaWaylandSeat * meta_wayland_pointer_constraint_get_seat (MetaWaylandPointerConstraint *constraint);
cairo_region_t * meta_wayland_pointer_constraint_calculate_effective_region (MetaWaylandPointerConstraint *constraint);
cairo_region_t * meta_wayland_pointer_constraint_get_region (MetaWaylandPointerConstraint *constraint);
MetaWaylandSurface * meta_wayland_pointer_constraint_get_surface (MetaWaylandPointerConstraint *constraint);
void meta_wayland_pointer_constraint_maybe_remove_for_seat (MetaWaylandSeat *seat,
MetaWindow *focus_window);
void meta_wayland_pointer_constraint_maybe_enable_for_window (MetaWindow *window);
#endif /* META_WAYLAND_POINTER_CONSTRAINTS_H */

View File

@@ -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)
{

View File

@@ -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 */

View File

@@ -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, &gtk_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

View File

@@ -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

View File

@@ -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

View File

@@ -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");

View File

@@ -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

View File

@@ -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);

View File

@@ -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"/>

View File

@@ -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 () &&

View File

@@ -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