[mutter/wayland] window: Move move_resize_internal logic to protocol-specific directories



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]