2013-08-30 16:26:18 +00:00
|
|
|
/*
|
|
|
|
* Wayland Support
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012,2013 Intel Corporation
|
2017-12-20 09:40:22 +00:00
|
|
|
* Copyright (C) 2013-2017 Red Hat, Inc.
|
2013-08-30 16:26:18 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2014-10-08 02:59:01 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "wayland/meta-wayland-surface.h"
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2016-01-28 09:14:06 +00:00
|
|
|
#include <gobject/gvaluecollector.h>
|
2013-08-30 16:26:18 +00:00
|
|
|
#include <wayland-server.h>
|
|
|
|
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "backends/meta-cursor-tracker-private.h"
|
|
|
|
#include "clutter/clutter.h"
|
|
|
|
#include "clutter/wayland/clutter-wayland-compositor.h"
|
|
|
|
#include "clutter/wayland/clutter-wayland-surface.h"
|
|
|
|
#include "cogl/cogl-wayland-server.h"
|
|
|
|
#include "compositor/meta-surface-actor-wayland.h"
|
|
|
|
#include "compositor/meta-surface-actor.h"
|
2018-04-04 08:15:25 +00:00
|
|
|
#include "compositor/meta-window-actor-private.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "compositor/region-utils.h"
|
|
|
|
#include "core/display-private.h"
|
|
|
|
#include "core/window-private.h"
|
2018-11-30 19:35:15 +00:00
|
|
|
#include "wayland/meta-wayland-actor-surface.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "wayland/meta-wayland-buffer.h"
|
|
|
|
#include "wayland/meta-wayland-data-device.h"
|
|
|
|
#include "wayland/meta-wayland-gtk-shell.h"
|
|
|
|
#include "wayland/meta-wayland-keyboard.h"
|
|
|
|
#include "wayland/meta-wayland-legacy-xdg-shell.h"
|
|
|
|
#include "wayland/meta-wayland-outputs.h"
|
|
|
|
#include "wayland/meta-wayland-pointer.h"
|
|
|
|
#include "wayland/meta-wayland-private.h"
|
|
|
|
#include "wayland/meta-wayland-region.h"
|
|
|
|
#include "wayland/meta-wayland-seat.h"
|
|
|
|
#include "wayland/meta-wayland-subsurface.h"
|
|
|
|
#include "wayland/meta-wayland-wl-shell.h"
|
|
|
|
#include "wayland/meta-wayland-xdg-shell.h"
|
|
|
|
#include "wayland/meta-window-wayland.h"
|
|
|
|
#include "wayland/meta-xwayland-private.h"
|
|
|
|
#include "wayland/meta-xwayland-private.h"
|
window-actor: Split into two subclasses of MetaSurfaceActor
The rendering logic before was somewhat complex. We had three independent
cases to take into account when doing rendering:
* X11 compositor. In this case, we're a traditional X11 compositor,
not a Wayland compositor. We use XCompositeNameWindowPixmap to get
the backing pixmap for the window, and deal with the COMPOSITE
extension messiness.
In this case, meta_is_wayland_compositor() is FALSE.
* Wayland clients. In this case, we're a Wayland compositor managing
Wayland surfaces. The rendering for this is fairly straightforward,
as Cogl handles most of the complexity with EGL and SHM buffers...
Wayland clients give us the input and opaque regions through
wl_surface.
In this case, meta_is_wayland_compositor() is TRUE and
priv->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND.
* XWayland clients. In this case, we're a Wayland compositor, like
above, and XWayland hands us Wayland surfaces. XWayland handles
the COMPOSITE extension messiness for us, and hands us a buffer
like any other Wayland client. We have to fetch the input and
opaque regions from the X11 window ourselves.
In this case, meta_is_wayland_compositor() is TRUE and
priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11.
We now split the rendering logic into two subclasses, which are:
* MetaSurfaceActorX11, which handles the X11 compositor case, in that
it uses XCompositeNameWindowPixmap to get the backing pixmap, and
deal with all the COMPOSITE extension messiness.
* MetaSurfaceActorWayland, which handles the Wayland compositor case
for both native Wayland clients and XWayland clients. XWayland handles
COMPOSITE for us, and handles pushing a surface over through the
xf86-video-wayland DDX.
Frame sync is still in MetaWindowActor, as it needs to work for both the
X11 compositor and XWayland client cases. When Wayland's video display
protocol lands, this will need to be significantly overhauled, as it would
have to work for any wl_surface, including subsurfaces, so we would need
surface-level discretion.
https://bugzilla.gnome.org/show_bug.cgi?id=720631
2014-02-01 22:21:11 +00:00
|
|
|
|
2015-06-17 04:10:52 +00:00
|
|
|
enum {
|
|
|
|
PENDING_STATE_SIGNAL_APPLIED,
|
|
|
|
|
|
|
|
PENDING_STATE_SIGNAL_LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
2016-01-28 08:55:42 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
SURFACE_ROLE_PROP_0,
|
|
|
|
|
|
|
|
SURFACE_ROLE_PROP_SURFACE,
|
|
|
|
};
|
|
|
|
|
2015-06-17 04:10:52 +00:00
|
|
|
static guint pending_state_signals[PENDING_STATE_SIGNAL_LAST_SIGNAL];
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
typedef struct _MetaWaylandSurfaceRolePrivate
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface;
|
|
|
|
} MetaWaylandSurfaceRolePrivate;
|
|
|
|
|
2015-07-08 03:21:23 +00:00
|
|
|
G_DEFINE_TYPE (MetaWaylandSurface, meta_wayland_surface, G_TYPE_OBJECT);
|
|
|
|
|
2018-02-23 11:05:05 +00:00
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaWaylandSurfaceRole,
|
|
|
|
meta_wayland_surface_role,
|
|
|
|
G_TYPE_OBJECT)
|
2015-07-08 08:14:00 +00:00
|
|
|
|
2015-12-14 09:13:35 +00:00
|
|
|
G_DEFINE_TYPE (MetaWaylandPendingState,
|
|
|
|
meta_wayland_pending_state,
|
|
|
|
G_TYPE_OBJECT);
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
struct _MetaWaylandSurfaceRoleDND
|
|
|
|
{
|
|
|
|
MetaWaylandSurfaceRole parent;
|
|
|
|
};
|
|
|
|
|
2018-11-30 19:35:15 +00:00
|
|
|
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleDND,
|
|
|
|
meta_wayland_surface_role_dnd,
|
|
|
|
META, WAYLAND_SURFACE_ROLE_DND,
|
|
|
|
MetaWaylandActorSurface);
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
G_DEFINE_TYPE (MetaWaylandSurfaceRoleDND,
|
|
|
|
meta_wayland_surface_role_dnd,
|
2018-11-30 19:35:15 +00:00
|
|
|
META_TYPE_WAYLAND_ACTOR_SURFACE);
|
2015-07-08 08:14:00 +00:00
|
|
|
|
2015-10-22 12:07:52 +00:00
|
|
|
enum {
|
|
|
|
SURFACE_DESTROY,
|
2016-08-18 04:57:17 +00:00
|
|
|
SURFACE_UNMAPPED,
|
2016-06-28 06:56:20 +00:00
|
|
|
SURFACE_CONFIGURE,
|
2017-03-17 12:34:52 +00:00
|
|
|
SURFACE_SHORTCUTS_INHIBITED,
|
|
|
|
SURFACE_SHORTCUTS_RESTORED,
|
2018-04-06 10:35:34 +00:00
|
|
|
SURFACE_GEOMETRY_CHANGED,
|
2015-10-22 12:07:52 +00:00
|
|
|
N_SURFACE_SIGNALS
|
|
|
|
};
|
|
|
|
|
|
|
|
guint surface_signals[N_SURFACE_SIGNALS] = { 0 };
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role);
|
|
|
|
|
2016-03-16 06:55:51 +00:00
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_pre_commit (MetaWaylandSurfaceRole *surface_role,
|
|
|
|
MetaWaylandPendingState *pending);
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
|
|
|
|
MetaWaylandPendingState *pending);
|
|
|
|
|
|
|
|
static gboolean
|
2016-11-25 06:38:28 +00:00
|
|
|
meta_wayland_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *surface_role,
|
|
|
|
MetaLogicalMonitor *logical_monitor);
|
2015-07-08 08:14:00 +00:00
|
|
|
|
2016-01-14 09:43:47 +00:00
|
|
|
static MetaWaylandSurface *
|
|
|
|
meta_wayland_surface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role);
|
|
|
|
|
2017-10-06 12:53:16 +00:00
|
|
|
static void
|
|
|
|
window_position_changed (MetaWindow *window,
|
|
|
|
MetaWaylandSurface *surface);
|
2018-04-04 08:15:25 +00:00
|
|
|
static void
|
|
|
|
window_actor_effects_completed (MetaWindowActor *window_actor,
|
|
|
|
MetaWaylandSurface *surface);
|
2016-12-13 10:32:16 +00:00
|
|
|
|
2016-01-28 09:14:06 +00:00
|
|
|
static void
|
2017-12-13 04:57:08 +00:00
|
|
|
role_assignment_valist_to_properties (GType role_type,
|
|
|
|
const char *first_property_name,
|
|
|
|
va_list var_args,
|
|
|
|
GArray *names,
|
|
|
|
GArray *values)
|
2016-01-28 09:14:06 +00:00
|
|
|
{
|
|
|
|
GObjectClass *object_class;
|
|
|
|
const char *property_name = first_property_name;
|
|
|
|
|
|
|
|
object_class = g_type_class_ref (role_type);
|
|
|
|
|
|
|
|
while (property_name)
|
|
|
|
{
|
2017-12-13 04:57:08 +00:00
|
|
|
GValue value = G_VALUE_INIT;
|
2016-01-28 09:14:06 +00:00
|
|
|
GParamSpec *pspec;
|
|
|
|
GType ptype;
|
|
|
|
gchar *error = NULL;
|
|
|
|
|
|
|
|
pspec = g_object_class_find_property (object_class,
|
|
|
|
property_name);
|
|
|
|
g_assert (pspec);
|
|
|
|
|
|
|
|
ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
|
2017-12-13 04:57:08 +00:00
|
|
|
G_VALUE_COLLECT_INIT (&value, ptype, var_args, 0, &error);
|
2016-01-28 09:14:06 +00:00
|
|
|
g_assert (!error);
|
|
|
|
|
2017-12-13 04:57:08 +00:00
|
|
|
g_array_append_val (names, property_name);
|
|
|
|
g_array_append_val (values, value);
|
2016-01-28 09:14:06 +00:00
|
|
|
|
|
|
|
property_name = va_arg (var_args, const char *);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_type_class_unref (object_class);
|
|
|
|
}
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
gboolean
|
|
|
|
meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
|
2016-01-28 09:14:06 +00:00
|
|
|
GType role_type,
|
|
|
|
const char *first_property_name,
|
|
|
|
...)
|
2015-07-08 08:14:00 +00:00
|
|
|
{
|
2016-01-28 09:14:06 +00:00
|
|
|
va_list var_args;
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
if (!surface->role)
|
2015-02-06 08:12:21 +00:00
|
|
|
{
|
2016-01-28 09:14:06 +00:00
|
|
|
if (first_property_name)
|
|
|
|
{
|
2017-12-13 04:57:08 +00:00
|
|
|
GArray *names;
|
|
|
|
GArray *values;
|
|
|
|
const char *surface_prop_name;
|
|
|
|
GValue surface_value = G_VALUE_INIT;
|
|
|
|
GObject *role_object;
|
|
|
|
|
|
|
|
names = g_array_new (FALSE, FALSE, sizeof (const char *));
|
|
|
|
values = g_array_new (FALSE, FALSE, sizeof (GValue));
|
|
|
|
g_array_set_clear_func (values, (GDestroyNotify) g_value_unset);
|
2016-01-28 09:14:06 +00:00
|
|
|
|
|
|
|
va_start (var_args, first_property_name);
|
2017-12-13 04:57:08 +00:00
|
|
|
role_assignment_valist_to_properties (role_type,
|
|
|
|
first_property_name,
|
|
|
|
var_args,
|
|
|
|
names,
|
|
|
|
values);
|
2016-01-28 09:14:06 +00:00
|
|
|
va_end (var_args);
|
|
|
|
|
2017-12-13 04:57:08 +00:00
|
|
|
surface_prop_name = "surface";
|
|
|
|
g_value_init (&surface_value, META_TYPE_WAYLAND_SURFACE);
|
|
|
|
g_value_set_object (&surface_value, surface);
|
|
|
|
g_array_append_val (names, surface_prop_name);
|
|
|
|
g_array_append_val (values, surface_value);
|
|
|
|
|
|
|
|
role_object =
|
|
|
|
g_object_new_with_properties (role_type,
|
|
|
|
values->len,
|
|
|
|
(const char **) names->data,
|
|
|
|
(const GValue *) values->data);
|
|
|
|
surface->role = META_WAYLAND_SURFACE_ROLE (role_object);
|
|
|
|
|
|
|
|
g_array_free (names, FALSE);
|
|
|
|
g_array_free (values, TRUE);
|
2016-01-28 09:14:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
surface->role = g_object_new (role_type, "surface", surface, NULL);
|
|
|
|
}
|
2015-07-08 08:14:00 +00:00
|
|
|
|
|
|
|
meta_wayland_surface_role_assigned (surface->role);
|
2015-08-19 03:06:46 +00:00
|
|
|
|
2016-03-16 06:55:51 +00:00
|
|
|
/* Release the use count held on behalf of the just assigned role. */
|
|
|
|
if (surface->unassigned.buffer)
|
|
|
|
{
|
|
|
|
meta_wayland_surface_unref_buffer_use_count (surface);
|
|
|
|
g_clear_object (&surface->unassigned.buffer);
|
|
|
|
}
|
|
|
|
|
2015-08-28 04:15:21 +00:00
|
|
|
return TRUE;
|
2015-02-06 08:12:21 +00:00
|
|
|
}
|
2015-07-08 08:14:00 +00:00
|
|
|
else if (G_OBJECT_TYPE (surface->role) != role_type)
|
2015-02-06 08:12:21 +00:00
|
|
|
{
|
2015-08-28 04:15:21 +00:00
|
|
|
return FALSE;
|
2015-02-06 08:12:21 +00:00
|
|
|
}
|
2015-07-08 08:14:00 +00:00
|
|
|
else
|
|
|
|
{
|
2016-01-28 09:14:06 +00:00
|
|
|
va_start (var_args, first_property_name);
|
|
|
|
g_object_set_valist (G_OBJECT (surface->role),
|
|
|
|
first_property_name, var_args);
|
|
|
|
va_end (var_args);
|
|
|
|
|
2016-07-01 07:30:21 +00:00
|
|
|
meta_wayland_surface_role_assigned (surface->role);
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2015-02-06 08:12:21 +00:00
|
|
|
}
|
|
|
|
|
2018-11-26 18:40:57 +00:00
|
|
|
static int
|
|
|
|
get_buffer_width (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
|
|
|
|
|
|
|
|
if (buffer)
|
|
|
|
{
|
|
|
|
CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
|
|
|
|
return cogl_texture_get_width (texture);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_buffer_height (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
|
|
|
|
|
|
|
|
if (buffer)
|
|
|
|
{
|
|
|
|
CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
|
|
|
|
return cogl_texture_get_height (texture);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
static void
|
|
|
|
surface_process_damage (MetaWaylandSurface *surface,
|
2017-06-05 12:08:04 +00:00
|
|
|
cairo_region_t *surface_region,
|
|
|
|
cairo_region_t *buffer_region)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2018-11-26 18:40:57 +00:00
|
|
|
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
|
2015-03-20 07:09:37 +00:00
|
|
|
cairo_rectangle_int_t surface_rect;
|
2015-03-03 03:07:36 +00:00
|
|
|
cairo_region_t *scaled_region;
|
2018-11-26 18:40:57 +00:00
|
|
|
cairo_region_t *transformed_region;
|
2014-10-08 02:48:49 +00:00
|
|
|
int i, n_rectangles;
|
2014-04-23 20:14:31 +00:00
|
|
|
|
2016-03-16 06:47:53 +00:00
|
|
|
/* If the client destroyed the buffer it attached before committing, but
|
|
|
|
* still posted damage, or posted damage without any buffer, don't try to
|
|
|
|
* process it on the non-existing buffer.
|
|
|
|
*/
|
|
|
|
if (!buffer)
|
2014-04-27 14:18:09 +00:00
|
|
|
return;
|
|
|
|
|
2015-03-20 07:09:37 +00:00
|
|
|
/* Intersect the damage region with the surface region before scaling in
|
|
|
|
* order to avoid integer overflow when scaling a damage region is too large
|
|
|
|
* (for example INT32_MAX which mesa passes). */
|
|
|
|
surface_rect = (cairo_rectangle_int_t) {
|
2018-06-29 15:53:21 +00:00
|
|
|
.width = meta_wayland_surface_get_width (surface),
|
|
|
|
.height = meta_wayland_surface_get_height (surface),
|
2015-03-20 07:09:37 +00:00
|
|
|
};
|
2017-06-05 12:08:04 +00:00
|
|
|
cairo_region_intersect_rectangle (surface_region, &surface_rect);
|
2014-04-23 20:14:31 +00:00
|
|
|
|
2015-03-03 03:07:36 +00:00
|
|
|
/* The damage region must be in the same coordinate space as the buffer,
|
|
|
|
* i.e. scaled with surface->scale. */
|
2017-06-05 12:08:04 +00:00
|
|
|
scaled_region = meta_region_scale (surface_region, surface->scale);
|
2018-11-26 18:40:57 +00:00
|
|
|
transformed_region = meta_region_transform (scaled_region,
|
|
|
|
surface->buffer_transform,
|
|
|
|
get_buffer_width (surface),
|
|
|
|
get_buffer_height (surface));
|
2017-06-05 12:08:04 +00:00
|
|
|
|
|
|
|
/* Now add the buffer damage on top of the scaled damage region, as buffer
|
|
|
|
* damage is already in that scale. */
|
2018-11-26 18:40:57 +00:00
|
|
|
cairo_region_union (transformed_region, buffer_region);
|
2015-03-03 03:07:36 +00:00
|
|
|
|
2014-10-08 02:48:49 +00:00
|
|
|
/* First update the buffer. */
|
2018-11-26 18:40:57 +00:00
|
|
|
meta_wayland_buffer_process_damage (buffer, transformed_region);
|
2014-08-21 20:19:23 +00:00
|
|
|
|
2015-03-03 03:07:36 +00:00
|
|
|
/* Now damage the actor. The actor expects damage in the unscaled texture
|
|
|
|
* coordinate space, i.e. same as the buffer. */
|
2014-10-08 02:48:49 +00:00
|
|
|
/* XXX: Should this be a signal / callback on MetaWaylandBuffer instead? */
|
2018-11-26 18:40:57 +00:00
|
|
|
n_rectangles = cairo_region_num_rectangles (transformed_region);
|
2013-11-25 22:40:21 +00:00
|
|
|
for (i = 0; i < n_rectangles; i++)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2013-11-25 22:40:21 +00:00
|
|
|
cairo_rectangle_int_t rect;
|
2018-11-26 18:40:57 +00:00
|
|
|
cairo_region_get_rectangle (transformed_region, i, &rect);
|
2014-08-21 20:19:23 +00:00
|
|
|
|
2018-04-06 11:27:52 +00:00
|
|
|
meta_surface_actor_process_damage (meta_wayland_surface_get_actor (surface),
|
2015-03-03 03:07:36 +00:00
|
|
|
rect.x, rect.y,
|
|
|
|
rect.width, rect.height);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
2015-03-03 03:07:36 +00:00
|
|
|
|
|
|
|
cairo_region_destroy (scaled_region);
|
2018-11-26 18:40:57 +00:00
|
|
|
cairo_region_destroy (transformed_region);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
void
|
|
|
|
meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandPendingState *pending)
|
|
|
|
{
|
|
|
|
wl_list_insert_list (&surface->compositor->frame_callbacks,
|
|
|
|
&pending->frame_callback_list);
|
|
|
|
wl_list_init (&pending->frame_callback_list);
|
|
|
|
}
|
|
|
|
|
2014-10-06 15:07:43 +00:00
|
|
|
static void
|
2015-07-08 08:14:00 +00:00
|
|
|
dnd_surface_commit (MetaWaylandSurfaceRole *surface_role,
|
2014-10-06 15:07:43 +00:00
|
|
|
MetaWaylandPendingState *pending)
|
|
|
|
{
|
2015-07-08 08:14:00 +00:00
|
|
|
MetaWaylandSurface *surface =
|
|
|
|
meta_wayland_surface_role_get_surface (surface_role);
|
|
|
|
|
|
|
|
meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
|
2014-10-06 15:07:43 +00:00
|
|
|
}
|
|
|
|
|
2015-12-15 04:51:24 +00:00
|
|
|
void
|
|
|
|
meta_wayland_surface_destroy_window (MetaWaylandSurface *surface)
|
2015-04-25 01:13:44 +00:00
|
|
|
{
|
|
|
|
if (surface->window)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_get_display ();
|
|
|
|
guint32 timestamp = meta_display_get_current_time_roundtrip (display);
|
|
|
|
|
|
|
|
meta_window_unmanage (surface->window, timestamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert (surface->window == NULL);
|
|
|
|
}
|
|
|
|
|
2016-03-16 06:47:53 +00:00
|
|
|
MetaWaylandBuffer *
|
|
|
|
meta_wayland_surface_get_buffer (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
return surface->buffer_ref.buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_ref_buffer_use_count (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
g_return_if_fail (surface->buffer_ref.buffer);
|
|
|
|
g_warn_if_fail (surface->buffer_ref.buffer->resource);
|
|
|
|
|
|
|
|
surface->buffer_ref.use_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
MetaWaylandBuffer *buffer = surface->buffer_ref.buffer;
|
|
|
|
|
|
|
|
g_return_if_fail (surface->buffer_ref.use_count != 0);
|
|
|
|
|
|
|
|
surface->buffer_ref.use_count--;
|
|
|
|
|
|
|
|
g_return_if_fail (buffer);
|
|
|
|
|
|
|
|
if (surface->buffer_ref.use_count == 0 && buffer->resource)
|
2017-09-26 15:28:44 +00:00
|
|
|
wl_buffer_send_release (buffer->resource);
|
2016-03-16 06:47:53 +00:00
|
|
|
}
|
|
|
|
|
2014-01-13 22:31:25 +00:00
|
|
|
static void
|
2016-03-15 04:46:06 +00:00
|
|
|
pending_buffer_resource_destroyed (MetaWaylandBuffer *buffer,
|
|
|
|
MetaWaylandPendingState *pending)
|
2014-01-13 22:31:25 +00:00
|
|
|
{
|
2016-03-15 04:46:06 +00:00
|
|
|
g_signal_handler_disconnect (buffer, pending->buffer_destroy_handler_id);
|
|
|
|
pending->buffer = NULL;
|
2014-01-13 22:31:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-04-18 22:07:05 +00:00
|
|
|
pending_state_init (MetaWaylandPendingState *state)
|
2014-01-13 22:31:25 +00:00
|
|
|
{
|
|
|
|
state->newly_attached = FALSE;
|
|
|
|
state->buffer = NULL;
|
2018-04-06 15:50:31 +00:00
|
|
|
state->buffer_destroy_handler_id = 0;
|
2014-01-13 22:31:25 +00:00
|
|
|
state->dx = 0;
|
|
|
|
state->dy = 0;
|
2014-04-26 08:27:34 +00:00
|
|
|
state->scale = 0;
|
2014-01-13 22:31:25 +00:00
|
|
|
|
2014-04-18 22:19:02 +00:00
|
|
|
state->input_region = NULL;
|
2015-08-04 06:58:26 +00:00
|
|
|
state->input_region_set = FALSE;
|
2014-04-18 22:19:02 +00:00
|
|
|
state->opaque_region = NULL;
|
2015-08-04 06:58:26 +00:00
|
|
|
state->opaque_region_set = FALSE;
|
2014-04-18 22:19:02 +00:00
|
|
|
|
2017-06-05 12:08:04 +00:00
|
|
|
state->surface_damage = cairo_region_create ();
|
|
|
|
state->buffer_damage = cairo_region_create ();
|
2014-01-13 22:31:25 +00:00
|
|
|
wl_list_init (&state->frame_callback_list);
|
2014-02-09 23:23:07 +00:00
|
|
|
|
2014-07-17 18:07:38 +00:00
|
|
|
state->has_new_geometry = FALSE;
|
2016-04-06 12:07:08 +00:00
|
|
|
state->has_new_min_size = FALSE;
|
|
|
|
state->has_new_max_size = FALSE;
|
2018-11-26 18:40:57 +00:00
|
|
|
|
|
|
|
state->has_new_buffer_transform = FALSE;
|
2014-01-13 22:31:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-04-18 22:07:05 +00:00
|
|
|
pending_state_destroy (MetaWaylandPendingState *state)
|
2014-01-13 22:31:25 +00:00
|
|
|
{
|
|
|
|
MetaWaylandFrameCallback *cb, *next;
|
|
|
|
|
2017-06-05 12:08:04 +00:00
|
|
|
g_clear_pointer (&state->surface_damage, cairo_region_destroy);
|
|
|
|
g_clear_pointer (&state->buffer_damage, cairo_region_destroy);
|
2014-01-13 22:31:25 +00:00
|
|
|
g_clear_pointer (&state->input_region, cairo_region_destroy);
|
|
|
|
g_clear_pointer (&state->opaque_region, cairo_region_destroy);
|
|
|
|
|
|
|
|
if (state->buffer)
|
2018-04-06 15:50:31 +00:00
|
|
|
{
|
|
|
|
g_signal_handler_disconnect (state->buffer,
|
|
|
|
state->buffer_destroy_handler_id);
|
|
|
|
state->buffer_destroy_handler_id = 0;
|
|
|
|
}
|
2014-01-13 22:31:25 +00:00
|
|
|
wl_list_for_each_safe (cb, next, &state->frame_callback_list, link)
|
|
|
|
wl_resource_destroy (cb->resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-04-18 22:07:05 +00:00
|
|
|
pending_state_reset (MetaWaylandPendingState *state)
|
2014-01-13 22:31:25 +00:00
|
|
|
{
|
2014-04-18 22:07:05 +00:00
|
|
|
pending_state_destroy (state);
|
|
|
|
pending_state_init (state);
|
2014-01-13 22:31:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-04-06 15:50:31 +00:00
|
|
|
merge_pending_state (MetaWaylandPendingState *from,
|
|
|
|
MetaWaylandPendingState *to)
|
2014-01-13 22:31:25 +00:00
|
|
|
{
|
2018-04-06 15:50:31 +00:00
|
|
|
if (from->newly_attached)
|
|
|
|
{
|
|
|
|
if (to->buffer)
|
|
|
|
{
|
|
|
|
g_signal_handler_disconnect (to->buffer,
|
|
|
|
to->buffer_destroy_handler_id);
|
|
|
|
to->buffer_destroy_handler_id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (from->buffer)
|
|
|
|
{
|
|
|
|
g_signal_handler_disconnect (from->buffer,
|
|
|
|
from->buffer_destroy_handler_id);
|
|
|
|
from->buffer_destroy_handler_id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
to->newly_attached = TRUE;
|
|
|
|
to->buffer = from->buffer;
|
|
|
|
to->dx = from->dx;
|
|
|
|
to->dy = from->dy;
|
|
|
|
}
|
2014-01-13 22:31:25 +00:00
|
|
|
|
2015-01-29 07:43:01 +00:00
|
|
|
wl_list_insert_list (&to->frame_callback_list, &from->frame_callback_list);
|
|
|
|
|
2018-04-06 15:50:31 +00:00
|
|
|
cairo_region_union (to->surface_damage, from->surface_damage);
|
|
|
|
cairo_region_union (to->buffer_damage, from->buffer_damage);
|
|
|
|
cairo_region_destroy (from->surface_damage);
|
|
|
|
cairo_region_destroy (from->buffer_damage);
|
|
|
|
|
|
|
|
if (from->input_region_set)
|
|
|
|
{
|
|
|
|
if (to->input_region)
|
|
|
|
cairo_region_union (to->input_region, from->input_region);
|
|
|
|
else
|
|
|
|
to->input_region = cairo_region_reference (from->input_region);
|
|
|
|
|
|
|
|
to->input_region_set = TRUE;
|
|
|
|
cairo_region_destroy (from->input_region);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (from->opaque_region_set)
|
|
|
|
{
|
|
|
|
if (to->opaque_region)
|
|
|
|
cairo_region_union (to->opaque_region, from->opaque_region);
|
|
|
|
else
|
|
|
|
to->opaque_region = cairo_region_reference (from->opaque_region);
|
|
|
|
|
|
|
|
to->opaque_region_set = TRUE;
|
|
|
|
cairo_region_destroy (from->opaque_region);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (from->has_new_geometry)
|
|
|
|
{
|
|
|
|
to->new_geometry = from->new_geometry;
|
|
|
|
to->has_new_geometry = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (from->has_new_min_size)
|
|
|
|
{
|
|
|
|
to->new_min_width = from->new_min_width;
|
|
|
|
to->new_min_height = from->new_min_height;
|
|
|
|
to->has_new_min_size = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (from->has_new_max_size)
|
|
|
|
{
|
|
|
|
to->new_max_width = from->new_max_width;
|
|
|
|
to->new_max_height = from->new_max_height;
|
|
|
|
to->has_new_max_size = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (from->scale > 0)
|
|
|
|
to->scale = from->scale;
|
|
|
|
|
2018-11-26 18:40:57 +00:00
|
|
|
if (from->has_new_buffer_transform)
|
|
|
|
{
|
|
|
|
to->buffer_transform = from->buffer_transform;
|
|
|
|
to->has_new_buffer_transform = TRUE;
|
|
|
|
}
|
|
|
|
|
2018-04-06 15:50:31 +00:00
|
|
|
if (to->buffer && to->buffer_destroy_handler_id == 0)
|
2016-03-15 04:46:06 +00:00
|
|
|
{
|
|
|
|
to->buffer_destroy_handler_id =
|
|
|
|
g_signal_connect (to->buffer, "resource-destroyed",
|
|
|
|
G_CALLBACK (pending_buffer_resource_destroyed),
|
|
|
|
to);
|
|
|
|
}
|
2014-01-13 22:31:25 +00:00
|
|
|
|
2014-04-18 22:19:02 +00:00
|
|
|
pending_state_init (from);
|
2014-01-13 22:31:25 +00:00
|
|
|
}
|
|
|
|
|
2015-12-14 09:13:35 +00:00
|
|
|
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;
|
2015-06-17 04:10:52 +00:00
|
|
|
|
|
|
|
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);
|
2015-12-14 09:13:35 +00:00
|
|
|
}
|
|
|
|
|
2015-01-26 08:46:20 +00:00
|
|
|
/* A non-subsurface is always desynchronized.
|
|
|
|
*
|
|
|
|
* A subsurface is effectively synchronized if either its parent is
|
|
|
|
* synchronized or itself is in synchronized mode. */
|
2017-12-20 09:40:22 +00:00
|
|
|
gboolean
|
|
|
|
meta_wayland_surface_is_effectively_synchronized (MetaWaylandSurface *surface)
|
2015-01-26 08:46:20 +00:00
|
|
|
{
|
|
|
|
if (surface->wl_subsurface == NULL)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (surface->sub.synchronous)
|
2017-12-20 09:40:22 +00:00
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
2015-01-26 08:46:20 +00:00
|
|
|
else
|
2017-12-20 09:40:22 +00:00
|
|
|
{
|
|
|
|
MetaWaylandSurface *parent = surface->sub.parent;
|
|
|
|
|
2018-05-03 07:17:24 +00:00
|
|
|
if (parent)
|
|
|
|
return meta_wayland_surface_is_effectively_synchronized (parent);
|
|
|
|
|
|
|
|
return TRUE;
|
2017-12-20 09:40:22 +00:00
|
|
|
}
|
2015-01-26 08:46:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-12 22:17:29 +00:00
|
|
|
static void
|
2017-12-20 09:40:22 +00:00
|
|
|
parent_surface_state_applied (gpointer data,
|
|
|
|
gpointer user_data)
|
2014-01-13 22:31:25 +00:00
|
|
|
{
|
2015-01-26 08:46:20 +00:00
|
|
|
MetaWaylandSurface *surface = data;
|
2017-12-20 09:40:22 +00:00
|
|
|
MetaWaylandSubsurface *subsurface = META_WAYLAND_SUBSURFACE (surface->role);
|
2015-01-26 08:46:20 +00:00
|
|
|
|
2017-12-20 09:40:22 +00:00
|
|
|
meta_wayland_subsurface_parent_state_applied (subsurface);
|
2014-01-13 22:31:25 +00:00
|
|
|
}
|
2014-01-12 22:17:29 +00:00
|
|
|
|
2018-08-27 10:05:58 +00:00
|
|
|
void
|
|
|
|
meta_wayland_surface_cache_pending_frame_callbacks (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandPendingState *pending)
|
|
|
|
{
|
|
|
|
wl_list_insert_list (&surface->pending_frame_callback_list,
|
|
|
|
&pending->frame_callback_list);
|
|
|
|
wl_list_init (&pending->frame_callback_list);
|
|
|
|
}
|
|
|
|
|
2017-12-20 09:40:22 +00:00
|
|
|
void
|
|
|
|
meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandPendingState *pending)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2016-03-16 06:55:51 +00:00
|
|
|
if (surface->role)
|
|
|
|
{
|
|
|
|
meta_wayland_surface_role_pre_commit (surface->role, pending);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (pending->newly_attached && surface->unassigned.buffer)
|
|
|
|
{
|
|
|
|
meta_wayland_surface_unref_buffer_use_count (surface);
|
|
|
|
g_clear_object (&surface->unassigned.buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-12 06:29:05 +00:00
|
|
|
if (pending->newly_attached)
|
2014-04-18 19:41:48 +00:00
|
|
|
{
|
2016-03-16 06:47:53 +00:00
|
|
|
gboolean switched_buffer;
|
|
|
|
|
|
|
|
if (!surface->buffer_ref.buffer && surface->window)
|
2015-06-08 09:59:42 +00:00
|
|
|
meta_window_queue (surface->window, META_QUEUE_CALC_SHOWING);
|
|
|
|
|
2016-03-16 06:47:53 +00:00
|
|
|
/* Always release any previously held buffer. If the buffer held is same
|
|
|
|
* as the newly attached buffer, we still need to release it here, because
|
|
|
|
* wl_surface.attach+commit and wl_buffer.release on the attached buffer
|
|
|
|
* is symmetric.
|
|
|
|
*/
|
|
|
|
if (surface->buffer_held)
|
|
|
|
meta_wayland_surface_unref_buffer_use_count (surface);
|
|
|
|
|
|
|
|
switched_buffer = g_set_object (&surface->buffer_ref.buffer,
|
|
|
|
pending->buffer);
|
2014-04-18 19:41:48 +00:00
|
|
|
|
2016-03-16 06:47:53 +00:00
|
|
|
if (pending->buffer)
|
|
|
|
meta_wayland_surface_ref_buffer_use_count (surface);
|
2016-02-08 21:07:34 +00:00
|
|
|
|
2016-10-20 07:35:29 +00:00
|
|
|
if (pending->buffer)
|
2016-03-16 06:47:53 +00:00
|
|
|
{
|
2016-10-20 07:35:29 +00:00
|
|
|
GError *error = NULL;
|
2016-02-08 21:07:34 +00:00
|
|
|
|
2016-10-20 07:35:29 +00:00
|
|
|
if (!meta_wayland_buffer_attach (pending->buffer, &error))
|
2016-08-26 07:41:59 +00:00
|
|
|
{
|
2016-10-20 07:35:29 +00:00
|
|
|
g_warning ("Could not import pending buffer: %s", error->message);
|
2016-08-26 07:41:59 +00:00
|
|
|
wl_resource_post_error (surface->resource, WL_DISPLAY_ERROR_NO_MEMORY,
|
2016-10-20 07:35:29 +00:00
|
|
|
"Failed to create a texture for surface %i: %s",
|
|
|
|
wl_resource_get_id (surface->resource),
|
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
2016-08-26 07:41:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2016-10-20 07:35:29 +00:00
|
|
|
|
2018-04-06 13:53:12 +00:00
|
|
|
if (switched_buffer && meta_wayland_surface_get_actor (surface))
|
2016-10-20 07:35:29 +00:00
|
|
|
{
|
2016-10-20 07:44:27 +00:00
|
|
|
MetaShapedTexture *stex;
|
2016-10-20 07:35:29 +00:00
|
|
|
CoglTexture *texture;
|
2016-10-20 07:59:09 +00:00
|
|
|
CoglSnippet *snippet;
|
2016-10-20 07:44:27 +00:00
|
|
|
gboolean is_y_inverted;
|
2016-10-20 07:35:29 +00:00
|
|
|
|
2018-04-06 11:27:52 +00:00
|
|
|
stex = meta_surface_actor_get_texture (meta_wayland_surface_get_actor (surface));
|
2016-10-20 07:35:29 +00:00
|
|
|
texture = meta_wayland_buffer_get_texture (pending->buffer);
|
2016-10-20 07:59:09 +00:00
|
|
|
snippet = meta_wayland_buffer_create_snippet (pending->buffer);
|
2016-10-20 07:44:27 +00:00
|
|
|
is_y_inverted = meta_wayland_buffer_is_y_inverted (pending->buffer);
|
|
|
|
|
|
|
|
meta_shaped_texture_set_texture (stex, texture);
|
2016-10-20 07:59:09 +00:00
|
|
|
meta_shaped_texture_set_snippet (stex, snippet);
|
2016-10-20 07:44:27 +00:00
|
|
|
meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted);
|
2016-10-20 07:59:09 +00:00
|
|
|
g_clear_pointer (&snippet, cogl_object_unref);
|
2016-10-20 07:35:29 +00:00
|
|
|
}
|
2014-04-18 19:41:48 +00:00
|
|
|
}
|
2016-03-16 06:47:53 +00:00
|
|
|
|
|
|
|
/* If the newly attached buffer is going to be accessed directly without
|
|
|
|
* making a copy, such as an EGL buffer, mark it as in-use don't release
|
|
|
|
* it until is replaced by a subsequent wl_surface.commit or when the
|
|
|
|
* wl_surface is destroyed.
|
|
|
|
*/
|
|
|
|
surface->buffer_held = (pending->buffer &&
|
|
|
|
!wl_shm_buffer_get (pending->buffer->resource));
|
2014-04-18 19:41:48 +00:00
|
|
|
}
|
|
|
|
|
2014-04-26 08:27:34 +00:00
|
|
|
if (pending->scale > 0)
|
2014-10-25 10:26:19 +00:00
|
|
|
surface->scale = pending->scale;
|
2014-04-26 08:27:34 +00:00
|
|
|
|
2018-11-26 18:40:57 +00:00
|
|
|
if (pending->has_new_buffer_transform)
|
|
|
|
surface->buffer_transform = pending->buffer_transform;
|
|
|
|
|
2018-04-06 13:53:12 +00:00
|
|
|
if (meta_wayland_surface_get_actor (surface) &&
|
|
|
|
(!cairo_region_is_empty (pending->surface_damage) ||
|
|
|
|
!cairo_region_is_empty (pending->buffer_damage)))
|
2017-06-05 12:08:04 +00:00
|
|
|
surface_process_damage (surface,
|
|
|
|
pending->surface_damage,
|
|
|
|
pending->buffer_damage);
|
2014-04-12 06:29:05 +00:00
|
|
|
|
2014-08-21 21:46:36 +00:00
|
|
|
surface->offset_x += pending->dx;
|
|
|
|
surface->offset_y += pending->dy;
|
|
|
|
|
2015-08-04 06:58:26 +00:00
|
|
|
if (pending->opaque_region_set)
|
2014-04-26 08:27:34 +00:00
|
|
|
{
|
2015-03-02 14:56:35 +00:00
|
|
|
if (surface->opaque_region)
|
|
|
|
cairo_region_destroy (surface->opaque_region);
|
2015-08-04 06:58:26 +00:00
|
|
|
if (pending->opaque_region)
|
|
|
|
surface->opaque_region = cairo_region_reference (pending->opaque_region);
|
|
|
|
else
|
|
|
|
surface->opaque_region = NULL;
|
2014-04-26 08:27:34 +00:00
|
|
|
}
|
2015-03-02 14:56:35 +00:00
|
|
|
|
2015-08-04 06:58:26 +00:00
|
|
|
if (pending->input_region_set)
|
2014-04-26 08:27:34 +00:00
|
|
|
{
|
2015-03-02 14:56:35 +00:00
|
|
|
if (surface->input_region)
|
|
|
|
cairo_region_destroy (surface->input_region);
|
2015-08-04 06:58:26 +00:00
|
|
|
if (pending->input_region)
|
|
|
|
surface->input_region = cairo_region_reference (pending->input_region);
|
|
|
|
else
|
|
|
|
surface->input_region = NULL;
|
2014-04-26 08:27:34 +00:00
|
|
|
}
|
2014-04-12 06:42:40 +00:00
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
if (surface->role)
|
|
|
|
{
|
|
|
|
meta_wayland_surface_role_commit (surface->role, pending);
|
|
|
|
g_assert (wl_list_empty (&pending->frame_callback_list));
|
|
|
|
}
|
|
|
|
else
|
2015-08-09 10:54:00 +00:00
|
|
|
{
|
2018-08-27 10:05:58 +00:00
|
|
|
meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
|
2016-03-16 06:55:51 +00:00
|
|
|
|
|
|
|
if (pending->newly_attached)
|
|
|
|
{
|
|
|
|
/* The need to keep the wl_buffer from being released depends on what
|
|
|
|
* role the surface is given. That means we need to also keep a use
|
|
|
|
* count for wl_buffer's that are used by unassigned wl_surface's.
|
|
|
|
*/
|
|
|
|
g_set_object (&surface->unassigned.buffer, surface->buffer_ref.buffer);
|
|
|
|
if (surface->unassigned.buffer)
|
|
|
|
meta_wayland_surface_ref_buffer_use_count (surface);
|
|
|
|
}
|
2015-02-05 10:50:27 +00:00
|
|
|
}
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2016-08-26 07:41:59 +00:00
|
|
|
cleanup:
|
2016-03-16 06:55:51 +00:00
|
|
|
/* If we have a buffer that we are not using, decrease the use count so it may
|
|
|
|
* be released if no-one else has a use-reference to it.
|
|
|
|
*/
|
|
|
|
if (pending->newly_attached &&
|
|
|
|
!surface->buffer_held && surface->buffer_ref.buffer)
|
|
|
|
meta_wayland_surface_unref_buffer_use_count (surface);
|
|
|
|
|
2015-06-17 04:10:52 +00:00
|
|
|
g_signal_emit (pending,
|
|
|
|
pending_state_signals[PENDING_STATE_SIGNAL_APPLIED],
|
|
|
|
0);
|
|
|
|
|
2014-04-18 22:07:05 +00:00
|
|
|
pending_state_reset (pending);
|
2015-01-26 08:46:20 +00:00
|
|
|
|
|
|
|
g_list_foreach (surface->subsurfaces, parent_surface_state_applied, NULL);
|
2014-02-01 21:24:43 +00:00
|
|
|
}
|
2014-01-13 22:31:25 +00:00
|
|
|
|
2014-04-12 06:45:38 +00:00
|
|
|
static void
|
2014-04-02 15:12:58 +00:00
|
|
|
meta_wayland_surface_commit (MetaWaylandSurface *surface)
|
|
|
|
{
|
2017-05-06 01:41:51 +00:00
|
|
|
if (surface->pending->buffer &&
|
|
|
|
!meta_wayland_buffer_is_realized (surface->pending->buffer))
|
|
|
|
meta_wayland_buffer_realize (surface->pending->buffer);
|
|
|
|
|
2015-01-26 08:46:20 +00:00
|
|
|
/*
|
|
|
|
* If this is a sub-surface and it is in effective synchronous mode, only
|
|
|
|
* cache the pending surface state until either one of the following two
|
|
|
|
* scenarios happens:
|
|
|
|
* 1) Its parent surface gets its state applied.
|
|
|
|
* 2) Its mode changes from synchronized to desynchronized and its parent
|
|
|
|
* surface is in effective desynchronized mode.
|
|
|
|
*/
|
2017-12-20 09:40:22 +00:00
|
|
|
if (meta_wayland_surface_is_effectively_synchronized (surface))
|
2018-04-06 15:50:31 +00:00
|
|
|
merge_pending_state (surface->pending, surface->sub.pending);
|
2015-01-26 08:46:20 +00:00
|
|
|
else
|
2017-12-20 09:40:22 +00:00
|
|
|
meta_wayland_surface_apply_pending_state (surface, surface->pending);
|
2014-04-02 15:12:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_surface_destroy (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
|
|
|
wl_resource_destroy (resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_surface_attach (struct wl_client *client,
|
|
|
|
struct wl_resource *surface_resource,
|
|
|
|
struct wl_resource *buffer_resource,
|
|
|
|
gint32 dx, gint32 dy)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface =
|
|
|
|
wl_resource_get_user_data (surface_resource);
|
|
|
|
MetaWaylandBuffer *buffer;
|
|
|
|
|
|
|
|
/* X11 unmanaged window */
|
|
|
|
if (!surface)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buffer_resource)
|
|
|
|
buffer = meta_wayland_buffer_from_resource (buffer_resource);
|
|
|
|
else
|
|
|
|
buffer = NULL;
|
|
|
|
|
2015-12-14 09:13:35 +00:00
|
|
|
if (surface->pending->buffer)
|
2016-03-15 04:46:06 +00:00
|
|
|
{
|
|
|
|
g_signal_handler_disconnect (surface->pending->buffer,
|
|
|
|
surface->pending->buffer_destroy_handler_id);
|
|
|
|
}
|
2014-04-02 15:12:58 +00:00
|
|
|
|
2015-12-14 09:13:35 +00:00
|
|
|
surface->pending->newly_attached = TRUE;
|
|
|
|
surface->pending->buffer = buffer;
|
|
|
|
surface->pending->dx = dx;
|
|
|
|
surface->pending->dy = dy;
|
2014-04-02 15:12:58 +00:00
|
|
|
|
|
|
|
if (buffer)
|
2016-03-15 04:46:06 +00:00
|
|
|
{
|
|
|
|
surface->pending->buffer_destroy_handler_id =
|
|
|
|
g_signal_connect (buffer, "resource-destroyed",
|
|
|
|
G_CALLBACK (pending_buffer_resource_destroyed),
|
|
|
|
surface->pending);
|
|
|
|
}
|
2014-04-02 15:12:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-06-05 12:08:04 +00:00
|
|
|
wl_surface_damage (struct wl_client *client,
|
2014-04-02 15:12:58 +00:00
|
|
|
struct wl_resource *surface_resource,
|
2017-06-05 12:08:04 +00:00
|
|
|
int32_t x,
|
|
|
|
int32_t y,
|
|
|
|
int32_t width,
|
|
|
|
int32_t height)
|
2014-04-02 15:12:58 +00:00
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
2017-06-05 12:08:04 +00:00
|
|
|
cairo_rectangle_int_t rectangle;
|
2014-04-02 15:12:58 +00:00
|
|
|
|
|
|
|
/* X11 unmanaged window */
|
|
|
|
if (!surface)
|
|
|
|
return;
|
|
|
|
|
2017-06-05 12:08:04 +00:00
|
|
|
rectangle = (cairo_rectangle_int_t) {
|
|
|
|
.x = x,
|
|
|
|
.y = y,
|
|
|
|
.width = width,
|
|
|
|
.height = height
|
|
|
|
};
|
|
|
|
cairo_region_union_rectangle (surface->pending->surface_damage, &rectangle);
|
2014-04-02 15:12:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
destroy_frame_callback (struct wl_resource *callback_resource)
|
|
|
|
{
|
|
|
|
MetaWaylandFrameCallback *callback =
|
|
|
|
wl_resource_get_user_data (callback_resource);
|
|
|
|
|
|
|
|
wl_list_remove (&callback->link);
|
|
|
|
g_slice_free (MetaWaylandFrameCallback, callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_surface_frame (struct wl_client *client,
|
|
|
|
struct wl_resource *surface_resource,
|
|
|
|
guint32 callback_id)
|
|
|
|
{
|
|
|
|
MetaWaylandFrameCallback *callback;
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
|
|
|
|
|
|
|
/* X11 unmanaged window */
|
|
|
|
if (!surface)
|
|
|
|
return;
|
|
|
|
|
|
|
|
callback = g_slice_new0 (MetaWaylandFrameCallback);
|
2015-02-25 15:26:01 +00:00
|
|
|
callback->surface = surface;
|
2014-04-02 15:12:58 +00:00
|
|
|
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);
|
|
|
|
|
2015-12-14 09:13:35 +00:00
|
|
|
wl_list_insert (surface->pending->frame_callback_list.prev, &callback->link);
|
2014-04-02 15:12:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_surface_set_opaque_region (struct wl_client *client,
|
|
|
|
struct wl_resource *surface_resource,
|
|
|
|
struct wl_resource *region_resource)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
|
|
|
|
|
|
|
/* X11 unmanaged window */
|
|
|
|
if (!surface)
|
|
|
|
return;
|
|
|
|
|
2015-12-14 09:13:35 +00:00
|
|
|
g_clear_pointer (&surface->pending->opaque_region, cairo_region_destroy);
|
2014-04-02 15:12:58 +00:00
|
|
|
if (region_resource)
|
|
|
|
{
|
|
|
|
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
|
2014-10-08 03:23:55 +00:00
|
|
|
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
|
2015-12-14 09:13:35 +00:00
|
|
|
surface->pending->opaque_region = cairo_region_copy (cr_region);
|
2014-04-02 15:12:58 +00:00
|
|
|
}
|
2015-12-14 09:13:35 +00:00
|
|
|
surface->pending->opaque_region_set = TRUE;
|
2014-04-02 15:12:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_surface_set_input_region (struct wl_client *client,
|
|
|
|
struct wl_resource *surface_resource,
|
|
|
|
struct wl_resource *region_resource)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
|
|
|
|
|
|
|
/* X11 unmanaged window */
|
|
|
|
if (!surface)
|
|
|
|
return;
|
|
|
|
|
2015-12-14 09:13:35 +00:00
|
|
|
g_clear_pointer (&surface->pending->input_region, cairo_region_destroy);
|
2014-04-02 15:12:58 +00:00
|
|
|
if (region_resource)
|
|
|
|
{
|
|
|
|
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
|
2014-10-08 03:23:55 +00:00
|
|
|
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
|
2015-12-14 09:13:35 +00:00
|
|
|
surface->pending->input_region = cairo_region_copy (cr_region);
|
2014-04-02 15:12:58 +00:00
|
|
|
}
|
2015-12-14 09:13:35 +00:00
|
|
|
surface->pending->input_region_set = TRUE;
|
2014-04-02 15:12:58 +00:00
|
|
|
}
|
|
|
|
|
2014-02-01 21:24:43 +00:00
|
|
|
static void
|
2014-04-02 15:10:20 +00:00
|
|
|
wl_surface_commit (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
2014-02-01 21:24:43 +00:00
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
|
|
|
|
|
|
|
/* X11 unmanaged window */
|
|
|
|
if (!surface)
|
|
|
|
return;
|
|
|
|
|
2014-04-02 15:12:58 +00:00
|
|
|
meta_wayland_surface_commit (surface);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2018-11-26 18:40:57 +00:00
|
|
|
static MetaMonitorTransform
|
|
|
|
transform_from_wl_output_transform (int32_t transform_value)
|
|
|
|
{
|
|
|
|
enum wl_output_transform transform = transform_value;
|
|
|
|
|
|
|
|
switch (transform)
|
|
|
|
{
|
|
|
|
case WL_OUTPUT_TRANSFORM_NORMAL:
|
|
|
|
return META_MONITOR_TRANSFORM_NORMAL;
|
|
|
|
case WL_OUTPUT_TRANSFORM_90:
|
|
|
|
return META_MONITOR_TRANSFORM_90;
|
|
|
|
case WL_OUTPUT_TRANSFORM_180:
|
|
|
|
return META_MONITOR_TRANSFORM_180;
|
|
|
|
case WL_OUTPUT_TRANSFORM_270:
|
|
|
|
return META_MONITOR_TRANSFORM_270;
|
|
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED:
|
|
|
|
return META_MONITOR_TRANSFORM_FLIPPED;
|
|
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
|
|
|
return META_MONITOR_TRANSFORM_FLIPPED_90;
|
|
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
|
|
|
|
return META_MONITOR_TRANSFORM_FLIPPED_180;
|
|
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
|
|
|
return META_MONITOR_TRANSFORM_FLIPPED_270;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
static void
|
2018-11-26 18:40:57 +00:00
|
|
|
wl_surface_set_buffer_transform (struct wl_client *client,
|
2014-04-02 15:10:20 +00:00
|
|
|
struct wl_resource *resource,
|
2018-11-26 18:40:57 +00:00
|
|
|
int32_t transform)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2018-11-26 18:40:57 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
|
|
|
MetaMonitorTransform buffer_transform;
|
|
|
|
|
|
|
|
buffer_transform = transform_from_wl_output_transform (transform);
|
|
|
|
|
|
|
|
if (buffer_transform == -1)
|
|
|
|
{
|
|
|
|
wl_resource_post_error (resource,
|
|
|
|
WL_SURFACE_ERROR_INVALID_TRANSFORM,
|
|
|
|
"Trying to set invalid buffer_transform of %d\n",
|
|
|
|
transform);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
surface->pending->buffer_transform = buffer_transform;
|
|
|
|
surface->pending->has_new_buffer_transform = TRUE;
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-04-02 15:10:20 +00:00
|
|
|
wl_surface_set_buffer_scale (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
int scale)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2014-04-26 08:27:34 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
|
|
|
if (scale > 0)
|
2015-12-14 09:13:35 +00:00
|
|
|
surface->pending->scale = scale;
|
2014-04-26 08:27:34 +00:00
|
|
|
else
|
|
|
|
g_warning ("Trying to set invalid buffer_scale of %d\n", scale);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2017-06-05 12:08:04 +00:00
|
|
|
static void
|
|
|
|
wl_surface_damage_buffer (struct wl_client *client,
|
|
|
|
struct wl_resource *surface_resource,
|
|
|
|
int32_t x,
|
|
|
|
int32_t y,
|
|
|
|
int32_t width,
|
|
|
|
int32_t height)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
|
|
|
cairo_rectangle_int_t rectangle;
|
|
|
|
|
|
|
|
/* X11 unmanaged window */
|
|
|
|
if (!surface)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rectangle = (cairo_rectangle_int_t) {
|
|
|
|
.x = x,
|
|
|
|
.y = y,
|
|
|
|
.width = width,
|
|
|
|
.height = height
|
|
|
|
};
|
|
|
|
cairo_region_union_rectangle (surface->pending->buffer_damage, &rectangle);
|
|
|
|
}
|
|
|
|
|
2014-08-04 14:28:44 +00:00
|
|
|
static const struct wl_surface_interface meta_wayland_wl_surface_interface = {
|
2014-04-02 15:10:20 +00:00
|
|
|
wl_surface_destroy,
|
|
|
|
wl_surface_attach,
|
|
|
|
wl_surface_damage,
|
|
|
|
wl_surface_frame,
|
|
|
|
wl_surface_set_opaque_region,
|
|
|
|
wl_surface_set_input_region,
|
|
|
|
wl_surface_commit,
|
|
|
|
wl_surface_set_buffer_transform,
|
2017-06-05 12:08:04 +00:00
|
|
|
wl_surface_set_buffer_scale,
|
|
|
|
wl_surface_damage_buffer,
|
2013-08-30 16:26:18 +00:00
|
|
|
};
|
|
|
|
|
2015-05-18 11:24:27 +00:00
|
|
|
static void
|
|
|
|
sync_drag_dest_funcs (MetaWaylandSurface *surface)
|
|
|
|
{
|
2015-04-29 15:44:05 +00:00
|
|
|
if (surface->window &&
|
|
|
|
surface->window->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
|
|
|
surface->dnd.funcs = meta_xwayland_selection_get_drag_dest_funcs ();
|
|
|
|
else
|
|
|
|
surface->dnd.funcs = meta_wayland_data_device_get_drag_dest_funcs ();
|
2015-05-18 11:24:27 +00:00
|
|
|
}
|
|
|
|
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 07:49:52 +00:00
|
|
|
static void
|
|
|
|
surface_entered_output (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandOutput *wayland_output)
|
|
|
|
{
|
|
|
|
GList *iter;
|
|
|
|
struct wl_resource *resource;
|
|
|
|
|
|
|
|
for (iter = wayland_output->resources; iter != NULL; iter = iter->next)
|
|
|
|
{
|
|
|
|
resource = iter->data;
|
|
|
|
|
|
|
|
if (wl_resource_get_client (resource) !=
|
|
|
|
wl_resource_get_client (surface->resource))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
wl_surface_send_enter (surface->resource, resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
surface_left_output (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandOutput *wayland_output)
|
|
|
|
{
|
|
|
|
GList *iter;
|
|
|
|
struct wl_resource *resource;
|
|
|
|
|
|
|
|
for (iter = wayland_output->resources; iter != NULL; iter = iter->next)
|
|
|
|
{
|
|
|
|
resource = iter->data;
|
|
|
|
|
|
|
|
if (wl_resource_get_client (resource) !=
|
|
|
|
wl_resource_get_client (surface->resource))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
wl_surface_send_leave (surface->resource, resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_surface_is_on_output (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandOutput *wayland_output,
|
|
|
|
gboolean is_on_output);
|
|
|
|
|
|
|
|
static void
|
|
|
|
surface_handle_output_destroy (MetaWaylandOutput *wayland_output,
|
|
|
|
MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
set_surface_is_on_output (surface, wayland_output, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_surface_is_on_output (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandOutput *wayland_output,
|
|
|
|
gboolean is_on_output)
|
|
|
|
{
|
2015-10-14 04:33:15 +00:00
|
|
|
gpointer orig_id;
|
|
|
|
gboolean was_on_output = g_hash_table_lookup_extended (surface->outputs_to_destroy_notify_id,
|
|
|
|
wayland_output,
|
|
|
|
NULL, &orig_id);
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 07:49:52 +00:00
|
|
|
|
|
|
|
if (!was_on_output && is_on_output)
|
|
|
|
{
|
2015-10-14 04:33:15 +00:00
|
|
|
gulong id;
|
|
|
|
|
|
|
|
id = g_signal_connect (wayland_output, "output-destroyed",
|
|
|
|
G_CALLBACK (surface_handle_output_destroy),
|
|
|
|
surface);
|
|
|
|
g_hash_table_insert (surface->outputs_to_destroy_notify_id, wayland_output,
|
|
|
|
GSIZE_TO_POINTER ((gsize)id));
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 07:49:52 +00:00
|
|
|
surface_entered_output (surface, wayland_output);
|
|
|
|
}
|
|
|
|
else if (was_on_output && !is_on_output)
|
|
|
|
{
|
2015-10-14 04:33:15 +00:00
|
|
|
g_hash_table_remove (surface->outputs_to_destroy_notify_id, wayland_output);
|
|
|
|
g_signal_handler_disconnect (wayland_output, (gulong) GPOINTER_TO_SIZE (orig_id));
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 07:49:52 +00:00
|
|
|
surface_left_output (surface, wayland_output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_surface_output_state (gpointer key, gpointer value, gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaWaylandOutput *wayland_output = value;
|
|
|
|
MetaWaylandSurface *surface = user_data;
|
2016-11-25 06:31:38 +00:00
|
|
|
MetaLogicalMonitor *logical_monitor;
|
2016-11-25 06:38:28 +00:00
|
|
|
gboolean is_on_logical_monitor;
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 07:49:52 +00:00
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
g_assert (surface->role);
|
|
|
|
|
2016-11-25 06:31:38 +00:00
|
|
|
logical_monitor = wayland_output->logical_monitor;
|
|
|
|
if (!logical_monitor)
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 07:49:52 +00:00
|
|
|
{
|
|
|
|
set_surface_is_on_output (surface, wayland_output, FALSE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-25 06:38:28 +00:00
|
|
|
is_on_logical_monitor =
|
|
|
|
meta_wayland_surface_role_is_on_logical_monitor (surface->role,
|
|
|
|
logical_monitor);
|
|
|
|
set_surface_is_on_output (surface, wayland_output, is_on_logical_monitor);
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 07:49:52 +00:00
|
|
|
}
|
|
|
|
|
2015-10-14 04:33:15 +00:00
|
|
|
static void
|
|
|
|
surface_output_disconnect_signal (gpointer key, gpointer value, gpointer user_data)
|
|
|
|
{
|
|
|
|
g_signal_handler_disconnect (key, (gulong) GPOINTER_TO_SIZE (value));
|
|
|
|
}
|
|
|
|
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 07:49:52 +00:00
|
|
|
void
|
|
|
|
meta_wayland_surface_update_outputs (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
if (!surface->compositor)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_hash_table_foreach (surface->compositor->outputs,
|
|
|
|
update_surface_output_state,
|
|
|
|
surface);
|
|
|
|
}
|
|
|
|
|
2017-10-06 12:53:16 +00:00
|
|
|
static void
|
|
|
|
meta_wayland_surface_update_outputs_recursively (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
meta_wayland_surface_update_outputs (surface);
|
|
|
|
|
|
|
|
for (l = surface->subsurfaces; l != NULL; l = l->next)
|
|
|
|
meta_wayland_surface_update_outputs_recursively (l->data);
|
|
|
|
}
|
|
|
|
|
2014-02-24 18:32:17 +00:00
|
|
|
void
|
2014-04-02 14:37:08 +00:00
|
|
|
meta_wayland_surface_set_window (MetaWaylandSurface *surface,
|
|
|
|
MetaWindow *window)
|
2013-11-26 18:04:37 +00:00
|
|
|
{
|
2016-08-18 04:57:17 +00:00
|
|
|
gboolean was_unmapped = surface->window && !window;
|
|
|
|
|
2017-10-06 12:53:16 +00:00
|
|
|
if (surface->window == window)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (surface->window)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (surface->window,
|
|
|
|
window_position_changed,
|
|
|
|
surface);
|
2018-04-04 08:15:25 +00:00
|
|
|
g_signal_handlers_disconnect_by_func (meta_window_actor_from_window (surface->window),
|
|
|
|
window_actor_effects_completed,
|
|
|
|
surface);
|
2017-10-06 12:53:16 +00:00
|
|
|
}
|
|
|
|
|
2014-04-02 14:37:08 +00:00
|
|
|
surface->window = window;
|
2017-12-20 09:40:22 +00:00
|
|
|
|
2018-04-06 11:27:52 +00:00
|
|
|
clutter_actor_set_reactive (CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface)), !!window);
|
2015-05-18 11:24:27 +00:00
|
|
|
sync_drag_dest_funcs (surface);
|
2016-08-18 04:57:17 +00:00
|
|
|
|
|
|
|
if (was_unmapped)
|
|
|
|
g_signal_emit (surface, surface_signals[SURFACE_UNMAPPED], 0);
|
2017-10-06 12:53:16 +00:00
|
|
|
|
|
|
|
if (window)
|
|
|
|
{
|
|
|
|
g_signal_connect_object (window,
|
|
|
|
"position-changed",
|
|
|
|
G_CALLBACK (window_position_changed),
|
|
|
|
surface, 0);
|
2018-04-04 08:15:25 +00:00
|
|
|
g_signal_connect_object (meta_window_actor_from_window (window),
|
|
|
|
"effects-completed",
|
|
|
|
G_CALLBACK (window_actor_effects_completed),
|
|
|
|
surface, 0);
|
2017-10-06 12:53:16 +00:00
|
|
|
}
|
2014-02-18 21:39:23 +00:00
|
|
|
}
|
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
static void
|
2014-02-18 00:10:25 +00:00
|
|
|
wl_surface_destructor (struct wl_resource *resource)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-02-18 21:39:23 +00:00
|
|
|
MetaWaylandCompositor *compositor = surface->compositor;
|
2015-08-19 03:06:46 +00:00
|
|
|
MetaWaylandFrameCallback *cb, *next;
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2016-09-06 04:41:49 +00:00
|
|
|
g_signal_emit (surface, surface_signals[SURFACE_DESTROY], 0);
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
g_clear_object (&surface->role);
|
|
|
|
|
2014-02-19 03:21:33 +00:00
|
|
|
/* If we still have a window at the time of destruction, that means that
|
|
|
|
* the client is disconnecting, as the resources are destroyed in a random
|
|
|
|
* order. Simply destroy the window in this case. */
|
|
|
|
if (surface->window)
|
2015-12-15 04:51:24 +00:00
|
|
|
meta_wayland_surface_destroy_window (surface);
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2016-03-16 06:55:51 +00:00
|
|
|
if (surface->unassigned.buffer)
|
|
|
|
{
|
|
|
|
meta_wayland_surface_unref_buffer_use_count (surface);
|
|
|
|
g_clear_object (&surface->unassigned.buffer);
|
|
|
|
}
|
|
|
|
|
2016-03-16 06:47:53 +00:00
|
|
|
if (surface->buffer_held)
|
|
|
|
meta_wayland_surface_unref_buffer_use_count (surface);
|
|
|
|
g_clear_object (&surface->buffer_ref.buffer);
|
|
|
|
|
2015-12-14 09:13:35 +00:00
|
|
|
g_clear_object (&surface->pending);
|
2014-02-18 22:07:36 +00:00
|
|
|
|
2015-03-02 14:56:35 +00:00
|
|
|
if (surface->opaque_region)
|
|
|
|
cairo_region_destroy (surface->opaque_region);
|
|
|
|
if (surface->input_region)
|
|
|
|
cairo_region_destroy (surface->input_region);
|
|
|
|
|
2015-02-25 15:26:01 +00:00
|
|
|
meta_wayland_compositor_destroy_frame_callbacks (compositor, surface);
|
|
|
|
|
2015-10-14 04:33:15 +00:00
|
|
|
g_hash_table_foreach (surface->outputs_to_destroy_notify_id, surface_output_disconnect_signal, surface);
|
|
|
|
g_hash_table_unref (surface->outputs_to_destroy_notify_id);
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 07:49:52 +00:00
|
|
|
|
2015-08-19 03:06:46 +00:00
|
|
|
wl_list_for_each_safe (cb, next, &surface->pending_frame_callback_list, link)
|
|
|
|
wl_resource_destroy (cb->resource);
|
|
|
|
|
2014-02-18 21:39:23 +00:00
|
|
|
if (surface->resource)
|
|
|
|
wl_resource_set_user_data (surface->resource, NULL);
|
2015-03-10 12:42:01 +00:00
|
|
|
|
|
|
|
if (surface->wl_subsurface)
|
|
|
|
wl_resource_destroy (surface->wl_subsurface);
|
|
|
|
|
2017-03-17 12:34:52 +00:00
|
|
|
g_hash_table_destroy (surface->shortcut_inhibited_seats);
|
|
|
|
|
2015-07-08 03:21:23 +00:00
|
|
|
g_object_unref (surface);
|
2013-11-26 18:04:37 +00:00
|
|
|
|
2014-02-18 21:39:23 +00:00
|
|
|
meta_wayland_compositor_repick (compositor);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2017-10-06 12:53:16 +00:00
|
|
|
static void
|
|
|
|
window_position_changed (MetaWindow *window,
|
|
|
|
MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
meta_wayland_surface_update_outputs_recursively (surface);
|
2016-12-01 15:18:48 +00:00
|
|
|
}
|
|
|
|
|
2018-04-04 08:15:25 +00:00
|
|
|
static void
|
|
|
|
window_actor_effects_completed (MetaWindowActor *window_actor,
|
|
|
|
MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
meta_wayland_surface_update_outputs_recursively (surface);
|
|
|
|
}
|
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
MetaWaylandSurface *
|
|
|
|
meta_wayland_surface_create (MetaWaylandCompositor *compositor,
|
2014-04-22 22:22:13 +00:00
|
|
|
struct wl_client *client,
|
|
|
|
struct wl_resource *compositor_resource,
|
|
|
|
guint32 id)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2015-07-08 03:21:23 +00:00
|
|
|
MetaWaylandSurface *surface = g_object_new (META_TYPE_WAYLAND_SURFACE, NULL);
|
2013-08-30 16:26:18 +00:00
|
|
|
|
|
|
|
surface->compositor = compositor;
|
2014-04-26 08:27:34 +00:00
|
|
|
surface->scale = 1;
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2014-08-04 14:22:23 +00:00
|
|
|
surface->resource = wl_resource_create (client, &wl_surface_interface, wl_resource_get_version (compositor_resource), id);
|
2014-04-02 15:10:20 +00:00
|
|
|
wl_resource_set_implementation (surface->resource, &meta_wayland_wl_surface_interface, surface, wl_surface_destructor);
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2015-08-19 03:06:46 +00:00
|
|
|
wl_list_init (&surface->pending_frame_callback_list);
|
|
|
|
|
2015-05-18 11:24:27 +00:00
|
|
|
sync_drag_dest_funcs (surface);
|
|
|
|
|
2015-10-14 04:33:15 +00:00
|
|
|
surface->outputs_to_destroy_notify_id = g_hash_table_new (NULL, NULL);
|
2017-03-17 12:34:52 +00:00
|
|
|
surface->shortcut_inhibited_seats = g_hash_table_new (NULL, NULL);
|
wayland: Send wl_surface.enter and wl_surface.leave
Whenever a MetaSurfaceActor is painted, update the list of what outputs
the surface is being drawed upon. Since we do this on paint, we
effectively avoids this whenever the surface is not drawn, for example
being minimized, on a non-active workspace, or simply outside of the
damage region of a frame.
DND icons and cursors are not affected by this patch, since they are not
drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
then we'll check the position of the original actor again when the clone is
drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
instead is cloned, as GNOME Shell does in many cases, then these clones
will not cause duplicate position checks.
https://bugzilla.gnome.org/show_bug.cgi?id=744453
2015-02-03 07:49:52 +00:00
|
|
|
|
2018-04-06 13:47:50 +00:00
|
|
|
meta_wayland_compositor_notify_surface_id (compositor, id, surface);
|
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
return surface;
|
|
|
|
}
|
|
|
|
|
2015-12-15 04:51:24 +00:00
|
|
|
gboolean
|
|
|
|
meta_wayland_surface_begin_grab_op (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandSeat *seat,
|
|
|
|
MetaGrabOp grab_op,
|
|
|
|
gfloat x,
|
|
|
|
gfloat y)
|
2013-11-15 02:45:34 +00:00
|
|
|
{
|
|
|
|
MetaWindow *window = surface->window;
|
|
|
|
|
|
|
|
if (grab_op == META_GRAB_OP_NONE)
|
|
|
|
return FALSE;
|
|
|
|
|
2016-03-23 17:45:45 +00:00
|
|
|
/* This is an input driven operation so we set frame_action to
|
|
|
|
constrain it in the same way as it would be if the window was
|
|
|
|
being moved/resized via a SSD event. */
|
2013-11-15 02:45:34 +00:00
|
|
|
return meta_display_begin_grab_op (window->display,
|
|
|
|
window,
|
|
|
|
grab_op,
|
|
|
|
TRUE, /* pointer_already_grabbed */
|
2016-03-23 17:45:45 +00:00
|
|
|
TRUE, /* frame_action */
|
2013-11-15 02:45:34 +00:00
|
|
|
1, /* button. XXX? */
|
|
|
|
0, /* modmask */
|
|
|
|
meta_display_get_current_time_roundtrip (window->display),
|
2014-07-21 23:28:39 +00:00
|
|
|
x, y);
|
2013-11-15 02:45:34 +00:00
|
|
|
}
|
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
void
|
2014-04-22 22:05:44 +00:00
|
|
|
meta_wayland_shell_init (MetaWaylandCompositor *compositor)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2015-12-15 04:51:24 +00:00
|
|
|
meta_wayland_xdg_shell_init (compositor);
|
2017-12-22 08:37:44 +00:00
|
|
|
meta_wayland_legacy_xdg_shell_init (compositor);
|
2015-12-15 04:51:24 +00:00
|
|
|
meta_wayland_wl_shell_init (compositor);
|
2018-08-23 13:53:55 +00:00
|
|
|
meta_wayland_init_gtk_shell (compositor);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 16:45:09 +00:00
|
|
|
void
|
2014-05-05 23:09:22 +00:00
|
|
|
meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
|
2016-07-01 07:14:12 +00:00
|
|
|
int new_x,
|
|
|
|
int new_y,
|
2014-07-17 21:39:43 +00:00
|
|
|
int new_width,
|
wayland-surface: Don't do pending move/resizes on all commits
We assume in meta_window_wayland_move_resize that the next commit that
changes the geometry will always be for our next pending operation, so
if we have a move pending on a resize, the next commit will trigger the
move. This is, of course, fundamentally wrong.
We broke this assumption even more now that we don't fizzle out calls to
meta_window_move_resize_internal and now call it on every commit, which
means that a simple damage and then commit would complete a pending
move.
This was even broken by apps like weston-terminal, which, when clicking
on the maximize button, first redraws the terminal with the maximize
button state back on hover on press, and would only redraw when it got
the configure event with the coordinates.
To track the correct commit to apply the move for, we implement the
ack_configure request and ignore all move/resizes that happen before
that.
Right now, we actually fizzle out the entire move/resize if there's a
future pending configure we're waiting on.
2014-07-27 15:23:17 +00:00
|
|
|
int new_height,
|
|
|
|
MetaWaylandSerial *sent_serial)
|
2014-05-05 23:09:07 +00:00
|
|
|
{
|
2017-12-13 04:37:23 +00:00
|
|
|
MetaWaylandShellSurface *shell_surface =
|
|
|
|
META_WAYLAND_SHELL_SURFACE (surface->role);
|
2014-05-05 23:09:07 +00:00
|
|
|
|
2016-06-28 06:56:20 +00:00
|
|
|
g_signal_emit (surface, surface_signals[SURFACE_CONFIGURE], 0);
|
|
|
|
|
2017-12-13 04:37:23 +00:00
|
|
|
meta_wayland_shell_surface_configure (shell_surface,
|
|
|
|
new_x, new_y,
|
|
|
|
new_width, new_height,
|
|
|
|
sent_serial);
|
2013-11-12 20:52:03 +00:00
|
|
|
}
|
2013-11-21 19:20:52 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_ping (MetaWaylandSurface *surface,
|
2014-02-15 15:26:43 +00:00
|
|
|
guint32 serial)
|
2013-11-21 19:20:52 +00:00
|
|
|
{
|
2017-12-13 04:37:23 +00:00
|
|
|
MetaWaylandShellSurface *shell_surface =
|
|
|
|
META_WAYLAND_SHELL_SURFACE (surface->role);
|
2015-12-15 04:51:24 +00:00
|
|
|
|
2017-12-13 04:37:23 +00:00
|
|
|
meta_wayland_shell_surface_ping (shell_surface, serial);
|
2013-11-21 19:20:52 +00:00
|
|
|
}
|
2014-02-07 22:28:33 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_delete (MetaWaylandSurface *surface)
|
|
|
|
{
|
2017-12-13 04:37:23 +00:00
|
|
|
MetaWaylandShellSurface *shell_surface =
|
|
|
|
META_WAYLAND_SHELL_SURFACE (surface->role);
|
2015-12-15 04:51:24 +00:00
|
|
|
|
2017-12-13 04:37:23 +00:00
|
|
|
meta_wayland_shell_surface_close (shell_surface);
|
2014-02-07 22:28:33 +00:00
|
|
|
}
|
2014-02-28 05:18:42 +00:00
|
|
|
|
2015-12-15 14:09:20 +00:00
|
|
|
void
|
|
|
|
meta_wayland_surface_window_managed (MetaWaylandSurface *surface,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
2017-12-13 04:37:23 +00:00
|
|
|
MetaWaylandShellSurface *shell_surface =
|
|
|
|
META_WAYLAND_SHELL_SURFACE (surface->role);
|
2015-12-15 14:09:20 +00:00
|
|
|
|
2017-12-13 04:37:23 +00:00
|
|
|
meta_wayland_shell_surface_managed (shell_surface, window);
|
2015-12-15 14:09:20 +00:00
|
|
|
}
|
|
|
|
|
2015-05-18 11:24:27 +00:00
|
|
|
void
|
|
|
|
meta_wayland_surface_drag_dest_focus_in (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandDataOffer *offer)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
|
|
|
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
|
|
|
|
|
|
|
|
surface->dnd.funcs->focus_in (data_device, surface, offer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_drag_dest_motion (MetaWaylandSurface *surface,
|
|
|
|
const ClutterEvent *event)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
|
|
|
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
|
|
|
|
|
|
|
|
surface->dnd.funcs->motion (data_device, surface, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_drag_dest_focus_out (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
|
|
|
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
|
|
|
|
|
|
|
|
surface->dnd.funcs->focus_out (data_device, surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_drag_dest_drop (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
|
|
|
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
|
|
|
|
|
|
|
|
surface->dnd.funcs->drop (data_device, surface);
|
2015-09-28 12:16:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_drag_dest_update (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
|
|
|
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
|
|
|
|
|
|
|
|
surface->dnd.funcs->update (data_device, surface);
|
2015-05-18 11:24:27 +00:00
|
|
|
}
|
2015-03-23 13:10:20 +00:00
|
|
|
|
2016-01-14 09:43:47 +00:00
|
|
|
MetaWaylandSurface *
|
|
|
|
meta_wayland_surface_get_toplevel (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
if (surface->role)
|
|
|
|
return meta_wayland_surface_role_get_toplevel (surface->role);
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-03-23 13:10:20 +00:00
|
|
|
MetaWindow *
|
|
|
|
meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface)
|
|
|
|
{
|
2016-01-14 09:43:47 +00:00
|
|
|
MetaWaylandSurface *toplevel;
|
2015-03-23 13:10:20 +00:00
|
|
|
|
2016-01-14 09:43:47 +00:00
|
|
|
toplevel = meta_wayland_surface_get_toplevel (surface);
|
|
|
|
if (toplevel)
|
|
|
|
return toplevel->window;
|
|
|
|
else
|
|
|
|
return NULL;
|
2015-03-23 13:10:20 +00:00
|
|
|
}
|
2015-07-08 03:21:23 +00:00
|
|
|
|
2015-06-17 02:16:02 +00:00
|
|
|
void
|
|
|
|
meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface,
|
|
|
|
float abs_x,
|
|
|
|
float abs_y,
|
|
|
|
float *sx,
|
|
|
|
float *sy)
|
|
|
|
{
|
2016-07-14 12:39:26 +00:00
|
|
|
/* Using clutter API to transform coordinates is only accurate right
|
|
|
|
* after a clutter layout pass but this function is used e.g. to
|
|
|
|
* deliver pointer motion events which can happen at any time. This
|
|
|
|
* isn't a problem for wayland clients since they don't control
|
|
|
|
* their position, but X clients do and we'd be sending outdated
|
|
|
|
* coordinates if a client is moving a window in response to motion
|
|
|
|
* events.
|
|
|
|
*/
|
|
|
|
if (surface->window &&
|
|
|
|
surface->window->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
|
|
|
{
|
|
|
|
MetaRectangle window_rect;
|
2015-06-17 02:16:02 +00:00
|
|
|
|
2016-07-14 12:39:26 +00:00
|
|
|
meta_window_get_buffer_rect (surface->window, &window_rect);
|
|
|
|
*sx = abs_x - window_rect.x;
|
|
|
|
*sy = abs_y - window_rect.y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ClutterActor *actor =
|
2018-04-06 11:27:52 +00:00
|
|
|
CLUTTER_ACTOR (meta_surface_actor_get_texture (meta_wayland_surface_get_actor (surface)));
|
2016-07-14 12:39:26 +00:00
|
|
|
|
|
|
|
clutter_actor_transform_stage_point (actor, abs_x, abs_y, sx, sy);
|
|
|
|
*sx /= surface->scale;
|
|
|
|
*sy /= surface->scale;
|
|
|
|
}
|
2015-06-17 02:16:02 +00:00
|
|
|
}
|
|
|
|
|
2015-06-17 04:10:52 +00:00
|
|
|
void
|
|
|
|
meta_wayland_surface_get_absolute_coordinates (MetaWaylandSurface *surface,
|
|
|
|
float sx,
|
|
|
|
float sy,
|
|
|
|
float *x,
|
|
|
|
float *y)
|
|
|
|
{
|
|
|
|
ClutterActor *actor =
|
2018-04-06 11:27:52 +00:00
|
|
|
CLUTTER_ACTOR (meta_surface_actor_get_texture (meta_wayland_surface_get_actor (surface)));
|
2015-06-17 04:10:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-07-08 03:21:23 +00:00
|
|
|
static void
|
|
|
|
meta_wayland_surface_init (MetaWaylandSurface *surface)
|
|
|
|
{
|
2015-12-14 09:13:35 +00:00
|
|
|
surface->pending = g_object_new (META_TYPE_WAYLAND_PENDING_STATE, NULL);
|
2018-04-06 10:35:34 +00:00
|
|
|
|
|
|
|
g_signal_connect (surface, "geometry-changed",
|
|
|
|
G_CALLBACK (meta_wayland_surface_update_outputs_recursively),
|
|
|
|
NULL);
|
2015-07-08 03:21:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_surface_class_init (MetaWaylandSurfaceClass *klass)
|
|
|
|
{
|
2015-10-22 12:07:52 +00:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
surface_signals[SURFACE_DESTROY] =
|
|
|
|
g_signal_new ("destroy",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0, NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2016-08-18 04:57:17 +00:00
|
|
|
|
|
|
|
surface_signals[SURFACE_UNMAPPED] =
|
|
|
|
g_signal_new ("unmapped",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0, NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2016-06-28 06:56:20 +00:00
|
|
|
|
|
|
|
surface_signals[SURFACE_CONFIGURE] =
|
|
|
|
g_signal_new ("configure",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0, NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2017-03-17 12:34:52 +00:00
|
|
|
|
|
|
|
surface_signals[SURFACE_SHORTCUTS_INHIBITED] =
|
|
|
|
g_signal_new ("shortcuts-inhibited",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0, NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
surface_signals[SURFACE_SHORTCUTS_RESTORED] =
|
|
|
|
g_signal_new ("shortcuts-restored",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0, NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2018-04-06 10:35:34 +00:00
|
|
|
surface_signals[SURFACE_GEOMETRY_CHANGED] =
|
|
|
|
g_signal_new ("geometry-changed",
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0, NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2015-07-08 03:21:23 +00:00
|
|
|
}
|
2015-07-08 08:14:00 +00:00
|
|
|
|
2016-01-28 08:55:42 +00:00
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (object);
|
|
|
|
MetaWaylandSurfaceRolePrivate *priv =
|
|
|
|
meta_wayland_surface_role_get_instance_private (surface_role);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case SURFACE_ROLE_PROP_SURFACE:
|
|
|
|
priv->surface = g_value_get_object (value);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (object);
|
|
|
|
MetaWaylandSurfaceRolePrivate *priv =
|
|
|
|
meta_wayland_surface_role_get_instance_private (surface_role);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case SURFACE_ROLE_PROP_SURFACE:
|
|
|
|
g_value_set_object (value, priv->surface);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_init (MetaWaylandSurfaceRole *role)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_class_init (MetaWaylandSurfaceRoleClass *klass)
|
|
|
|
{
|
2016-01-28 08:55:42 +00:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->set_property = meta_wayland_surface_role_set_property;
|
|
|
|
object_class->get_property = meta_wayland_surface_role_get_property;
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class,
|
|
|
|
SURFACE_ROLE_PROP_SURFACE,
|
|
|
|
g_param_spec_object ("surface",
|
|
|
|
"MetaWaylandSurface",
|
|
|
|
"The MetaWaylandSurface instance",
|
|
|
|
META_TYPE_WAYLAND_SURFACE,
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_STATIC_STRINGS));
|
2015-07-08 08:14:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
|
|
|
|
{
|
|
|
|
META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role)->assigned (surface_role);
|
|
|
|
}
|
|
|
|
|
2016-03-16 06:55:51 +00:00
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_pre_commit (MetaWaylandSurfaceRole *surface_role,
|
|
|
|
MetaWaylandPendingState *pending)
|
|
|
|
{
|
|
|
|
MetaWaylandSurfaceRoleClass *klass;
|
|
|
|
|
|
|
|
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
|
|
|
|
if (klass->pre_commit)
|
|
|
|
klass->pre_commit (surface_role, pending);
|
|
|
|
}
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
|
|
|
|
MetaWaylandPendingState *pending)
|
|
|
|
{
|
|
|
|
META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role)->commit (surface_role,
|
|
|
|
pending);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2016-11-25 06:38:28 +00:00
|
|
|
meta_wayland_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *surface_role,
|
|
|
|
MetaLogicalMonitor *logical_monitor)
|
2015-07-08 08:14:00 +00:00
|
|
|
{
|
|
|
|
MetaWaylandSurfaceRoleClass *klass;
|
|
|
|
|
|
|
|
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
|
2016-11-25 06:38:28 +00:00
|
|
|
if (klass->is_on_logical_monitor)
|
|
|
|
return klass->is_on_logical_monitor (surface_role, logical_monitor);
|
2015-07-08 08:14:00 +00:00
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2016-01-14 09:43:47 +00:00
|
|
|
static MetaWaylandSurface *
|
|
|
|
meta_wayland_surface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role)
|
|
|
|
{
|
|
|
|
MetaWaylandSurfaceRoleClass *klass;
|
|
|
|
|
|
|
|
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
|
|
|
|
if (klass->get_toplevel)
|
|
|
|
return klass->get_toplevel (surface_role);
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
MetaWaylandSurface *
|
|
|
|
meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role)
|
|
|
|
{
|
|
|
|
MetaWaylandSurfaceRolePrivate *priv =
|
|
|
|
meta_wayland_surface_role_get_instance_private (role);
|
|
|
|
|
|
|
|
return priv->surface;
|
|
|
|
}
|
|
|
|
|
2015-07-17 14:02:15 +00:00
|
|
|
void
|
|
|
|
meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
wl_list_insert_list (&surface->compositor->frame_callbacks,
|
|
|
|
&surface->pending_frame_callback_list);
|
|
|
|
wl_list_init (&surface->pending_frame_callback_list);
|
|
|
|
}
|
|
|
|
|
2015-07-08 08:14:00 +00:00
|
|
|
static void
|
|
|
|
default_role_assigned (MetaWaylandSurfaceRole *surface_role)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface =
|
|
|
|
meta_wayland_surface_role_get_surface (surface_role);
|
|
|
|
|
2015-07-17 14:02:15 +00:00
|
|
|
meta_wayland_surface_queue_pending_frame_callbacks (surface);
|
2015-07-08 08:14:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-12-15 04:51:24 +00:00
|
|
|
meta_wayland_surface_role_dnd_init (MetaWaylandSurfaceRoleDND *role)
|
2015-07-08 08:14:00 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-12-15 04:51:24 +00:00
|
|
|
meta_wayland_surface_role_dnd_class_init (MetaWaylandSurfaceRoleDNDClass *klass)
|
2015-07-08 08:14:00 +00:00
|
|
|
{
|
|
|
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
|
|
|
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
|
|
|
|
|
2015-12-15 04:51:24 +00:00
|
|
|
surface_role_class->assigned = default_role_assigned;
|
|
|
|
surface_role_class->commit = dnd_surface_commit;
|
2015-07-08 08:14:00 +00:00
|
|
|
}
|
|
|
|
|
2016-02-23 13:26:52 +00:00
|
|
|
cairo_region_t *
|
|
|
|
meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
cairo_region_t *region;
|
|
|
|
cairo_rectangle_int_t buffer_rect;
|
|
|
|
|
2016-03-16 06:47:53 +00:00
|
|
|
if (!surface->buffer_ref.buffer)
|
2016-02-23 13:26:52 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
buffer_rect = (cairo_rectangle_int_t) {
|
2018-06-29 15:53:21 +00:00
|
|
|
.width = meta_wayland_surface_get_width (surface),
|
|
|
|
.height = meta_wayland_surface_get_height (surface),
|
2016-02-23 13:26:52 +00:00
|
|
|
};
|
|
|
|
region = cairo_region_create_rectangle (&buffer_rect);
|
|
|
|
|
|
|
|
if (surface->input_region)
|
|
|
|
cairo_region_intersect (region, surface->input_region);
|
|
|
|
|
|
|
|
return region;
|
|
|
|
}
|
2017-03-17 12:34:52 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_inhibit_shortcuts (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandSeat *seat)
|
|
|
|
{
|
|
|
|
g_hash_table_add (surface->shortcut_inhibited_seats, seat);
|
|
|
|
g_signal_emit (surface, surface_signals[SURFACE_SHORTCUTS_INHIBITED], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_restore_shortcuts (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandSeat *seat)
|
|
|
|
{
|
|
|
|
g_signal_emit (surface, surface_signals[SURFACE_SHORTCUTS_RESTORED], 0);
|
|
|
|
g_hash_table_remove (surface->shortcut_inhibited_seats, seat);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandSeat *seat)
|
|
|
|
{
|
|
|
|
if (surface->shortcut_inhibited_seats == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return g_hash_table_contains (surface->shortcut_inhibited_seats, seat);
|
|
|
|
}
|
2018-04-06 10:29:37 +00:00
|
|
|
|
|
|
|
MetaSurfaceActor *
|
|
|
|
meta_wayland_surface_get_actor (MetaWaylandSurface *surface)
|
|
|
|
{
|
2018-04-06 11:27:52 +00:00
|
|
|
if (!surface->role || !META_IS_WAYLAND_ACTOR_SURFACE (surface->role))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return meta_wayland_actor_surface_get_actor (META_WAYLAND_ACTOR_SURFACE (surface->role));
|
2018-04-06 10:29:37 +00:00
|
|
|
}
|
2018-04-06 10:35:34 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_notify_geometry_changed (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
g_signal_emit (surface, surface_signals[SURFACE_GEOMETRY_CHANGED], 0);
|
|
|
|
}
|
2018-06-29 15:45:28 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
meta_wayland_surface_get_width (MetaWaylandSurface *surface)
|
|
|
|
{
|
2018-11-26 18:40:57 +00:00
|
|
|
int width;
|
2018-06-29 15:45:28 +00:00
|
|
|
|
2018-11-26 18:40:57 +00:00
|
|
|
if (meta_monitor_transform_is_rotated (surface->buffer_transform))
|
|
|
|
width = get_buffer_height (surface);
|
2018-06-29 15:45:28 +00:00
|
|
|
else
|
2018-11-26 18:40:57 +00:00
|
|
|
width = get_buffer_width (surface);
|
|
|
|
|
|
|
|
return width / surface->scale;
|
2018-06-29 15:45:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
meta_wayland_surface_get_height (MetaWaylandSurface *surface)
|
|
|
|
{
|
2018-11-26 18:40:57 +00:00
|
|
|
int height;
|
2018-06-29 15:45:28 +00:00
|
|
|
|
2018-11-26 18:40:57 +00:00
|
|
|
if (meta_monitor_transform_is_rotated (surface->buffer_transform))
|
|
|
|
height = get_buffer_width (surface);
|
2018-06-29 15:45:28 +00:00
|
|
|
else
|
2018-11-26 18:40:57 +00:00
|
|
|
height = get_buffer_height (surface);
|
|
|
|
|
|
|
|
return height / surface->scale;
|
2018-06-29 15:45:28 +00:00
|
|
|
}
|