[mutter/wip/gbsneto/tiling-improvements: 12/17] window: Allow tiled windows be resized



commit ed4586f8f86b4e864af73c3c5a25d864fc5c1950
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sun Jun 11 14:58:21 2017 -0300

    window: Allow tiled windows be resized
    
    The current code forbids resizing tiled windows, and enforces that
    side-by-side tiled windows cover half of the current screen's width.
    
    This patch removes this restriction, and adds code to track the
    tiled window size isolated from the actual window size, using the
    following heuristics:
    
     * If the window was not tiled, cover 1/2 of the screen.
     * If the window was tiled, use the complement of the current width
       to cover the "hole" in the screen.
     * When resizing a tiled window to the oposite border, maximize the
       window.
    
    Windows with client-side decoration does not follow this behavior
    for the moment, and patches for GTK+ shall be crafted to fix this
    in the client side.
    
    To make the current code work with the tile constraint, the constraint
    had to ignore the width and x positions of the window, because now
    these axis are not constrained.
    
    Long term, the best way to handle it is using constrained edges rather
    than tile modes themselves. Constrained edges are more generic and
    are better suited to the future quarter tiling. With constrained edges,
    we can isolate the tiling logic from the CSD implementations.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=645153

 src/core/constraints.c    |   14 +++-
 src/core/keybindings.c    |   32 +++++++--
 src/core/screen.c         |   13 +++-
 src/core/window-private.h |   24 ++++++-
 src/core/window.c         |  172 +++++++++++++++++++++++++++++++++------------
 src/ui/frames.c           |    7 ++-
 6 files changed, 200 insertions(+), 62 deletions(-)
---
diff --git a/src/core/constraints.c b/src/core/constraints.c
index 14044a9..160ddbb 100644
--- a/src/core/constraints.c
+++ b/src/core/constraints.c
@@ -943,7 +943,11 @@ constrain_maximization (MetaWindow         *window,
   /* Calculate target_size = maximized size of (window + frame) */
   if (META_WINDOW_TILED_MAXIMIZED (window))
     {
-      meta_window_get_current_tile_area (window, &target_size);
+      meta_window_get_tile_area_for_mode (window,
+                                          META_TILE_MAXIMIZED,
+                                          window->tile_mode,
+                                          window->monitor->number,
+                                          &target_size);
     }
   else if (META_WINDOW_MAXIMIZED (window))
     {
@@ -1030,7 +1034,11 @@ constrain_tiling (MetaWindow         *window,
   /* Calculate target_size - as the tile previews need this as well, we
    * use an external function for the actual calculation
    */
-  meta_window_get_current_tile_area (window, &target_size);
+  meta_window_get_tile_area_for_mode (window,
+                                      window->tile_mode,
+                                      window->tile_mode,
+                                      window->monitor->number,
+                                      &target_size);
 
   /* Check min size constraints; max size constraints are ignored as for
    * maximized windows.
@@ -1051,8 +1059,6 @@ constrain_tiling (MetaWindow         *window,
     return constraint_already_satisfied;
 
   /*** Enforce constraint ***/
-  info->current.x      = target_size.x;
-  info->current.width  = target_size.width;
   info->current.y      = target_size.y;
   info->current.height = target_size.height;
 
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index f2aafdd..2fa2131 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -2029,12 +2029,15 @@ process_mouse_move_resize_grab (MetaDisplay     *display,
 
   if (event->keyval == CLUTTER_KEY_Escape)
     {
+      MetaTileMode mode;
+
+      mode = display->grab_tile_mode;
+
       /* Hide the tiling preview if necessary */
-      if (window->tile_mode != META_TILE_NONE)
+      if (window->preview_tile_mode != META_TILE_NONE)
         meta_screen_hide_tile_preview (screen);
 
       /* Restore the original tile mode */
-      window->tile_mode = display->grab_tile_mode;
       window->tile_monitor_number = display->grab_tile_monitor_number;
 
       /* End move or resize and restore to original state.  If the
@@ -2042,10 +2045,24 @@ process_mouse_move_resize_grab (MetaDisplay     *display,
        * need to remaximize it.  In normal cases, we need to do a
        * moveresize now to get the position back to the original.
        */
-      if (window->shaken_loose || window->tile_mode == META_TILE_MAXIMIZED)
+      if (window->shaken_loose || mode == META_TILE_MAXIMIZED)
         meta_window_maximize (window, META_MAXIMIZE_BOTH);
-      else if (window->tile_mode != META_TILE_NONE)
-        meta_window_tile (window);
+      else if (mode != META_TILE_NONE)
+        {
+          /* If the window is tiled, the user resizes it and cancels, calling
+           * meta_window_tile() would break the window position. Thus, if the
+           * window was tiled and continues to be tiled, just resize it to the
+           * previous position and size.
+           */
+          if (window->tile_mode != mode)
+            meta_window_tile (window, mode);
+          else
+            meta_window_update_resize (window,
+                                       FALSE,
+                                       display->grab_initial_window_pos.x,
+                                       display->grab_initial_window_pos.y,
+                                       TRUE);
+        }
       else
         meta_window_move_resize_frame (display->grab_window,
                                        TRUE,
@@ -2981,6 +2998,7 @@ handle_toggle_tiled (MetaDisplay     *display,
     {
       window->tile_monitor_number = window->saved_maximize ? window->monitor->number
         : -1;
+      window->previous_tile_mode = window->tile_mode;
       window->tile_mode = window->saved_maximize ? META_TILE_MAXIMIZED
         : META_TILE_NONE;
 
@@ -2992,7 +3010,7 @@ handle_toggle_tiled (MetaDisplay     *display,
   else if (meta_window_can_tile_side_by_side (window))
     {
       window->tile_monitor_number = window->monitor->number;
-      window->tile_mode = mode;
+
       /* Maximization constraints beat tiling constraints, so if the window
        * is maximized, tiling won't have any effect unless we unmaximize it
        * horizontally first; rather than calling meta_window_unmaximize(),
@@ -3000,7 +3018,7 @@ handle_toggle_tiled (MetaDisplay     *display,
        * save an additional roundtrip.
        */
       window->maximized_horizontally = FALSE;
-      meta_window_tile (window);
+      meta_window_tile (window, mode);
     }
 }
 
diff --git a/src/core/screen.c b/src/core/screen.c
index d6b5eac..f1db989 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -1407,7 +1407,7 @@ meta_screen_update_tile_preview_timeout (gpointer data)
 
   if (window)
     {
-      switch (window->tile_mode)
+      switch (window->preview_tile_mode)
         {
           case META_TILE_LEFT:
           case META_TILE_RIGHT:
@@ -1432,7 +1432,11 @@ meta_screen_update_tile_preview_timeout (gpointer data)
       int monitor;
 
       monitor = meta_window_get_current_tile_monitor_number (window);
-      meta_window_get_current_tile_area (window, &tile_rect);
+      meta_window_get_tile_area_for_mode (window,
+                                          window->preview_tile_mode,
+                                          window->tile_mode,
+                                          monitor,
+                                          &tile_rect);
       meta_compositor_show_tile_preview (screen->display->compositor,
                                          window, &tile_rect, monitor);
     }
@@ -1472,10 +1476,15 @@ meta_screen_update_tile_preview (MetaScreen *screen,
 void
 meta_screen_hide_tile_preview (MetaScreen *screen)
 {
+  MetaWindow *window = screen->display->grab_window;
+
   if (screen->tile_preview_timeout_id > 0)
     g_source_remove (screen->tile_preview_timeout_id);
 
   meta_compositor_hide_tile_preview (screen->display->compositor);
+
+  if (window)
+    window->preview_tile_mode = META_TILE_NONE;
 }
 
 MetaWindow*
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 5c8ed98..f20494b 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -207,6 +207,12 @@ struct _MetaWindow
    * that to toggle between normal/tiled or maximized/tiled states. */
   guint saved_maximize : 1;
   int tile_monitor_number;
+
+  /* Keep track of the previous tile mode so when changing between left and
+   * right tiles we can resize the window with the complementary width */
+  guint previous_tile_mode : 2;
+  guint preview_tile_mode : 2;
+
   int preferred_output_winsys_id;
 
   /* Whether we're shaded */
@@ -554,12 +560,20 @@ struct _MetaWindowClass
 #define META_WINDOW_TILED_MAXIMIZED(w)(META_WINDOW_MAXIMIZED(w) && \
                                        (w)->tile_mode == META_TILE_MAXIMIZED)
 #define META_WINDOW_ALLOWS_MOVE(w)     ((w)->has_move_func && !(w)->fullscreen)
-#define META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS(w)   ((w)->has_resize_func && !META_WINDOW_MAXIMIZED (w) && 
!META_WINDOW_TILED_SIDE_BY_SIDE(w) && !(w)->fullscreen && !(w)->shaded)
+#define META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS(w)   ((w)->has_resize_func && !META_WINDOW_MAXIMIZED (w) && 
!(w)->fullscreen && !(w)->shaded)
 #define META_WINDOW_ALLOWS_RESIZE(w)   (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) &&                \
                                         (((w)->size_hints.min_width < (w)->size_hints.max_width) ||  \
                                          ((w)->size_hints.min_height < (w)->size_hints.max_height)))
 #define META_WINDOW_ALLOWS_HORIZONTAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && 
(w)->size_hints.min_width < (w)->size_hints.max_width)
 #define META_WINDOW_ALLOWS_VERTICAL_RESIZE(w)   (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && 
(w)->size_hints.min_height < (w)->size_hints.max_height)
+#define META_WINDOW_TILED_LEFT_RESIZING(w) \
+  ((w)->tile_mode == META_TILE_LEFT && \
+   ((w)->display->grab_op == META_GRAB_OP_RESIZING_E || \
+    (w)->display->grab_op == META_GRAB_OP_KEYBOARD_RESIZING_E))
+#define META_WINDOW_TILED_RIGHT_RESIZING(w) \
+  ((w)->tile_mode == META_TILE_RIGHT && \
+   ((w)->display->grab_op == META_GRAB_OP_RESIZING_W || \
+    (w)->display->grab_op == META_GRAB_OP_KEYBOARD_RESIZING_W))
 
 MetaWindow * _meta_window_shared_new       (MetaDisplay         *display,
                                             MetaScreen          *screen,
@@ -574,7 +588,8 @@ void        meta_window_unmanage           (MetaWindow  *window,
                                             guint32      timestamp);
 void        meta_window_queue              (MetaWindow  *window,
                                             guint queuebits);
-void        meta_window_tile               (MetaWindow        *window);
+void        meta_window_tile               (MetaWindow        *window,
+                                            MetaTileMode       mode);
 void        meta_window_maximize_internal  (MetaWindow        *window,
                                             MetaMaximizeFlags  directions,
                                             MetaRectangle     *saved_rect);
@@ -643,7 +658,10 @@ void meta_window_get_work_area_for_logical_monitor (MetaWindow         *window,
                                                     MetaRectangle      *area);
 
 int meta_window_get_current_tile_monitor_number (MetaWindow *window);
-void meta_window_get_current_tile_area         (MetaWindow    *window,
+void meta_window_get_tile_area_for_mode        (MetaWindow    *window,
+                                                MetaTileMode   mode,
+                                                MetaTileMode   previous_mode,
+                                                guint          monitor_number,
                                                 MetaRectangle *tile_area);
 
 
diff --git a/src/core/window.c b/src/core/window.c
index a6ec04f..8422fe8 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -2726,6 +2726,12 @@ meta_window_maximize (MetaWindow        *window,
           meta_window_unshade (window, timestamp);
         }
 
+      if (maximize_vertically && maximize_horizontally)
+        {
+          window->previous_tile_mode = window->tile_mode;
+          window->tile_mode = META_TILE_MAXIMIZED;
+        }
+
       /* if the window hasn't been placed yet, we'll maximize it then
        */
       if (!window->placed)
@@ -2886,24 +2892,88 @@ meta_window_requested_dont_bypass_compositor (MetaWindow *window)
   return window->bypass_compositor == _NET_WM_BYPASS_COMPOSITOR_HINT_OFF;
 }
 
+static void
+meta_window_calculate_area_for_tile_mode (MetaWindow    *window,
+                                          MetaTileMode   mode,
+                                          MetaTileMode   previous_mode,
+                                          gint           monitor_number,
+                                          MetaRectangle *rect)
+{
+  MetaRectangle monitor_area;
+  gboolean was_tiled;
+
+  meta_window_get_work_area_for_monitor (window, monitor_number, &monitor_area);
+
+  rect->x = monitor_area.x;
+  rect->y = monitor_area.y;
+  rect->height = monitor_area.height;
+
+  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;
+  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)
+    rect->x = monitor_area.x + monitor_area.width - rect->width;
+}
+
 void
-meta_window_tile (MetaWindow *window)
+meta_window_tile (MetaWindow   *window,
+                  MetaTileMode  mode)
 {
   MetaMaximizeFlags directions;
   MetaRectangle old_frame_rect, old_buffer_rect;
+  MetaRectangle new_rect;
+  gint monitor_number;
 
-  /* Don't do anything if no tiling is requested */
-  if (window->tile_mode == META_TILE_NONE)
+  if (mode == window->tile_mode)
     return;
 
-  if (window->tile_mode == META_TILE_MAXIMIZED)
+  /* Don't do anything if no tiling is requested */
+  if (mode == META_TILE_NONE)
+    {
+      window->previous_tile_mode = window->tile_mode;
+      window->tile_mode = mode;
+      return;
+    }
+
+  if (mode == META_TILE_MAXIMIZED)
     directions = META_MAXIMIZE_BOTH;
   else
     directions = META_MAXIMIZE_VERTICAL;
 
+  /* When moving the window around, we want to use the tile monitor
+   * number; otherwise, the current monitor number */
+  if (window->tile_monitor_number != -1)
+    monitor_number = window->tile_monitor_number;
+  else
+    monitor_number = window->monitor->number;
+
   meta_window_maximize_internal (window, directions, NULL);
   meta_screen_update_tile_preview (window->screen, FALSE);
 
+  /* Calculate the new area before updating the tile mode, so that the window is still
+   * able to track which is the current and the next tile mode */
+  meta_window_calculate_area_for_tile_mode (window,
+                                            mode,
+                                            window->tile_mode,
+                                            monitor_number,
+                                            &new_rect);
+
+  /* Track the previous mode */
+  window->previous_tile_mode = window->tile_mode;
+  window->tile_mode = mode;
+
   meta_window_get_frame_rect (window, &old_frame_rect);
   meta_window_get_buffer_rect (window, &old_buffer_rect);
 
@@ -2916,7 +2986,7 @@ meta_window_tile (MetaWindow *window)
                                      META_MOVE_RESIZE_RESIZE_ACTION |
                                      META_MOVE_RESIZE_STATE_CHANGED),
                                     NorthWestGravity,
-                                    window->unconstrained_rect);
+                                    new_rect);
 
   if (window->frame)
     meta_frame_queue_draw (window->frame);
@@ -3020,6 +3090,12 @@ meta_window_unmaximize (MetaWindow        *window,
       meta_window_get_frame_rect (window, &old_frame_rect);
       meta_window_get_buffer_rect (window, &old_buffer_rect);
 
+      if (unmaximize_vertically)
+        {
+          window->previous_tile_mode = window->tile_mode;
+          window->tile_mode = META_TILE_NONE;
+        }
+
       meta_topic (META_DEBUG_WINDOW_OPS,
                   "Unmaximizing %s%s\n",
                   window->desc,
@@ -5640,7 +5716,7 @@ update_move (MetaWindow  *window,
     {
       /* We don't want to tile while snapping. Also, clear any previous tile
          request. */
-      window->tile_mode = META_TILE_NONE;
+      window->preview_tile_mode = META_TILE_NONE;
       window->tile_monitor_number = -1;
     }
   else if (meta_prefs_get_edge_tiling () &&
@@ -5673,22 +5749,22 @@ update_move (MetaWindow  *window,
                                              &work_area);
 
       /* Check if the cursor is in a position which triggers tiling
-       * and set tile_mode accordingly.
+       * and set preview_tile_mode accordingly.
        */
       if (meta_window_can_tile_side_by_side (window) &&
           x >= monitor->rect.x && x < (work_area.x + shake_threshold))
-        window->tile_mode = META_TILE_LEFT;
+        window->preview_tile_mode = META_TILE_LEFT;
       else if (meta_window_can_tile_side_by_side (window) &&
                x >= work_area.x + work_area.width - shake_threshold &&
                x < (monitor->rect.x + monitor->rect.width))
-        window->tile_mode = META_TILE_RIGHT;
+        window->preview_tile_mode = META_TILE_RIGHT;
       else if (meta_window_can_tile_maximized (window) &&
                y >= monitor->rect.y && y <= work_area.y)
-        window->tile_mode = META_TILE_MAXIMIZED;
+        window->preview_tile_mode = META_TILE_MAXIMIZED;
       else
-        window->tile_mode = META_TILE_NONE;
+        window->preview_tile_mode = META_TILE_NONE;
 
-      if (window->tile_mode != META_TILE_NONE)
+      if (window->preview_tile_mode != META_TILE_NONE)
         window->tile_monitor_number = monitor->number;
     }
 
@@ -5799,7 +5875,7 @@ update_move (MetaWindow  *window,
    * it to another monitor.
    */
   meta_screen_update_tile_preview (window->screen,
-                                   window->tile_mode != META_TILE_NONE);
+                                   window->preview_tile_mode != META_TILE_NONE);
 
   meta_window_get_frame_rect (window, &old);
 
@@ -5966,19 +6042,28 @@ update_resize (MetaWindow *window,
 }
 
 static void
-update_tile_mode (MetaWindow *window)
+update_tile_mode_after_resize (MetaWindow *window,
+                               gint        x,
+                               gint        y)
 {
-  switch (window->tile_mode)
+  const MetaLogicalMonitor *monitor;
+  MetaMonitorManager *monitor_manager;
+  MetaRectangle work_area;
+  MetaBackend *backend;
+  gint shake_threshold;
+
+  backend = meta_get_backend ();
+  shake_threshold = meta_prefs_get_drag_threshold ();
+  monitor_manager = meta_backend_get_monitor_manager (backend);
+  monitor = meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
+
+  meta_window_get_work_area_for_monitor (window, monitor->number, &work_area);
+
+  /* If the window is tiled and we reach the oposite edge, maximize the window */
+  if ((META_WINDOW_TILED_LEFT (window) && x >= work_area.x + work_area.width - shake_threshold) ||
+      (META_WINDOW_TILED_RIGHT (window) && x <= work_area.x + shake_threshold))
     {
-      case META_TILE_LEFT:
-      case META_TILE_RIGHT:
-          if (!META_WINDOW_TILED_SIDE_BY_SIDE (window))
-              window->tile_mode = META_TILE_NONE;
-          break;
-      case META_TILE_MAXIMIZED:
-          if (!META_WINDOW_MAXIMIZED (window))
-              window->tile_mode = META_TILE_NONE;
-          break;
+      meta_window_maximize (window, META_MAXIMIZE_BOTH);
     }
 }
 
@@ -6012,8 +6097,11 @@ end_grab_op (MetaWindow *window,
     {
       if (meta_grab_op_is_moving (window->display->grab_op))
         {
-          if (window->tile_mode != META_TILE_NONE)
-            meta_window_tile (window);
+          if (window->preview_tile_mode != META_TILE_NONE)
+            {
+              meta_window_tile (window, window->preview_tile_mode);
+              meta_screen_hide_tile_preview (window->screen);
+            }
           else
             update_move (window,
                          modifiers & CLUTTER_SHIFT_MASK,
@@ -6033,7 +6121,7 @@ end_grab_op (MetaWindow *window,
            * would break the ability to snap back to the tiled
            * state, so we wait until mouse release.
            */
-          update_tile_mode (window);
+          update_tile_mode_after_resize (window, x, y);
         }
     }
   meta_display_end_grab_op (window->display, clutter_event_get_time (event));
@@ -6239,23 +6327,19 @@ meta_window_get_current_tile_monitor_number (MetaWindow *window)
 }
 
 void
-meta_window_get_current_tile_area (MetaWindow    *window,
-                                   MetaRectangle *tile_area)
-{
-  int tile_monitor_number;
-
-  g_return_if_fail (window->tile_mode != META_TILE_NONE);
-
-  tile_monitor_number = meta_window_get_current_tile_monitor_number (window);
-
-  meta_window_get_work_area_for_monitor (window, tile_monitor_number, tile_area);
-
-  if (window->tile_mode == META_TILE_LEFT  ||
-      window->tile_mode == META_TILE_RIGHT)
-    tile_area->width /= 2;
-
-  if (window->tile_mode == META_TILE_RIGHT)
-    tile_area->x += tile_area->width;
+meta_window_get_tile_area_for_mode (MetaWindow    *window,
+                                    MetaTileMode   mode,
+                                    MetaTileMode   previous_mode,
+                                    guint          monitor_number,
+                                    MetaRectangle *tile_area)
+{
+  g_return_if_fail (mode != META_TILE_NONE);
+
+  meta_window_calculate_area_for_tile_mode (window,
+                                            mode,
+                                            previous_mode,
+                                            monitor_number,
+                                            tile_area);
 }
 
 gboolean
diff --git a/src/ui/frames.c b/src/ui/frames.c
index 2d86254..129a9e5 100644
--- a/src/ui/frames.c
+++ b/src/ui/frames.c
@@ -1621,6 +1621,9 @@ get_control (MetaUIFrame *frame, int root_x, int root_y)
   has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0;
   has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0;
 
+  if (flags & META_FRAME_TILED_LEFT || flags & META_FRAME_TILED_RIGHT)
+    has_vert = has_horiz = FALSE;
+
   if (POINT_IN_RECT (x, y, fgeom.title_rect))
     {
       if (has_vert && y <= TOP_RESIZE_HEIGHT && has_north_resize)
@@ -1693,12 +1696,12 @@ get_control (MetaUIFrame *frame, int root_x, int root_y)
     }
   else if (x <= fgeom.borders.total.left)
     {
-      if (has_horiz)
+      if (has_horiz || flags & META_FRAME_TILED_RIGHT)
         return META_FRAME_CONTROL_RESIZE_W;
     }
   else if (x >= (fgeom.width - fgeom.borders.total.right))
     {
-      if (has_horiz)
+      if (has_horiz || flags & META_FRAME_TILED_LEFT)
         return META_FRAME_CONTROL_RESIZE_E;
     }
 


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