[mutter/wip/gbsneto/edge-constraints: 66/75] window: Tile and resize considering the tile match



commit bc583b663f1e4ae343557b2ebb384f3b168da4bc
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sun Jun 11 22:13:03 2017 -0300

    window: Tile and resize considering the tile match
    
    After the introduction of the possibility to resize tiled windows,
    it is a sensible decision to make windows aware of their tiling
    match. A tiling match is another window that is tiled in such a
    way that is the complement of the current window.
    
    The newly introduced behavior attepts to make tiling as smooth as
    possible, with the following rules:
    
     * Windows now compute their tile match when tiling and, if there's
       a match, they automatically complement the sibling's width.
     * Resizing a window with a sibling automatically resizes the sibling
       too to be the complement of the window's width.
     * It is not possible to resize below windows' minimum widths.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=645153

 src/core/stack.c          |    6 ++-
 src/core/window-private.h |    4 +-
 src/core/window.c         |  111 +++++++++++++++++++++++++++++++++++++--------
 3 files changed, 99 insertions(+), 22 deletions(-)
---
diff --git a/src/core/stack.c b/src/core/stack.c
index 5895b89..01fdc4b 100644
--- a/src/core/stack.c
+++ b/src/core/stack.c
@@ -267,7 +267,11 @@ meta_stack_update_window_tile_matches (MetaStack     *stack,
   tmp = windows;
   while (tmp)
     {
-      meta_window_compute_tile_match ((MetaWindow *) tmp->data);
+      MetaWindow *window = tmp->data;
+
+      window->tile_match = meta_window_compute_tile_match (window,
+                                                           window->tile_mode,
+                                                           window->monitor->number);
       tmp = tmp->next;
     }
 
diff --git a/src/core/window-private.h b/src/core/window-private.h
index aa68ebe..c96ddc9 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -709,7 +709,9 @@ void meta_window_on_all_workspaces_changed (MetaWindow *window);
 gboolean meta_window_should_attach_to_parent (MetaWindow *window);
 gboolean meta_window_can_tile_side_by_side   (MetaWindow *window);
 
-void meta_window_compute_tile_match (MetaWindow *window);
+MetaWindow* meta_window_compute_tile_match (MetaWindow   *window,
+                                            MetaTileMode  current_mode,
+                                            gint          target_monitor);
 
 gboolean meta_window_updates_are_frozen (MetaWindow *window);
 
diff --git a/src/core/window.c b/src/core/window.c
index 4321ef0..99fb45e 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -2903,8 +2903,14 @@ meta_window_calculate_area_for_tile_mode (MetaWindow    *window,
                                           MetaRectangle *rect)
 {
   MetaRectangle monitor_area;
+  MetaWindow *tile_match;
   gboolean was_tiled;
 
+  /* When tiling a window, the new matching tile window is not yet synchronized,
+   * so we must do that now manually. It is not necessary to recompute all windows'
+   * tile matches, just the current one */
+  tile_match = meta_window_compute_tile_match (window, mode, monitor_number);
+
   meta_window_get_work_area_for_monitor (window, monitor_number, &monitor_area);
 
   rect->x = monitor_area.x;
@@ -2913,17 +2919,24 @@ meta_window_calculate_area_for_tile_mode (MetaWindow    *window,
 
   was_tiled = previous_mode == META_TILE_LEFT || previous_mode == META_TILE_RIGHT;
 
-  if (mode == META_TILE_MAXIMIZED)
-    /* When maximized, cover the entire width */
-    rect->width = monitor_area.width;
-  else if (mode == previous_mode)
-    /* When retrieving the size of the current tile mode, just use the current size */
-    rect->width = window->rect.width;
-  else if (was_tiled && (mode == META_TILE_LEFT || mode == META_TILE_RIGHT))
-    rect->width = monitor_area.width - window->rect.width;
+  if (tile_match)
+    {
+      rect->width = monitor_area.width - tile_match->rect.width;
+    }
   else
-    /* Assume half of the work area of the current monitor */
-    rect->width = monitor_area.width / 2;
+    {
+      if (mode == META_TILE_MAXIMIZED)
+        /* When maximized, cover the entire width */
+        rect->width = monitor_area.width;
+      else if (mode == previous_mode)
+        /* When retrieving the size of the current tile mode, just use the current size */
+        rect->width = window->rect.width;
+      else if (was_tiled && (mode == META_TILE_LEFT || mode == META_TILE_RIGHT))
+        rect->width = monitor_area.width - window->rect.width;
+      else
+        /* Assume half of the work area of the current monitor */
+        rect->width = monitor_area.width / 2;
+    }
 
   /* Update the horizontal position */
   if (mode == META_TILE_RIGHT)
@@ -2973,6 +2986,8 @@ meta_window_tile (MetaWindow   *window,
                                             monitor_number,
                                             &new_rect);
 
+  window->tile_match = meta_window_compute_tile_match (window, mode, monitor_number);
+
   /* Track the previous mode */
   window->previous_tile_mode = window->tile_mode;
   window->tile_mode = mode;
@@ -5944,6 +5959,56 @@ update_resize_timeout (gpointer data)
   return FALSE;
 }
 
+static inline gint
+opposite_gravity (guint gravity)
+{
+  return StaticGravity - gravity;
+}
+
+static void
+resize_tile_match (MetaWindow *window,
+                   int         gravity,
+                   int        *out_new_w)
+{
+  MetaRectangle work_area;
+  MetaWindow *tile_match;
+  int new_w;
+
+  if (!META_WINDOW_TILED_SIDE_BY_SIDE (window) || !window->tile_match)
+    return;
+
+  new_w = *out_new_w;
+  tile_match = window->tile_match;
+
+  /* Make sure the resize does not break minimum sizes */
+  new_w = MAX (new_w, window->size_hints.min_width);
+
+  meta_window_get_work_area_for_monitor (window, window->tile_monitor_number, &work_area);
+
+  if (tile_match)
+    {
+      guint tile_width;
+
+      /* If there's a tile match window, we have to make sure we're not resizing
+       * the tile match below its min width */
+      if (work_area.width - new_w < tile_match->size_hints.min_width)
+        new_w = work_area.width - tile_match->size_hints.min_width;
+
+      tile_width = work_area.width - new_w;
+
+      /* The tile match window's new width is stored in tile_rect.width directly */
+      meta_window_resize_frame_with_gravity (window->tile_match,
+                                             TRUE,
+                                             tile_width,
+                                             work_area.height,
+                                             opposite_gravity (gravity));
+    }
+
+  /* We can potentially change the new width, so make sure update_resize() always
+   * has the most recent value */
+  *out_new_w = new_w;
+}
+
 static void
 update_resize (MetaWindow *window,
                gboolean    snap,
@@ -6069,6 +6134,10 @@ update_resize (MetaWindow *window,
                                           snap,
                                           FALSE);
 
+  /* If the window has a tile match, we have to respect the match's minimum
+   * width. */
+  resize_tile_match (window, gravity, &new_w);
+
   meta_window_resize_frame_with_gravity (window, TRUE, new_w, new_h, gravity);
 
   /* Store the latest resize time, if we actually resized. */
@@ -7479,8 +7548,10 @@ meta_window_get_tile_match (MetaWindow *window)
   return window->tile_match;
 }
 
-void
-meta_window_compute_tile_match (MetaWindow *window)
+MetaWindow *
+meta_window_compute_tile_match (MetaWindow   *window,
+                                MetaTileMode  current_mode,
+                                gint          target_monitor)
 {
   MetaWindow *match;
   MetaStack *stack;
@@ -7489,14 +7560,14 @@ meta_window_compute_tile_match (MetaWindow *window)
   window->tile_match = NULL;
 
   if (window->shaded || window->minimized)
-    return;
+    return NULL;
 
-  if (META_WINDOW_TILED_LEFT (window))
+  if (current_mode == META_TILE_LEFT)
     match_tile_mode = META_TILE_RIGHT;
-  else if (META_WINDOW_TILED_RIGHT (window))
+  else if (current_mode == META_TILE_RIGHT)
     match_tile_mode = META_TILE_LEFT;
   else
-    return;
+    return NULL;
 
   stack = window->screen->stack;
 
@@ -7507,7 +7578,7 @@ meta_window_compute_tile_match (MetaWindow *window)
       if (!match->shaded &&
           !match->minimized &&
           match->tile_mode == match_tile_mode &&
-          match->monitor == window->monitor &&
+          match->monitor->number == target_monitor &&
           meta_window_get_workspace (match) == meta_window_get_workspace (window))
         break;
     }
@@ -7547,11 +7618,11 @@ meta_window_compute_tile_match (MetaWindow *window)
 
           if (meta_rectangle_overlap (&above_rect, &bottommost_rect) &&
               meta_rectangle_overlap (&above_rect, &topmost_rect))
-            return;
+            return NULL;
         }
-
-      window->tile_match = match;
     }
+
+  return match;
 }
 
 void


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