mirror of
https://github.com/brl/mutter.git
synced 2025-04-01 08:03:46 +00:00
wayland: implement resizing and maximization for wayland clients
To properly resize clients, we need to send them configure events with the size we computed from the constraint system, and then check if the new size they ask is compatible with our expectation. Note that this does not handle interactive resizing yet, it merely makes the API calls work for wayland clients. https://bugzilla.gnome.org/show_bug.cgi?id=707401
This commit is contained in:
parent
514fec7275
commit
a7eaf43e18
@ -237,7 +237,7 @@ set_cogl_texture (MetaShapedTexture *stex,
|
||||
if (priv->texture)
|
||||
cogl_object_unref (priv->texture);
|
||||
|
||||
priv->texture = cogl_tex;
|
||||
priv->texture = cogl_object_ref (cogl_tex);
|
||||
|
||||
if (cogl_tex != NULL)
|
||||
{
|
||||
@ -875,26 +875,7 @@ meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
|
||||
g_return_if_fail (priv->wayland.surface->buffer_ref.buffer == buffer);
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
CoglContext *ctx =
|
||||
clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
CoglError *catch_error = NULL;
|
||||
CoglTexture *texture =
|
||||
COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
|
||||
buffer->resource,
|
||||
&catch_error));
|
||||
if (!texture)
|
||||
{
|
||||
cogl_error_free (catch_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->width = cogl_texture_get_width (texture);
|
||||
buffer->height = cogl_texture_get_height (texture);
|
||||
}
|
||||
|
||||
set_cogl_texture (stex, texture);
|
||||
}
|
||||
set_cogl_texture (stex, buffer->texture);
|
||||
else
|
||||
set_cogl_texture (stex, NULL);
|
||||
|
||||
|
@ -35,7 +35,8 @@ typedef enum
|
||||
META_DO_GRAVITY_ADJUST = 1 << 1,
|
||||
META_IS_USER_ACTION = 1 << 2,
|
||||
META_IS_MOVE_ACTION = 1 << 3,
|
||||
META_IS_RESIZE_ACTION = 1 << 4
|
||||
META_IS_RESIZE_ACTION = 1 << 4,
|
||||
META_IS_WAYLAND_RESIZE = 1 << 5
|
||||
} MetaMoveResizeFlags;
|
||||
|
||||
void meta_window_constrain (MetaWindow *window,
|
||||
|
@ -403,6 +403,12 @@ struct _MetaWindow
|
||||
*/
|
||||
MetaRectangle rect;
|
||||
|
||||
/* The size and position we want the window to be (i.e. what we last asked
|
||||
* the client to configure).
|
||||
* This is only used for wayland clients.
|
||||
*/
|
||||
MetaRectangle expected_rect;
|
||||
|
||||
gboolean has_custom_frame_extents;
|
||||
GtkBorder custom_frame_extents;
|
||||
|
||||
@ -600,6 +606,11 @@ void meta_window_move_resize_request(MetaWindow *window,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
void meta_window_move_resize_wayland (MetaWindow *window,
|
||||
int width,
|
||||
int height,
|
||||
int dx,
|
||||
int dy);
|
||||
gboolean meta_window_configure_request (MetaWindow *window,
|
||||
XEvent *event);
|
||||
gboolean meta_window_property_notify (MetaWindow *window,
|
||||
|
@ -5008,6 +5008,7 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
* 2 | A not-resize-only ConfigureRequest/net_moveresize_window request
|
||||
* 3 | meta_window_move
|
||||
* 3 | meta_window_move_resize
|
||||
* 4 | meta_window_move_resize_wayland
|
||||
*
|
||||
* For each of the cases, root_x_nw and root_y_nw must be treated as follows:
|
||||
*
|
||||
@ -5018,8 +5019,12 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
* coordinates are relative to some corner or side of the outer
|
||||
* window (except for the case of StaticGravity) and we want to
|
||||
* know the location of the upper left corner of the inner window.
|
||||
* (3) These values are already the desired positon of the NW corner
|
||||
* (3) These values are already the desired position of the NW corner
|
||||
* of the inner window
|
||||
* (4) These values are already the desired position of the NW corner
|
||||
* of the inner window (which is also the outer window, because
|
||||
* we don't decorate wayland clients), and the client has acknowledged
|
||||
* the window size change.
|
||||
*/
|
||||
XWindowChanges values;
|
||||
unsigned int mask;
|
||||
@ -5035,6 +5040,7 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
gboolean is_configure_request;
|
||||
gboolean do_gravity_adjust;
|
||||
gboolean is_user_action;
|
||||
gboolean is_wayland_resize;
|
||||
gboolean did_placement;
|
||||
gboolean configure_frame_first;
|
||||
gboolean use_static_gravity;
|
||||
@ -5051,9 +5057,12 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
|
||||
do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
|
||||
is_user_action = (flags & META_IS_USER_ACTION) != 0;
|
||||
is_wayland_resize = (flags & META_IS_WAYLAND_RESIZE) != 0;
|
||||
|
||||
/* The action has to be a move or a resize or both... */
|
||||
g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION));
|
||||
/* The action has to be a move, a resize or the wayland client
|
||||
* acking our choice of size.
|
||||
*/
|
||||
g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION | META_IS_WAYLAND_RESIZE));
|
||||
|
||||
/* We don't need it in the idle queue anymore. */
|
||||
meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE);
|
||||
@ -5111,18 +5120,111 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
|
||||
did_placement = !window->placed && window->calc_placement;
|
||||
|
||||
if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION))
|
||||
{
|
||||
meta_window_constrain (window,
|
||||
window->frame ? &borders : NULL,
|
||||
flags,
|
||||
gravity,
|
||||
&old_rect,
|
||||
&new_rect);
|
||||
}
|
||||
|
||||
w = new_rect.width;
|
||||
h = new_rect.height;
|
||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
{
|
||||
g_assert (window->frame == NULL);
|
||||
|
||||
/* For wayland clients, the size is completely determined by the client,
|
||||
* and while this allows to avoid some trickery with frames and the resulting
|
||||
* lagging, we also need to insist a bit when the constraints would apply
|
||||
* a different size than the client decides.
|
||||
*
|
||||
* Note that this is not generally a problem for normal toplevel windows (the
|
||||
* constraints don't see the size hints, or just change the position), but
|
||||
* it can be for maximized or fullscreen.
|
||||
*
|
||||
*/
|
||||
root_x_nw = new_rect.x;
|
||||
root_y_nw = new_rect.y;
|
||||
|
||||
/* First, save where we would like the client to be. This is used by the next
|
||||
* attach to determine if the client is really moving/resizing or not.
|
||||
*/
|
||||
window->expected_rect = new_rect;
|
||||
|
||||
if (is_wayland_resize)
|
||||
{
|
||||
/* This is a call to wl_surface_commit(), ignore the new_rect and
|
||||
* update the real client size to match the buffer size.
|
||||
*/
|
||||
|
||||
window->rect.width = w;
|
||||
window->rect.height = h;
|
||||
}
|
||||
|
||||
if (new_rect.width != window->rect.width ||
|
||||
new_rect.height != window->rect.height)
|
||||
{
|
||||
/* We need to resize the client. Resizing is in two parts:
|
||||
* some of the movement happens immediately, and some happens as part
|
||||
* of the resizing (through dx/dy in wl_surface_attach).
|
||||
*
|
||||
* To do so, we need to compute the resize from the point of the view
|
||||
* of the client, and then adjust the immediate resize to match.
|
||||
*
|
||||
* dx/dy are the values we expect from the new attach(), while deltax/
|
||||
* deltay reflect the overall movement.
|
||||
*/
|
||||
MetaRectangle client_rect;
|
||||
int dx, dy;
|
||||
int deltax, deltay;
|
||||
|
||||
meta_rectangle_resize_with_gravity (&old_rect,
|
||||
&client_rect,
|
||||
gravity,
|
||||
new_rect.width,
|
||||
new_rect.height);
|
||||
|
||||
deltax = new_rect.x - old_rect.x;
|
||||
deltay = new_rect.y - old_rect.y;
|
||||
dx = client_rect.x - old_rect.x;
|
||||
dy = client_rect.y - old_rect.y;
|
||||
|
||||
if (deltax != dx || deltay != dy)
|
||||
need_move_client = TRUE;
|
||||
|
||||
window->rect.x += (deltax - dx);
|
||||
window->rect.y += (deltay - dy);
|
||||
|
||||
need_resize_client = TRUE;
|
||||
meta_wayland_surface_configure_notify (window->surface,
|
||||
new_rect.width,
|
||||
new_rect.height,
|
||||
(dx != 0 ? WL_SHELL_SURFACE_RESIZE_LEFT : 0) |
|
||||
(dy != 0 ? WL_SHELL_SURFACE_RESIZE_TOP : 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No resize happening, we can just move the window and live with it. */
|
||||
if (window->rect.x != new_rect.x ||
|
||||
window->rect.y != new_rect.y)
|
||||
need_move_client = TRUE;
|
||||
|
||||
window->rect.x = new_rect.x;
|
||||
window->rect.y = new_rect.y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Everything else is the old X11 code, including weird gravities,
|
||||
* the interaction with frames and the synthetic configure notifies.
|
||||
*/
|
||||
|
||||
root_x_nw = new_rect.x;
|
||||
root_y_nw = new_rect.y;
|
||||
w = new_rect.width;
|
||||
h = new_rect.height;
|
||||
|
||||
if (w != window->rect.width ||
|
||||
h != window->rect.height)
|
||||
need_resize_client = TRUE;
|
||||
@ -5414,6 +5516,7 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
|
||||
if (need_configure_notify)
|
||||
send_configure_notify (window);
|
||||
}
|
||||
|
||||
if (!window->placed && window->force_save_user_rect && !window->fullscreen)
|
||||
force_save_user_window_placement (window);
|
||||
@ -5422,7 +5525,7 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
|
||||
if (need_move_frame || need_resize_frame ||
|
||||
need_move_client || need_resize_client ||
|
||||
did_placement)
|
||||
did_placement || is_wayland_resize)
|
||||
{
|
||||
int newx, newy;
|
||||
meta_window_get_position (window, &newx, &newy);
|
||||
@ -5492,6 +5595,37 @@ meta_window_resize (MetaWindow *window,
|
||||
x, y, w, h);
|
||||
}
|
||||
|
||||
/*
|
||||
* meta_window_move_resize_wayland:
|
||||
*
|
||||
* Complete a resize operation from a wayland client.
|
||||
*
|
||||
*/
|
||||
void
|
||||
meta_window_move_resize_wayland (MetaWindow *window,
|
||||
int width,
|
||||
int height,
|
||||
int dx,
|
||||
int dy)
|
||||
{
|
||||
int x, y;
|
||||
MetaMoveResizeFlags flags;
|
||||
|
||||
flags = META_IS_WAYLAND_RESIZE;
|
||||
|
||||
meta_window_get_position (window, &x, &y);
|
||||
x += dx; y += dy;
|
||||
|
||||
if (x != window->expected_rect.x || y != window->expected_rect.y)
|
||||
flags |= META_IS_MOVE_ACTION;
|
||||
if (width != window->expected_rect.width ||
|
||||
height != window->expected_rect.height)
|
||||
flags |= META_IS_RESIZE_ACTION;
|
||||
|
||||
meta_window_move_resize_internal (window, flags, NorthWestGravity,
|
||||
x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_window_move:
|
||||
* @window: a #MetaWindow
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <clutter/clutter.h>
|
||||
#include <clutter/wayland/clutter-wayland-compositor.h>
|
||||
#include <clutter/wayland/clutter-wayland-surface.h>
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <sys/time.h>
|
||||
@ -64,8 +65,9 @@ static void
|
||||
surface_process_damage (MetaWaylandSurface *surface,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
if (surface->window &&
|
||||
surface->buffer_ref.buffer)
|
||||
g_assert (surface->window);
|
||||
|
||||
if (surface->buffer_ref.buffer)
|
||||
{
|
||||
MetaWindowActor *window_actor =
|
||||
META_WINDOW_ACTOR (meta_window_get_compositor_private (surface->window));
|
||||
@ -111,7 +113,7 @@ static void
|
||||
meta_wayland_surface_attach (struct wl_client *wayland_client,
|
||||
struct wl_resource *wayland_surface_resource,
|
||||
struct wl_resource *wayland_buffer_resource,
|
||||
gint32 sx, gint32 sy)
|
||||
gint32 dx, gint32 dy)
|
||||
{
|
||||
MetaWaylandSurface *surface =
|
||||
wl_resource_get_user_data (wayland_surface_resource);
|
||||
@ -130,8 +132,8 @@ meta_wayland_surface_attach (struct wl_client *wayland_client,
|
||||
if (surface->pending.buffer)
|
||||
wl_list_remove (&surface->pending.buffer_destroy_listener.link);
|
||||
|
||||
surface->pending.sx = sx;
|
||||
surface->pending.sy = sy;
|
||||
surface->pending.dx = dx;
|
||||
surface->pending.dy = dy;
|
||||
surface->pending.buffer = buffer;
|
||||
surface->pending.newly_attached = TRUE;
|
||||
|
||||
@ -247,36 +249,86 @@ meta_wayland_surface_commit (struct wl_client *client,
|
||||
if (surface->pending.newly_attached &&
|
||||
surface->buffer_ref.buffer != surface->pending.buffer)
|
||||
{
|
||||
MetaWaylandBuffer *buffer = surface->pending.buffer;
|
||||
CoglContext *ctx =
|
||||
clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
CoglError *catch_error = NULL;
|
||||
CoglTexture *texture =
|
||||
COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
|
||||
buffer->resource,
|
||||
&catch_error));
|
||||
if (!texture)
|
||||
{
|
||||
cogl_error_free (catch_error);
|
||||
meta_warning ("Could not import pending buffer, ignoring commit\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->texture = texture;
|
||||
buffer->width = cogl_texture_get_width (texture);
|
||||
buffer->height = cogl_texture_get_height (texture);
|
||||
}
|
||||
|
||||
/* Note: we set this before informing any window-actor since the
|
||||
* window actor will expect to find the new buffer within the
|
||||
* surface. */
|
||||
meta_wayland_buffer_reference (&surface->buffer_ref,
|
||||
surface->pending.buffer);
|
||||
}
|
||||
|
||||
if (!surface->buffer_ref.buffer)
|
||||
{
|
||||
meta_warning ("Commit without a buffer? Ignoring\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface->initial_state)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
int width;
|
||||
int height;
|
||||
|
||||
width = surface->buffer_ref.buffer->width;
|
||||
height = surface->buffer_ref.buffer->height;
|
||||
|
||||
/* This will free and clear initial_state */
|
||||
surface->window = meta_window_new_for_wayland (display, width, height, surface);
|
||||
}
|
||||
|
||||
if (surface == compositor->seat->sprite)
|
||||
meta_wayland_seat_update_sprite (compositor->seat);
|
||||
else if (surface->window)
|
||||
{
|
||||
MetaWindow *window = surface->window;
|
||||
|
||||
if (surface->pending.buffer)
|
||||
{
|
||||
MetaWaylandBuffer *buffer = surface->pending.buffer;
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
|
||||
if (surface->window)
|
||||
{
|
||||
MetaWindow *window = surface->window;
|
||||
MetaWindowActor *window_actor =
|
||||
META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
MetaRectangle rect;
|
||||
|
||||
meta_window_get_input_rect (surface->window, &rect);
|
||||
|
||||
if (window_actor)
|
||||
meta_window_actor_attach_wayland_buffer (window_actor, buffer);
|
||||
}
|
||||
|
||||
/* XXX: we resize X based surfaces according to X events */
|
||||
if (surface->xid == 0 &&
|
||||
(buffer->width != rect.width || buffer->height != rect.height))
|
||||
meta_window_resize (surface->window, FALSE, buffer->width, buffer->height);
|
||||
}
|
||||
else if (surface == compositor->seat->sprite)
|
||||
meta_wayland_seat_update_sprite (compositor->seat);
|
||||
/* We resize X based surfaces according to X events */
|
||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
{
|
||||
int new_width;
|
||||
int new_height;
|
||||
|
||||
new_width = surface->buffer_ref.buffer->width;
|
||||
new_height = surface->buffer_ref.buffer->height;
|
||||
if (new_width != window->rect.width ||
|
||||
new_height != window->rect.height ||
|
||||
surface->pending.dx != 0 ||
|
||||
surface->pending.dy != 0)
|
||||
meta_window_move_resize_wayland (surface->window, new_width, new_height,
|
||||
surface->pending.dx, surface->pending.dy);
|
||||
}
|
||||
|
||||
meta_window_set_opaque_region (surface->window, surface->pending.opaque_region);
|
||||
meta_window_set_input_region (surface->window, surface->pending.input_region);
|
||||
surface_process_damage (surface, surface->pending.damage);
|
||||
}
|
||||
|
||||
if (surface->pending.buffer)
|
||||
@ -284,20 +336,11 @@ meta_wayland_surface_commit (struct wl_client *client,
|
||||
wl_list_remove (&surface->pending.buffer_destroy_listener.link);
|
||||
surface->pending.buffer = NULL;
|
||||
}
|
||||
surface->pending.sx = 0;
|
||||
surface->pending.sy = 0;
|
||||
surface->pending.dx = 0;
|
||||
surface->pending.dy = 0;
|
||||
surface->pending.newly_attached = FALSE;
|
||||
|
||||
if (surface->window)
|
||||
{
|
||||
meta_window_set_opaque_region (surface->window, surface->pending.opaque_region);
|
||||
g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
|
||||
|
||||
meta_window_set_input_region (surface->window, surface->pending.input_region);
|
||||
g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
|
||||
}
|
||||
|
||||
surface_process_damage (surface, surface->pending.damage);
|
||||
empty_region (surface->pending.damage);
|
||||
|
||||
/* wl_surface.frame */
|
||||
@ -1050,3 +1093,14 @@ free_initial_state (MetaWaylandSurfaceInitialState *initial)
|
||||
|
||||
g_slice_free (MetaWaylandSurfaceInitialState, initial);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
|
||||
int new_width,
|
||||
int new_height,
|
||||
int edges)
|
||||
{
|
||||
if (surface->shell_surface)
|
||||
wl_shell_surface_send_configure (surface->shell_surface->resource,
|
||||
edges, new_width, new_height);
|
||||
}
|
||||
|
@ -52,8 +52,8 @@ typedef struct
|
||||
gboolean newly_attached;
|
||||
MetaWaylandBuffer *buffer;
|
||||
struct wl_listener buffer_destroy_listener;
|
||||
int32_t sx;
|
||||
int32_t sy;
|
||||
int32_t dx;
|
||||
int32_t dy;
|
||||
|
||||
/* wl_surface.damage */
|
||||
cairo_region_t *damage;
|
||||
@ -82,9 +82,6 @@ struct _MetaWaylandSurface
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
MetaWaylandCompositor *compositor;
|
||||
guint32 xid;
|
||||
int x;
|
||||
int y;
|
||||
MetaWaylandBufferReference buffer_ref;
|
||||
MetaWindow *window;
|
||||
gboolean has_shell_surface;
|
||||
@ -116,4 +113,9 @@ void meta_wayland_surface_free (MetaWaylandSurface *surface)
|
||||
void meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
|
||||
MetaWindow *window);
|
||||
|
||||
void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
int edges);
|
||||
|
||||
#endif
|
||||
|
@ -187,6 +187,7 @@ meta_wayland_buffer_reference (MetaWaylandBufferReference *ref,
|
||||
|
||||
if (ref->buffer->busy_count == 0)
|
||||
{
|
||||
g_clear_pointer (&ref->buffer->texture, cogl_object_unref);
|
||||
g_assert (wl_resource_get_client (ref->buffer->resource));
|
||||
wl_resource_queue_event (ref->buffer->resource, WL_BUFFER_RELEASE);
|
||||
}
|
||||
@ -613,8 +614,8 @@ synthesize_motion_event (MetaWaylandCompositor *compositor,
|
||||
device_event.event_y = wl_fixed_to_double (pointer->y);
|
||||
}
|
||||
|
||||
if (surface && surface->xid != None)
|
||||
device_event.event = surface->xid;
|
||||
if (surface && surface->window != NULL)
|
||||
device_event.event = surface->window->xwindow;
|
||||
else
|
||||
device_event.event = device_event.root;
|
||||
|
||||
|
@ -45,10 +45,6 @@ xserver_set_window_id (struct wl_client *client,
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
MetaWindow *window;
|
||||
|
||||
g_return_if_fail (surface->xid == None);
|
||||
|
||||
surface->xid = xid;
|
||||
|
||||
window = meta_display_lookup_x_window (display, xid);
|
||||
if (window)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user