diff options
author | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2017-06-11 14:58:21 -0300 |
---|---|---|
committer | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2017-09-08 14:05:49 -0300 |
commit | 131651f9ffdbbcc5b3788b93e6212166a87512e8 (patch) | |
tree | 0b5cf1869a9be7b54cfe0995783b435820df3bd7 | |
parent | aa30e11c8b1551360b30a9018ecd9674e83282fe (diff) | |
download | mutter-131651f9ffdbbcc5b3788b93e6212166a87512e8.tar.gz |
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
-rw-r--r-- | src/core/constraints.c | 14 | ||||
-rw-r--r-- | src/core/keybindings.c | 32 | ||||
-rw-r--r-- | src/core/screen.c | 13 | ||||
-rw-r--r-- | src/core/window-private.h | 24 | ||||
-rw-r--r-- | src/core/window.c | 178 | ||||
-rw-r--r-- | src/ui/frames.c | 7 |
6 files changed, 203 insertions, 65 deletions
diff --git a/src/core/constraints.c b/src/core/constraints.c index 14044a957..1fa572dac 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->tile_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 26c781787..e76dae287 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -2045,12 +2045,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 @@ -2058,10 +2061,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, @@ -2997,6 +3014,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; @@ -3008,7 +3026,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(), @@ -3016,7 +3034,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 98c5538e3..d8385cdee 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -1410,7 +1410,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: @@ -1435,7 +1435,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); } @@ -1475,10 +1479,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 521682d0a..aa68ebe52 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 */ @@ -559,12 +565,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, @@ -579,7 +593,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); @@ -648,7 +663,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 af1140c3b..4321ef012 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -2729,6 +2729,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) @@ -2889,24 +2895,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); @@ -2919,7 +2989,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); @@ -3023,6 +3093,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, @@ -3905,6 +3981,9 @@ meta_window_move_to_monitor (MetaWindow *window, monitor, &new_area); + if (window->tile_mode != META_TILE_NONE) + window->tile_monitor_number = monitor; + if (window->unconstrained_rect.width == 0 || window->unconstrained_rect.height == 0 || !meta_rectangle_overlap (&window->unconstrained_rect, &old_area)) @@ -3919,9 +3998,6 @@ meta_window_move_to_monitor (MetaWindow *window, meta_window_move_between_rects (window, &old_area, &new_area); } - if (window->tile_mode != META_TILE_NONE) - window->tile_monitor_number = monitor; - window->preferred_output_winsys_id = window->monitor->winsys_id; if (window->fullscreen || window->override_redirect) @@ -5650,22 +5726,22 @@ update_move_maybe_tile (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 >= logical_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 < (logical_monitor->rect.x + logical_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 >= logical_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 = logical_monitor->number; } @@ -5717,7 +5793,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 () && @@ -5834,7 +5910,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); @@ -6001,19 +6077,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); } } @@ -6047,8 +6132,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, @@ -6068,7 +6156,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)); @@ -6274,23 +6362,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 2d862545b..129a9e59b 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; } |