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:
Giovanni Campagna 2013-09-03 12:00:29 +02:00
parent 514fec7275
commit a7eaf43e18
8 changed files with 516 additions and 336 deletions

View File

@ -237,7 +237,7 @@ set_cogl_texture (MetaShapedTexture *stex,
if (priv->texture) if (priv->texture)
cogl_object_unref (priv->texture); cogl_object_unref (priv->texture);
priv->texture = cogl_tex; priv->texture = cogl_object_ref (cogl_tex);
if (cogl_tex != NULL) 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); g_return_if_fail (priv->wayland.surface->buffer_ref.buffer == buffer);
if (buffer) if (buffer)
{ set_cogl_texture (stex, buffer->texture);
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);
}
else else
set_cogl_texture (stex, NULL); set_cogl_texture (stex, NULL);

View File

@ -35,7 +35,8 @@ typedef enum
META_DO_GRAVITY_ADJUST = 1 << 1, META_DO_GRAVITY_ADJUST = 1 << 1,
META_IS_USER_ACTION = 1 << 2, META_IS_USER_ACTION = 1 << 2,
META_IS_MOVE_ACTION = 1 << 3, 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; } MetaMoveResizeFlags;
void meta_window_constrain (MetaWindow *window, void meta_window_constrain (MetaWindow *window,

View File

@ -403,6 +403,12 @@ struct _MetaWindow
*/ */
MetaRectangle rect; 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; gboolean has_custom_frame_extents;
GtkBorder custom_frame_extents; GtkBorder custom_frame_extents;
@ -600,6 +606,11 @@ void meta_window_move_resize_request(MetaWindow *window,
int y, int y,
int width, int width,
int height); 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, gboolean meta_window_configure_request (MetaWindow *window,
XEvent *event); XEvent *event);
gboolean meta_window_property_notify (MetaWindow *window, gboolean meta_window_property_notify (MetaWindow *window,

View File

@ -5008,6 +5008,7 @@ meta_window_move_resize_internal (MetaWindow *window,
* 2 | A not-resize-only ConfigureRequest/net_moveresize_window request * 2 | A not-resize-only ConfigureRequest/net_moveresize_window request
* 3 | meta_window_move * 3 | meta_window_move
* 3 | meta_window_move_resize * 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: * 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 * coordinates are relative to some corner or side of the outer
* window (except for the case of StaticGravity) and we want to * window (except for the case of StaticGravity) and we want to
* know the location of the upper left corner of the inner window. * 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 * 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; XWindowChanges values;
unsigned int mask; unsigned int mask;
@ -5035,6 +5040,7 @@ meta_window_move_resize_internal (MetaWindow *window,
gboolean is_configure_request; gboolean is_configure_request;
gboolean do_gravity_adjust; gboolean do_gravity_adjust;
gboolean is_user_action; gboolean is_user_action;
gboolean is_wayland_resize;
gboolean did_placement; gboolean did_placement;
gboolean configure_frame_first; gboolean configure_frame_first;
gboolean use_static_gravity; gboolean use_static_gravity;
@ -5051,9 +5057,12 @@ meta_window_move_resize_internal (MetaWindow *window,
is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0; is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0; do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
is_user_action = (flags & META_IS_USER_ACTION) != 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... */ /* The action has to be a move, a resize or the wayland client
g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)); * 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. */ /* We don't need it in the idle queue anymore. */
meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE); meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE);
@ -5111,310 +5120,404 @@ meta_window_move_resize_internal (MetaWindow *window,
did_placement = !window->placed && window->calc_placement; did_placement = !window->placed && window->calc_placement;
meta_window_constrain (window, if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION))
window->frame ? &borders : NULL,
flags,
gravity,
&old_rect,
&new_rect);
w = new_rect.width;
h = new_rect.height;
root_x_nw = new_rect.x;
root_y_nw = new_rect.y;
if (w != window->rect.width ||
h != window->rect.height)
need_resize_client = TRUE;
window->rect.width = w;
window->rect.height = h;
if (window->frame)
{ {
int frame_size_dx, frame_size_dy; meta_window_constrain (window,
int new_w, new_h; window->frame ? &borders : NULL,
flags,
new_w = window->rect.width + borders.total.left + borders.total.right; gravity,
&old_rect,
if (window->shaded) &new_rect);
new_h = borders.total.top;
else
new_h = window->rect.height + borders.total.top + borders.total.bottom;
frame_size_dx = new_w - window->frame->rect.width;
frame_size_dy = new_h - window->frame->rect.height;
need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0);
window->frame->rect.width = new_w;
window->frame->rect.height = new_h;
meta_topic (META_DEBUG_GEOMETRY,
"Calculated frame size %dx%d\n",
window->frame->rect.width,
window->frame->rect.height);
} }
/* For nice effect, when growing the window we want to move/resize if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
* the frame first, when shrinking the window we want to move/resize
* the client first. If we grow one way and shrink the other,
* see which way we're moving "more"
*
* Mail from Owen subject "Suggestion: Gravity and resizing from the left"
* http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html
*
* An annoying fact you need to know in this code is that StaticGravity
* does nothing if you _only_ resize or _only_ move the frame;
* it must move _and_ resize, otherwise you get NorthWestGravity
* behavior. The move and resize must actually occur, it is not
* enough to set CWX | CWWidth but pass in the current size/pos.
*/
if (window->frame)
{ {
int new_x, new_y; g_assert (window->frame == NULL);
int frame_pos_dx, frame_pos_dy;
/* Compute new frame coords */ /* For wayland clients, the size is completely determined by the client,
new_x = root_x_nw - borders.total.left; * and while this allows to avoid some trickery with frames and the resulting
new_y = root_y_nw - borders.total.top; * lagging, we also need to insist a bit when the constraints would apply
* a different size than the client decides.
frame_pos_dx = new_x - window->frame->rect.x; *
frame_pos_dy = new_y - window->frame->rect.y; * 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
need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0); * it can be for maximized or fullscreen.
*
window->frame->rect.x = new_x;
window->frame->rect.y = new_y;
/* If frame will both move and resize, then StaticGravity
* on the child window will kick in and implicitly move
* the child with respect to the frame. The implicit
* move will keep the child in the same place with
* respect to the root window. If frame only moves
* or only resizes, then the child will just move along
* with the frame.
*/ */
root_x_nw = new_rect.x;
root_y_nw = new_rect.y;
/* window->rect.x, window->rect.y are relative to frame, /* First, save where we would like the client to be. This is used by the next
* remember they are the server coords * attach to determine if the client is really moving/resizing or not.
*/ */
window->expected_rect = new_rect;
new_x = borders.total.left; if (is_wayland_resize)
new_y = borders.total.top;
if (need_resize_frame && need_move_frame &&
static_gravity_works (window->display))
{ {
/* static gravity kicks in because frame /* This is a call to wl_surface_commit(), ignore the new_rect and
* is both moved and resized * update the real client size to match the buffer size.
*/
/* when we move the frame by frame_pos_dx, frame_pos_dy the
* client will implicitly move relative to frame by the
* inverse delta.
*
* When moving client then frame, we move the client by the
* frame delta, to be canceled out by the implicit move by
* the inverse frame delta, resulting in a client at new_x,
* new_y.
*
* When moving frame then client, we move the client
* by the same delta as the frame, because the client
* was "left behind" by the frame - resulting in a client
* at new_x, new_y.
*
* In both cases we need to move the client window
* in all cases where we had to move the frame window.
*/ */
client_move_x = new_x + frame_pos_dx; window->rect.width = w;
client_move_y = new_y + frame_pos_dy; window->rect.height = h;
}
if (need_move_frame) 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; need_move_client = TRUE;
use_static_gravity = 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 else
{ {
client_move_x = new_x; /* No resize happening, we can just move the window and live with it. */
client_move_y = new_y; if (window->rect.x != new_rect.x ||
window->rect.y != new_rect.y)
if (client_move_x != window->rect.x ||
client_move_y != window->rect.y)
need_move_client = TRUE; 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;
window->rect.width = w;
window->rect.height = h;
if (window->frame)
{
int frame_size_dx, frame_size_dy;
int new_w, new_h;
new_w = window->rect.width + borders.total.left + borders.total.right;
if (window->shaded)
new_h = borders.total.top;
else
new_h = window->rect.height + borders.total.top + borders.total.bottom;
frame_size_dx = new_w - window->frame->rect.width;
frame_size_dy = new_h - window->frame->rect.height;
need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0);
window->frame->rect.width = new_w;
window->frame->rect.height = new_h;
meta_topic (META_DEBUG_GEOMETRY,
"Calculated frame size %dx%d\n",
window->frame->rect.width,
window->frame->rect.height);
}
/* For nice effect, when growing the window we want to move/resize
* the frame first, when shrinking the window we want to move/resize
* the client first. If we grow one way and shrink the other,
* see which way we're moving "more"
*
* Mail from Owen subject "Suggestion: Gravity and resizing from the left"
* http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html
*
* An annoying fact you need to know in this code is that StaticGravity
* does nothing if you _only_ resize or _only_ move the frame;
* it must move _and_ resize, otherwise you get NorthWestGravity
* behavior. The move and resize must actually occur, it is not
* enough to set CWX | CWWidth but pass in the current size/pos.
*/
if (window->frame)
{
int new_x, new_y;
int frame_pos_dx, frame_pos_dy;
/* Compute new frame coords */
new_x = root_x_nw - borders.total.left;
new_y = root_y_nw - borders.total.top;
frame_pos_dx = new_x - window->frame->rect.x;
frame_pos_dy = new_y - window->frame->rect.y;
need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0);
window->frame->rect.x = new_x;
window->frame->rect.y = new_y;
/* If frame will both move and resize, then StaticGravity
* on the child window will kick in and implicitly move
* the child with respect to the frame. The implicit
* move will keep the child in the same place with
* respect to the root window. If frame only moves
* or only resizes, then the child will just move along
* with the frame.
*/
/* window->rect.x, window->rect.y are relative to frame,
* remember they are the server coords
*/
new_x = borders.total.left;
new_y = borders.total.top;
if (need_resize_frame && need_move_frame &&
static_gravity_works (window->display))
{
/* static gravity kicks in because frame
* is both moved and resized
*/
/* when we move the frame by frame_pos_dx, frame_pos_dy the
* client will implicitly move relative to frame by the
* inverse delta.
*
* When moving client then frame, we move the client by the
* frame delta, to be canceled out by the implicit move by
* the inverse frame delta, resulting in a client at new_x,
* new_y.
*
* When moving frame then client, we move the client
* by the same delta as the frame, because the client
* was "left behind" by the frame - resulting in a client
* at new_x, new_y.
*
* In both cases we need to move the client window
* in all cases where we had to move the frame window.
*/
client_move_x = new_x + frame_pos_dx;
client_move_y = new_y + frame_pos_dy;
if (need_move_frame)
need_move_client = TRUE;
use_static_gravity = TRUE;
}
else
{
client_move_x = new_x;
client_move_y = new_y;
if (client_move_x != window->rect.x ||
client_move_y != window->rect.y)
need_move_client = TRUE;
use_static_gravity = FALSE;
}
/* This is the final target position, but not necessarily what
* we pass to XConfigureWindow, due to StaticGravity implicit
* movement.
*/
window->rect.x = new_x;
window->rect.y = new_y;
}
else
{
if (root_x_nw != window->rect.x ||
root_y_nw != window->rect.y)
need_move_client = TRUE;
window->rect.x = root_x_nw;
window->rect.y = root_y_nw;
client_move_x = window->rect.x;
client_move_y = window->rect.y;
use_static_gravity = FALSE; use_static_gravity = FALSE;
} }
/* This is the final target position, but not necessarily what /* If frame extents have changed, fill in other frame fields and
* we pass to XConfigureWindow, due to StaticGravity implicit change frame's extents property. */
* movement. if (window->frame &&
(window->frame->child_x != borders.total.left ||
window->frame->child_y != borders.total.top ||
window->frame->right_width != borders.total.right ||
window->frame->bottom_height != borders.total.bottom))
{
window->frame->child_x = borders.total.left;
window->frame->child_y = borders.total.top;
window->frame->right_width = borders.total.right;
window->frame->bottom_height = borders.total.bottom;
update_net_frame_extents (window);
}
/* See ICCCM 4.1.5 for when to send ConfigureNotify */
need_configure_notify = FALSE;
/* If this is a configure request and we change nothing, then we
* must send configure notify.
*/ */
window->rect.x = new_x; if (is_configure_request &&
window->rect.y = new_y; !(need_move_client || need_move_frame ||
} need_resize_client || need_resize_frame ||
else window->border_width != 0))
{ need_configure_notify = TRUE;
if (root_x_nw != window->rect.x ||
root_y_nw != window->rect.y)
need_move_client = TRUE;
window->rect.x = root_x_nw; /* We must send configure notify if we move but don't resize, since
window->rect.y = root_y_nw; * the client window may not get a real event
*/
if ((need_move_client || need_move_frame) &&
!(need_resize_client || need_resize_frame))
need_configure_notify = TRUE;
client_move_x = window->rect.x; /* MapRequest events with a PPosition or UPosition hint with a frame
client_move_y = window->rect.y; * are moved by mutter without resizing; send a configure notify
* in such cases. See #322840. (Note that window->constructing is
* only true iff this call is due to a MapRequest, and when
* PPosition/UPosition hints aren't set, mutter seems to send a
* ConfigureNotify anyway due to the above code.)
*/
if (window->constructing && window->frame &&
((window->size_hints.flags & PPosition) ||
(window->size_hints.flags & USPosition)))
need_configure_notify = TRUE;
use_static_gravity = FALSE; /* The rest of this function syncs our new size/pos with X as
} * efficiently as possible
*/
/* If frame extents have changed, fill in other frame fields and /* Normally, we configure the frame first depending on whether
change frame's extents property. */ * we grow the frame more than we shrink. The idea is to avoid
if (window->frame && * messing up the window contents by having a temporary situation
(window->frame->child_x != borders.total.left || * where the frame is smaller than the window. However, if we're
window->frame->child_y != borders.total.top || * cooperating with the client to create an atomic frame upate,
window->frame->right_width != borders.total.right || * and the window is redirected, then we should always update
window->frame->bottom_height != borders.total.bottom)) * the frame first, since updating the frame will force a new
{ * backing pixmap to be allocated, and the old backing pixmap
window->frame->child_x = borders.total.left; * will be left undisturbed for us to paint to the screen until
window->frame->child_y = borders.total.top; * the client finishes redrawing.
window->frame->right_width = borders.total.right; */
window->frame->bottom_height = borders.total.bottom; if (window->extended_sync_request_counter)
{
configure_frame_first = TRUE;
}
else
{
size_dx = w - window->rect.width;
size_dy = h - window->rect.height;
update_net_frame_extents (window); configure_frame_first = size_dx + size_dy >= 0;
} }
/* See ICCCM 4.1.5 for when to send ConfigureNotify */ if (use_static_gravity)
meta_window_set_gravity (window, StaticGravity);
need_configure_notify = FALSE; if (configure_frame_first && window->frame)
frame_shape_changed = meta_frame_sync_to_window (window->frame,
gravity,
need_move_frame, need_resize_frame);
/* If this is a configure request and we change nothing, then we values.border_width = 0;
* must send configure notify. values.x = client_move_x;
*/ values.y = client_move_y;
if (is_configure_request && values.width = window->rect.width;
!(need_move_client || need_move_frame || values.height = window->rect.height;
need_resize_client || need_resize_frame ||
window->border_width != 0))
need_configure_notify = TRUE;
/* We must send configure notify if we move but don't resize, since mask = 0;
* the client window may not get a real event if (is_configure_request && window->border_width != 0)
*/ mask |= CWBorderWidth; /* must force to 0 */
if ((need_move_client || need_move_frame) && if (need_move_client)
!(need_resize_client || need_resize_frame)) mask |= (CWX | CWY);
need_configure_notify = TRUE; if (need_resize_client)
mask |= (CWWidth | CWHeight);
/* MapRequest events with a PPosition or UPosition hint with a frame if (mask != 0)
* are moved by mutter without resizing; send a configure notify {
* in such cases. See #322840. (Note that window->constructing is {
* only true iff this call is due to a MapRequest, and when int newx, newy;
* PPosition/UPosition hints aren't set, mutter seems to send a meta_window_get_position (window, &newx, &newy);
* ConfigureNotify anyway due to the above code.) meta_topic (META_DEBUG_GEOMETRY,
*/ "Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n",
if (window->constructing && window->frame && newx, newy,
((window->size_hints.flags & PPosition) || window->rect.width, window->rect.height,
(window->size_hints.flags & USPosition))) mask & CWBorderWidth ? "true" : "false",
need_configure_notify = TRUE; need_move_client ? "true" : "false",
need_resize_client ? "true" : "false");
}
/* The rest of this function syncs our new size/pos with X as meta_error_trap_push (window->display);
* efficiently as possible
*/
/* Normally, we configure the frame first depending on whether
* we grow the frame more than we shrink. The idea is to avoid
* messing up the window contents by having a temporary situation
* where the frame is smaller than the window. However, if we're
* cooperating with the client to create an atomic frame upate,
* and the window is redirected, then we should always update
* the frame first, since updating the frame will force a new
* backing pixmap to be allocated, and the old backing pixmap
* will be left undisturbed for us to paint to the screen until
* the client finishes redrawing.
*/
if (window->extended_sync_request_counter)
{
configure_frame_first = TRUE;
}
else
{
size_dx = w - window->rect.width;
size_dy = h - window->rect.height;
configure_frame_first = size_dx + size_dy >= 0;
}
if (use_static_gravity)
meta_window_set_gravity (window, StaticGravity);
if (configure_frame_first && window->frame)
frame_shape_changed = meta_frame_sync_to_window (window->frame,
gravity,
need_move_frame, need_resize_frame);
values.border_width = 0;
values.x = client_move_x;
values.y = client_move_y;
values.width = window->rect.width;
values.height = window->rect.height;
mask = 0;
if (is_configure_request && window->border_width != 0)
mask |= CWBorderWidth; /* must force to 0 */
if (need_move_client)
mask |= (CWX | CWY);
if (need_resize_client)
mask |= (CWWidth | CWHeight);
if (mask != 0)
{
{
int newx, newy;
meta_window_get_position (window, &newx, &newy);
meta_topic (META_DEBUG_GEOMETRY,
"Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n",
newx, newy,
window->rect.width, window->rect.height,
mask & CWBorderWidth ? "true" : "false",
need_move_client ? "true" : "false",
need_resize_client ? "true" : "false");
}
meta_error_trap_push (window->display);
#ifdef HAVE_XSYNC #ifdef HAVE_XSYNC
if (window == window->display->grab_window && if (window == window->display->grab_window &&
meta_grab_op_is_resizing (window->display->grab_op) && meta_grab_op_is_resizing (window->display->grab_op) &&
!window->disable_sync && !window->disable_sync &&
window->sync_request_counter != None && window->sync_request_counter != None &&
window->sync_request_alarm != None && window->sync_request_alarm != None &&
window->sync_request_timeout_id == 0) window->sync_request_timeout_id == 0)
{ {
send_sync_request (window); send_sync_request (window);
} }
#endif #endif
XConfigureWindow (window->display->xdisplay, XConfigureWindow (window->display->xdisplay,
window->xwindow, window->xwindow,
mask, mask,
&values); &values);
meta_error_trap_pop (window->display); meta_error_trap_pop (window->display);
}
if (!configure_frame_first && window->frame)
frame_shape_changed = meta_frame_sync_to_window (window->frame,
gravity,
need_move_frame, need_resize_frame);
/* Put gravity back to be nice to lesser window managers */
if (use_static_gravity)
meta_window_set_gravity (window, NorthWestGravity);
if (need_configure_notify)
send_configure_notify (window);
} }
if (!configure_frame_first && window->frame)
frame_shape_changed = meta_frame_sync_to_window (window->frame,
gravity,
need_move_frame, need_resize_frame);
/* Put gravity back to be nice to lesser window managers */
if (use_static_gravity)
meta_window_set_gravity (window, NorthWestGravity);
if (need_configure_notify)
send_configure_notify (window);
if (!window->placed && window->force_save_user_rect && !window->fullscreen) if (!window->placed && window->force_save_user_rect && !window->fullscreen)
force_save_user_window_placement (window); force_save_user_window_placement (window);
else if (is_user_action) else if (is_user_action)
@ -5422,7 +5525,7 @@ meta_window_move_resize_internal (MetaWindow *window,
if (need_move_frame || need_resize_frame || if (need_move_frame || need_resize_frame ||
need_move_client || need_resize_client || need_move_client || need_resize_client ||
did_placement) did_placement || is_wayland_resize)
{ {
int newx, newy; int newx, newy;
meta_window_get_position (window, &newx, &newy); meta_window_get_position (window, &newx, &newy);
@ -5492,6 +5595,37 @@ meta_window_resize (MetaWindow *window,
x, y, w, h); 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: * meta_window_move:
* @window: a #MetaWindow * @window: a #MetaWindow

View File

@ -25,6 +25,7 @@
#include <clutter/clutter.h> #include <clutter/clutter.h>
#include <clutter/wayland/clutter-wayland-compositor.h> #include <clutter/wayland/clutter-wayland-compositor.h>
#include <clutter/wayland/clutter-wayland-surface.h> #include <clutter/wayland/clutter-wayland-surface.h>
#include <cogl/cogl-wayland-server.h>
#include <glib.h> #include <glib.h>
#include <sys/time.h> #include <sys/time.h>
@ -64,8 +65,9 @@ static void
surface_process_damage (MetaWaylandSurface *surface, surface_process_damage (MetaWaylandSurface *surface,
cairo_region_t *region) cairo_region_t *region)
{ {
if (surface->window && g_assert (surface->window);
surface->buffer_ref.buffer)
if (surface->buffer_ref.buffer)
{ {
MetaWindowActor *window_actor = MetaWindowActor *window_actor =
META_WINDOW_ACTOR (meta_window_get_compositor_private (surface->window)); 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, meta_wayland_surface_attach (struct wl_client *wayland_client,
struct wl_resource *wayland_surface_resource, struct wl_resource *wayland_surface_resource,
struct wl_resource *wayland_buffer_resource, struct wl_resource *wayland_buffer_resource,
gint32 sx, gint32 sy) gint32 dx, gint32 dy)
{ {
MetaWaylandSurface *surface = MetaWaylandSurface *surface =
wl_resource_get_user_data (wayland_surface_resource); 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) if (surface->pending.buffer)
wl_list_remove (&surface->pending.buffer_destroy_listener.link); wl_list_remove (&surface->pending.buffer_destroy_listener.link);
surface->pending.sx = sx; surface->pending.dx = dx;
surface->pending.sy = sy; surface->pending.dy = dy;
surface->pending.buffer = buffer; surface->pending.buffer = buffer;
surface->pending.newly_attached = TRUE; surface->pending.newly_attached = TRUE;
@ -247,36 +249,86 @@ meta_wayland_surface_commit (struct wl_client *client,
if (surface->pending.newly_attached && if (surface->pending.newly_attached &&
surface->buffer_ref.buffer != surface->pending.buffer) 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 /* Note: we set this before informing any window-actor since the
* window actor will expect to find the new buffer within the * window actor will expect to find the new buffer within the
* surface. */ * surface. */
meta_wayland_buffer_reference (&surface->buffer_ref, meta_wayland_buffer_reference (&surface->buffer_ref,
surface->pending.buffer); 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) if (surface->pending.buffer)
{ {
MetaWaylandBuffer *buffer = surface->pending.buffer; MetaWaylandBuffer *buffer = surface->pending.buffer;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
if (surface->window) meta_window_actor_attach_wayland_buffer (window_actor, buffer);
{ }
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); /* We resize X based surfaces according to X events */
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
{
int new_width;
int new_height;
if (window_actor) new_width = surface->buffer_ref.buffer->width;
meta_window_actor_attach_wayland_buffer (window_actor, buffer); 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);
}
/* XXX: we resize X based surfaces according to X events */ meta_window_set_opaque_region (surface->window, surface->pending.opaque_region);
if (surface->xid == 0 && meta_window_set_input_region (surface->window, surface->pending.input_region);
(buffer->width != rect.width || buffer->height != rect.height)) surface_process_damage (surface, surface->pending.damage);
meta_window_resize (surface->window, FALSE, buffer->width, buffer->height);
}
else if (surface == compositor->seat->sprite)
meta_wayland_seat_update_sprite (compositor->seat);
}
} }
if (surface->pending.buffer) 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); wl_list_remove (&surface->pending.buffer_destroy_listener.link);
surface->pending.buffer = NULL; surface->pending.buffer = NULL;
} }
surface->pending.sx = 0; surface->pending.dx = 0;
surface->pending.sy = 0; surface->pending.dy = 0;
surface->pending.newly_attached = FALSE; surface->pending.newly_attached = FALSE;
g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
if (surface->window) g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
{
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); empty_region (surface->pending.damage);
/* wl_surface.frame */ /* wl_surface.frame */
@ -1050,3 +1093,14 @@ free_initial_state (MetaWaylandSurfaceInitialState *initial)
g_slice_free (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);
}

View File

@ -52,8 +52,8 @@ typedef struct
gboolean newly_attached; gboolean newly_attached;
MetaWaylandBuffer *buffer; MetaWaylandBuffer *buffer;
struct wl_listener buffer_destroy_listener; struct wl_listener buffer_destroy_listener;
int32_t sx; int32_t dx;
int32_t sy; int32_t dy;
/* wl_surface.damage */ /* wl_surface.damage */
cairo_region_t *damage; cairo_region_t *damage;
@ -82,9 +82,6 @@ struct _MetaWaylandSurface
{ {
struct wl_resource *resource; struct wl_resource *resource;
MetaWaylandCompositor *compositor; MetaWaylandCompositor *compositor;
guint32 xid;
int x;
int y;
MetaWaylandBufferReference buffer_ref; MetaWaylandBufferReference buffer_ref;
MetaWindow *window; MetaWindow *window;
gboolean has_shell_surface; gboolean has_shell_surface;
@ -116,4 +113,9 @@ void meta_wayland_surface_free (MetaWaylandSurface *surface)
void meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface, void meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
MetaWindow *window); MetaWindow *window);
void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
int width,
int height,
int edges);
#endif #endif

View File

@ -187,6 +187,7 @@ meta_wayland_buffer_reference (MetaWaylandBufferReference *ref,
if (ref->buffer->busy_count == 0) if (ref->buffer->busy_count == 0)
{ {
g_clear_pointer (&ref->buffer->texture, cogl_object_unref);
g_assert (wl_resource_get_client (ref->buffer->resource)); g_assert (wl_resource_get_client (ref->buffer->resource));
wl_resource_queue_event (ref->buffer->resource, WL_BUFFER_RELEASE); 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); device_event.event_y = wl_fixed_to_double (pointer->y);
} }
if (surface && surface->xid != None) if (surface && surface->window != NULL)
device_event.event = surface->xid; device_event.event = surface->window->xwindow;
else else
device_event.event = device_event.root; device_event.event = device_event.root;

View File

@ -45,10 +45,6 @@ xserver_set_window_id (struct wl_client *client,
MetaDisplay *display = meta_get_display (); MetaDisplay *display = meta_get_display ();
MetaWindow *window; MetaWindow *window;
g_return_if_fail (surface->xid == None);
surface->xid = xid;
window = meta_display_lookup_x_window (display, xid); window = meta_display_lookup_x_window (display, xid);
if (window) if (window)
{ {