[mutter/wip/gbsneto/tiling-improvements: 5/9] window: Tile and resize considering the tile match



commit c6c3c373688fd0dd70289811192d3aee2ffe6e8d
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.
    
    !!!WARNING!!! This is work-in-progress, and is flawed. There's one
    big issue with this patch, that I'm yet to fix:
    
    Windows tiled in a complementary way in different workspaces,
    if moved to the same workspace, are considered matches and enters in
    an inconsistent state. Steps to reproduce:
    
      - Open window A and B. Move B to another workspace.
      - Tile A right, and B left. Resize them.
      - Move B to A's workspace.
      - Resize them again
    
    https://bugzilla.gnome.org/show_bug.cgi?id=645153

 src/core/window.c |   84 +++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 69 insertions(+), 15 deletions(-)
---
diff --git a/src/core/window.c b/src/core/window.c
index 99ad4db..59fe3e1 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -2893,9 +2893,16 @@ static void
 meta_window_update_tile_state_internal (MetaWindow *window)
 {
   MetaRectangle monitor_area;
+  MetaWindow *tile_match_window;
   gboolean was_tiled;
   gint borders_width = 0;
 
+  /* 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_window = meta_window_compute_tile_match (window, FALSE);
+  window->tile_match = tile_match_window;
+
   meta_window_get_work_area_current_monitor (window, &monitor_area);
 
   /* window->tile_rect must consider the visible borders */
@@ -2915,14 +2922,21 @@ meta_window_update_tile_state_internal (MetaWindow *window)
   was_tiled = window->previous_tile_mode == META_TILE_LEFT ||
               window->previous_tile_mode == META_TILE_RIGHT;
 
-  if (window->tile_mode == META_TILE_MAXIMIZED)
-    /* When maximized, cover the entire width*/
-    window->tile_rect.width = monitor_area.width;
-  else if (was_tiled && META_WINDOW_TILED_SIDE_BY_SIDE (window))
-    window->tile_rect.width = monitor_area.width - window->tile_rect.width;
+  if (tile_match_window)
+    {
+      window->tile_rect.width = monitor_area.width - tile_match_window->tile_rect.width - borders_width;
+    }
   else
-    /* Assume half of the work area of the current monitor */
-    window->tile_rect.width = monitor_area.width / 2 + borders_width;
+    {
+      if (window->tile_mode == META_TILE_MAXIMIZED)
+        /* When maximized, cover the entire width*/
+        window->tile_rect.width = monitor_area.width;
+      else if (was_tiled && META_WINDOW_TILED_SIDE_BY_SIDE (window))
+        window->tile_rect.width = monitor_area.width - window->tile_rect.width;
+      else
+        /* Assume half of the work area of the current monitor */
+        window->tile_rect.width = monitor_area.width / 2 + borders_width;
+    }
 
   /* Update the horizontal position */
   if (window->tile_mode == META_TILE_RIGHT)
@@ -5889,21 +5903,39 @@ update_resize_timeout (gpointer data)
 }
 
 static void
-update_tile_rect (MetaWindow *window,
-                  int        *out_new_w)
+update_tile_rects (MetaWindow *window,
+                   int        *out_new_w)
 {
+  MetaRectangle work_area;
+  MetaWindow *tile_match;
   int new_w;
 
   if (!META_WINDOW_TILED_SIDE_BY_SIDE (window))
     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)
+    {
+      /* 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_match->tile_rect.width = work_area.width - new_w;
+    }
+
   if (META_WINDOW_TILED_LEFT_RESIZING (window))
     {
+      if (tile_match)
+        tile_match->tile_rect.x += new_w - window->tile_rect.width;
+
       window->tile_rect.width = new_w;
     }
   else if (META_WINDOW_TILED_RIGHT_RESIZING (window))
@@ -5917,6 +5949,12 @@ update_tile_rect (MetaWindow *window,
   *out_new_w = new_w;
 }
 
+static gint
+opposite_gravity (guint gravity)
+{
+  return StaticGravity - gravity;
+}
+
 static void
 update_resize (MetaWindow *window,
                gboolean    snap,
@@ -6042,9 +6080,19 @@ update_resize (MetaWindow *window,
                                           snap,
                                           FALSE);
 
-  update_tile_rect (window, &new_w);
+  update_tile_rects (window, &new_w);
   meta_window_resize_frame_with_gravity (window, TRUE, new_w, new_h, gravity);
 
+  if (window->tile_match)
+    {
+      /* The tile match window's new width is stored in tile_rect.width directly */
+      meta_window_resize_frame_with_gravity (window->tile_match,
+                                             TRUE,
+                                             window->tile_match->tile_rect.width,
+                                             window->tile_match->tile_rect.height,
+                                             opposite_gravity (gravity));
+    }
+
   /* Store the latest resize time, if we actually resized. */
   if (window->rect.width != old.width || window->rect.height != old.height)
     g_get_current_time (&window->display->grab_last_moveresize_time);
@@ -6356,16 +6404,18 @@ meta_window_get_current_tile_area (MetaWindow    *window,
 {
   MetaRectangle monitor_area;
   MetaTileMode tile_mode;
+  MetaWindow *tile_match_window;
+  gboolean preview;
   gint borders_height = 0;
   gint borders_width = 0;
 
   g_return_if_fail (window->tile_mode != META_TILE_NONE || window->preview_tile_mode != META_TILE_NONE);
 
+  preview = window->preview_tile_mode != META_TILE_NONE;
+
   /* If we are previewing, don't change the actual tile mode */
-  if (window->preview_tile_mode != META_TILE_NONE)
-    tile_mode = window->preview_tile_mode;
-  else
-    tile_mode = window->tile_mode;
+  tile_mode = preview ? window->preview_tile_mode : window->tile_mode;
+  tile_match_window = meta_window_compute_tile_match (window, preview);
 
   meta_window_get_work_area_current_monitor (window, &monitor_area);
 
@@ -6387,7 +6437,11 @@ meta_window_get_current_tile_area (MetaWindow    *window,
   tile_area->y = monitor_area.y;
   tile_area->height = monitor_area.height + borders_height;
 
-  if (tile_mode == META_TILE_MAXIMIZED)
+  if (tile_match_window)
+    {
+      window->tile_rect.width = monitor_area.width - tile_match_window->tile_rect.width - borders_width;
+    }
+  else if (tile_mode == META_TILE_MAXIMIZED)
     {
       /* When maximized, cover the entire width*/
       tile_area->width = monitor_area.width;


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