window: Move move_resize_internal logic to protocol-specific directories
This commit is contained in:
parent
a377a1a110
commit
a53e094fcd
@ -27,16 +27,6 @@
|
|||||||
#include "window-private.h"
|
#include "window-private.h"
|
||||||
#include "frame.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,
|
void meta_window_constrain (MetaWindow *window,
|
||||||
MetaMoveResizeFlags flags,
|
MetaMoveResizeFlags flags,
|
||||||
int resize_gravity,
|
int resize_gravity,
|
||||||
|
@ -65,13 +65,28 @@ typedef enum {
|
|||||||
|
|
||||||
#define NUMBER_OF_QUEUES 3
|
#define NUMBER_OF_QUEUES 3
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
_NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0,
|
_NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0,
|
||||||
_NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1,
|
_NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1,
|
||||||
_NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2,
|
_NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2,
|
||||||
} MetaBypassCompositorHintValue;
|
} 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
|
struct _MetaWindow
|
||||||
{
|
{
|
||||||
@ -456,6 +471,12 @@ struct _MetaWindowClass
|
|||||||
|
|
||||||
void (*manage) (MetaWindow *window);
|
void (*manage) (MetaWindow *window);
|
||||||
void (*unmanage) (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,
|
void (*get_default_skip_hints) (MetaWindow *window,
|
||||||
gboolean *skip_taskbar_out,
|
gboolean *skip_taskbar_out,
|
||||||
gboolean *skip_pager_out);
|
gboolean *skip_pager_out);
|
||||||
@ -732,4 +753,9 @@ void meta_window_update_monitor (MetaWindow *window);
|
|||||||
void meta_window_set_urgent (MetaWindow *window,
|
void meta_window_set_urgent (MetaWindow *window,
|
||||||
gboolean urgent);
|
gboolean urgent);
|
||||||
|
|
||||||
|
void meta_window_update_resize (MetaWindow *window,
|
||||||
|
gboolean snap,
|
||||||
|
int x, int y,
|
||||||
|
gboolean force);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -73,15 +73,12 @@
|
|||||||
static int destroying_windows_disallowed = 0;
|
static int destroying_windows_disallowed = 0;
|
||||||
|
|
||||||
|
|
||||||
static void update_net_frame_extents (MetaWindow *window);
|
|
||||||
static void invalidate_work_areas (MetaWindow *window);
|
static void invalidate_work_areas (MetaWindow *window);
|
||||||
static void set_wm_state (MetaWindow *window);
|
static void set_wm_state (MetaWindow *window);
|
||||||
static void set_net_wm_state (MetaWindow *window);
|
static void set_net_wm_state (MetaWindow *window);
|
||||||
static void meta_window_set_above (MetaWindow *window,
|
static void meta_window_set_above (MetaWindow *window,
|
||||||
gboolean new_value);
|
gboolean new_value);
|
||||||
|
|
||||||
static void send_configure_notify (MetaWindow *window);
|
|
||||||
|
|
||||||
static void meta_window_force_placement (MetaWindow *window);
|
static void meta_window_force_placement (MetaWindow *window);
|
||||||
|
|
||||||
static void meta_window_show (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)
|
if (window->maximized_horizontally || window->maximized_vertically)
|
||||||
unmaximize_window_before_freeing (window);
|
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_window_unqueue (window, META_QUEUE_CALC_SHOWING |
|
||||||
META_QUEUE_MOVE_RESIZE |
|
META_QUEUE_MOVE_RESIZE |
|
||||||
META_QUEUE_UPDATE_ICON);
|
META_QUEUE_UPDATE_ICON);
|
||||||
@ -1619,9 +1610,6 @@ meta_window_unmanage (MetaWindow *window,
|
|||||||
|
|
||||||
meta_window_destroy_sync_request_alarm (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
|
/* If an undecorated window is being withdrawn, that will change the
|
||||||
* stack as presented to the compositing manager, without actually
|
* stack as presented to the compositing manager, without actually
|
||||||
* changing the stacking order of X windows.
|
* changing the stacking order of X windows.
|
||||||
@ -1636,6 +1624,9 @@ meta_window_unmanage (MetaWindow *window,
|
|||||||
|
|
||||||
META_WINDOW_GET_CLASS (window)->unmanage (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_prefs_remove_listener (prefs_changed_callback, window);
|
||||||
meta_screen_queue_check_fullscreen (window->screen);
|
meta_screen_queue_check_fullscreen (window->screen);
|
||||||
|
|
||||||
@ -4034,90 +4025,6 @@ meta_window_destroy_sync_request_alarm (MetaWindow *window)
|
|||||||
#endif /* HAVE_XSYNC */
|
#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:
|
* meta_window_updates_are_frozen:
|
||||||
* @window: a #MetaWindow
|
* @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
|
* we don't decorate wayland clients), and the client has acknowledged
|
||||||
* the window size change.
|
* 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 frame_shape_changed = FALSE;
|
||||||
|
|
||||||
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 is_wayland_resize;
|
||||||
gboolean did_placement;
|
gboolean did_placement;
|
||||||
gboolean configure_frame_first;
|
|
||||||
/* used for the configure request, but may not be final
|
/* used for the configure request, but may not be final
|
||||||
* destination due to StaticGravity etc.
|
* destination due to StaticGravity etc.
|
||||||
*/
|
*/
|
||||||
int client_move_x;
|
|
||||||
int client_move_y;
|
|
||||||
MetaRectangle new_rect;
|
MetaRectangle new_rect;
|
||||||
MetaRectangle old_rect;
|
MetaRectangle old_rect;
|
||||||
|
MetaRectangle requested_rect;
|
||||||
|
MetaMoveResizeResultFlags result;
|
||||||
|
MetaFrameBorders borders;
|
||||||
|
|
||||||
g_return_if_fail (!window->override_redirect);
|
g_return_if_fail (!window->override_redirect);
|
||||||
|
|
||||||
@ -4356,13 +4254,14 @@ meta_window_move_resize_internal (MetaWindow *window,
|
|||||||
is_user_action ? " (user move/resize)" : "",
|
is_user_action ? " (user move/resize)" : "",
|
||||||
old_rect.x, old_rect.y, old_rect.width, old_rect.height);
|
old_rect.x, old_rect.y, old_rect.width, old_rect.height);
|
||||||
|
|
||||||
meta_frame_calc_borders (window->frame,
|
meta_frame_calc_borders (window->frame, &borders);
|
||||||
&borders);
|
|
||||||
|
|
||||||
new_rect.x = root_x_nw;
|
requested_rect.x = root_x_nw;
|
||||||
new_rect.y = root_y_nw;
|
requested_rect.y = root_y_nw;
|
||||||
new_rect.width = w;
|
requested_rect.width = w;
|
||||||
new_rect.height = h;
|
requested_rect.height = h;
|
||||||
|
|
||||||
|
new_rect = requested_rect;
|
||||||
|
|
||||||
/* If this is a resize only, the position should be ignored and
|
/* If this is a resize only, the position should be ignored and
|
||||||
* instead obtained by resizing the old rectangle according to the
|
* instead obtained by resizing the old rectangle according to the
|
||||||
@ -4409,363 +4308,21 @@ meta_window_move_resize_internal (MetaWindow *window,
|
|||||||
&new_rect);
|
&new_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
/* Do the protocol-specific move/resize logic */
|
||||||
{
|
META_WINDOW_GET_CLASS (window)->move_resize_internal (window, gravity, requested_rect, new_rect, flags, &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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
save_user_window_placement (window);
|
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);
|
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);
|
g_signal_emit (window, window_signals[SIZE_CHANGED], 0);
|
||||||
|
|
||||||
if (need_move_frame || need_resize_frame ||
|
if ((result & (META_MOVE_RESIZE_RESULT_MOVED | META_MOVE_RESIZE_RESULT_RESIZED)) != 0 ||
|
||||||
need_move_client || need_resize_client ||
|
|
||||||
did_placement || is_wayland_resize)
|
did_placement || is_wayland_resize)
|
||||||
{
|
{
|
||||||
int newx, newy;
|
int newx, newy;
|
||||||
@ -5751,35 +5308,6 @@ meta_window_get_net_wm_desktop (MetaWindow *window)
|
|||||||
return meta_workspace_index (window->workspace);
|
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
|
void
|
||||||
meta_window_set_current_workspace_hint (MetaWindow *window)
|
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:
|
* meta_window_get_icon_geometry:
|
||||||
* @window: a #MetaWindow
|
* @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
|
#ifdef HAVE_XSYNC
|
||||||
void
|
void
|
||||||
meta_window_update_sync_request_counter (MetaWindow *window,
|
meta_window_update_sync_request_counter (MetaWindow *window,
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "window-wayland.h"
|
#include "window-wayland.h"
|
||||||
|
|
||||||
#include "window-private.h"
|
#include "window-private.h"
|
||||||
|
#include "boxes-private.h"
|
||||||
#include "stack-tracker.h"
|
#include "stack-tracker.h"
|
||||||
#include "meta-wayland-surface.h"
|
#include "meta-wayland-surface.h"
|
||||||
|
|
||||||
@ -74,6 +75,95 @@ meta_window_wayland_unmanage (MetaWindow *window)
|
|||||||
meta_display_unregister_wayland_window (window->display, window);
|
meta_display_unregister_wayland_window (window->display, 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
|
static void
|
||||||
meta_window_wayland_init (MetaWindowWayland *window_wayland)
|
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->manage = meta_window_wayland_manage;
|
||||||
window_class->unmanage = meta_window_wayland_unmanage;
|
window_class->unmanage = meta_window_wayland_unmanage;
|
||||||
|
window_class->move_resize_internal = meta_window_wayland_move_resize_internal;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include <meta/prefs.h>
|
#include <meta/prefs.h>
|
||||||
#include <meta/meta-cursor-tracker.h>
|
#include <meta/meta-cursor-tracker.h>
|
||||||
|
|
||||||
|
#include "frame.h"
|
||||||
#include "window-private.h"
|
#include "window-private.h"
|
||||||
#include "window-props.h"
|
#include "window-props.h"
|
||||||
#include "xprops.h"
|
#include "xprops.h"
|
||||||
@ -158,6 +159,59 @@ update_sm_hints (MetaWindow *window)
|
|||||||
window->sm_client_id ? window->sm_client_id : "none");
|
window->sm_client_id ? window->sm_client_id : "none");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
meta_window_x11_manage (MetaWindow *window)
|
meta_window_x11_manage (MetaWindow *window)
|
||||||
{
|
{
|
||||||
@ -259,9 +313,418 @@ meta_window_x11_unmanage (MetaWindow *window)
|
|||||||
XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
|
XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
|
||||||
#endif
|
#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);
|
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
|
static void
|
||||||
meta_window_x11_get_default_skip_hints (MetaWindow *window,
|
meta_window_x11_get_default_skip_hints (MetaWindow *window,
|
||||||
gboolean *skip_taskbar_out,
|
gboolean *skip_taskbar_out,
|
||||||
@ -281,6 +744,7 @@ meta_window_x11_class_init (MetaWindowX11Class *klass)
|
|||||||
|
|
||||||
window_class->manage = meta_window_x11_manage;
|
window_class->manage = meta_window_x11_manage;
|
||||||
window_class->unmanage = meta_window_x11_unmanage;
|
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;
|
window_class->get_default_skip_hints = meta_window_x11_get_default_skip_hints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user