[mutter/wayland] window: Move move_resize_internal logic to protocol-specific directories
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wayland] window: Move move_resize_internal logic to protocol-specific directories
- Date: Thu, 20 Mar 2014 15:03:38 +0000 (UTC)
commit a53e094fcd4bec77873d201c582b9a5a74e733ac
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Wed Mar 19 10:30:12 2014 -0400
window: Move move_resize_internal logic to protocol-specific directories
src/core/constraints.h | 10 -
src/core/window-private.h | 28 ++-
src/core/window.c | 572 ++---------------------------------------
src/wayland/window-wayland.c | 91 +++++++
src/x11/window-x11.c | 464 ++++++++++++++++++++++++++++++++++
5 files changed, 610 insertions(+), 555 deletions(-)
---
diff --git a/src/core/constraints.h b/src/core/constraints.h
index 52a6f20..9c3c41e 100644
--- a/src/core/constraints.h
+++ b/src/core/constraints.h
@@ -27,16 +27,6 @@
#include "window-private.h"
#include "frame.h"
-typedef enum
-{
- META_IS_CONFIGURE_REQUEST = 1 << 0,
- 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_WAYLAND_RESIZE = 1 << 5
-} MetaMoveResizeFlags;
-
void meta_window_constrain (MetaWindow *window,
MetaMoveResizeFlags flags,
int resize_gravity,
diff --git a/src/core/window-private.h b/src/core/window-private.h
index d706ff9..aa57332 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -65,13 +65,28 @@ typedef enum {
#define NUMBER_OF_QUEUES 3
-
typedef enum {
_NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0,
_NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1,
_NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2,
} MetaBypassCompositorHintValue;
+typedef enum
+{
+ META_IS_CONFIGURE_REQUEST = 1 << 0,
+ 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_WAYLAND_RESIZE = 1 << 5
+} MetaMoveResizeFlags;
+
+typedef enum
+{
+ META_MOVE_RESIZE_RESULT_MOVED = 1 << 0,
+ META_MOVE_RESIZE_RESULT_RESIZED = 1 << 1,
+ META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED = 1 << 2,
+} MetaMoveResizeResultFlags;
struct _MetaWindow
{
@@ -456,6 +471,12 @@ struct _MetaWindowClass
void (*manage) (MetaWindow *window);
void (*unmanage) (MetaWindow *window);
+ void (*move_resize_internal) (MetaWindow *window,
+ int gravity,
+ MetaRectangle requested_rect,
+ MetaRectangle constrained_rect,
+ MetaMoveResizeFlags flags,
+ MetaMoveResizeResultFlags *result);
void (*get_default_skip_hints) (MetaWindow *window,
gboolean *skip_taskbar_out,
gboolean *skip_pager_out);
@@ -732,4 +753,9 @@ void meta_window_update_monitor (MetaWindow *window);
void meta_window_set_urgent (MetaWindow *window,
gboolean urgent);
+void meta_window_update_resize (MetaWindow *window,
+ gboolean snap,
+ int x, int y,
+ gboolean force);
+
#endif
diff --git a/src/core/window.c b/src/core/window.c
index 4e930dc..3c4c539 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -73,15 +73,12 @@
static int destroying_windows_disallowed = 0;
-static void update_net_frame_extents (MetaWindow *window);
static void invalidate_work_areas (MetaWindow *window);
static void set_wm_state (MetaWindow *window);
static void set_net_wm_state (MetaWindow *window);
static void meta_window_set_above (MetaWindow *window,
gboolean new_value);
-static void send_configure_notify (MetaWindow *window);
-
static void meta_window_force_placement (MetaWindow *window);
static void meta_window_show (MetaWindow *window);
@@ -1578,12 +1575,6 @@ meta_window_unmanage (MetaWindow *window,
if (window->maximized_horizontally || window->maximized_vertically)
unmaximize_window_before_freeing (window);
- /* The XReparentWindow call in meta_window_destroy_frame() moves the
- * window so we need to send a configure notify; see bug 399552. (We
- * also do this just in case a window got unmaximized.)
- */
- send_configure_notify (window);
-
meta_window_unqueue (window, META_QUEUE_CALC_SHOWING |
META_QUEUE_MOVE_RESIZE |
META_QUEUE_UPDATE_ICON);
@@ -1619,9 +1610,6 @@ meta_window_unmanage (MetaWindow *window,
meta_window_destroy_sync_request_alarm (window);
- if (window->frame)
- meta_window_destroy_frame (window);
-
/* If an undecorated window is being withdrawn, that will change the
* stack as presented to the compositing manager, without actually
* changing the stacking order of X windows.
@@ -1636,6 +1624,9 @@ meta_window_unmanage (MetaWindow *window,
META_WINDOW_GET_CLASS (window)->unmanage (window);
+ if (window->frame)
+ meta_window_destroy_frame (window);
+
meta_prefs_remove_listener (prefs_changed_callback, window);
meta_screen_queue_check_fullscreen (window->screen);
@@ -4034,90 +4025,6 @@ meta_window_destroy_sync_request_alarm (MetaWindow *window)
#endif /* HAVE_XSYNC */
}
-#ifdef HAVE_XSYNC
-static gboolean
-sync_request_timeout (gpointer data)
-{
- MetaWindow *window = data;
-
- window->sync_request_timeout_id = 0;
-
- /* We have now waited for more than a second for the
- * application to respond to the sync request
- */
- window->disable_sync = TRUE;
-
- /* Reset the wait serial, so we don't continue freezing
- * window updates
- */
- window->sync_request_wait_serial = 0;
- meta_compositor_set_updates_frozen (window->display->compositor, window,
- meta_window_updates_are_frozen (window));
-
- if (window == window->display->grab_window &&
- meta_grab_op_is_resizing (window->display->grab_op))
- {
- update_resize (window,
- window->display->grab_last_user_action_was_snap,
- window->display->grab_latest_motion_x,
- window->display->grab_latest_motion_y,
- TRUE);
- }
-
- return FALSE;
-}
-
-static void
-send_sync_request (MetaWindow *window)
-{
- XClientMessageEvent ev;
- gint64 wait_serial;
-
- /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to
- * increase the value, but for the new "extended" style we need to
- * pick an even (unfrozen) value sufficiently ahead of the last serial
- * that we received from the client; the same code still works
- * for the old style. The increment of 240 is specified by the EWMH
- * and is (1 second) * (60fps) * (an increment of 4 per frame).
- */
- wait_serial = window->sync_request_serial + 240;
-
- window->sync_request_wait_serial = wait_serial;
-
- ev.type = ClientMessage;
- ev.window = window->xwindow;
- ev.message_type = window->display->atom_WM_PROTOCOLS;
- ev.format = 32;
- ev.data.l[0] = window->display->atom__NET_WM_SYNC_REQUEST;
- /* FIXME: meta_display_get_current_time() is bad, but since calls
- * come from meta_window_move_resize_internal (which in turn come
- * from all over), I'm not sure what we can do to fix it. Do we
- * want to use _roundtrip, though?
- */
- ev.data.l[1] = meta_display_get_current_time (window->display);
- ev.data.l[2] = wait_serial & G_GUINT64_CONSTANT(0xffffffff);
- ev.data.l[3] = wait_serial >> 32;
- ev.data.l[4] = window->extended_sync_request_counter ? 1 : 0;
-
- /* We don't need to trap errors here as we are already
- * inside an error_trap_push()/pop() pair.
- */
- XSendEvent (window->display->xdisplay,
- window->xwindow, False, 0, (XEvent*) &ev);
-
- /* We give the window 1 sec to respond to _NET_WM_SYNC_REQUEST;
- * if this time expires, we consider the window unresponsive
- * and resize it unsynchonized.
- */
- window->sync_request_timeout_id = g_timeout_add (1000,
- sync_request_timeout,
- window);
-
- meta_compositor_set_updates_frozen (window->display->compositor, window,
- meta_window_updates_are_frozen (window));
-}
-#endif
-
/**
* meta_window_updates_are_frozen:
* @window: a #MetaWindow
@@ -4307,30 +4214,21 @@ meta_window_move_resize_internal (MetaWindow *window,
* we don't decorate wayland clients), and the client has acknowledged
* the window size change.
*/
- XWindowChanges values;
- unsigned int mask;
- gboolean need_configure_notify;
- MetaFrameBorders borders;
- gboolean need_move_client = FALSE;
- gboolean need_move_frame = FALSE;
- gboolean need_resize_client = FALSE;
- gboolean need_resize_frame = FALSE;
- int size_dx;
- int size_dy;
gboolean frame_shape_changed = FALSE;
+
gboolean is_configure_request;
gboolean do_gravity_adjust;
gboolean is_user_action;
gboolean is_wayland_resize;
gboolean did_placement;
- gboolean configure_frame_first;
/* used for the configure request, but may not be final
* destination due to StaticGravity etc.
*/
- int client_move_x;
- int client_move_y;
MetaRectangle new_rect;
MetaRectangle old_rect;
+ MetaRectangle requested_rect;
+ MetaMoveResizeResultFlags result;
+ MetaFrameBorders borders;
g_return_if_fail (!window->override_redirect);
@@ -4356,13 +4254,14 @@ meta_window_move_resize_internal (MetaWindow *window,
is_user_action ? " (user move/resize)" : "",
old_rect.x, old_rect.y, old_rect.width, old_rect.height);
- meta_frame_calc_borders (window->frame,
- &borders);
+ meta_frame_calc_borders (window->frame, &borders);
- new_rect.x = root_x_nw;
- new_rect.y = root_y_nw;
- new_rect.width = w;
- new_rect.height = h;
+ requested_rect.x = root_x_nw;
+ requested_rect.y = root_y_nw;
+ requested_rect.width = w;
+ requested_rect.height = h;
+
+ new_rect = requested_rect;
/* If this is a resize only, the position should be ignored and
* instead obtained by resizing the old rectangle according to the
@@ -4409,363 +4308,21 @@ meta_window_move_resize_internal (MetaWindow *window,
&new_rect);
}
- 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);
- }
- 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.
- */
-
- /* meta_window_constrain() might have maximized the window after placement,
- * changing the borders.
- */
- meta_frame_calc_borders (window->frame, &borders);
-
- 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;
- 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;
-
- /* 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;
- }
-
- /* If frame extents have changed, fill in other frame fields and
- change frame's extents property. */
- 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.
- */
- if (is_configure_request &&
- !(need_move_client || need_move_frame ||
- 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
- * 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;
-
- /* MapRequest events with a PPosition or UPosition hint with a frame
- * 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;
-
- /* The rest of this function syncs our new size/pos with X as
- * 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 (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
- if (window == window->display->grab_window &&
- meta_grab_op_is_resizing (window->display->grab_op) &&
- !window->disable_sync &&
- window->sync_request_counter != None &&
- window->sync_request_alarm != None &&
- window->sync_request_timeout_id == 0)
- {
- send_sync_request (window);
- }
-#endif
-
- XConfigureWindow (window->display->xdisplay,
- window->xwindow,
- mask,
- &values);
-
- 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);
-
- if (need_configure_notify)
- send_configure_notify (window);
- }
+ /* Do the protocol-specific move/resize logic */
+ META_WINDOW_GET_CLASS (window)->move_resize_internal (window, gravity, requested_rect, new_rect, flags,
&result);
if (!window->placed && window->force_save_user_rect && !window->fullscreen)
force_save_user_window_placement (window);
else if (is_user_action)
save_user_window_placement (window);
- if (need_move_client || need_move_frame)
+ if (result & META_MOVE_RESIZE_RESULT_MOVED)
g_signal_emit (window, window_signals[POSITION_CHANGED], 0);
- if (need_resize_client || need_resize_frame)
+ if (result & META_MOVE_RESIZE_RESULT_RESIZED)
g_signal_emit (window, window_signals[SIZE_CHANGED], 0);
- if (need_move_frame || need_resize_frame ||
- need_move_client || need_resize_client ||
+ if ((result & (META_MOVE_RESIZE_RESULT_MOVED | META_MOVE_RESIZE_RESULT_RESIZED)) != 0 ||
did_placement || is_wayland_resize)
{
int newx, newy;
@@ -5751,35 +5308,6 @@ meta_window_get_net_wm_desktop (MetaWindow *window)
return meta_workspace_index (window->workspace);
}
-static void
-update_net_frame_extents (MetaWindow *window)
-{
- unsigned long data[4];
- MetaFrameBorders borders;
-
- meta_frame_calc_borders (window->frame, &borders);
- /* Left */
- data[0] = borders.visible.left;
- /* Right */
- data[1] = borders.visible.right;
- /* Top */
- data[2] = borders.visible.top;
- /* Bottom */
- data[3] = borders.visible.bottom;
-
- meta_topic (META_DEBUG_GEOMETRY,
- "Setting _NET_FRAME_EXTENTS on managed window 0x%lx "
- "to left = %lu, right = %lu, top = %lu, bottom = %lu\n",
- window->xwindow, data[0], data[1], data[2], data[3]);
-
- meta_error_trap_push (window->display);
- XChangeProperty (window->display->xdisplay, window->xwindow,
- window->display->atom__NET_FRAME_EXTENTS,
- XA_CARDINAL,
- 32, PropModeReplace, (guchar*) data, 4);
- meta_error_trap_pop (window->display);
-}
-
void
meta_window_set_current_workspace_hint (MetaWindow *window)
{
@@ -6304,59 +5832,6 @@ meta_window_set_focused_internal (MetaWindow *window,
}
}
-static void
-send_configure_notify (MetaWindow *window)
-{
- XEvent event;
-
- /* from twm */
-
- event.type = ConfigureNotify;
- event.xconfigure.display = window->display->xdisplay;
- event.xconfigure.event = window->xwindow;
- event.xconfigure.window = window->xwindow;
- event.xconfigure.x = window->rect.x - window->border_width;
- event.xconfigure.y = window->rect.y - window->border_width;
- if (window->frame)
- {
- if (window->withdrawn)
- {
- MetaFrameBorders borders;
- /* We reparent the client window and put it to the position
- * where the visible top-left of the frame window currently is.
- */
-
- meta_frame_calc_borders (window->frame, &borders);
-
- event.xconfigure.x = window->frame->rect.x + borders.invisible.left;
- event.xconfigure.y = window->frame->rect.y + borders.invisible.top;
- }
- else
- {
- /* Need to be in root window coordinates */
- event.xconfigure.x += window->frame->rect.x;
- event.xconfigure.y += window->frame->rect.y;
- }
- }
- event.xconfigure.width = window->rect.width;
- event.xconfigure.height = window->rect.height;
- event.xconfigure.border_width = window->border_width; /* requested not actual */
- event.xconfigure.above = None; /* FIXME */
- event.xconfigure.override_redirect = False;
-
- meta_topic (META_DEBUG_GEOMETRY,
- "Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d\n",
- window->desc,
- event.xconfigure.x, event.xconfigure.y,
- event.xconfigure.width, event.xconfigure.height);
-
- meta_error_trap_push (window->display);
- XSendEvent (window->display->xdisplay,
- window->xwindow,
- False, StructureNotifyMask, &event);
- meta_error_trap_pop (window->display);
-}
-
/**
* meta_window_get_icon_geometry:
* @window: a #MetaWindow
@@ -8083,6 +7558,15 @@ update_tile_mode (MetaWindow *window)
}
}
+void
+meta_window_update_resize (MetaWindow *window,
+ gboolean snap,
+ int x, int y,
+ gboolean force)
+{
+ update_resize (window, snap, x, y, force);
+}
+
#ifdef HAVE_XSYNC
void
meta_window_update_sync_request_counter (MetaWindow *window,
diff --git a/src/wayland/window-wayland.c b/src/wayland/window-wayland.c
index 9a0a15c..8b75da7 100644
--- a/src/wayland/window-wayland.c
+++ b/src/wayland/window-wayland.c
@@ -27,6 +27,7 @@
#include "window-wayland.h"
#include "window-private.h"
+#include "boxes-private.h"
#include "stack-tracker.h"
#include "meta-wayland-surface.h"
@@ -75,6 +76,95 @@ meta_window_wayland_unmanage (MetaWindow *window)
}
static void
+meta_window_wayland_move_resize_internal (MetaWindow *window,
+ int gravity,
+ MetaRectangle requested_rect,
+ MetaRectangle constrained_rect,
+ MetaMoveResizeFlags flags,
+ MetaMoveResizeResultFlags *result)
+{
+ 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.
+ */
+
+ /* 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 = constrained_rect;
+
+ if (flags & META_IS_WAYLAND_RESIZE)
+ {
+ /* This is a call to wl_surface_commit(), ignore the constrained_rect and
+ * update the real client size to match the buffer size.
+ */
+
+ window->rect.width = requested_rect.width;
+ window->rect.height = requested_rect.height;
+ }
+
+ if (constrained_rect.width != window->rect.width ||
+ constrained_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 old_rect;
+ MetaRectangle client_rect;
+ int dx, dy;
+ int deltax, deltay;
+
+ meta_window_get_client_root_coords (window, &old_rect);
+
+ meta_rectangle_resize_with_gravity (&old_rect,
+ &client_rect,
+ gravity,
+ constrained_rect.width,
+ constrained_rect.height);
+
+ deltax = constrained_rect.x - old_rect.x;
+ deltay = constrained_rect.y - old_rect.y;
+ dx = client_rect.x - constrained_rect.x;
+ dy = client_rect.y - constrained_rect.y;
+
+ if (deltax != dx || deltay != dy)
+ *result |= META_MOVE_RESIZE_RESULT_MOVED;
+
+ window->rect.x += (deltax - dx);
+ window->rect.y += (deltay - dy);
+
+ *result |= META_MOVE_RESIZE_RESULT_RESIZED;
+ meta_wayland_surface_configure_notify (window->surface,
+ constrained_rect.width,
+ constrained_rect.height);
+ }
+ else
+ {
+ /* No resize happening, we can just move the window and live with it. */
+ if (window->rect.x != constrained_rect.x ||
+ window->rect.y != constrained_rect.y)
+ *result |= META_MOVE_RESIZE_RESULT_MOVED;
+
+ window->rect.x = constrained_rect.x;
+ window->rect.y = constrained_rect.y;
+ }
+}
+
+static void
meta_window_wayland_init (MetaWindowWayland *window_wayland)
{
}
@@ -86,4 +176,5 @@ meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
window_class->manage = meta_window_wayland_manage;
window_class->unmanage = meta_window_wayland_unmanage;
+ window_class->move_resize_internal = meta_window_wayland_move_resize_internal;
}
diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
index f1f98b2..86491a6 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -41,6 +41,7 @@
#include <meta/prefs.h>
#include <meta/meta-cursor-tracker.h>
+#include "frame.h"
#include "window-private.h"
#include "window-props.h"
#include "xprops.h"
@@ -159,6 +160,59 @@ update_sm_hints (MetaWindow *window)
}
static void
+send_configure_notify (MetaWindow *window)
+{
+ XEvent event;
+
+ /* from twm */
+
+ event.type = ConfigureNotify;
+ event.xconfigure.display = window->display->xdisplay;
+ event.xconfigure.event = window->xwindow;
+ event.xconfigure.window = window->xwindow;
+ event.xconfigure.x = window->rect.x - window->border_width;
+ event.xconfigure.y = window->rect.y - window->border_width;
+ if (window->frame)
+ {
+ if (window->withdrawn)
+ {
+ MetaFrameBorders borders;
+ /* We reparent the client window and put it to the position
+ * where the visible top-left of the frame window currently is.
+ */
+
+ meta_frame_calc_borders (window->frame, &borders);
+
+ event.xconfigure.x = window->frame->rect.x + borders.invisible.left;
+ event.xconfigure.y = window->frame->rect.y + borders.invisible.top;
+ }
+ else
+ {
+ /* Need to be in root window coordinates */
+ event.xconfigure.x += window->frame->rect.x;
+ event.xconfigure.y += window->frame->rect.y;
+ }
+ }
+ event.xconfigure.width = window->rect.width;
+ event.xconfigure.height = window->rect.height;
+ event.xconfigure.border_width = window->border_width; /* requested not actual */
+ event.xconfigure.above = None; /* FIXME */
+ event.xconfigure.override_redirect = False;
+
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d\n",
+ window->desc,
+ event.xconfigure.x, event.xconfigure.y,
+ event.xconfigure.width, event.xconfigure.height);
+
+ meta_error_trap_push (window->display);
+ XSendEvent (window->display->xdisplay,
+ window->xwindow,
+ False, StructureNotifyMask, &event);
+ meta_error_trap_pop (window->display);
+}
+
+static void
meta_window_x11_manage (MetaWindow *window)
{
MetaDisplay *display = window->display;
@@ -259,9 +313,418 @@ meta_window_x11_unmanage (MetaWindow *window)
XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
#endif
+ /* The XReparentWindow call in meta_window_destroy_frame() moves the
+ * window so we need to send a configure notify; see bug 399552. (We
+ * also do this just in case a window got unmaximized.)
+ */
+ send_configure_notify (window);
+
+ meta_error_trap_pop (window->display);
+}
+
+static void
+update_net_frame_extents (MetaWindow *window)
+{
+ unsigned long data[4];
+ MetaFrameBorders borders;
+
+ meta_frame_calc_borders (window->frame, &borders);
+ /* Left */
+ data[0] = borders.visible.left;
+ /* Right */
+ data[1] = borders.visible.right;
+ /* Top */
+ data[2] = borders.visible.top;
+ /* Bottom */
+ data[3] = borders.visible.bottom;
+
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Setting _NET_FRAME_EXTENTS on managed window 0x%lx "
+ "to left = %lu, right = %lu, top = %lu, bottom = %lu\n",
+ window->xwindow, data[0], data[1], data[2], data[3]);
+
+ meta_error_trap_push (window->display);
+ XChangeProperty (window->display->xdisplay, window->xwindow,
+ window->display->atom__NET_FRAME_EXTENTS,
+ XA_CARDINAL,
+ 32, PropModeReplace, (guchar*) data, 4);
meta_error_trap_pop (window->display);
}
+#ifdef HAVE_XSYNC
+static gboolean
+sync_request_timeout (gpointer data)
+{
+ MetaWindow *window = data;
+
+ window->sync_request_timeout_id = 0;
+
+ /* We have now waited for more than a second for the
+ * application to respond to the sync request
+ */
+ window->disable_sync = TRUE;
+
+ /* Reset the wait serial, so we don't continue freezing
+ * window updates
+ */
+ window->sync_request_wait_serial = 0;
+ meta_compositor_set_updates_frozen (window->display->compositor, window,
+ meta_window_updates_are_frozen (window));
+
+ if (window == window->display->grab_window &&
+ meta_grab_op_is_resizing (window->display->grab_op))
+ {
+ meta_window_update_resize (window,
+ window->display->grab_last_user_action_was_snap,
+ window->display->grab_latest_motion_x,
+ window->display->grab_latest_motion_y,
+ TRUE);
+ }
+
+ return FALSE;
+}
+
+static void
+send_sync_request (MetaWindow *window)
+{
+ XClientMessageEvent ev;
+ gint64 wait_serial;
+
+ /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to
+ * increase the value, but for the new "extended" style we need to
+ * pick an even (unfrozen) value sufficiently ahead of the last serial
+ * that we received from the client; the same code still works
+ * for the old style. The increment of 240 is specified by the EWMH
+ * and is (1 second) * (60fps) * (an increment of 4 per frame).
+ */
+ wait_serial = window->sync_request_serial + 240;
+
+ window->sync_request_wait_serial = wait_serial;
+
+ ev.type = ClientMessage;
+ ev.window = window->xwindow;
+ ev.message_type = window->display->atom_WM_PROTOCOLS;
+ ev.format = 32;
+ ev.data.l[0] = window->display->atom__NET_WM_SYNC_REQUEST;
+ /* FIXME: meta_display_get_current_time() is bad, but since calls
+ * come from meta_window_move_resize_internal (which in turn come
+ * from all over), I'm not sure what we can do to fix it. Do we
+ * want to use _roundtrip, though?
+ */
+ ev.data.l[1] = meta_display_get_current_time (window->display);
+ ev.data.l[2] = wait_serial & G_GUINT64_CONSTANT(0xffffffff);
+ ev.data.l[3] = wait_serial >> 32;
+ ev.data.l[4] = window->extended_sync_request_counter ? 1 : 0;
+
+ /* We don't need to trap errors here as we are already
+ * inside an error_trap_push()/pop() pair.
+ */
+ XSendEvent (window->display->xdisplay,
+ window->xwindow, False, 0, (XEvent*) &ev);
+
+ /* We give the window 1 sec to respond to _NET_WM_SYNC_REQUEST;
+ * if this time expires, we consider the window unresponsive
+ * and resize it unsynchonized.
+ */
+ window->sync_request_timeout_id = g_timeout_add (1000,
+ sync_request_timeout,
+ window);
+
+ meta_compositor_set_updates_frozen (window->display->compositor, window,
+ meta_window_updates_are_frozen (window));
+}
+#endif
+
+static void
+meta_window_x11_move_resize_internal (MetaWindow *window,
+ int gravity,
+ MetaRectangle requested_rect,
+ MetaRectangle constrained_rect,
+ MetaMoveResizeFlags flags,
+ MetaMoveResizeResultFlags *result)
+{
+ int root_x_nw, root_y_nw;
+ int w, h;
+ int client_move_x, client_move_y;
+ int size_dx, size_dy;
+ XWindowChanges values;
+ unsigned int mask;
+ gboolean need_configure_notify;
+ MetaFrameBorders borders;
+ gboolean need_move_client = FALSE;
+ gboolean need_move_frame = FALSE;
+ gboolean need_resize_client = FALSE;
+ gboolean need_resize_frame = FALSE;
+ gboolean frame_shape_changed = FALSE;
+ gboolean configure_frame_first;
+
+ gboolean is_configure_request;
+
+ is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
+
+ /* meta_window_constrain() might have maximized the window after placement,
+ * changing the borders.
+ */
+ meta_frame_calc_borders (window->frame, &borders);
+
+ root_x_nw = constrained_rect.x;
+ root_y_nw = constrained_rect.y;
+ w = constrained_rect.width;
+ h = constrained_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;
+ 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;
+
+ /* 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;
+ }
+
+ /* If frame extents have changed, fill in other frame fields and
+ change frame's extents property. */
+ 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.
+ */
+ if (is_configure_request &&
+ !(need_move_client || need_move_frame ||
+ 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
+ * 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;
+
+ /* MapRequest events with a PPosition or UPosition hint with a frame
+ * 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;
+
+ /* The rest of this function syncs our new size/pos with X as
+ * 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 (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
+ if (window == window->display->grab_window &&
+ meta_grab_op_is_resizing (window->display->grab_op) &&
+ !window->disable_sync &&
+ window->sync_request_counter != None &&
+ window->sync_request_alarm != None &&
+ window->sync_request_timeout_id == 0)
+ {
+ send_sync_request (window);
+ }
+#endif
+
+ XConfigureWindow (window->display->xdisplay,
+ window->xwindow,
+ mask,
+ &values);
+
+ 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);
+
+ if (need_configure_notify)
+ send_configure_notify (window);
+
+ if (frame_shape_changed)
+ *result |= META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED;
+ if (need_move_client || need_move_frame)
+ *result |= META_MOVE_RESIZE_RESULT_MOVED;
+ if (need_resize_client || need_resize_frame)
+ *result |= META_MOVE_RESIZE_RESULT_RESIZED;
+}
+
static void
meta_window_x11_get_default_skip_hints (MetaWindow *window,
gboolean *skip_taskbar_out,
@@ -281,6 +744,7 @@ meta_window_x11_class_init (MetaWindowX11Class *klass)
window_class->manage = meta_window_x11_manage;
window_class->unmanage = meta_window_x11_unmanage;
+ window_class->move_resize_internal = meta_window_x11_move_resize_internal;
window_class->get_default_skip_hints = meta_window_x11_get_default_skip_hints;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]