[mutter/wip/tiling-2: 2/4] Add "size states" which save window size information



commit 8e587e2e42a6ff2ab5f538baf4db75918d9647f9
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Tue Jun 30 22:36:23 2015 -0700

    Add "size states" which save window size information
    
    https://bugzilla.gnome.org/show_bug.cgi?id=751857

 src/core/window-private.h         |   23 +++-
 src/core/window.c                 |  269 ++++++++++++++++++++-----------------
 src/wayland/meta-window-wayland.c |    4 +-
 src/x11/session.c                 |    8 +-
 src/x11/window-x11.c              |    8 +-
 5 files changed, 174 insertions(+), 138 deletions(-)
---
diff --git a/src/core/window-private.h b/src/core/window-private.h
index d76aed8..7a2e5d8 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -88,6 +88,20 @@ typedef enum
   META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED = 1 << 2,
 } MetaMoveResizeResultFlags;
 
+/* This contains all the "state" needed for a certain size configuration.
+ * We have three of these size configurations: normal, tiled, and
+ * maximized. The idea here is that if the user tiles a normal window,
+ * then maximizes it, we should, upon unmaximizing and untiling the window,
+ * return to a normal state. We need a way of storing this information
+ * while maximized, so we use this structure. */
+struct _MetaWindowSizeState
+{
+  guint maximized_horizontally : 1;
+  guint maximized_vertically : 1;
+  MetaRectangle rect;
+};
+typedef struct _MetaWindowSizeState MetaWindowSizeState;
+
 struct _MetaWindow
 {
   GObject parent_instance;
@@ -393,9 +407,6 @@ struct _MetaWindow
   /* The current window geometry of the window. */
   MetaRectangle rect;
 
-  /* The geometry to restore when we unmaximize. */
-  MetaRectangle saved_rect;
-
   /* This is the geometry the window will have if no constraints have
    * applied. We use this whenever we are moving implicitly (for example,
    * if we move to avoid a panel, we can snap back to this position if
@@ -435,6 +446,12 @@ struct _MetaWindow
 
   /* Bypass compositor hints */
   guint bypass_compositor;
+
+  /* This is where we store data while in another state. The information
+   * above in MetaWindow is always the current state of the window. */
+  struct {
+    MetaWindowSizeState normal, maximized;
+  } size_states;
 };
 
 struct _MetaWindowClass
diff --git a/src/core/window.c b/src/core/window.c
index 0edf2ab..429b079 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -89,8 +89,6 @@ static void     meta_window_force_placement (MetaWindow     *window);
 static void     meta_window_show          (MetaWindow     *window);
 static void     meta_window_hide          (MetaWindow     *window);
 
-static void     meta_window_save_rect         (MetaWindow    *window);
-
 static void     ensure_mru_position_after (MetaWindow *window,
                                            MetaWindow *after_this_one);
 
@@ -872,7 +870,7 @@ _meta_window_shared_new (MetaDisplay         *display,
   meta_set_normal_hints (window, NULL);
 
   /* And this is our unmaximized size */
-  window->saved_rect = window->rect;
+  window->size_states.normal.rect = window->rect;
   window->unconstrained_rect = window->rect;
 
   window->depth = attrs->depth;
@@ -2606,23 +2604,23 @@ ensure_size_hints_satisfied (MetaRectangle    *rect,
     rect->height += ((minh - rect->height)/hinc + 1)*hinc;
 }
 
+static inline MetaWindowSizeState *
+get_current_size_state (MetaWindow *window)
+{
+  if (META_WINDOW_MAXIMIZED (window))
+    return &window->size_states.maximized;
+  else
+    return &window->size_states.normal;
+}
+
 static void
-meta_window_save_rect (MetaWindow *window)
+save_size_state (MetaWindow          *window,
+                 MetaWindowSizeState *size_state,
+                 MetaRectangle       *saved_rect)
 {
-  if (!(META_WINDOW_MAXIMIZED (window) || window->fullscreen))
-    {
-      /* save size/pos as appropriate args for move_resize */
-      if (!window->maximized_horizontally)
-        {
-          window->saved_rect.x      = window->rect.x;
-          window->saved_rect.width  = window->rect.width;
-        }
-      if (!window->maximized_vertically)
-        {
-          window->saved_rect.y      = window->rect.y;
-          window->saved_rect.height = window->rect.height;
-        }
-    }
+  size_state->rect = *saved_rect;
+  size_state->maximized_horizontally = window->maximized_horizontally;
+  size_state->maximized_vertically = window->maximized_vertically;
 }
 
 void
@@ -2643,10 +2641,11 @@ meta_window_maximize_internal (MetaWindow        *window,
                 maximize_horizontally ? " horizontally" :
                   maximize_vertically ? " vertically" : "BUGGGGG");
 
-  if (saved_rect != NULL)
-    window->saved_rect = *saved_rect;
-  else
-    meta_window_save_rect (window);
+  if (!saved_rect)
+    saved_rect = &window->rect;
+
+  MetaWindowSizeState *size_state = get_current_size_state (window);
+  save_size_state (window, size_state, saved_rect);
 
   window->maximized_horizontally =
     window->maximized_horizontally || maximize_horizontally;
@@ -2924,7 +2923,7 @@ unmaximize_window_before_freeing (MetaWindow        *window)
 
   if (window->withdrawn)                /* See bug #137185 */
     {
-      window->rect = window->saved_rect;
+      window->rect = window->size_states.normal.rect;
       set_net_wm_state (window);
     }
   else if (window->screen->closing)     /* See bug #358042 */
@@ -2937,19 +2936,83 @@ unmaximize_window_before_freeing (MetaWindow        *window)
        * before closing it. */
       meta_window_move_resize_frame (window,
                                      FALSE,
-                                     window->saved_rect.x,
-                                     window->saved_rect.y,
-                                     window->saved_rect.width,
-                                     window->saved_rect.height);
+                                     window->size_states.normal.rect.x,
+                                     window->size_states.normal.rect.y,
+                                     window->size_states.normal.rect.width,
+                                     window->size_states.normal.rect.height);
     }
 }
 
+static void
+meta_window_unmaximize_internal (MetaWindow          *window,
+                                 MetaWindowSizeState *size_state)
+{
+  MetaRectangle old_frame_rect, old_buffer_rect, target_rect;
+
+  g_return_if_fail (!window->override_redirect);
+
+  meta_window_get_frame_rect (window, &old_frame_rect);
+  meta_window_get_buffer_rect (window, &old_buffer_rect);
+
+  window->maximized_horizontally = size_state->maximized_horizontally;
+  window->maximized_vertically = size_state->maximized_vertically;
+
+  /* recalc_features() will eventually clear the cached frame
+   * extents, but we need the correct frame extents in the code below,
+   * so invalidate the old frame extents manually up front.
+   */
+  meta_window_frame_size_changed (window);
+
+  target_rect = size_state->rect;
+
+  /* Window's size hints may have changed while maximized, making
+   * saved_rect invalid.  #329152
+   */
+  meta_window_frame_rect_to_client_rect (window, &target_rect, &target_rect);
+  ensure_size_hints_satisfied (&target_rect, &window->size_hints);
+  meta_window_client_rect_to_frame_rect (window, &target_rect, &target_rect);
+
+  meta_window_move_resize_internal (window,
+                                    (META_MOVE_RESIZE_MOVE_ACTION |
+                                     META_MOVE_RESIZE_RESIZE_ACTION |
+                                     META_MOVE_RESIZE_STATE_CHANGED |
+                                     META_MOVE_RESIZE_DONT_SYNC_COMPOSITOR),
+                                    NorthWestGravity,
+                                    target_rect);
+
+  meta_compositor_size_change_window (window->display->compositor, window,
+                                      META_SIZE_CHANGE_UNMAXIMIZE,
+                                      &old_frame_rect, &old_buffer_rect);
+
+  /* When we unmaximize, if we're doing a mouse move also we could
+   * get the window suddenly jumping to the upper left corner of
+   * the workspace, since that's where it was when the grab op
+   * started.  So we need to update the grab state. We have to do
+   * it after the actual operation, as the window may have been moved
+   * by constraints.
+   */
+  if (meta_grab_op_is_moving (window->display->grab_op) &&
+      window->display->grab_window == window)
+    {
+      window->display->grab_anchor_window_pos = window->unconstrained_rect;
+    }
+
+  meta_window_recalc_features (window);
+  set_net_wm_state (window);
+  if (!window->monitor->in_fullscreen)
+    meta_screen_queue_check_fullscreen (window->screen);
+
+  g_object_freeze_notify (G_OBJECT (window));
+  g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_HORIZONTALLY]);
+  g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_VERTICALLY]);
+  g_object_thaw_notify (G_OBJECT (window));
+}
+
 void
 meta_window_unmaximize (MetaWindow        *window,
                         MetaMaximizeFlags  directions)
 {
   gboolean unmaximize_horizontally, unmaximize_vertically;
-  MetaRectangle new_rect;
 
   g_return_if_fail (!window->override_redirect);
 
@@ -2958,45 +3021,46 @@ meta_window_unmaximize (MetaWindow        *window,
   unmaximize_vertically   = directions & META_MAXIMIZE_VERTICAL;
   g_assert (unmaximize_horizontally || unmaximize_vertically);
 
-  /* Only do something if the window isn't already maximized in the
-   * given direction(s).
-   */
-  if ((unmaximize_horizontally && window->maximized_horizontally) ||
-      (unmaximize_vertically   && window->maximized_vertically))
+  MetaWindowSizeState *size_state;
+  size_state = &window->size_states.normal;
+
+  /* Special-case unmaximizing both directions to restoring the
+   * last state. This makes the unmaximize buttons go back to the
+   * tiled state... */
+  if (META_WINDOW_MAXIMIZED (window) && directions == META_MAXIMIZE_BOTH)
     {
+      meta_window_unmaximize_internal (window, size_state);
+    }
+  else if ((unmaximize_horizontally && window->maximized_horizontally) ||
+           (unmaximize_vertically   && window->maximized_vertically))
+    {
+      MetaWindowSizeState new_size_state;
       MetaRectangle *desired_rect;
       MetaRectangle target_rect;
       MetaRectangle work_area;
-      MetaRectangle old_frame_rect, old_buffer_rect;
 
       meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
-      meta_window_get_frame_rect (window, &old_frame_rect);
-      meta_window_get_buffer_rect (window, &old_buffer_rect);
-
-      meta_topic (META_DEBUG_WINDOW_OPS,
-                  "Unmaximizing %s%s\n",
-                  window->desc,
-                  unmaximize_horizontally && unmaximize_vertically ? "" :
-                    unmaximize_horizontally ? " horizontally" :
-                      unmaximize_vertically ? " vertically" : "BUGGGGG");
-
-      window->maximized_horizontally =
-        window->maximized_horizontally && !unmaximize_horizontally;
-      window->maximized_vertically =
-        window->maximized_vertically   && !unmaximize_vertically;
-
-      /* recalc_features() will eventually clear the cached frame
-       * extents, but we need the correct frame extents in the code below,
-       * so invalidate the old frame extents manually up front.
-       */
-      meta_window_frame_size_changed (window);
 
-      desired_rect = &window->saved_rect;
+      new_size_state.maximized_horizontally = window->maximized_horizontally && !unmaximize_horizontally;
+      new_size_state.maximized_vertically = window->maximized_vertically && !unmaximize_vertically;
 
       /* Unmaximize to the saved_rect position in the direction(s)
        * being unmaximized.
        */
-      target_rect = old_frame_rect;
+      target_rect = window->rect;
+
+      desired_rect = &size_state->rect;
+
+      if (unmaximize_horizontally)
+        {
+          target_rect.x     = desired_rect->x;
+          target_rect.width = desired_rect->width;
+        }
+      if (unmaximize_vertically)
+        {
+          target_rect.y      = desired_rect->y;
+          target_rect.height = desired_rect->height;
+        }
 
       /* Avoid unmaximizing to "almost maximized" size when the previous size
        * is greater then 80% of the work area use MAX_UNMAXIMIZED_WINDOW_AREA of the work area as upper limit
@@ -3008,71 +3072,21 @@ meta_window_unmaximize (MetaWindow        *window,
           if (desired_rect->width > desired_rect->height)
             {
               float aspect = (float)desired_rect->height / (float)desired_rect->width;
-              desired_rect->width = MAX (work_area.width * sqrt (MAX_UNMAXIMIZED_WINDOW_AREA), 
window->size_hints.min_width);
-              desired_rect->height = MAX (desired_rect->width * aspect, window->size_hints.min_height);
+              target_rect.width = MAX (work_area.width * sqrt (MAX_UNMAXIMIZED_WINDOW_AREA), 
window->size_hints.min_width);
+              target_rect.height = MAX (desired_rect->width * aspect, window->size_hints.min_height);
             }
           else
             {
               float aspect = (float)desired_rect->width / (float)desired_rect->height;
-              desired_rect->height = MAX (work_area.height * sqrt (MAX_UNMAXIMIZED_WINDOW_AREA), 
window->size_hints.min_height);
-              desired_rect->width = MAX (desired_rect->height * aspect, window->size_hints.min_width);
+              target_rect.height = MAX (work_area.height * sqrt (MAX_UNMAXIMIZED_WINDOW_AREA), 
window->size_hints.min_height);
+              target_rect.width = MAX (desired_rect->height * aspect, window->size_hints.min_width);
             }
         }
 
-      if (unmaximize_horizontally)
-        {
-          target_rect.x     = desired_rect->x;
-          target_rect.width = desired_rect->width;
-        }
-      if (unmaximize_vertically)
-        {
-          target_rect.y      = desired_rect->y;
-          target_rect.height = desired_rect->height;
-        }
+      new_size_state.rect = target_rect;
 
-      /* Window's size hints may have changed while maximized, making
-       * saved_rect invalid.  #329152
-       */
-      meta_window_frame_rect_to_client_rect (window, &target_rect, &target_rect);
-      ensure_size_hints_satisfied (&target_rect, &window->size_hints);
-      meta_window_client_rect_to_frame_rect (window, &target_rect, &target_rect);
-
-      meta_window_move_resize_internal (window,
-                                        (META_MOVE_RESIZE_MOVE_ACTION |
-                                         META_MOVE_RESIZE_RESIZE_ACTION |
-                                         META_MOVE_RESIZE_STATE_CHANGED |
-                                         META_MOVE_RESIZE_DONT_SYNC_COMPOSITOR),
-                                        NorthWestGravity,
-                                        target_rect);
-
-      meta_window_get_frame_rect (window, &new_rect);
-      meta_compositor_size_change_window (window->display->compositor, window,
-                                          META_SIZE_CHANGE_UNMAXIMIZE,
-                                          &old_frame_rect, &old_buffer_rect);
-
-      /* When we unmaximize, if we're doing a mouse move also we could
-       * get the window suddenly jumping to the upper left corner of
-       * the workspace, since that's where it was when the grab op
-       * started.  So we need to update the grab state. We have to do
-       * it after the actual operation, as the window may have been moved
-       * by constraints.
-       */
-      if (meta_grab_op_is_moving (window->display->grab_op) &&
-          window->display->grab_window == window)
-        {
-          window->display->grab_anchor_window_pos = window->unconstrained_rect;
-        }
-
-      meta_window_recalc_features (window);
-      set_net_wm_state (window);
-      if (!window->monitor->in_fullscreen)
-        meta_screen_queue_check_fullscreen (window->screen);
+      meta_window_unmaximize_internal (window, &new_size_state);
     }
-
-  g_object_freeze_notify (G_OBJECT (window));
-  g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_HORIZONTALLY]);
-  g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_VERTICALLY]);
-  g_object_thaw_notify (G_OBJECT (window));
 }
 
 void
@@ -3126,7 +3140,8 @@ meta_window_make_fullscreen_internal (MetaWindow  *window)
           meta_window_unshade (window, timestamp);
         }
 
-      meta_window_save_rect (window);
+      MetaWindowSizeState *size_state = get_current_size_state (window);
+      save_size_state (window, size_state, &window->rect);
 
       window->fullscreen = TRUE;
 
@@ -3186,7 +3201,9 @@ meta_window_unmake_fullscreen (MetaWindow  *window)
                   "Unfullscreening %s\n", window->desc);
 
       window->fullscreen = FALSE;
-      target_rect = window->saved_rect;
+
+      MetaWindowSizeState *size_state = get_current_size_state (window);
+      target_rect = size_state->rect;
 
       meta_window_frame_size_changed (window);
       meta_window_get_frame_rect (window, &old_frame_rect);
@@ -3736,8 +3753,8 @@ meta_window_move_between_rects (MetaWindow  *window,
 
   window->unconstrained_rect.x = new_area->x + rel_x * scale_x;
   window->unconstrained_rect.y = new_area->y + rel_y * scale_y;
-  window->saved_rect.x = window->unconstrained_rect.x;
-  window->saved_rect.y = window->unconstrained_rect.y;
+  window->size_states.normal.rect.x = window->unconstrained_rect.x;
+  window->size_states.normal.rect.y = window->unconstrained_rect.y;
 
   meta_window_move_resize_now (window);
 }
@@ -5532,7 +5549,7 @@ update_move (MetaWindow  *window,
         ((double)(x - display->grab_initial_window_pos.x)) /
         ((double)display->grab_initial_window_pos.width);
 
-      display->grab_initial_window_pos.x = x - window->saved_rect.width * prop;
+      display->grab_initial_window_pos.x = x - window->size_states.normal.rect.width * prop;
 
       /* If we started dragging the window from above the top of the window,
        * pretend like we started dragging from the middle of the titlebar
@@ -5544,10 +5561,10 @@ update_move (MetaWindow  *window,
           display->grab_anchor_root_y = display->grab_initial_window_pos.y + titlebar_rect.height / 2;
         }
 
-      window->saved_rect.x = display->grab_initial_window_pos.x;
-      window->saved_rect.y = display->grab_initial_window_pos.y;
+      window->size_states.normal.rect.x = display->grab_initial_window_pos.x;
+      window->size_states.normal.rect.y = display->grab_initial_window_pos.y;
 
-      meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
+      meta_window_unmaximize_internal (window, &window->size_states.normal);
       return;
     }
 
@@ -5577,17 +5594,17 @@ update_move (MetaWindow  *window,
                */
               if (wmonitor->number != monitor)
                 {
-                  window->saved_rect.x = work_area.x;
-                  window->saved_rect.y = work_area.y;
+                  window->size_states.normal.rect.x = work_area.x;
+                  window->size_states.normal.rect.y = work_area.y;
 
                   if (window->frame)
                     {
-                      window->saved_rect.x += window->frame->child_x;
-                      window->saved_rect.y += window->frame->child_y;
+                      window->size_states.normal.rect.x += window->frame->child_x;
+                      window->size_states.normal.rect.y += window->frame->child_y;
                     }
 
-                  window->unconstrained_rect.x = window->saved_rect.x;
-                  window->unconstrained_rect.y = window->saved_rect.y;
+                  window->unconstrained_rect.x = window->size_states.normal.rect.x;
+                  window->unconstrained_rect.y = window->size_states.normal.rect.y;
 
                   meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
 
diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c
index f38e4b9..e103b50 100644
--- a/src/wayland/meta-window-wayland.c
+++ b/src/wayland/meta-window-wayland.c
@@ -363,7 +363,9 @@ meta_window_wayland_main_monitor_changed (MetaWindow *window,
   /* Window size. */
   scale_rect_size (&window->rect, scale_factor);
   scale_rect_size (&window->unconstrained_rect, scale_factor);
-  scale_rect_size (&window->saved_rect, scale_factor);
+  scale_rect_size (&window->size_states.normal.rect, scale_factor);
+  scale_rect_size (&window->size_states.tiled.rect, scale_factor);
+  scale_rect_size (&window->size_states.maximized.rect, scale_factor);
 
   /* Window geometry offset (XXX: Need a better place, see
    * meta_window_wayland_move_resize). */
diff --git a/src/x11/session.c b/src/x11/session.c
index 13cf764..f4e80b2 100644
--- a/src/x11/session.c
+++ b/src/x11/session.c
@@ -965,10 +965,10 @@ save_state (void)
             {
               fprintf (outfile,
                        "    <maximized saved_x=\"%d\" saved_y=\"%d\" saved_width=\"%d\" 
saved_height=\"%d\"/>\n",
-                       window->saved_rect.x,
-                       window->saved_rect.y,
-                       window->saved_rect.width,
-                       window->saved_rect.height);
+                       window->size_states.normal.rect.x,
+                       window->size_states.normal.rect.y,
+                       window->size_states.normal.rect.width,
+                       window->size_states.normal.rect.height);
             }
 
           /* Gravity */
diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
index 3d47f0d..1bdb5d5 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -413,10 +413,10 @@ meta_window_apply_session_info (MetaWindow *window,
                           info->saved_rect.height,
                           window->desc);
 
-              window->saved_rect.x = info->saved_rect.x;
-              window->saved_rect.y = info->saved_rect.y;
-              window->saved_rect.width = info->saved_rect.width;
-              window->saved_rect.height = info->saved_rect.height;
+              window->size_states.normal.rect.x = info->saved_rect.x;
+              window->size_states.normal.rect.y = info->saved_rect.y;
+              window->size_states.normal.rect.width = info->saved_rect.width;
+              window->size_states.normal.rect.height = info->saved_rect.height;
             }
        }
     }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]