2013-08-30 16:26:18 +00:00
|
|
|
/*
|
|
|
|
* Wayland Support
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012,2013 Intel Corporation
|
|
|
|
* 2013 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* 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"
|
|
|
|
|
|
|
|
#include "meta-wayland-surface.h"
|
2013-08-30 16:26:18 +00:00
|
|
|
|
|
|
|
#include <clutter/clutter.h>
|
|
|
|
#include <clutter/wayland/clutter-wayland-compositor.h>
|
|
|
|
#include <clutter/wayland/clutter-wayland-surface.h>
|
2013-09-03 10:00:29 +00:00
|
|
|
#include <cogl/cogl-wayland-server.h>
|
2013-08-30 16:26:18 +00:00
|
|
|
|
|
|
|
#include <wayland-server.h>
|
2013-08-30 07:40:36 +00:00
|
|
|
#include "gtk-shell-server-protocol.h"
|
2013-11-08 22:05:07 +00:00
|
|
|
#include "xdg-shell-server-protocol.h"
|
2013-08-30 16:26:18 +00:00
|
|
|
|
|
|
|
#include "meta-wayland-private.h"
|
|
|
|
#include "meta-xwayland-private.h"
|
2014-10-08 02:39:00 +00:00
|
|
|
#include "meta-wayland-buffer.h"
|
2014-10-08 03:12:36 +00:00
|
|
|
#include "meta-wayland-region.h"
|
2013-08-30 16:26:18 +00:00
|
|
|
#include "meta-wayland-seat.h"
|
|
|
|
#include "meta-wayland-keyboard.h"
|
|
|
|
#include "meta-wayland-pointer.h"
|
2015-02-11 09:34:15 +00:00
|
|
|
#include "meta-wayland-popup.h"
|
2013-08-30 16:26:18 +00:00
|
|
|
#include "meta-wayland-data-device.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
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
#include "meta-cursor-tracker-private.h"
|
|
|
|
#include "display-private.h"
|
|
|
|
#include "window-private.h"
|
2015-04-28 01:09:16 +00:00
|
|
|
#include "meta-window-wayland.h"
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2015-03-03 03:07:36 +00:00
|
|
|
#include "compositor/region-utils.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
|
|
|
#include "meta-surface-actor.h"
|
|
|
|
#include "meta-surface-actor-wayland.h"
|
|
|
|
|
2014-01-12 22:24:00 +00:00
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE,
|
|
|
|
META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW
|
|
|
|
} MetaWaylandSubsurfacePlacement;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
MetaWaylandSubsurfacePlacement placement;
|
|
|
|
MetaWaylandSurface *sibling;
|
|
|
|
struct wl_listener sibling_destroy_listener;
|
|
|
|
} MetaWaylandSubsurfacePlacementOp;
|
|
|
|
|
2015-02-06 08:12:21 +00:00
|
|
|
int
|
|
|
|
meta_wayland_surface_set_role (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandSurfaceRole role,
|
|
|
|
struct wl_resource *error_resource,
|
|
|
|
uint32_t error_code)
|
|
|
|
{
|
|
|
|
if (surface->role == META_WAYLAND_SURFACE_ROLE_NONE ||
|
|
|
|
surface->role == role)
|
|
|
|
{
|
|
|
|
surface->role = role;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wl_resource_post_error (error_resource, error_code,
|
|
|
|
"wl_surface@%d already has a different role",
|
|
|
|
wl_resource_get_id (surface->resource));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-01 22:45:51 +00:00
|
|
|
static void
|
|
|
|
surface_set_buffer (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandBuffer *buffer)
|
|
|
|
{
|
|
|
|
if (surface->buffer == buffer)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (surface->buffer)
|
2014-02-03 23:36:46 +00:00
|
|
|
{
|
|
|
|
wl_list_remove (&surface->buffer_destroy_listener.link);
|
2014-03-25 15:59:16 +00:00
|
|
|
meta_wayland_buffer_unref (surface->buffer);
|
2014-02-03 23:36:46 +00:00
|
|
|
}
|
2014-02-01 22:45:51 +00:00
|
|
|
|
|
|
|
surface->buffer = buffer;
|
|
|
|
|
|
|
|
if (surface->buffer)
|
2014-02-03 23:36:46 +00:00
|
|
|
{
|
|
|
|
meta_wayland_buffer_ref (surface->buffer);
|
|
|
|
wl_signal_add (&surface->buffer->destroy_signal, &surface->buffer_destroy_listener);
|
|
|
|
}
|
2014-02-01 22:45:51 +00:00
|
|
|
}
|
|
|
|
|
wayland: Kill the buffer destroy error
Previously, a sequence like this would crash a client:
=> surface.attach(buffer)
=> buffer.destroy()
The correct behavior is to wait until we release the buffer before
destroying it.
=> surface.attach(buffer)
=> surface.attach(buffer2)
<= buffer.release()
=> buffer.destroy()
The protocol upstream says that "the surface contents are undefined"
in a case like this. Personally, I think that this is broken behavior
and no client should ever do it, so I explicitly killed any client
that tried to do this.
But unfortunately, as we're all well aware, XWayland does this.
Rather than wait for XWayland to be fixed, let's just allow this.
Technically, since we always copy SHM buffers into GL textures, we
could release the buffer as soon as the Cogl texture is made.
Since we do this copy, the semantics we apply are that the texture is
"frozen" in time until another newer buffer is attached. For simple
clients that simply abort on exit and don't wait for the buffer event
anyhow, this has the added bonus that we'll get nice destroy animations.
2014-03-20 17:20:47 +00:00
|
|
|
static void
|
|
|
|
surface_handle_buffer_destroy (struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_container_of (listener, surface, buffer_destroy_listener);
|
|
|
|
|
|
|
|
surface_set_buffer (surface, NULL);
|
|
|
|
}
|
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
static void
|
|
|
|
surface_process_damage (MetaWaylandSurface *surface,
|
|
|
|
cairo_region_t *region)
|
|
|
|
{
|
2015-03-20 07:09:37 +00:00
|
|
|
unsigned int buffer_width;
|
|
|
|
unsigned int buffer_height;
|
|
|
|
cairo_rectangle_int_t surface_rect;
|
2015-03-03 03:07:36 +00:00
|
|
|
cairo_region_t *scaled_region;
|
2014-10-08 02:48:49 +00:00
|
|
|
int i, n_rectangles;
|
2014-04-23 20:14:31 +00:00
|
|
|
|
2014-04-27 14:18:09 +00:00
|
|
|
if (!surface->buffer)
|
|
|
|
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). */
|
|
|
|
buffer_width = cogl_texture_get_width (surface->buffer->texture);
|
|
|
|
buffer_height = cogl_texture_get_height (surface->buffer->texture);
|
|
|
|
surface_rect = (cairo_rectangle_int_t) {
|
|
|
|
.width = buffer_width / surface->scale,
|
|
|
|
.height = buffer_height / surface->scale,
|
|
|
|
};
|
|
|
|
cairo_region_intersect_rectangle (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. */
|
|
|
|
scaled_region = meta_region_scale (region, surface->scale);
|
|
|
|
|
2014-10-08 02:48:49 +00:00
|
|
|
/* First update the buffer. */
|
2015-03-03 03:07:36 +00:00
|
|
|
meta_wayland_buffer_process_damage (surface->buffer, scaled_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? */
|
2015-03-03 03:07:36 +00:00
|
|
|
n_rectangles = cairo_region_num_rectangles (scaled_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;
|
2015-03-03 03:07:36 +00:00
|
|
|
cairo_region_get_rectangle (scaled_region, i, &rect);
|
2014-08-21 20:19:23 +00:00
|
|
|
|
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
|
|
|
meta_surface_actor_process_damage (surface->surface_actor,
|
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);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2013-11-25 20:50:05 +00:00
|
|
|
static void
|
2014-04-18 22:07:05 +00:00
|
|
|
cursor_surface_commit (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandPendingState *pending)
|
2013-11-25 20:50:05 +00:00
|
|
|
{
|
2014-04-12 06:26:38 +00:00
|
|
|
if (pending->newly_attached)
|
2014-02-01 22:55:03 +00:00
|
|
|
meta_wayland_seat_update_cursor_surface (surface->compositor->seat);
|
2013-11-25 20:50:05 +00:00
|
|
|
}
|
|
|
|
|
2014-10-06 15:07:43 +00:00
|
|
|
static void
|
|
|
|
dnd_surface_commit (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandPendingState *pending)
|
|
|
|
{
|
|
|
|
meta_wayland_data_device_update_dnd_surface (&surface->compositor->seat->data_device);
|
|
|
|
}
|
|
|
|
|
2014-07-17 19:24:06 +00:00
|
|
|
static void
|
|
|
|
calculate_surface_window_geometry (MetaWaylandSurface *surface,
|
|
|
|
MetaRectangle *total_geometry,
|
|
|
|
float parent_x,
|
|
|
|
float parent_y)
|
|
|
|
{
|
|
|
|
ClutterActor *surface_actor = CLUTTER_ACTOR (surface->surface_actor);
|
|
|
|
MetaRectangle geom;
|
|
|
|
float x, y;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
/* Unmapped surfaces don't count. */
|
|
|
|
if (!CLUTTER_ACTOR_IS_VISIBLE (surface_actor))
|
|
|
|
return;
|
|
|
|
|
2014-08-26 14:12:38 +00:00
|
|
|
if (!surface->buffer)
|
|
|
|
return;
|
|
|
|
|
2014-07-17 19:24:06 +00:00
|
|
|
/* XXX: Is there a better way to do this using Clutter APIs? */
|
|
|
|
clutter_actor_get_position (surface_actor, &x, &y);
|
|
|
|
|
|
|
|
geom.x = parent_x + x;
|
|
|
|
geom.y = parent_x + y;
|
|
|
|
geom.width = cogl_texture_get_width (surface->buffer->texture);
|
|
|
|
geom.height = cogl_texture_get_height (surface->buffer->texture);
|
|
|
|
|
|
|
|
meta_rectangle_union (total_geometry, &geom, total_geometry);
|
|
|
|
|
|
|
|
for (l = surface->subsurfaces; l != NULL; l = l->next)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *subsurface = l->data;
|
|
|
|
calculate_surface_window_geometry (subsurface, total_geometry, x, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-25 01:13:44 +00:00
|
|
|
static void
|
|
|
|
destroy_window (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-11-25 21:26:02 +00:00
|
|
|
static void
|
2014-07-14 18:49:18 +00:00
|
|
|
toplevel_surface_commit (MetaWaylandSurface *surface,
|
2014-04-18 22:07:05 +00:00
|
|
|
MetaWaylandPendingState *pending)
|
2013-11-25 21:26:02 +00:00
|
|
|
{
|
2014-07-17 18:15:05 +00:00
|
|
|
MetaWindow *window = surface->window;
|
2014-07-03 14:28:31 +00:00
|
|
|
|
2015-04-25 01:13:44 +00:00
|
|
|
if (surface->role == META_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE)
|
2013-11-25 21:26:02 +00:00
|
|
|
{
|
2015-04-25 01:13:44 +00:00
|
|
|
/* For wl_shell, it's equivalent to an unmap. Semantics
|
|
|
|
* are poorly defined, so we can choose some that are
|
|
|
|
* convenient for us. */
|
|
|
|
if (surface->buffer && !window)
|
|
|
|
{
|
|
|
|
window = meta_window_wayland_new (meta_get_display (), surface);
|
|
|
|
meta_wayland_surface_set_window (surface, window);
|
|
|
|
}
|
|
|
|
else if (surface->buffer == NULL && window)
|
|
|
|
{
|
|
|
|
destroy_window (surface);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (surface->buffer == NULL)
|
|
|
|
{
|
|
|
|
/* XDG surfaces can't commit NULL buffers */
|
|
|
|
wl_resource_post_error (surface->resource,
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
"Cannot commit a NULL buffer to an xdg_surface");
|
|
|
|
return;
|
|
|
|
}
|
2014-07-17 18:15:05 +00:00
|
|
|
}
|
2013-11-25 20:50:05 +00:00
|
|
|
|
2014-07-17 18:15:05 +00:00
|
|
|
/* We resize X based surfaces according to X events */
|
|
|
|
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
|
|
|
{
|
2014-07-27 13:21:51 +00:00
|
|
|
MetaRectangle geom = { 0 };
|
2013-11-25 22:35:44 +00:00
|
|
|
|
2014-07-28 09:30:15 +00:00
|
|
|
CoglTexture *texture = surface->buffer->texture;
|
|
|
|
/* Update the buffer rect immediately. */
|
|
|
|
window->buffer_rect.width = cogl_texture_get_width (texture);
|
|
|
|
window->buffer_rect.height = cogl_texture_get_height (texture);
|
|
|
|
|
2014-07-17 18:07:38 +00:00
|
|
|
if (pending->has_new_geometry)
|
|
|
|
{
|
|
|
|
/* If we have new geometry, use it. */
|
|
|
|
geom = pending->new_geometry;
|
|
|
|
surface->has_set_geometry = TRUE;
|
|
|
|
}
|
|
|
|
else if (!surface->has_set_geometry)
|
|
|
|
{
|
|
|
|
/* If the surface has never set any geometry, calculate
|
|
|
|
* a default one unioning the surface and all subsurfaces together. */
|
|
|
|
calculate_surface_window_geometry (surface, &geom, 0, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Otherwise, keep the geometry the same. */
|
|
|
|
|
|
|
|
/* XXX: We don't store the geometry in any consistent place
|
|
|
|
* right now, so we can't re-fetch it. We should change
|
|
|
|
* meta_window_wayland_move_resize. */
|
|
|
|
|
|
|
|
/* XXX: This is the common case. Recognize it to prevent
|
|
|
|
* a warning. */
|
|
|
|
if (pending->dx == 0 && pending->dy == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_warning ("XXX: Attach-initiated move without a new geometry. This is unimplemented right now.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
meta_window_wayland_move_resize (window,
|
|
|
|
&surface->acked_configure_serial,
|
|
|
|
geom, pending->dx, pending->dy);
|
|
|
|
surface->acked_configure_serial.set = FALSE;
|
2013-11-25 20:50:05 +00:00
|
|
|
}
|
2013-11-25 21:26:02 +00:00
|
|
|
}
|
2013-11-25 20:50:05 +00:00
|
|
|
|
2014-01-13 22:31:25 +00:00
|
|
|
static void
|
|
|
|
surface_handle_pending_buffer_destroy (struct wl_listener *listener, void *data)
|
|
|
|
{
|
2014-04-18 22:07:05 +00:00
|
|
|
MetaWaylandPendingState *state = wl_container_of (listener, state, buffer_destroy_listener);
|
2014-01-13 22:31:25 +00:00
|
|
|
|
|
|
|
state->buffer = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
state->opaque_region = NULL;
|
|
|
|
|
2014-01-13 22:31:25 +00:00
|
|
|
state->damage = cairo_region_create ();
|
2014-04-18 22:19:02 +00:00
|
|
|
state->buffer_destroy_listener.notify = surface_handle_pending_buffer_destroy;
|
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;
|
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;
|
|
|
|
|
|
|
|
g_clear_pointer (&state->damage, cairo_region_destroy);
|
|
|
|
g_clear_pointer (&state->input_region, cairo_region_destroy);
|
|
|
|
g_clear_pointer (&state->opaque_region, cairo_region_destroy);
|
|
|
|
|
|
|
|
if (state->buffer)
|
|
|
|
wl_list_remove (&state->buffer_destroy_listener.link);
|
|
|
|
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
|
2014-04-18 22:07:05 +00:00
|
|
|
move_pending_state (MetaWaylandPendingState *from,
|
|
|
|
MetaWaylandPendingState *to)
|
2014-01-13 22:31:25 +00:00
|
|
|
{
|
|
|
|
if (from->buffer)
|
|
|
|
wl_list_remove (&from->buffer_destroy_listener.link);
|
|
|
|
|
2014-04-18 22:19:02 +00:00
|
|
|
*to = *from;
|
2014-01-13 22:31:25 +00:00
|
|
|
|
2015-01-29 07:43:01 +00:00
|
|
|
wl_list_init (&to->frame_callback_list);
|
|
|
|
wl_list_insert_list (&to->frame_callback_list, &from->frame_callback_list);
|
|
|
|
|
2014-01-13 22:31:25 +00:00
|
|
|
if (to->buffer)
|
|
|
|
wl_signal_add (&to->buffer->destroy_signal, &to->buffer_destroy_listener);
|
|
|
|
|
2014-04-18 22:19:02 +00:00
|
|
|
pending_state_init (from);
|
2014-01-13 22:31:25 +00:00
|
|
|
}
|
|
|
|
|
2013-11-25 21:26:02 +00:00
|
|
|
static void
|
2014-04-18 22:07:05 +00:00
|
|
|
subsurface_surface_commit (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandPendingState *pending)
|
2013-11-25 21:26:02 +00:00
|
|
|
{
|
2014-07-17 18:15:05 +00:00
|
|
|
MetaSurfaceActor *surface_actor = surface->surface_actor;
|
|
|
|
float x, y;
|
|
|
|
|
|
|
|
if (surface->buffer != NULL)
|
|
|
|
clutter_actor_show (CLUTTER_ACTOR (surface_actor));
|
|
|
|
else
|
|
|
|
clutter_actor_hide (CLUTTER_ACTOR (surface_actor));
|
|
|
|
|
|
|
|
clutter_actor_get_position (CLUTTER_ACTOR (surface_actor), &x, &y);
|
|
|
|
x += pending->dx;
|
|
|
|
y += pending->dy;
|
|
|
|
clutter_actor_set_position (CLUTTER_ACTOR (surface_actor), x, y);
|
2013-11-25 20:50:05 +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. */
|
|
|
|
static gboolean
|
|
|
|
is_surface_effectively_synchronized (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
if (surface->wl_subsurface == NULL)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (surface->sub.synchronous)
|
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
return is_surface_effectively_synchronized (surface->sub.parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-12 22:17:29 +00:00
|
|
|
static void
|
2015-01-26 08:46:20 +00:00
|
|
|
apply_pending_state (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandPendingState *pending);
|
2014-01-13 22:31:25 +00:00
|
|
|
|
|
|
|
static void
|
2015-01-26 08:46:20 +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;
|
|
|
|
|
|
|
|
if (surface->sub.pending_pos)
|
|
|
|
{
|
|
|
|
clutter_actor_set_position (CLUTTER_ACTOR (surface->surface_actor),
|
|
|
|
surface->sub.pending_x,
|
|
|
|
surface->sub.pending_y);
|
|
|
|
surface->sub.pending_pos = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (surface->sub.pending_placement_ops)
|
|
|
|
{
|
|
|
|
GSList *it;
|
|
|
|
for (it = surface->sub.pending_placement_ops; it; it = it->next)
|
|
|
|
{
|
|
|
|
MetaWaylandSubsurfacePlacementOp *op = it->data;
|
|
|
|
ClutterActor *surface_actor;
|
|
|
|
ClutterActor *parent_actor;
|
|
|
|
ClutterActor *sibling_actor;
|
|
|
|
|
|
|
|
if (!op->sibling)
|
|
|
|
{
|
|
|
|
g_slice_free (MetaWaylandSubsurfacePlacementOp, op);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
surface_actor = CLUTTER_ACTOR (surface->surface_actor);
|
|
|
|
parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->sub.parent));
|
|
|
|
sibling_actor = CLUTTER_ACTOR (op->sibling->surface_actor);
|
|
|
|
|
|
|
|
switch (op->placement)
|
|
|
|
{
|
|
|
|
case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE:
|
|
|
|
clutter_actor_set_child_above_sibling (parent_actor,
|
|
|
|
surface_actor,
|
|
|
|
sibling_actor);
|
|
|
|
break;
|
|
|
|
case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW:
|
|
|
|
clutter_actor_set_child_below_sibling (parent_actor,
|
|
|
|
surface_actor,
|
|
|
|
sibling_actor);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_list_remove (&op->sibling_destroy_listener.link);
|
|
|
|
g_slice_free (MetaWaylandSubsurfacePlacementOp, op);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_slist_free (surface->sub.pending_placement_ops);
|
|
|
|
surface->sub.pending_placement_ops = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_surface_effectively_synchronized (surface))
|
|
|
|
apply_pending_state (surface, &surface->sub.pending);
|
2014-01-13 22:31:25 +00:00
|
|
|
}
|
2014-01-12 22:17:29 +00:00
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
static void
|
2015-01-26 08:46:20 +00:00
|
|
|
apply_pending_state (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandPendingState *pending)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2014-02-01 21:24:43 +00:00
|
|
|
MetaWaylandCompositor *compositor = surface->compositor;
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2014-04-12 06:29:05 +00:00
|
|
|
if (pending->newly_attached)
|
2014-04-18 19:41:48 +00:00
|
|
|
{
|
|
|
|
surface_set_buffer (surface, pending->buffer);
|
|
|
|
|
|
|
|
if (pending->buffer)
|
|
|
|
{
|
2014-10-08 02:48:49 +00:00
|
|
|
CoglTexture *texture = meta_wayland_buffer_ensure_texture (pending->buffer);
|
|
|
|
meta_surface_actor_wayland_set_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), texture);
|
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
|
|
|
|
2014-04-27 14:12:02 +00:00
|
|
|
if (!cairo_region_is_empty (pending->damage))
|
|
|
|
surface_process_damage (surface, pending->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;
|
|
|
|
|
2014-04-18 19:41:48 +00:00
|
|
|
if (pending->opaque_region)
|
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);
|
|
|
|
surface->opaque_region = cairo_region_reference (pending->opaque_region);
|
2014-04-26 08:27:34 +00:00
|
|
|
}
|
2015-03-02 14:56:35 +00:00
|
|
|
|
2014-04-18 19:41:48 +00:00
|
|
|
if (pending->input_region)
|
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);
|
|
|
|
surface->input_region = cairo_region_reference (pending->input_region);
|
2014-04-26 08:27:34 +00:00
|
|
|
}
|
2014-04-12 06:42:40 +00:00
|
|
|
|
2015-03-02 14:56:35 +00:00
|
|
|
meta_surface_actor_wayland_sync_state (
|
|
|
|
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
|
2014-10-25 10:26:19 +00:00
|
|
|
|
2014-10-07 02:53:41 +00:00
|
|
|
/* wl_surface.frame */
|
|
|
|
wl_list_insert_list (&compositor->frame_callbacks, &pending->frame_callback_list);
|
|
|
|
wl_list_init (&pending->frame_callback_list);
|
|
|
|
|
2014-04-17 20:54:30 +00:00
|
|
|
if (surface == compositor->seat->pointer.cursor_surface)
|
2014-04-02 15:24:19 +00:00
|
|
|
cursor_surface_commit (surface, pending);
|
2014-10-06 15:07:43 +00:00
|
|
|
else if (meta_wayland_data_device_is_dnd_surface (&compositor->seat->data_device, surface))
|
|
|
|
dnd_surface_commit (surface, pending);
|
2013-09-03 10:00:29 +00:00
|
|
|
else if (surface->window)
|
2014-04-02 15:24:19 +00:00
|
|
|
toplevel_surface_commit (surface, pending);
|
2014-10-07 17:44:16 +00:00
|
|
|
else if (surface->wl_subsurface)
|
2014-04-02 15:24:19 +00:00
|
|
|
subsurface_surface_commit (surface, pending);
|
2013-08-30 16:26:18 +00:00
|
|
|
|
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)
|
|
|
|
{
|
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.
|
|
|
|
*/
|
|
|
|
if (is_surface_effectively_synchronized (surface))
|
|
|
|
move_pending_state (&surface->pending, &surface->sub.pending);
|
|
|
|
else
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (surface->pending.buffer)
|
|
|
|
wl_list_remove (&surface->pending.buffer_destroy_listener.link);
|
|
|
|
|
2014-07-17 18:15:05 +00:00
|
|
|
surface->pending.newly_attached = TRUE;
|
|
|
|
surface->pending.buffer = buffer;
|
2014-04-02 15:12:58 +00:00
|
|
|
surface->pending.dx = dx;
|
|
|
|
surface->pending.dy = dy;
|
|
|
|
|
|
|
|
if (buffer)
|
|
|
|
wl_signal_add (&buffer->destroy_signal,
|
|
|
|
&surface->pending.buffer_destroy_listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_surface_damage (struct wl_client *client,
|
|
|
|
struct wl_resource *surface_resource,
|
|
|
|
gint32 x,
|
|
|
|
gint32 y,
|
|
|
|
gint32 width,
|
|
|
|
gint32 height)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
|
|
|
cairo_rectangle_int_t rectangle = { x, y, width, height };
|
|
|
|
|
|
|
|
/* X11 unmanaged window */
|
|
|
|
if (!surface)
|
|
|
|
return;
|
|
|
|
|
|
|
|
cairo_region_union_rectangle (surface->pending.damage, &rectangle);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
wl_list_insert (surface->pending.frame_callback_list.prev, &callback->link);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
|
|
|
|
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);
|
|
|
|
surface->pending.opaque_region = cairo_region_copy (cr_region);
|
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;
|
|
|
|
|
|
|
|
g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
|
|
|
|
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);
|
|
|
|
surface->pending.input_region = cairo_region_copy (cr_region);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-04-02 15:10:20 +00:00
|
|
|
wl_surface_set_buffer_transform (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
int32_t transform)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
|
|
|
g_warning ("TODO: support set_buffer_transform request");
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
surface->pending.scale = scale;
|
|
|
|
else
|
|
|
|
g_warning ("Trying to set invalid buffer_scale of %d\n", scale);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
wl_surface_set_buffer_scale
|
2013-08-30 16:26:18 +00:00
|
|
|
};
|
|
|
|
|
2014-04-16 19:41:50 +00:00
|
|
|
static gboolean
|
|
|
|
surface_should_be_reactive (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
/* If we have a toplevel window, we should be reactive */
|
|
|
|
if (surface->window)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* If we're a subsurface, we should be reactive */
|
2014-10-07 17:44:16 +00:00
|
|
|
if (surface->wl_subsurface)
|
2014-04-16 19:41:50 +00:00
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sync_reactive (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
clutter_actor_set_reactive (CLUTTER_ACTOR (surface->surface_actor),
|
|
|
|
surface_should_be_reactive (surface));
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2014-04-02 14:37:08 +00:00
|
|
|
surface->window = window;
|
2014-04-16 19:41:50 +00:00
|
|
|
sync_reactive (surface);
|
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;
|
2013-08-30 16:26:18 +00:00
|
|
|
|
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)
|
|
|
|
destroy_window (surface);
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2014-02-18 21:39:23 +00:00
|
|
|
surface_set_buffer (surface, NULL);
|
2014-04-18 22:07:05 +00:00
|
|
|
pending_state_destroy (&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);
|
|
|
|
|
2014-02-18 21:39:23 +00:00
|
|
|
g_object_unref (surface->surface_actor);
|
2014-02-18 22:07:36 +00:00
|
|
|
|
2015-02-25 15:26:01 +00:00
|
|
|
meta_wayland_compositor_destroy_frame_callbacks (compositor, surface);
|
|
|
|
|
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->xdg_surface)
|
|
|
|
wl_resource_destroy (surface->xdg_surface);
|
|
|
|
if (surface->xdg_popup)
|
|
|
|
wl_resource_destroy (surface->xdg_popup);
|
|
|
|
if (surface->wl_subsurface)
|
|
|
|
wl_resource_destroy (surface->wl_subsurface);
|
|
|
|
if (surface->wl_shell_surface)
|
|
|
|
wl_resource_destroy (surface->wl_shell_surface);
|
|
|
|
if (surface->gtk_surface)
|
|
|
|
wl_resource_destroy (surface->gtk_surface);
|
|
|
|
|
2014-02-18 21:39:23 +00:00
|
|
|
g_slice_free (MetaWaylandSurface, 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
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = g_slice_new0 (MetaWaylandSurface);
|
|
|
|
|
|
|
|
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
|
|
|
|
2014-02-03 23:36:46 +00:00
|
|
|
surface->buffer_destroy_listener.notify = surface_handle_buffer_destroy;
|
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
|
|
|
surface->surface_actor = g_object_ref_sink (meta_surface_actor_wayland_new (surface));
|
2014-02-18 00:10:25 +00:00
|
|
|
|
2014-04-18 22:07:05 +00:00
|
|
|
pending_state_init (&surface->pending);
|
2013-08-30 16:26:18 +00:00
|
|
|
return surface;
|
|
|
|
}
|
|
|
|
|
2015-02-06 08:28:28 +00:00
|
|
|
static void
|
|
|
|
xdg_shell_destroy (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
|
|
|
wl_resource_destroy (resource);
|
|
|
|
}
|
|
|
|
|
2014-02-15 15:02:04 +00:00
|
|
|
static void
|
|
|
|
xdg_shell_use_unstable_version (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
int32_t version)
|
|
|
|
{
|
2014-02-15 15:02:48 +00:00
|
|
|
if (version != XDG_SHELL_VERSION_CURRENT)
|
2014-09-05 23:21:43 +00:00
|
|
|
wl_resource_post_error (resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
"bad xdg-shell version: %d\n", version);
|
2014-02-15 15:02:04 +00:00
|
|
|
}
|
|
|
|
|
2014-02-15 15:26:43 +00:00
|
|
|
static void
|
|
|
|
xdg_shell_pong (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
uint32_t serial)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_get_display ();
|
|
|
|
|
|
|
|
meta_display_pong_for_serial (display, serial);
|
|
|
|
}
|
|
|
|
|
2013-11-26 18:04:37 +00:00
|
|
|
static void
|
|
|
|
xdg_surface_destructor (struct wl_resource *resource)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-26 18:04:37 +00:00
|
|
|
|
2015-02-25 15:26:01 +00:00
|
|
|
meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
|
|
|
|
surface);
|
2013-11-26 18:04:37 +00:00
|
|
|
destroy_window (surface);
|
2014-10-07 17:44:16 +00:00
|
|
|
surface->xdg_surface = NULL;
|
2013-11-26 18:04:37 +00:00
|
|
|
}
|
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
static void
|
2013-11-08 22:05:07 +00:00
|
|
|
xdg_surface_destroy (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
2013-11-20 04:33:46 +00:00
|
|
|
wl_resource_destroy (resource);
|
2013-11-08 22:05:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-04-12 05:33:38 +00:00
|
|
|
xdg_surface_set_parent (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *parent_resource)
|
2013-11-08 22:05:07 +00:00
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-21 18:09:13 +00:00
|
|
|
MetaWindow *transient_for = NULL;
|
2013-11-08 22:05:07 +00:00
|
|
|
|
2013-11-21 18:09:13 +00:00
|
|
|
if (parent_resource)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *parent_surface = wl_resource_get_user_data (parent_resource);
|
|
|
|
transient_for = parent_surface->window;
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_window_set_transient_for (surface->window, transient_for);
|
2013-11-08 22:05:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xdg_surface_set_title (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
const char *title)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-08 22:05:07 +00:00
|
|
|
|
2013-11-19 21:04:14 +00:00
|
|
|
meta_window_set_title (surface->window, title);
|
2013-11-08 22:05:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xdg_surface_set_app_id (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
const char *app_id)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-08 22:05:07 +00:00
|
|
|
|
2013-11-19 21:04:14 +00:00
|
|
|
meta_window_set_wm_class (surface->window, app_id, app_id);
|
2013-11-08 22:05:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-13 20:54:04 +00:00
|
|
|
static void
|
|
|
|
xdg_surface_show_window_menu (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *seat_resource,
|
|
|
|
uint32_t serial,
|
2014-07-17 18:51:12 +00:00
|
|
|
int32_t x,
|
|
|
|
int32_t y)
|
2014-03-13 20:54:04 +00:00
|
|
|
{
|
|
|
|
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
|
|
|
|
2014-07-21 23:28:39 +00:00
|
|
|
if (!meta_wayland_seat_get_grab_info (seat, surface, serial, NULL, NULL))
|
2014-03-13 20:54:04 +00:00
|
|
|
return;
|
|
|
|
|
2014-07-28 08:02:52 +00:00
|
|
|
meta_window_show_menu (surface->window, META_WINDOW_MENU_WM,
|
|
|
|
surface->window->buffer_rect.x + x,
|
|
|
|
surface->window->buffer_rect.y + y);
|
2014-03-13 20:54:04 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 02:45:34 +00:00
|
|
|
static gboolean
|
|
|
|
begin_grab_op_on_surface (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandSeat *seat,
|
2014-07-21 23:28:39 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
return meta_display_begin_grab_op (window->display,
|
|
|
|
window->screen,
|
|
|
|
window,
|
|
|
|
grab_op,
|
|
|
|
TRUE, /* pointer_already_grabbed */
|
|
|
|
FALSE, /* frame_action */
|
|
|
|
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
|
|
|
static void
|
2013-11-08 22:05:07 +00:00
|
|
|
xdg_surface_move (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *seat_resource,
|
|
|
|
guint32 serial)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
|
|
|
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-07-21 23:28:39 +00:00
|
|
|
gfloat x, y;
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2014-07-21 23:28:39 +00:00
|
|
|
if (!meta_wayland_seat_get_grab_info (seat, surface, serial, &x, &y))
|
2013-08-30 16:26:18 +00:00
|
|
|
return;
|
|
|
|
|
2014-07-21 23:28:39 +00:00
|
|
|
begin_grab_op_on_surface (surface, seat, META_GRAB_OP_MOVING, x, y);
|
2013-11-15 02:45:34 +00:00
|
|
|
}
|
2013-09-11 12:06:05 +00:00
|
|
|
|
2013-11-15 02:45:34 +00:00
|
|
|
static MetaGrabOp
|
2014-02-28 05:18:42 +00:00
|
|
|
grab_op_for_xdg_surface_resize_edge (int edge)
|
2013-11-15 02:45:34 +00:00
|
|
|
{
|
2014-08-15 18:05:04 +00:00
|
|
|
MetaGrabOp op = META_GRAB_OP_WINDOW_BASE;
|
|
|
|
|
|
|
|
if (edge & XDG_SURFACE_RESIZE_EDGE_TOP)
|
|
|
|
op |= META_GRAB_OP_WINDOW_DIR_NORTH;
|
|
|
|
if (edge & XDG_SURFACE_RESIZE_EDGE_BOTTOM)
|
|
|
|
op |= META_GRAB_OP_WINDOW_DIR_SOUTH;
|
|
|
|
if (edge & XDG_SURFACE_RESIZE_EDGE_LEFT)
|
|
|
|
op |= META_GRAB_OP_WINDOW_DIR_WEST;
|
|
|
|
if (edge & XDG_SURFACE_RESIZE_EDGE_RIGHT)
|
|
|
|
op |= META_GRAB_OP_WINDOW_DIR_EAST;
|
|
|
|
|
|
|
|
if (op == META_GRAB_OP_WINDOW_BASE)
|
2013-11-15 02:45:34 +00:00
|
|
|
{
|
|
|
|
g_warning ("invalid edge: %d", edge);
|
|
|
|
return META_GRAB_OP_NONE;
|
|
|
|
}
|
2014-08-15 18:05:04 +00:00
|
|
|
|
|
|
|
return op;
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-11-08 22:05:07 +00:00
|
|
|
xdg_surface_resize (struct wl_client *client,
|
2013-11-15 02:45:34 +00:00
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *seat_resource,
|
|
|
|
guint32 serial,
|
|
|
|
guint32 edges)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2013-11-15 02:45:34 +00:00
|
|
|
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-07-21 23:28:39 +00:00
|
|
|
gfloat x, y;
|
2013-11-15 02:45:34 +00:00
|
|
|
|
2014-07-21 23:28:39 +00:00
|
|
|
if (!meta_wayland_seat_get_grab_info (seat, surface, serial, &x, &y))
|
2013-11-15 02:45:34 +00:00
|
|
|
return;
|
|
|
|
|
2014-07-21 23:28:39 +00:00
|
|
|
begin_grab_op_on_surface (surface, seat, grab_op_for_xdg_surface_resize_edge (edges), x, y);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-05-05 23:09:22 +00:00
|
|
|
xdg_surface_ack_configure (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
uint32_t serial)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
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
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
|
|
|
|
|
|
|
surface->acked_configure_serial.set = TRUE;
|
|
|
|
surface->acked_configure_serial.value = serial;
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2014-07-17 18:07:38 +00:00
|
|
|
static void
|
|
|
|
xdg_surface_set_window_geometry (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
int32_t x, int32_t y, int32_t width, int32_t height)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-08-30 16:26:18 +00:00
|
|
|
static void
|
2014-05-05 23:09:22 +00:00
|
|
|
xdg_surface_set_maximized (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-05-05 23:09:22 +00:00
|
|
|
meta_window_maximize (surface->window, META_MAXIMIZE_BOTH);
|
|
|
|
}
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2014-05-05 23:09:22 +00:00
|
|
|
static void
|
|
|
|
xdg_surface_unset_maximized (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
|
|
|
meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH);
|
|
|
|
}
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2014-05-05 23:09:22 +00:00
|
|
|
static void
|
|
|
|
xdg_surface_set_fullscreen (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *output_resource)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
|
|
|
meta_window_make_fullscreen (surface->window);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-05-05 23:09:22 +00:00
|
|
|
xdg_surface_unset_fullscreen (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2014-05-05 23:09:22 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
|
|
|
meta_window_unmake_fullscreen (surface->window);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-11-08 22:05:07 +00:00
|
|
|
xdg_surface_set_minimized (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-19 22:33:57 +00:00
|
|
|
meta_window_minimize (surface->window);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 02:49:51 +00:00
|
|
|
static const struct xdg_surface_interface meta_wayland_xdg_surface_interface = {
|
2013-11-08 22:05:07 +00:00
|
|
|
xdg_surface_destroy,
|
2014-04-12 05:33:38 +00:00
|
|
|
xdg_surface_set_parent,
|
2013-11-08 22:05:07 +00:00
|
|
|
xdg_surface_set_title,
|
|
|
|
xdg_surface_set_app_id,
|
2014-03-13 20:54:04 +00:00
|
|
|
xdg_surface_show_window_menu,
|
2013-11-08 22:05:07 +00:00
|
|
|
xdg_surface_move,
|
|
|
|
xdg_surface_resize,
|
2014-05-05 23:09:22 +00:00
|
|
|
xdg_surface_ack_configure,
|
2014-07-17 18:07:38 +00:00
|
|
|
xdg_surface_set_window_geometry,
|
2014-05-05 23:09:22 +00:00
|
|
|
xdg_surface_set_maximized,
|
|
|
|
xdg_surface_unset_maximized,
|
|
|
|
xdg_surface_set_fullscreen,
|
|
|
|
xdg_surface_unset_fullscreen,
|
2013-11-08 22:05:07 +00:00
|
|
|
xdg_surface_set_minimized,
|
2013-08-30 16:26:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2014-02-15 15:02:04 +00:00
|
|
|
xdg_shell_get_xdg_surface (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
guint32 id,
|
|
|
|
struct wl_resource *surface_resource)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
2014-04-02 14:37:08 +00:00
|
|
|
MetaWindow *window;
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
if (surface->xdg_surface != NULL)
|
2013-11-25 23:15:03 +00:00
|
|
|
{
|
|
|
|
wl_resource_post_error (surface_resource,
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
"xdg_shell::get_xdg_surface already requested");
|
|
|
|
return;
|
|
|
|
}
|
2013-11-19 22:33:57 +00:00
|
|
|
|
2015-02-06 08:12:21 +00:00
|
|
|
if (meta_wayland_surface_set_role (surface,
|
|
|
|
META_WAYLAND_SURFACE_ROLE_XDG_SURFACE,
|
|
|
|
surface_resource,
|
|
|
|
XDG_SHELL_ERROR_ROLE) != 0)
|
|
|
|
return;
|
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
surface->xdg_surface = wl_resource_create (client, &xdg_surface_interface, wl_resource_get_version (resource), id);
|
|
|
|
wl_resource_set_implementation (surface->xdg_surface, &meta_wayland_xdg_surface_interface, surface, xdg_surface_destructor);
|
2014-10-07 18:21:31 +00:00
|
|
|
|
2014-08-22 16:52:18 +00:00
|
|
|
surface->xdg_shell_resource = resource;
|
|
|
|
|
2014-04-02 14:37:08 +00:00
|
|
|
window = meta_window_wayland_new (meta_get_display (), surface);
|
|
|
|
meta_wayland_surface_set_window (surface, window);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2013-11-26 18:04:37 +00:00
|
|
|
static void
|
|
|
|
xdg_popup_destructor (struct wl_resource *resource)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-26 18:04:37 +00:00
|
|
|
|
2015-02-25 15:26:01 +00:00
|
|
|
meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
|
|
|
|
surface);
|
2015-02-24 19:53:55 +00:00
|
|
|
if (surface->popup.parent)
|
|
|
|
{
|
|
|
|
wl_list_remove (&surface->popup.parent_destroy_listener.link);
|
|
|
|
surface->popup.parent = NULL;
|
|
|
|
}
|
|
|
|
|
2015-02-12 03:13:55 +00:00
|
|
|
if (surface->popup.popup)
|
|
|
|
meta_wayland_popup_dismiss (surface->popup.popup);
|
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
surface->xdg_popup = NULL;
|
2013-11-26 18:04:37 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 02:55:37 +00:00
|
|
|
static void
|
|
|
|
xdg_popup_destroy (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
2013-11-20 04:33:46 +00:00
|
|
|
wl_resource_destroy (resource);
|
2013-11-15 02:55:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = {
|
|
|
|
xdg_popup_destroy,
|
|
|
|
};
|
|
|
|
|
2015-02-24 19:53:55 +00:00
|
|
|
static void
|
|
|
|
handle_popup_parent_destroyed (struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface =
|
|
|
|
wl_container_of (listener, surface, popup.parent_destroy_listener);
|
|
|
|
|
|
|
|
wl_resource_post_error (surface->xdg_popup,
|
|
|
|
XDG_POPUP_ERROR_NOT_THE_TOPMOST_POPUP,
|
|
|
|
"destroyed popup not top most popup");
|
|
|
|
surface->popup.parent = NULL;
|
|
|
|
|
|
|
|
destroy_window (surface);
|
|
|
|
}
|
|
|
|
|
2015-02-12 03:13:55 +00:00
|
|
|
static void
|
|
|
|
handle_popup_destroyed (struct wl_listener *listener, void *data)
|
|
|
|
{
|
2015-02-12 03:20:52 +00:00
|
|
|
MetaWaylandPopup *popup = data;
|
|
|
|
MetaWaylandSurface *top_popup;
|
2015-02-12 03:13:55 +00:00
|
|
|
MetaWaylandSurface *surface =
|
|
|
|
wl_container_of (listener, surface, popup.destroy_listener);
|
|
|
|
|
2015-02-12 03:20:52 +00:00
|
|
|
top_popup = meta_wayland_popup_get_top_popup (popup);
|
|
|
|
if (surface != top_popup)
|
|
|
|
{
|
|
|
|
wl_resource_post_error (surface->xdg_popup,
|
|
|
|
XDG_POPUP_ERROR_NOT_THE_TOPMOST_POPUP,
|
|
|
|
"destroyed popup not top most popup");
|
|
|
|
}
|
|
|
|
|
2015-02-12 03:13:55 +00:00
|
|
|
surface->popup.popup = NULL;
|
|
|
|
|
|
|
|
destroy_window (surface);
|
|
|
|
}
|
|
|
|
|
2013-11-08 22:05:07 +00:00
|
|
|
static void
|
2014-02-15 15:02:04 +00:00
|
|
|
xdg_shell_get_xdg_popup (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
uint32_t id,
|
|
|
|
struct wl_resource *surface_resource,
|
|
|
|
struct wl_resource *parent_resource,
|
|
|
|
struct wl_resource *seat_resource,
|
|
|
|
uint32_t serial,
|
|
|
|
int32_t x,
|
2015-02-06 08:28:28 +00:00
|
|
|
int32_t y)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2015-02-10 13:11:17 +00:00
|
|
|
struct wl_resource *popup_resource;
|
2013-11-15 02:55:37 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
|
|
|
MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource);
|
2015-02-12 03:20:52 +00:00
|
|
|
MetaWaylandSurface *top_popup;
|
2013-11-15 02:55:37 +00:00
|
|
|
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
2014-04-02 14:37:08 +00:00
|
|
|
MetaWindow *window;
|
2014-10-06 23:58:39 +00:00
|
|
|
MetaDisplay *display = meta_get_display ();
|
2015-02-12 03:13:55 +00:00
|
|
|
MetaWaylandPopup *popup;
|
2013-11-15 02:55:37 +00:00
|
|
|
|
|
|
|
if (parent_surf == NULL || parent_surf->window == NULL)
|
|
|
|
return;
|
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
if (surface->xdg_popup != NULL)
|
2013-11-25 23:15:03 +00:00
|
|
|
{
|
|
|
|
wl_resource_post_error (surface_resource,
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
2013-11-25 23:15:19 +00:00
|
|
|
"xdg_shell::get_xdg_popup already requested");
|
2013-11-25 23:15:03 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-11-15 02:55:37 +00:00
|
|
|
|
2015-02-06 08:12:21 +00:00
|
|
|
if (meta_wayland_surface_set_role (surface,
|
|
|
|
META_WAYLAND_SURFACE_ROLE_XDG_POPUP,
|
|
|
|
surface_resource,
|
|
|
|
XDG_SHELL_ERROR_ROLE) != 0)
|
|
|
|
return;
|
|
|
|
|
2015-02-10 12:58:09 +00:00
|
|
|
if (parent_surf->xdg_popup == NULL && parent_surf->xdg_surface == NULL)
|
|
|
|
{
|
|
|
|
wl_resource_post_error (resource,
|
|
|
|
XDG_POPUP_ERROR_INVALID_PARENT,
|
|
|
|
"invalid parent surface");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-02-12 03:20:52 +00:00
|
|
|
top_popup = meta_wayland_pointer_get_top_popup (&seat->pointer);
|
|
|
|
if ((top_popup == NULL && parent_surf->xdg_surface == NULL) ||
|
|
|
|
(top_popup != NULL && parent_surf != top_popup))
|
|
|
|
{
|
|
|
|
wl_resource_post_error (resource,
|
|
|
|
XDG_POPUP_ERROR_NOT_THE_TOPMOST_POPUP,
|
|
|
|
"parent not top most surface");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-02-10 13:11:17 +00:00
|
|
|
popup_resource = wl_resource_create (client, &xdg_popup_interface,
|
|
|
|
wl_resource_get_version (resource), id);
|
|
|
|
wl_resource_set_implementation (popup_resource,
|
|
|
|
&meta_wayland_xdg_popup_interface,
|
|
|
|
surface,
|
|
|
|
xdg_popup_destructor);
|
2014-10-07 18:21:31 +00:00
|
|
|
|
2015-02-10 13:11:17 +00:00
|
|
|
if (!meta_wayland_pointer_can_popup (&seat->pointer, serial))
|
|
|
|
{
|
|
|
|
xdg_popup_send_popup_done (popup_resource);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
surface->xdg_popup = popup_resource;
|
2014-08-22 16:52:18 +00:00
|
|
|
surface->xdg_shell_resource = resource;
|
|
|
|
|
2015-02-24 19:53:55 +00:00
|
|
|
surface->popup.parent = parent_surf;
|
|
|
|
surface->popup.parent_destroy_listener.notify = handle_popup_parent_destroyed;
|
|
|
|
wl_resource_add_destroy_listener (parent_surf->resource,
|
|
|
|
&surface->popup.parent_destroy_listener);
|
|
|
|
|
2014-10-06 23:58:39 +00:00
|
|
|
window = meta_window_wayland_new (display, surface);
|
2014-05-21 12:46:18 +00:00
|
|
|
meta_window_move_frame (window, FALSE,
|
|
|
|
parent_surf->window->rect.x + x,
|
|
|
|
parent_surf->window->rect.y + y);
|
2014-04-02 14:37:08 +00:00
|
|
|
window->showing_for_first_time = FALSE;
|
|
|
|
window->placed = TRUE;
|
2013-11-15 02:55:37 +00:00
|
|
|
|
2014-04-02 14:37:08 +00:00
|
|
|
meta_wayland_surface_set_window (surface, window);
|
2013-12-04 15:41:30 +00:00
|
|
|
|
2014-10-06 23:58:39 +00:00
|
|
|
meta_window_focus (window, meta_display_get_current_time (display));
|
2015-02-12 03:13:55 +00:00
|
|
|
popup = meta_wayland_pointer_start_popup_grab (&seat->pointer, surface);
|
|
|
|
if (popup == NULL)
|
|
|
|
{
|
|
|
|
destroy_window (surface);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
surface->popup.destroy_listener.notify = handle_popup_destroyed;
|
|
|
|
surface->popup.popup = popup;
|
|
|
|
wl_signal_add (meta_wayland_popup_get_destroy_signal (popup),
|
|
|
|
&surface->popup.destroy_listener);
|
2013-11-08 22:05:07 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 02:49:51 +00:00
|
|
|
static const struct xdg_shell_interface meta_wayland_xdg_shell_interface = {
|
2015-02-06 08:28:28 +00:00
|
|
|
xdg_shell_destroy,
|
2014-02-15 15:02:04 +00:00
|
|
|
xdg_shell_use_unstable_version,
|
|
|
|
xdg_shell_get_xdg_surface,
|
|
|
|
xdg_shell_get_xdg_popup,
|
2014-02-15 15:26:43 +00:00
|
|
|
xdg_shell_pong,
|
2013-08-30 16:26:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2013-11-08 22:05:07 +00:00
|
|
|
bind_xdg_shell (struct wl_client *client,
|
|
|
|
void *data,
|
|
|
|
guint32 version,
|
|
|
|
guint32 id)
|
2013-08-30 16:26:18 +00:00
|
|
|
{
|
2014-08-22 16:52:18 +00:00
|
|
|
struct wl_resource *resource;
|
2013-08-30 16:26:18 +00:00
|
|
|
|
2014-07-17 21:37:29 +00:00
|
|
|
if (version != META_XDG_SHELL_VERSION)
|
2014-02-15 15:02:48 +00:00
|
|
|
{
|
2014-07-17 21:37:29 +00:00
|
|
|
g_warning ("using xdg-shell without stable version %d\n", META_XDG_SHELL_VERSION);
|
2014-02-15 15:02:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-22 16:52:18 +00:00
|
|
|
resource = wl_resource_create (client, &xdg_shell_interface, version, id);
|
|
|
|
wl_resource_set_implementation (resource, &meta_wayland_xdg_shell_interface, data, NULL);
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2014-02-28 05:18:42 +00:00
|
|
|
static void
|
|
|
|
wl_shell_surface_destructor (struct wl_resource *resource)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-02-28 05:18:42 +00:00
|
|
|
|
2015-02-25 15:26:01 +00:00
|
|
|
meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
|
|
|
|
surface);
|
2014-10-07 17:44:16 +00:00
|
|
|
surface->wl_shell_surface = NULL;
|
2014-02-28 05:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_pong (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
uint32_t serial)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_get_display ();
|
|
|
|
|
|
|
|
meta_display_pong_for_serial (display, serial);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_move (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *seat_resource,
|
|
|
|
uint32_t serial)
|
|
|
|
{
|
|
|
|
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-07-21 23:28:39 +00:00
|
|
|
gfloat x, y;
|
2014-02-28 05:18:42 +00:00
|
|
|
|
2014-07-21 23:28:39 +00:00
|
|
|
if (!meta_wayland_seat_get_grab_info (seat, surface, serial, &x, &y))
|
2014-02-28 05:18:42 +00:00
|
|
|
return;
|
|
|
|
|
2014-07-21 23:28:39 +00:00
|
|
|
begin_grab_op_on_surface (surface, seat, META_GRAB_OP_MOVING, x, y);
|
2014-02-28 05:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static MetaGrabOp
|
|
|
|
grab_op_for_wl_shell_surface_resize_edge (int edge)
|
|
|
|
{
|
2014-08-15 18:05:04 +00:00
|
|
|
MetaGrabOp op = META_GRAB_OP_WINDOW_BASE;
|
|
|
|
|
|
|
|
if (edge & WL_SHELL_SURFACE_RESIZE_TOP)
|
|
|
|
op |= META_GRAB_OP_WINDOW_DIR_NORTH;
|
|
|
|
if (edge & WL_SHELL_SURFACE_RESIZE_BOTTOM)
|
|
|
|
op |= META_GRAB_OP_WINDOW_DIR_SOUTH;
|
|
|
|
if (edge & WL_SHELL_SURFACE_RESIZE_LEFT)
|
|
|
|
op |= META_GRAB_OP_WINDOW_DIR_WEST;
|
|
|
|
if (edge & WL_SHELL_SURFACE_RESIZE_RIGHT)
|
|
|
|
op |= META_GRAB_OP_WINDOW_DIR_EAST;
|
|
|
|
|
|
|
|
if (op == META_GRAB_OP_WINDOW_BASE)
|
2014-02-28 05:18:42 +00:00
|
|
|
{
|
|
|
|
g_warning ("invalid edge: %d", edge);
|
|
|
|
return META_GRAB_OP_NONE;
|
|
|
|
}
|
2014-08-15 18:05:04 +00:00
|
|
|
|
|
|
|
return op;
|
2014-02-28 05:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_resize (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *seat_resource,
|
|
|
|
uint32_t serial,
|
|
|
|
uint32_t edges)
|
|
|
|
{
|
|
|
|
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-07-21 23:28:39 +00:00
|
|
|
gfloat x, y;
|
2014-02-28 05:18:42 +00:00
|
|
|
|
2014-07-21 23:28:39 +00:00
|
|
|
if (!meta_wayland_seat_get_grab_info (seat, surface, serial, &x, &y))
|
2014-02-28 05:18:42 +00:00
|
|
|
return;
|
|
|
|
|
2014-07-21 23:28:39 +00:00
|
|
|
begin_grab_op_on_surface (surface, seat, grab_op_for_wl_shell_surface_resize_edge (edges), x, y);
|
2014-02-28 05:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
SURFACE_STATE_TOPLEVEL,
|
|
|
|
SURFACE_STATE_FULLSCREEN,
|
|
|
|
SURFACE_STATE_MAXIMIZED,
|
|
|
|
} SurfaceState;
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_set_state (MetaWaylandSurface *surface,
|
|
|
|
SurfaceState state)
|
|
|
|
{
|
|
|
|
if (state == SURFACE_STATE_FULLSCREEN)
|
|
|
|
meta_window_make_fullscreen (surface->window);
|
|
|
|
else
|
|
|
|
meta_window_unmake_fullscreen (surface->window);
|
|
|
|
|
|
|
|
if (state == SURFACE_STATE_MAXIMIZED)
|
2014-03-13 22:32:20 +00:00
|
|
|
meta_window_maximize (surface->window, META_MAXIMIZE_BOTH);
|
2014-02-28 05:18:42 +00:00
|
|
|
else
|
2014-03-13 22:32:20 +00:00
|
|
|
meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH);
|
2014-02-28 05:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_set_toplevel (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-02-28 05:18:42 +00:00
|
|
|
|
|
|
|
wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_set_transient (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *parent_resource,
|
|
|
|
int32_t x,
|
|
|
|
int32_t y,
|
|
|
|
uint32_t flags)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource);
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-02-28 05:18:42 +00:00
|
|
|
|
|
|
|
wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL);
|
|
|
|
|
|
|
|
meta_window_set_transient_for (surface->window, parent_surf->window);
|
2014-05-21 12:46:18 +00:00
|
|
|
meta_window_move_frame (surface->window, FALSE,
|
|
|
|
parent_surf->window->rect.x + x,
|
|
|
|
parent_surf->window->rect.y + y);
|
2014-02-28 05:18:42 +00:00
|
|
|
surface->window->placed = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_set_fullscreen (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
uint32_t method,
|
|
|
|
uint32_t framerate,
|
|
|
|
struct wl_resource *output)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-02-28 05:18:42 +00:00
|
|
|
|
|
|
|
wl_shell_surface_set_state (surface, SURFACE_STATE_FULLSCREEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_set_popup (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *seat_resource,
|
|
|
|
uint32_t serial,
|
|
|
|
struct wl_resource *parent_resource,
|
|
|
|
int32_t x,
|
|
|
|
int32_t y,
|
|
|
|
uint32_t flags)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-02-28 05:18:42 +00:00
|
|
|
MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource);
|
|
|
|
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
|
|
|
|
|
|
|
wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL);
|
|
|
|
|
2015-02-10 13:11:17 +00:00
|
|
|
if (!meta_wayland_pointer_can_popup (&seat->pointer, serial))
|
|
|
|
{
|
|
|
|
wl_shell_surface_send_popup_done (resource);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-28 05:18:42 +00:00
|
|
|
meta_window_set_transient_for (surface->window, parent_surf->window);
|
2014-05-21 12:46:18 +00:00
|
|
|
meta_window_move_frame (surface->window, FALSE,
|
|
|
|
parent_surf->window->rect.x + x,
|
|
|
|
parent_surf->window->rect.y + y);
|
2014-02-28 05:18:42 +00:00
|
|
|
surface->window->placed = TRUE;
|
|
|
|
|
|
|
|
meta_wayland_pointer_start_popup_grab (&seat->pointer, surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_set_maximized (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *output)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-02-28 05:18:42 +00:00
|
|
|
|
|
|
|
wl_shell_surface_set_state (surface, SURFACE_STATE_MAXIMIZED);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_set_title (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
const char *title)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-02-28 05:18:42 +00:00
|
|
|
|
|
|
|
meta_window_set_title (surface->window, title);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_surface_set_class (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
const char *class_)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-02-28 05:18:42 +00:00
|
|
|
|
|
|
|
meta_window_set_wm_class (surface->window, class_, class_);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_shell_surface_interface meta_wayland_wl_shell_surface_interface = {
|
|
|
|
wl_shell_surface_pong,
|
|
|
|
wl_shell_surface_move,
|
|
|
|
wl_shell_surface_resize,
|
|
|
|
wl_shell_surface_set_toplevel,
|
|
|
|
wl_shell_surface_set_transient,
|
|
|
|
wl_shell_surface_set_fullscreen,
|
|
|
|
wl_shell_surface_set_popup,
|
|
|
|
wl_shell_surface_set_maximized,
|
|
|
|
wl_shell_surface_set_title,
|
|
|
|
wl_shell_surface_set_class,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_shell_get_shell_surface (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
uint32_t id,
|
|
|
|
struct wl_resource *surface_resource)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
if (surface->wl_shell_surface != NULL)
|
2014-02-28 05:18:42 +00:00
|
|
|
{
|
|
|
|
wl_resource_post_error (surface_resource,
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
"wl_shell::get_shell_surface already requested");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-02-06 08:12:21 +00:00
|
|
|
if (meta_wayland_surface_set_role (surface,
|
|
|
|
META_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE,
|
|
|
|
surface_resource,
|
|
|
|
WL_SHELL_ERROR_ROLE) != 0)
|
|
|
|
return;
|
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
surface->wl_shell_surface = wl_resource_create (client, &wl_shell_surface_interface, wl_resource_get_version (resource), id);
|
|
|
|
wl_resource_set_implementation (surface->wl_shell_surface, &meta_wayland_wl_shell_surface_interface, surface, wl_shell_surface_destructor);
|
2014-02-28 05:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_shell_interface meta_wayland_wl_shell_interface = {
|
|
|
|
wl_shell_get_shell_surface,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
bind_wl_shell (struct wl_client *client,
|
|
|
|
void *data,
|
|
|
|
uint32_t version,
|
|
|
|
uint32_t id)
|
|
|
|
{
|
|
|
|
struct wl_resource *resource;
|
|
|
|
|
2014-08-04 14:24:59 +00:00
|
|
|
resource = wl_resource_create (client, &wl_shell_interface, version, id);
|
2014-02-28 05:18:42 +00:00
|
|
|
wl_resource_set_implementation (resource, &meta_wayland_wl_shell_interface, data, NULL);
|
|
|
|
}
|
|
|
|
|
2013-11-26 18:04:37 +00:00
|
|
|
static void
|
|
|
|
gtk_surface_destructor (struct wl_resource *resource)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-26 18:04:37 +00:00
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
surface->gtk_surface = NULL;
|
2013-11-26 18:04:37 +00:00
|
|
|
}
|
|
|
|
|
2013-08-30 07:40:36 +00:00
|
|
|
static void
|
2015-03-06 03:44:42 +00:00
|
|
|
gtk_surface_set_dbus_properties (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
const char *application_id,
|
|
|
|
const char *app_menu_path,
|
|
|
|
const char *menubar_path,
|
|
|
|
const char *window_object_path,
|
|
|
|
const char *application_object_path,
|
|
|
|
const char *unique_bus_name)
|
2013-08-30 07:40:36 +00:00
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-08-30 07:40:36 +00:00
|
|
|
|
2014-02-16 15:15:14 +00:00
|
|
|
/* Broken client, let it die instead of us */
|
|
|
|
if (!surface->window)
|
|
|
|
{
|
|
|
|
meta_warning ("meta-wayland-surface: set_dbus_properties called with invalid window!\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-19 21:04:14 +00:00
|
|
|
meta_window_set_gtk_dbus_properties (surface->window,
|
|
|
|
application_id,
|
|
|
|
unique_bus_name,
|
|
|
|
app_menu_path,
|
|
|
|
menubar_path,
|
|
|
|
application_object_path,
|
|
|
|
window_object_path);
|
2013-08-30 07:40:36 +00:00
|
|
|
}
|
|
|
|
|
2015-03-06 03:44:42 +00:00
|
|
|
static void
|
|
|
|
gtk_surface_set_modal (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
|
|
|
|
|
|
|
if (surface->is_modal)
|
|
|
|
return;
|
|
|
|
|
|
|
|
surface->is_modal = TRUE;
|
|
|
|
meta_window_set_type (surface->window, META_WINDOW_MODAL_DIALOG);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_surface_unset_modal (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
|
|
|
|
|
|
|
if (!surface->is_modal)
|
|
|
|
return;
|
|
|
|
|
|
|
|
surface->is_modal = FALSE;
|
|
|
|
meta_window_set_type (surface->window, META_WINDOW_NORMAL);
|
|
|
|
}
|
|
|
|
|
2013-11-15 02:49:51 +00:00
|
|
|
static const struct gtk_surface_interface meta_wayland_gtk_surface_interface = {
|
2015-03-06 03:44:42 +00:00
|
|
|
gtk_surface_set_dbus_properties,
|
|
|
|
gtk_surface_set_modal,
|
|
|
|
gtk_surface_unset_modal,
|
2013-08-30 07:40:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_gtk_surface (struct wl_client *client,
|
2014-07-17 21:39:43 +00:00
|
|
|
struct wl_resource *resource,
|
|
|
|
guint32 id,
|
|
|
|
struct wl_resource *surface_resource)
|
2013-08-30 07:40:36 +00:00
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
if (surface->gtk_surface != NULL)
|
2013-11-25 23:15:03 +00:00
|
|
|
{
|
|
|
|
wl_resource_post_error (surface_resource,
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
"gtk_shell::get_gtk_surface already requested");
|
|
|
|
return;
|
|
|
|
}
|
2014-10-07 18:21:31 +00:00
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
surface->gtk_surface = wl_resource_create (client, >k_surface_interface, wl_resource_get_version (resource), id);
|
|
|
|
wl_resource_set_implementation (surface->gtk_surface, &meta_wayland_gtk_surface_interface, surface, gtk_surface_destructor);
|
2013-08-30 07:40:36 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 02:49:51 +00:00
|
|
|
static const struct gtk_shell_interface meta_wayland_gtk_shell_interface = {
|
2013-08-30 07:40:36 +00:00
|
|
|
get_gtk_surface
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
bind_gtk_shell (struct wl_client *client,
|
2014-07-17 21:39:43 +00:00
|
|
|
void *data,
|
|
|
|
guint32 version,
|
|
|
|
guint32 id)
|
2013-08-30 07:40:36 +00:00
|
|
|
{
|
|
|
|
struct wl_resource *resource;
|
2014-09-17 14:37:51 +00:00
|
|
|
uint32_t capabilities = 0;
|
2013-08-30 07:40:36 +00:00
|
|
|
|
2014-08-04 14:24:59 +00:00
|
|
|
resource = wl_resource_create (client, >k_shell_interface, version, id);
|
2015-03-05 10:09:35 +00:00
|
|
|
|
|
|
|
if (version != META_GTK_SHELL_VERSION)
|
|
|
|
{
|
|
|
|
wl_resource_post_error (resource,
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
"Incompatible gtk-shell version "
|
|
|
|
"(supported version: %d)",
|
|
|
|
META_GTK_SHELL_VERSION);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-30 07:40:36 +00:00
|
|
|
wl_resource_set_implementation (resource, &meta_wayland_gtk_shell_interface, data, NULL);
|
|
|
|
|
2014-09-17 14:37:51 +00:00
|
|
|
if (!meta_prefs_get_show_fallback_app_menu ())
|
|
|
|
capabilities = GTK_SHELL_CAPABILITY_GLOBAL_APP_MENU;
|
|
|
|
|
|
|
|
gtk_shell_send_capabilities (resource, capabilities);
|
2013-08-30 07:40:36 +00:00
|
|
|
}
|
|
|
|
|
2014-02-24 18:32:17 +00:00
|
|
|
static void
|
|
|
|
unparent_actor (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
ClutterActor *parent_actor;
|
|
|
|
parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->surface_actor));
|
|
|
|
clutter_actor_remove_child (parent_actor, CLUTTER_ACTOR (surface->surface_actor));
|
|
|
|
}
|
|
|
|
|
2013-11-26 18:04:37 +00:00
|
|
|
static void
|
|
|
|
wl_subsurface_destructor (struct wl_resource *resource)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-26 18:04:37 +00:00
|
|
|
|
2015-02-25 15:26:01 +00:00
|
|
|
meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
|
|
|
|
surface);
|
2014-01-12 21:02:09 +00:00
|
|
|
if (surface->sub.parent)
|
|
|
|
{
|
|
|
|
wl_list_remove (&surface->sub.parent_destroy_listener.link);
|
|
|
|
surface->sub.parent->subsurfaces =
|
|
|
|
g_list_remove (surface->sub.parent->subsurfaces, surface);
|
|
|
|
unparent_actor (surface);
|
|
|
|
surface->sub.parent = NULL;
|
|
|
|
}
|
2014-01-13 22:31:25 +00:00
|
|
|
|
2014-04-18 22:12:54 +00:00
|
|
|
pending_state_destroy (&surface->sub.pending);
|
2014-10-07 17:44:16 +00:00
|
|
|
surface->wl_subsurface = NULL;
|
2013-11-26 18:04:37 +00:00
|
|
|
}
|
|
|
|
|
2013-11-25 21:26:02 +00:00
|
|
|
static void
|
|
|
|
wl_subsurface_destroy (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
|
|
|
wl_resource_destroy (resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_subsurface_set_position (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
int32_t x,
|
|
|
|
int32_t y)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-25 21:26:02 +00:00
|
|
|
|
2014-01-12 22:17:29 +00:00
|
|
|
surface->sub.pending_x = x;
|
|
|
|
surface->sub.pending_y = y;
|
|
|
|
surface->sub.pending_pos = TRUE;
|
2013-11-25 21:26:02 +00:00
|
|
|
}
|
|
|
|
|
2014-01-12 21:02:09 +00:00
|
|
|
static gboolean
|
|
|
|
is_valid_sibling (MetaWaylandSurface *surface, MetaWaylandSurface *sibling)
|
|
|
|
{
|
|
|
|
if (surface->sub.parent == sibling)
|
|
|
|
return TRUE;
|
|
|
|
if (surface->sub.parent == sibling->sub.parent)
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2014-01-12 22:24:00 +00:00
|
|
|
static void
|
|
|
|
subsurface_handle_pending_sibling_destroyed (struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
MetaWaylandSubsurfacePlacementOp *op =
|
|
|
|
wl_container_of (listener, op, sibling_destroy_listener);
|
|
|
|
|
|
|
|
op->sibling = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
queue_subsurface_placement (MetaWaylandSurface *surface,
|
|
|
|
MetaWaylandSurface *sibling,
|
|
|
|
MetaWaylandSubsurfacePlacement placement)
|
|
|
|
{
|
|
|
|
MetaWaylandSubsurfacePlacementOp *op =
|
|
|
|
g_slice_new (MetaWaylandSubsurfacePlacementOp);
|
|
|
|
|
|
|
|
op->placement = placement;
|
|
|
|
op->sibling = sibling;
|
|
|
|
op->sibling_destroy_listener.notify =
|
|
|
|
subsurface_handle_pending_sibling_destroyed;
|
|
|
|
wl_resource_add_destroy_listener (sibling->resource,
|
|
|
|
&op->sibling_destroy_listener);
|
|
|
|
|
|
|
|
surface->sub.pending_placement_ops =
|
|
|
|
g_slist_append (surface->sub.pending_placement_ops, op);
|
|
|
|
}
|
|
|
|
|
2013-11-25 21:26:02 +00:00
|
|
|
static void
|
|
|
|
wl_subsurface_place_above (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *sibling_resource)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-25 21:26:02 +00:00
|
|
|
MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource);
|
|
|
|
|
2014-01-12 21:02:09 +00:00
|
|
|
if (!is_valid_sibling (surface, sibling))
|
|
|
|
{
|
|
|
|
wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE,
|
|
|
|
"wl_subsurface::place_above: wl_surface@%d is "
|
|
|
|
"not a valid parent or sibling",
|
|
|
|
wl_resource_get_id (sibling->resource));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-12 22:24:00 +00:00
|
|
|
queue_subsurface_placement (surface,
|
|
|
|
sibling,
|
|
|
|
META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE);
|
2013-11-25 21:26:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_subsurface_place_below (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
struct wl_resource *sibling_resource)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2013-11-25 21:26:02 +00:00
|
|
|
MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource);
|
|
|
|
|
2014-01-12 21:02:09 +00:00
|
|
|
if (!is_valid_sibling (surface, sibling))
|
|
|
|
{
|
|
|
|
wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE,
|
|
|
|
"wl_subsurface::place_below: wl_surface@%d is "
|
|
|
|
"not a valid parent or sibling",
|
|
|
|
wl_resource_get_id (sibling->resource));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-12 22:24:00 +00:00
|
|
|
queue_subsurface_placement (surface,
|
|
|
|
sibling,
|
|
|
|
META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW);
|
2013-11-25 21:26:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_subsurface_set_sync (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2014-01-13 22:31:25 +00:00
|
|
|
|
|
|
|
surface->sub.synchronous = TRUE;
|
2013-11-25 21:26:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_subsurface_set_desync (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
2014-02-28 13:45:07 +00:00
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2015-01-26 08:46:20 +00:00
|
|
|
gboolean was_effectively_synchronized;
|
2014-01-13 22:31:25 +00:00
|
|
|
|
2015-01-26 08:46:20 +00:00
|
|
|
was_effectively_synchronized = is_surface_effectively_synchronized (surface);
|
2014-01-13 22:31:25 +00:00
|
|
|
surface->sub.synchronous = FALSE;
|
2015-01-26 08:46:20 +00:00
|
|
|
if (was_effectively_synchronized &&
|
|
|
|
!is_surface_effectively_synchronized (surface))
|
|
|
|
apply_pending_state (surface, &surface->sub.pending);
|
2013-11-25 21:26:02 +00:00
|
|
|
}
|
|
|
|
|
2014-10-07 03:19:45 +00:00
|
|
|
static const struct wl_subsurface_interface meta_wayland_wl_subsurface_interface = {
|
2013-11-25 21:26:02 +00:00
|
|
|
wl_subsurface_destroy,
|
|
|
|
wl_subsurface_set_position,
|
|
|
|
wl_subsurface_place_above,
|
|
|
|
wl_subsurface_place_below,
|
|
|
|
wl_subsurface_set_sync,
|
|
|
|
wl_subsurface_set_desync,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
wl_subcompositor_destroy (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
|
|
|
wl_resource_destroy (resource);
|
|
|
|
}
|
|
|
|
|
2014-01-12 21:02:09 +00:00
|
|
|
static void
|
|
|
|
surface_handle_parent_surface_destroyed (struct wl_listener *listener,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_container_of (listener,
|
|
|
|
surface,
|
|
|
|
sub.parent_destroy_listener);
|
|
|
|
|
|
|
|
surface->sub.parent = NULL;
|
|
|
|
unparent_actor (surface);
|
|
|
|
}
|
|
|
|
|
2013-11-25 21:26:02 +00:00
|
|
|
static void
|
|
|
|
wl_subcompositor_get_subsurface (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
guint32 id,
|
|
|
|
struct wl_resource *surface_resource,
|
|
|
|
struct wl_resource *parent_resource)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
|
|
|
MetaWaylandSurface *parent = wl_resource_get_user_data (parent_resource);
|
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
if (surface->wl_subsurface != NULL)
|
2013-11-25 21:26:02 +00:00
|
|
|
{
|
|
|
|
wl_resource_post_error (surface_resource,
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
"wl_subcompositor::get_subsurface already requested");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-02-06 08:12:21 +00:00
|
|
|
if (meta_wayland_surface_set_role (surface,
|
|
|
|
META_WAYLAND_SURFACE_ROLE_SUBSURFACE,
|
|
|
|
surface_resource,
|
|
|
|
WL_SHELL_ERROR_ROLE) != 0)
|
|
|
|
return;
|
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
surface->wl_subsurface = wl_resource_create (client, &wl_subsurface_interface, wl_resource_get_version (resource), id);
|
2014-10-07 19:09:52 +00:00
|
|
|
wl_resource_set_implementation (surface->wl_subsurface, &meta_wayland_wl_subsurface_interface, surface, wl_subsurface_destructor);
|
2014-10-07 18:21:31 +00:00
|
|
|
|
2014-04-18 22:12:54 +00:00
|
|
|
pending_state_init (&surface->sub.pending);
|
2014-06-11 16:34:44 +00:00
|
|
|
surface->sub.synchronous = TRUE;
|
2014-01-12 21:02:09 +00:00
|
|
|
surface->sub.parent = parent;
|
2014-06-11 16:34:17 +00:00
|
|
|
surface->sub.parent_destroy_listener.notify = surface_handle_parent_surface_destroyed;
|
|
|
|
wl_resource_add_destroy_listener (parent->resource, &surface->sub.parent_destroy_listener);
|
2014-01-12 21:02:09 +00:00
|
|
|
parent->subsurfaces = g_list_append (parent->subsurfaces, surface);
|
|
|
|
|
2013-11-25 21:26:02 +00:00
|
|
|
clutter_actor_add_child (CLUTTER_ACTOR (parent->surface_actor),
|
|
|
|
CLUTTER_ACTOR (surface->surface_actor));
|
2014-04-16 19:41:50 +00:00
|
|
|
|
|
|
|
sync_reactive (surface);
|
2013-11-25 21:26:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_subcompositor_interface meta_wayland_subcompositor_interface = {
|
|
|
|
wl_subcompositor_destroy,
|
|
|
|
wl_subcompositor_get_subsurface,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
bind_subcompositor (struct wl_client *client,
|
|
|
|
void *data,
|
|
|
|
guint32 version,
|
|
|
|
guint32 id)
|
|
|
|
{
|
|
|
|
struct wl_resource *resource;
|
|
|
|
|
2014-08-04 14:24:59 +00:00
|
|
|
resource = wl_resource_create (client, &wl_subcompositor_interface, version, id);
|
2013-11-25 21:26:02 +00:00
|
|
|
wl_resource_set_implementation (resource, &meta_wayland_subcompositor_interface, data, NULL);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
if (wl_global_create (compositor->wayland_display,
|
2014-07-17 21:37:29 +00:00
|
|
|
&xdg_shell_interface,
|
|
|
|
META_XDG_SHELL_VERSION,
|
2014-07-17 21:39:43 +00:00
|
|
|
compositor, bind_xdg_shell) == NULL)
|
2013-11-08 22:05:07 +00:00
|
|
|
g_error ("Failed to register a global xdg-shell object");
|
2013-08-30 07:40:36 +00:00
|
|
|
|
2014-02-28 05:18:42 +00:00
|
|
|
if (wl_global_create (compositor->wayland_display,
|
2014-07-17 21:40:10 +00:00
|
|
|
&wl_shell_interface,
|
|
|
|
META_WL_SHELL_VERSION,
|
2014-07-17 21:39:43 +00:00
|
|
|
compositor, bind_wl_shell) == NULL)
|
2014-02-28 05:18:42 +00:00
|
|
|
g_error ("Failed to register a global wl-shell object");
|
|
|
|
|
2013-08-30 07:40:36 +00:00
|
|
|
if (wl_global_create (compositor->wayland_display,
|
2014-07-17 21:39:43 +00:00
|
|
|
>k_shell_interface,
|
|
|
|
META_GTK_SHELL_VERSION,
|
|
|
|
compositor, bind_gtk_shell) == NULL)
|
2013-08-30 07:40:36 +00:00
|
|
|
g_error ("Failed to register a global gtk-shell object");
|
2013-11-25 21:26:02 +00:00
|
|
|
|
|
|
|
if (wl_global_create (compositor->wayland_display,
|
|
|
|
&wl_subcompositor_interface,
|
|
|
|
META_WL_SUBCOMPOSITOR_VERSION,
|
|
|
|
compositor, bind_subcompositor) == NULL)
|
|
|
|
g_error ("Failed to register a global wl-subcompositor object");
|
2013-08-30 16:26:18 +00:00
|
|
|
}
|
|
|
|
|
2014-05-05 23:09:07 +00:00
|
|
|
static void
|
2014-05-05 23:09:22 +00:00
|
|
|
fill_states (struct wl_array *states, MetaWindow *window)
|
2014-05-05 23:09:07 +00:00
|
|
|
{
|
2014-05-05 23:09:22 +00:00
|
|
|
uint32_t *s;
|
2014-05-05 23:09:07 +00:00
|
|
|
|
2014-05-05 23:09:22 +00:00
|
|
|
if (META_WINDOW_MAXIMIZED (window))
|
|
|
|
{
|
|
|
|
s = wl_array_add (states, sizeof *s);
|
|
|
|
*s = XDG_SURFACE_STATE_MAXIMIZED;
|
|
|
|
}
|
|
|
|
if (meta_window_is_fullscreen (window))
|
|
|
|
{
|
|
|
|
s = wl_array_add (states, sizeof *s);
|
|
|
|
*s = XDG_SURFACE_STATE_FULLSCREEN;
|
|
|
|
}
|
|
|
|
if (meta_grab_op_is_resizing (window->display->grab_op))
|
|
|
|
{
|
|
|
|
s = wl_array_add (states, sizeof *s);
|
|
|
|
*s = XDG_SURFACE_STATE_RESIZING;
|
|
|
|
}
|
|
|
|
if (meta_window_appears_focused (window))
|
|
|
|
{
|
|
|
|
s = wl_array_add (states, sizeof *s);
|
|
|
|
*s = XDG_SURFACE_STATE_ACTIVATED;
|
2014-02-09 16:45:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-05-05 23:09:22 +00:00
|
|
|
meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
|
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
|
|
|
{
|
2014-10-07 17:44:16 +00:00
|
|
|
if (surface->xdg_surface)
|
2014-05-05 23:09:22 +00:00
|
|
|
{
|
2014-10-07 17:44:16 +00:00
|
|
|
struct wl_client *client = wl_resource_get_client (surface->xdg_surface);
|
2014-05-05 23:09:22 +00:00
|
|
|
struct wl_display *display = wl_client_get_display (client);
|
|
|
|
uint32_t serial = wl_display_next_serial (display);
|
|
|
|
struct wl_array states;
|
2013-11-12 20:52:03 +00:00
|
|
|
|
2014-05-05 23:09:22 +00:00
|
|
|
wl_array_init (&states);
|
|
|
|
fill_states (&states, surface->window);
|
2014-04-23 20:00:55 +00:00
|
|
|
|
2014-05-05 23:09:22 +00:00
|
|
|
/* new_width and new_height comes from window->rect, which is based on
|
|
|
|
* the buffer size, not the surface size. The configure event requires
|
|
|
|
* surface size. */
|
|
|
|
new_width /= surface->scale;
|
|
|
|
new_height /= surface->scale;
|
2014-04-23 20:00:55 +00:00
|
|
|
|
2014-10-07 17:44:16 +00:00
|
|
|
xdg_surface_send_configure (surface->xdg_surface, new_width, new_height, &states, serial);
|
2014-05-05 23:09:07 +00:00
|
|
|
|
2014-05-05 23:09:22 +00:00
|
|
|
wl_array_release (&states);
|
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
|
|
|
|
|
|
|
if (sent_serial)
|
|
|
|
{
|
|
|
|
sent_serial->set = TRUE;
|
|
|
|
sent_serial->value = serial;
|
|
|
|
}
|
2014-05-05 23:09:22 +00:00
|
|
|
}
|
2014-10-07 17:44:16 +00:00
|
|
|
else if (surface->xdg_popup)
|
2014-08-13 22:09:55 +00:00
|
|
|
{
|
|
|
|
/* This can happen if the popup window loses or receives focus.
|
|
|
|
* Just ignore it. */
|
|
|
|
}
|
2014-10-07 17:44:16 +00:00
|
|
|
else if (surface->wl_shell_surface)
|
|
|
|
wl_shell_surface_send_configure (surface->wl_shell_surface,
|
2014-05-05 23:09:22 +00:00
|
|
|
0, new_width, new_height);
|
2014-07-27 15:13:31 +00:00
|
|
|
else
|
|
|
|
g_assert_not_reached ();
|
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
|
|
|
{
|
2014-08-22 16:52:18 +00:00
|
|
|
if (surface->xdg_shell_resource)
|
|
|
|
xdg_shell_send_ping (surface->xdg_shell_resource, serial);
|
2014-10-07 17:44:16 +00:00
|
|
|
else if (surface->wl_shell_surface)
|
|
|
|
wl_shell_surface_send_ping (surface->wl_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)
|
|
|
|
{
|
2014-10-07 17:44:16 +00:00
|
|
|
if (surface->xdg_surface)
|
|
|
|
xdg_surface_send_close (surface->xdg_surface);
|
2014-02-07 22:28:33 +00:00
|
|
|
}
|
2014-02-28 05:18:42 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_surface_popup_done (MetaWaylandSurface *surface)
|
|
|
|
{
|
2014-10-07 17:44:16 +00:00
|
|
|
if (surface->xdg_popup)
|
2015-02-06 08:28:28 +00:00
|
|
|
xdg_popup_send_popup_done (surface->xdg_popup);
|
2014-10-07 17:44:16 +00:00
|
|
|
else if (surface->wl_shell_surface)
|
|
|
|
wl_shell_surface_send_popup_done (surface->wl_shell_surface);
|
2014-02-28 05:18:42 +00:00
|
|
|
}
|