From bec068ef5ddc73f23ffd6298122bf818fd4d2084 Mon Sep 17 00:00:00 2001 From: infirit Date: Fri, 24 Oct 2014 21:59:58 +0200 Subject: Rework tiling code based off Consortium Taken from https://github.com/SolusOS-discontinued/consortium/commit/b463e03f5bdeab307ceee6b969c681f29537c76d --- src/core/boxes.c | 123 +++++++++------------------------ src/core/constraints.c | 6 +- src/core/display-private.h | 9 +++ src/core/display.c | 23 +++++++ src/core/frame.c | 6 ++ src/core/keybindings.c | 43 ++++++++++++ src/core/screen-private.h | 2 + src/core/screen.c | 36 +++++++++- src/core/testboxes.c | 8 ++- src/core/window-private.h | 19 ++++-- src/core/window.c | 166 +++++++++++++++++++++++++++++++++------------ src/core/workspace.c | 3 +- src/include/boxes.h | 3 +- src/include/common.h | 4 +- src/ui/theme-parser.c | 44 ++++++++++++ src/ui/theme.c | 63 ++++++++++++++++- src/ui/theme.h | 8 +++ 17 files changed, 414 insertions(+), 152 deletions(-) diff --git a/src/core/boxes.c b/src/core/boxes.c index 877fa458..93f7db44 100644 --- a/src/core/boxes.c +++ b/src/core/boxes.c @@ -1791,6 +1791,7 @@ meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect, GList* meta_rectangle_find_nonintersected_xinerama_edges ( + const MetaRectangle *screen_rect, const GList *xinerama_rects, const GSList *all_struts) { @@ -1813,98 +1814,38 @@ meta_rectangle_find_nonintersected_xinerama_edges ( while (cur) { MetaRectangle *cur_rect = cur->data; - const GList *compare = xinerama_rects; - while (compare) + MetaEdge *new_edge; + if (BOX_LEFT(*cur_rect) != BOX_LEFT(*screen_rect)) { - MetaRectangle *compare_rect = compare->data; - - /* Check if cur might be horizontally adjacent to compare */ - if (meta_rectangle_vert_overlap(cur_rect, compare_rect)) - { - MetaSide side_type; - int y = MAX (cur_rect->y, compare_rect->y); - int height = MIN (BOX_BOTTOM (*cur_rect) - y, - BOX_BOTTOM (*compare_rect) - y); - int width = 0; - int x; - - if (BOX_LEFT (*cur_rect) == BOX_RIGHT (*compare_rect)) - { - /* compare_rect is to the left of cur_rect */ - x = BOX_LEFT (*cur_rect); - side_type = META_SIDE_LEFT; - } - else if (BOX_RIGHT (*cur_rect) == BOX_LEFT (*compare_rect)) - { - /* compare_rect is to the right of cur_rect */ - x = BOX_RIGHT (*cur_rect); - side_type = META_SIDE_RIGHT; - } - else - /* These rectangles aren't adjacent after all */ - x = INT_MIN; - - /* If the rectangles really are adjacent */ - if (x != INT_MIN) - { - /* We need a left edge for the xinerama on the right, and - * a right edge for the xinerama on the left. Just fill - * up the edges and stick 'em on the list. - */ - MetaEdge *new_edge = g_new (MetaEdge, 1); - - new_edge->rect = meta_rect (x, y, width, height); - new_edge->side_type = side_type; - new_edge->edge_type = META_EDGE_XINERAMA; - - ret = g_list_prepend (ret, new_edge); - } - } - - /* Check if cur might be vertically adjacent to compare */ - if (meta_rectangle_horiz_overlap(cur_rect, compare_rect)) - { - MetaSide side_type; - int x = MAX (cur_rect->x, compare_rect->x); - int width = MIN (BOX_RIGHT (*cur_rect) - x, - BOX_RIGHT (*compare_rect) - x); - int height = 0; - int y; - - if (BOX_TOP (*cur_rect) == BOX_BOTTOM (*compare_rect)) - { - /* compare_rect is to the top of cur_rect */ - y = BOX_TOP (*cur_rect); - side_type = META_SIDE_TOP; - } - else if (BOX_BOTTOM (*cur_rect) == BOX_TOP (*compare_rect)) - { - /* compare_rect is to the bottom of cur_rect */ - y = BOX_BOTTOM (*cur_rect); - side_type = META_SIDE_BOTTOM; - } - else - /* These rectangles aren't adjacent after all */ - y = INT_MIN; - - /* If the rectangles really are adjacent */ - if (y != INT_MIN) - { - /* We need a top edge for the xinerama on the bottom, and - * a bottom edge for the xinerama on the top. Just fill - * up the edges and stick 'em on the list. - */ - MetaEdge *new_edge = g_new (MetaEdge, 1); - - new_edge->rect = meta_rect (x, y, width, height); - new_edge->side_type = side_type; - new_edge->edge_type = META_EDGE_XINERAMA; - - ret = g_list_prepend (ret, new_edge); - } - } - - compare = compare->next; + new_edge = g_new (MetaEdge, 1); + new_edge->rect = meta_rect (BOX_LEFT (*cur_rect), BOX_TOP (*cur_rect), 0, cur_rect->height); + new_edge->side_type = META_SIDE_LEFT; + new_edge->edge_type = META_EDGE_XINERAMA; + ret = g_list_prepend (ret, new_edge); + } + if (BOX_RIGHT(*cur_rect) != BOX_RIGHT(*screen_rect)) + { + new_edge = g_new (MetaEdge, 1); + new_edge->rect = meta_rect (BOX_RIGHT (*cur_rect), BOX_TOP (*cur_rect), 0, cur_rect->height); + new_edge->side_type = META_SIDE_RIGHT; + new_edge->edge_type = META_EDGE_XINERAMA; + ret = g_list_prepend (ret, new_edge); + } + if (BOX_TOP(*cur_rect) != BOX_TOP(*screen_rect)) + { + new_edge = g_new (MetaEdge, 1); + new_edge->rect = meta_rect (BOX_LEFT (*cur_rect), BOX_TOP (*cur_rect), cur_rect->width, 0); + new_edge->side_type = META_SIDE_TOP; + new_edge->edge_type = META_EDGE_XINERAMA; + ret = g_list_prepend (ret, new_edge); + } + if (BOX_BOTTOM(*cur_rect) != BOX_BOTTOM(*screen_rect)) + { + new_edge = g_new (MetaEdge, 1); + new_edge->rect = meta_rect (BOX_LEFT (*cur_rect), BOX_BOTTOM (*cur_rect), cur_rect->width, 0); + new_edge->side_type = META_SIDE_BOTTOM; + new_edge->edge_type = META_EDGE_XINERAMA; + ret = g_list_prepend (ret, new_edge); } cur = cur->next; } diff --git a/src/core/constraints.c b/src/core/constraints.c index 68cf5ae1..656d1529 100644 --- a/src/core/constraints.c +++ b/src/core/constraints.c @@ -748,8 +748,10 @@ constrain_maximization (MetaWindow *window, return TRUE; /* Calculate target_size = maximized size of (window + frame) */ - if (window->maximized_horizontally && window->maximized_vertically) - target_size = info->work_area_xinerama; + if (META_WINDOW_MAXIMIZED (window)) + { + target_size = info->work_area_xinerama; + } else { /* Amount of maximization possible in a single direction depends diff --git a/src/core/display-private.h b/src/core/display-private.h index d8842a3e..dc270a96 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -67,6 +67,13 @@ typedef void (*MetaWindowPingFunc) (MetaDisplay* display, Window xwindow, guint3 */ #define N_IGNORED_SERIALS 4 +typedef enum { + META_TILE_NONE, + META_TILE_LEFT, + META_TILE_RIGHT, + META_TILE_MAXIMIZED /* only used for previews */ +} MetaTileMode; + struct _MetaDisplay { char* name; Display* xdisplay; @@ -155,6 +162,8 @@ struct _MetaDisplay { int grab_anchor_root_x; int grab_anchor_root_y; MetaRectangle grab_anchor_window_pos; + MetaTileMode grab_tile_mode; + int grab_tile_monitor_number; int grab_latest_motion_x; int grab_latest_motion_y; gulong grab_mask; diff --git a/src/core/display.c b/src/core/display.c index e12dd60a..76408930 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -465,6 +465,8 @@ meta_display_open (void) the_display->grab_window = NULL; the_display->grab_screen = NULL; the_display->grab_resize_popup = NULL; + the_display->grab_tile_mode = META_TILE_NONE; + the_display->grab_tile_monitor_number = -1; the_display->grab_edge_resistance_data = NULL; @@ -3527,6 +3529,16 @@ meta_display_begin_grab_op (MetaDisplay *display, display->grab_xwindow = grab_xwindow; display->grab_button = button; display->grab_mask = modmask; + if (window) + { + display->grab_tile_mode = window->tile_mode; + display->grab_tile_monitor_number = window->tile_monitor_number; + } + else + { + display->grab_tile_mode = META_TILE_NONE; + display->grab_tile_monitor_number = -1; + } display->grab_anchor_root_x = root_x; display->grab_anchor_root_y = root_y; display->grab_latest_motion_x = root_x; @@ -3724,6 +3736,11 @@ meta_display_end_grab_op (MetaDisplay *display, if (display->grab_window != NULL) display->grab_window->shaken_loose = FALSE; + /*if(display->grab_window != NULL && display->grab_window->tile_mode == META_TILE_MAXIMIZED) + { + display->grab_window->tile_mode = META_TILE_NONE; + }*/ + if (display->grab_window != NULL && !meta_prefs_get_raise_on_click () && (meta_grab_op_is_moving (display->grab_op) || @@ -3826,9 +3843,15 @@ meta_display_end_grab_op (MetaDisplay *display, } #endif /* HAVE_XSYNC */ + /* Hide the tile preview if it exists */ + if (display->grab_screen->tile_preview) + meta_tile_preview_hide (display->grab_screen->tile_preview); + display->grab_window = NULL; display->grab_screen = NULL; display->grab_xwindow = None; + display->grab_tile_mode = META_TILE_NONE; + display->grab_tile_monitor_number = -1; display->grab_op = META_GRAB_OP_NONE; if (display->grab_resize_popup) diff --git a/src/core/frame.c b/src/core/frame.c index 68af4b52..cabfefcd 100644 --- a/src/core/frame.c +++ b/src/core/frame.c @@ -282,6 +282,12 @@ meta_frame_get_flags (MetaFrame *frame) if (META_WINDOW_MAXIMIZED (frame->window)) flags |= META_FRAME_MAXIMIZED; + if (META_WINDOW_TILED_LEFT (frame->window)) + flags |= META_FRAME_TILED_LEFT; + + if (META_WINDOW_TILED_RIGHT (frame->window)) + flags |= META_FRAME_TILED_RIGHT; + if (frame->window->fullscreen) flags |= META_FRAME_FULLSCREEN; diff --git a/src/core/keybindings.c b/src/core/keybindings.c index 83dc4f93..8176b96f 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -1394,6 +1394,10 @@ process_mouse_move_resize_grab (MetaDisplay *display, if (keysym == XK_Escape) { + /* 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 * window was a maximized window that had been "shaken loose" we * need to remaximize it. In normal cases, we need to do a @@ -1405,6 +1409,8 @@ process_mouse_move_resize_grab (MetaDisplay *display, meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); + else if (window->tile_mode == META_TILE_LEFT || window->tile_mode == META_TILE_RIGHT) + meta_window_tile (window); else if (!display->grab_wireframe_active) meta_window_move_resize (display->grab_window, TRUE, @@ -3016,6 +3022,43 @@ handle_toggle_above (MetaDisplay *display, meta_window_make_above (window); } +/* TODO: actually use this keybinding, without messing up the existing keybinding schema */ +static void +handle_toggle_tiled (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + XEvent *event, + MetaKeyBinding *binding) +{ + MetaTileMode mode = binding->handler->data; + + if ((META_WINDOW_TILED_LEFT (window) && mode == META_TILE_LEFT) || + (META_WINDOW_TILED_RIGHT (window) && mode == META_TILE_RIGHT)) + { + window->tile_mode = META_TILE_NONE; + + if (window->saved_maximize) + meta_window_maximize (window, META_MAXIMIZE_VERTICAL | + META_MAXIMIZE_HORIZONTAL); + else + meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL | + META_MAXIMIZE_HORIZONTAL); + } + else if (meta_window_can_tile (window)) + { + window->tile_mode = mode; + window->tile_monitor_number = meta_screen_get_xinerama_for_window (window->screen, window)->number; + /* 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(), + * we just set the flag and rely on meta_window_tile() syncing it to + * save an additional roundtrip. + */ + window->maximized_horizontally = FALSE; + meta_window_tile (window); + } +} + static void handle_toggle_maximized (MetaDisplay *display, MetaScreen *screen, diff --git a/src/core/screen-private.h b/src/core/screen-private.h index c2114144..6784cc9b 100644 --- a/src/core/screen-private.h +++ b/src/core/screen-private.h @@ -169,6 +169,8 @@ void meta_screen_ensure_workspace_popup (MetaScreen *screen); void meta_screen_tile_preview_update (MetaScreen *screen, gboolean delay); +void meta_screen_tile_preview_hide (MetaScreen *screen); + MetaWindow* meta_screen_get_mouse_window (MetaScreen *screen, MetaWindow *not_this_one); diff --git a/src/core/screen.c b/src/core/screen.c index 998bd6e4..bd3667e8 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -1476,6 +1476,7 @@ meta_screen_tile_preview_update_timeout (gpointer data) MetaScreen *screen = data; MetaWindow *window = screen->display->grab_window; gboolean composited = screen->display->compositor != NULL; + gboolean needs_preview = FALSE; screen->tile_preview_timeout_id = 0; @@ -1483,9 +1484,28 @@ meta_screen_tile_preview_update_timeout (gpointer data) screen->tile_preview = meta_tile_preview_new (screen->number, composited); - if (window - && !META_WINDOW_TILED (window) - && window->tile_mode != META_TILE_NONE) + if (window) + { + switch (window->tile_mode) + { + case META_TILE_LEFT: + case META_TILE_RIGHT: + if (!META_WINDOW_TILED (window)) + needs_preview = TRUE; + break; + + case META_TILE_MAXIMIZED: + if (!META_WINDOW_MAXIMIZED (window)) + needs_preview = TRUE; + break; + + default: + needs_preview = FALSE; + break; + } + } + + if (needs_preview) { MetaRectangle tile_rect; @@ -1523,6 +1543,16 @@ meta_screen_tile_preview_update (MetaScreen *screen, } } +void +meta_screen_tile_preview_hide (MetaScreen *screen) +{ + if (screen->tile_preview_timeout_id > 0) + g_source_remove (screen->tile_preview_timeout_id); + + if (screen->tile_preview) + meta_tile_preview_hide (screen->tile_preview); +} + MetaWindow* meta_screen_get_mouse_window (MetaScreen *screen, MetaWindow *not_this_one) diff --git a/src/core/testboxes.c b/src/core/testboxes.c index fda9795b..dfd65c69 100644 --- a/src/core/testboxes.c +++ b/src/core/testboxes.c @@ -347,8 +347,14 @@ get_xinerama_edges (int which_xinerama_set, int which_strut_set) ret = NULL; + MetaRectangle screenrect; + screenrect.x = 0; + screenrect.y = 0; + screenrect.width = 1600; + screenrect.height = 1200; + struts = get_strut_list (which_strut_set); - ret = meta_rectangle_find_nonintersected_xinerama_edges (xins, struts); + ret = meta_rectangle_find_nonintersected_xinerama_edges (&screenrect, xins, struts); free_strut_list (struts); meta_rectangle_free_list_and_elements (xins); diff --git a/src/core/window-private.h b/src/core/window-private.h index 882c8901..20e619cb 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -84,13 +84,6 @@ typedef enum { #define NUMBER_OF_QUEUES 3 -typedef enum { - META_TILE_NONE, - META_TILE_LEFT, - META_TILE_RIGHT, - META_TILE_MAXIMIZE -} MetaTileMode; - struct _MetaWindow { MetaDisplay *display; @@ -151,6 +144,11 @@ struct _MetaWindow * requested after the window grab is released */ guint tile_mode : 2; + /* The last "full" maximized/unmaximized state. We need to keep track of + * that to toggle between normal/tiled or maximized/tiled states. */ + guint saved_maximize : 1; + int tile_monitor_number; + /* Whether we're shaded */ guint shaded : 1; @@ -405,6 +403,10 @@ struct _MetaWindow #define META_WINDOW_TILED(w) ((w)->maximized_vertically && \ !(w)->maximized_horizontally && \ (w)->tile_mode != META_TILE_NONE) +#define META_WINDOW_TILED_LEFT(w) (META_WINDOW_TILED(w) && \ + (w)->tile_mode == META_TILE_LEFT) +#define META_WINDOW_TILED_RIGHT(w) (META_WINDOW_TILED(w) && \ + (w)->tile_mode == META_TILE_RIGHT) #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(w) && !(w)->fullscreen && !(w)->shaded) #define META_WINDOW_ALLOWS_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && \ @@ -425,6 +427,7 @@ void meta_window_free (MetaWindow *window, void meta_window_calc_showing (MetaWindow *window); void meta_window_queue (MetaWindow *window, guint queuebits); +void meta_window_tile (MetaWindow *window); void meta_window_minimize (MetaWindow *window); void meta_window_unminimize (MetaWindow *window); void meta_window_maximize (MetaWindow *window, @@ -663,4 +666,6 @@ gboolean meta_window_is_client_decorated (MetaWindow *window); void meta_window_update_role (MetaWindow *window); void meta_window_update_net_wm_type (MetaWindow *window); +gboolean meta_window_can_tile (MetaWindow *window); + #endif diff --git a/src/core/window.c b/src/core/window.c index b0e69548..a811d668 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -471,6 +471,7 @@ meta_window_new_with_attrs (MetaDisplay *display, window->require_titlebar_visible = TRUE; window->on_all_workspaces = FALSE; window->tile_mode = META_TILE_NONE; + window->tile_monitor_number = -1; window->shaded = FALSE; window->initially_iconic = FALSE; window->minimized = FALSE; @@ -2612,6 +2613,9 @@ meta_window_maximize_internal (MetaWindow *window, else meta_window_save_rect (window); + if (maximize_horizontally && maximize_vertically) + window->saved_maximize = TRUE; + window->maximized_horizontally = window->maximized_horizontally || maximize_horizontally; window->maximized_vertically = @@ -2660,13 +2664,15 @@ meta_window_maximize (MetaWindow *window, */ if (!window->placed) { - window->maximize_horizontally_after_placement = - window->maximize_horizontally_after_placement || - maximize_horizontally; - window->maximize_vertically_after_placement = - window->maximize_vertically_after_placement || - maximize_vertically; - return; + window->maximize_horizontally_after_placement = window->maximize_horizontally_after_placement || maximize_horizontally; + window->maximize_vertically_after_placement = window->maximize_vertically_after_placement || maximize_vertically; + return; + } + + if (window->tile_mode != META_TILE_NONE) + { + saved_rect = &window->saved_rect; + window->maximized_vertically = FALSE; } if (window->tile_mode != META_TILE_NONE) @@ -2720,7 +2726,7 @@ unmaximize_window_before_freeing (MetaWindow *window) } } -static void +void meta_window_tile (MetaWindow *window) { /* Don't do anything if no tiling is requested */ @@ -2728,7 +2734,6 @@ meta_window_tile (MetaWindow *window) return; meta_window_maximize_internal (window, META_MAXIMIZE_VERTICAL, NULL); - meta_screen_tile_preview_update (window->screen, FALSE); /* move_resize with new tiling constraints */ @@ -2736,11 +2741,18 @@ meta_window_tile (MetaWindow *window) } static gboolean +meta_window_can_tile_maximized (MetaWindow *window) +{ + return window->has_maximize_func; +} + +gboolean meta_window_can_tile (MetaWindow *window) { const MetaXineramaScreenInfo *monitor; MetaRectangle tile_area; + /*if (!META_WINDOW_ALLOWS_RESIZE (window))*/ if (!META_WINDOW_ALLOWS_RESIZE (window)) return FALSE; @@ -2771,7 +2783,8 @@ meta_window_unmaximize (MetaWindow *window, gboolean unmaximize_horizontally, unmaximize_vertically; /* Restore tiling if necessary */ - if (window->tile_mode != META_TILE_NONE) + if (window->tile_mode == META_TILE_LEFT || + window->tile_mode == META_TILE_RIGHT) { window->maximized_horizontally = FALSE; meta_window_tile (window); @@ -2782,6 +2795,9 @@ meta_window_unmaximize (MetaWindow *window, unmaximize_vertically = directions & META_MAXIMIZE_VERTICAL; g_assert (unmaximize_horizontally || unmaximize_vertically); + if (unmaximize_horizontally && unmaximize_vertically) + window->saved_maximize = FALSE; + /* Only do something if the window isn't already maximized in the * given direction(s). */ @@ -7019,35 +7035,56 @@ update_move (MetaWindow *window, DRAG_THRESHOLD_TO_SHAKE_THRESHOLD_FACTOR; - if (meta_prefs_get_side_by_side_tiling () && - meta_window_can_tile (window)) + if (snap) + { + /* We don't want to tile while snapping. Also, clear any previous tile + request. */ + window->tile_mode = META_TILE_NONE; + window->tile_monitor_number = -1; + } + else if (meta_prefs_get_side_by_side_tiling () && + !META_WINDOW_MAXIMIZED (window) && + !META_WINDOW_TILED (window)) { const MetaXineramaScreenInfo *monitor; MetaRectangle work_area; - /* For tiling we are interested in the work area of the monitor where - * the pointer is located. - * Also see comment in meta_window_get_current_tile_area() + /* For side-by-side tiling we are interested in the inside vertical + * edges of the work area of the monitor where the pointer is located, + * and in the outside top edge for maximized tiling. + * + * For maximized tiling we use the outside edge instead of the + * inside edge, because we don't want to force users to maximize + * windows they are placing near the top of their screens. + * + * The "current" idea of meta_window_get_work_area_current_monitor() and + * meta_screen_get_current_monitor() is slightly different: the former + * refers to the monitor which contains the largest part of the window, + * the latter to the one where the pointer is located. */ monitor = meta_screen_get_current_xinerama (window->screen); meta_window_get_work_area_for_xinerama (window, monitor->number, &work_area); - if (y >= monitor->rect.y && - y < (monitor->rect.y + monitor->rect.height)) - { - /* check if cursor is near an edge of the work area */ - if (x >= monitor->rect.x && x < (work_area.x + shake_threshold)) - window->tile_mode = META_TILE_LEFT; - else if (x >= work_area.x + work_area.width - shake_threshold && - x < (monitor->rect.x + monitor->rect.width)) - window->tile_mode = META_TILE_RIGHT; - else if ((y >= monitor->rect.y) && (y < work_area.y + shake_threshold)) - window->tile_mode = META_TILE_MAXIMIZE; - else - window->tile_mode = META_TILE_NONE; - } + /* Check if the cursor is in a position which triggers tiling + * and set tile_mode accordingly. + */ + if (meta_window_can_tile (window) && + x >= monitor->rect.x && x < (work_area.x + shake_threshold)) + window->tile_mode = META_TILE_LEFT; + else if (meta_window_can_tile (window) && + x >= work_area.x + work_area.width - shake_threshold && + x < (monitor->rect.x + monitor->rect.width)) + window->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; + else + window->tile_mode = META_TILE_NONE; + + if (window->tile_mode != META_TILE_NONE) + window->tile_monitor_number = monitor->number; } /* shake loose (unmaximize) maximized or tiled window if dragged beyond @@ -7060,7 +7097,10 @@ update_move (MetaWindow *window, { double prop; - /* Shake loose */ + /* Shake loose, so that the window snaps back to maximized + * when dragged near the top; do not snap back if the window + * was tiled. + */ window->shaken_loose = META_WINDOW_MAXIMIZED (window); window->tile_mode = META_TILE_NONE; @@ -7137,6 +7177,8 @@ update_move (MetaWindow *window, display->grab_anchor_root_y = y; window->shaken_loose = FALSE; + window->tile_mode = META_TILE_NONE; + meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); @@ -7507,6 +7549,19 @@ check_use_this_motion_notify (MetaWindow *window, } } +static void +update_tile_mode (MetaWindow *window) +{ + switch (window->tile_mode) + { + case META_TILE_LEFT: + case META_TILE_RIGHT: + if (!META_WINDOW_TILED (window)) + window->tile_mode = META_TILE_NONE; + break; + } +} + void meta_window_handle_mouse_grab_op_event (MetaWindow *window, XEvent *event) @@ -7575,11 +7630,17 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window, { if (meta_grab_op_is_moving (window->display->grab_op)) { - if (window->tile_mode != META_TILE_NONE) - meta_window_tile (window); - else if (window->tile_mode == META_TILE_MAXIMIZE) - meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); - else if (event->xbutton.root == window->screen->xroot) + if (window->tile_mode == META_TILE_MAXIMIZED) + { + meta_window_maximize (window, META_MAXIMIZE_VERTICAL | + META_MAXIMIZE_HORIZONTAL); + window->tile_mode = META_TILE_NONE; + } + else if (window->tile_mode != META_TILE_NONE) + { + meta_window_tile (window); + } + else if (event->xbutton.root == window->screen->xroot) update_move (window, event->xbutton.state & ShiftMask, event->xbutton.x_root, event->xbutton.y_root); } @@ -7593,6 +7654,15 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window, TRUE); if (window->display->compositor) meta_compositor_set_updates (window->display->compositor, window, TRUE); + + /* If a tiled window has been dragged free with a + * mouse resize without snapping back to the tiled + * state, it will end up with an inconsistent tile + * mode on mouse release; cleaning the mode earlier + * would break the ability to snap back to the tiled + * state, so we wait until mouse release. + */ + update_tile_mode (window); } } @@ -7741,17 +7811,29 @@ void meta_window_get_current_tile_area (MetaWindow *window, MetaRectangle *tile_area) { - const MetaXineramaScreenInfo *monitor; + int tile_monitor_number; g_return_if_fail (window->tile_mode != META_TILE_NONE); - /* The definition of "current" of meta_window_get_work_area_current_xinerama() - * and meta_screen_get_current_xinerama() is slightly different: the former - * refers to the monitor which contains the largest part of the window, the - * latter to the one where the pointer is located. + /* I don't know how to detect monitor configuration changes, so I have to take into account that + * tile_monitor_number might be invalid. If this happens, I replace it with whatever monitor + * the window is currently on. This is usually the correct monitor anyway, only in some special + * cases is the real monitor number actually required (e.g. the window is being moved with the mouse but + * is still mostly on the wrong monitor). */ - monitor = meta_screen_get_current_xinerama (window->screen); - meta_window_get_work_area_for_xinerama (window, monitor->number, tile_area); + if (window->tile_monitor_number >= window->screen->n_xinerama_infos) + { + window->tile_monitor_number = meta_screen_get_xinerama_for_window (window->screen, window)->number; + } + + tile_monitor_number = window->tile_monitor_number; + if (tile_monitor_number < 0) + { + meta_warning ("%s called with an invalid monitor number; using 0 instead\n", G_STRFUNC); + tile_monitor_number = 0; + } + + meta_window_get_work_area_for_xinerama (window, tile_monitor_number, tile_area); if (window->tile_mode == META_TILE_LEFT || window->tile_mode == META_TILE_RIGHT) diff --git a/src/core/workspace.c b/src/core/workspace.c index ef7ee1dd..eb2db05a 100644 --- a/src/core/workspace.c +++ b/src/core/workspace.c @@ -741,8 +741,7 @@ ensure_work_areas_validated (MetaWorkspace *workspace) for (i = 0; i < workspace->screen->n_xinerama_infos; i++) tmp = g_list_prepend (tmp, &workspace->screen->xinerama_infos[i].rect); workspace->xinerama_edges = - meta_rectangle_find_nonintersected_xinerama_edges (tmp, - workspace->all_struts); + meta_rectangle_find_nonintersected_xinerama_edges (&workspace->screen->rect, tmp, workspace->all_struts); g_list_free (tmp); /* We're all done, YAAY! Record that everything has been validated. */ diff --git a/src/include/boxes.h b/src/include/boxes.h index 0e30b2a8..cf49fe62 100644 --- a/src/include/boxes.h +++ b/src/include/boxes.h @@ -284,7 +284,8 @@ GList* meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect, * struts. */ GList* meta_rectangle_find_nonintersected_xinerama_edges ( - const GList *xinerama_rects, + const MetaRectangle *screen_rect, + const GList *xinerama_rects, const GSList *all_struts); #endif /* META_BOXES_H */ diff --git a/src/include/common.h b/src/include/common.h index c72ed834..69755e24 100644 --- a/src/include/common.h +++ b/src/include/common.h @@ -47,7 +47,9 @@ typedef enum META_FRAME_ALLOWS_MOVE = 1 << 11, META_FRAME_FULLSCREEN = 1 << 12, META_FRAME_IS_FLASHING = 1 << 13, - META_FRAME_ABOVE = 1 << 14 + META_FRAME_ABOVE = 1 << 14, + META_FRAME_TILED_LEFT = 1 << 15, + META_FRAME_TILED_RIGHT = 1 << 16 } MetaFrameFlags; typedef enum diff --git a/src/ui/theme-parser.c b/src/ui/theme-parser.c index c94e0e9a..dccb47ad 100644 --- a/src/ui/theme-parser.c +++ b/src/ui/theme-parser.c @@ -3136,6 +3136,28 @@ parse_style_set_element (GMarkupParseContext *context, meta_frame_style_ref (frame_style); info->style_set->maximized_styles[frame_focus] = frame_style; break; + case META_FRAME_STATE_TILED_LEFT: + if (info->style_set->tiled_left_styles[frame_focus]) + { + set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + _("Style has already been specified for state %s focus %s"), + state, focus); + return; + } + meta_frame_style_ref (frame_style); + info->style_set->tiled_left_styles[frame_focus] = frame_style; + break; + case META_FRAME_STATE_TILED_RIGHT: + if (info->style_set->tiled_right_styles[frame_focus]) + { + set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + _("Style has already been specified for state %s focus %s"), + state, focus); + return; + } + meta_frame_style_ref (frame_style); + info->style_set->tiled_right_styles[frame_focus] = frame_style; + break; case META_FRAME_STATE_SHADED: if (info->style_set->shaded_styles[frame_resize][frame_focus]) { @@ -3158,6 +3180,28 @@ parse_style_set_element (GMarkupParseContext *context, meta_frame_style_ref (frame_style); info->style_set->maximized_and_shaded_styles[frame_focus] = frame_style; break; + case META_FRAME_STATE_TILED_LEFT_AND_SHADED: + if (info->style_set->tiled_left_and_shaded_styles[frame_focus]) + { + set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + _("Style has already been specified for state %s focus %s"), + state, focus); + return; + } + meta_frame_style_ref (frame_style); + info->style_set->tiled_left_and_shaded_styles[frame_focus] = frame_style; + break; + case META_FRAME_STATE_TILED_RIGHT_AND_SHADED: + if (info->style_set->tiled_right_and_shaded_styles[frame_focus]) + { + set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + _("Style has already been specified for state %s focus %s"), + state, focus); + return; + } + meta_frame_style_ref (frame_style); + info->style_set->tiled_right_and_shaded_styles[frame_focus] = frame_style; + break; case META_FRAME_STATE_LAST: g_assert_not_reached (); break; diff --git a/src/ui/theme.c b/src/ui/theme.c index aa49963a..763f4f3a 100644 --- a/src/ui/theme.c +++ b/src/ui/theme.c @@ -851,7 +851,9 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout, rect->visible.width = button_width; rect->visible.height = button_height; - if (flags & META_FRAME_MAXIMIZED) + if (flags & META_FRAME_MAXIMIZED || + flags & META_FRAME_TILED_LEFT || + flags & META_FRAME_TILED_RIGHT) { rect->clickable.x = rect->visible.x; rect->clickable.y = rect->visible.y; @@ -4995,7 +4997,11 @@ meta_frame_style_set_unref (MetaFrameStyleSet *style_set) } free_focus_styles (style_set->maximized_styles); + free_focus_styles (style_set->tiled_left_styles); + free_focus_styles (style_set->tiled_right_styles); free_focus_styles (style_set->maximized_and_shaded_styles); + free_focus_styles (style_set->tiled_left_and_shaded_styles); + free_focus_styles (style_set->tiled_right_and_shaded_styles); if (style_set->parent) meta_frame_style_set_unref (style_set->parent); @@ -5047,9 +5053,21 @@ get_style (MetaFrameStyleSet *style_set, case META_FRAME_STATE_MAXIMIZED: styles = style_set->maximized_styles; break; + case META_FRAME_STATE_TILED_LEFT: + styles = style_set->tiled_left_styles; + break; + case META_FRAME_STATE_TILED_RIGHT: + styles = style_set->tiled_right_styles; + break; case META_FRAME_STATE_MAXIMIZED_AND_SHADED: styles = style_set->maximized_and_shaded_styles; break; + case META_FRAME_STATE_TILED_LEFT_AND_SHADED: + styles = style_set->tiled_left_and_shaded_styles; + break; + case META_FRAME_STATE_TILED_RIGHT_AND_SHADED: + styles = style_set->tiled_right_and_shaded_styles; + break; case META_FRAME_STATE_NORMAL: case META_FRAME_STATE_SHADED: case META_FRAME_STATE_LAST: @@ -5059,6 +5077,19 @@ get_style (MetaFrameStyleSet *style_set, style = styles[focus]; + /* Tiled states are optional, try falling back to non-tiled states */ + if (style == NULL) + { + if (state == META_FRAME_STATE_TILED_LEFT || + state == META_FRAME_STATE_TILED_RIGHT) + style = get_style (style_set, META_FRAME_STATE_NORMAL, + resize, focus); + else if (state == META_FRAME_STATE_TILED_LEFT_AND_SHADED || + state == META_FRAME_STATE_TILED_RIGHT_AND_SHADED) + style = get_style (style_set, META_FRAME_STATE_SHADED, + resize, focus); + } + /* Try parent if we failed here */ if (style == NULL && style_set->parent) style = get_style (style_set->parent, state, resize, focus); @@ -5404,7 +5435,7 @@ theme_get_style (MetaTheme *theme, if (style_set == NULL) return NULL; - switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED)) + switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED | META_FRAME_TILED_LEFT | META_FRAME_TILED_RIGHT)) { case 0: state = META_FRAME_STATE_NORMAL; @@ -5412,12 +5443,24 @@ theme_get_style (MetaTheme *theme, case META_FRAME_MAXIMIZED: state = META_FRAME_STATE_MAXIMIZED; break; + case META_FRAME_TILED_LEFT: + state = META_FRAME_STATE_TILED_LEFT; + break; + case META_FRAME_TILED_RIGHT: + state = META_FRAME_STATE_TILED_RIGHT; + break; case META_FRAME_SHADED: state = META_FRAME_STATE_SHADED; break; case (META_FRAME_MAXIMIZED | META_FRAME_SHADED): state = META_FRAME_STATE_MAXIMIZED_AND_SHADED; break; + case (META_FRAME_TILED_LEFT | META_FRAME_SHADED): + state = META_FRAME_STATE_TILED_LEFT_AND_SHADED; + break; + case (META_FRAME_TILED_RIGHT | META_FRAME_SHADED): + state = META_FRAME_STATE_TILED_RIGHT_AND_SHADED; + break; default: g_assert_not_reached (); state = META_FRAME_STATE_LAST; /* compiler */ @@ -6264,10 +6307,18 @@ meta_frame_state_from_string (const char *str) return META_FRAME_STATE_NORMAL; else if (strcmp ("maximized", str) == 0) return META_FRAME_STATE_MAXIMIZED; + else if (strcmp ("tiled_left", str) == 0) + return META_FRAME_STATE_TILED_LEFT; + else if (strcmp ("tiled_right", str) == 0) + return META_FRAME_STATE_TILED_RIGHT; else if (strcmp ("shaded", str) == 0) return META_FRAME_STATE_SHADED; else if (strcmp ("maximized_and_shaded", str) == 0) return META_FRAME_STATE_MAXIMIZED_AND_SHADED; + else if (strcmp ("tiled_left_and_shaded", str) == 0) + return META_FRAME_STATE_TILED_LEFT_AND_SHADED; + else if (strcmp ("tiled_right_and_shaded", str) == 0) + return META_FRAME_STATE_TILED_RIGHT_AND_SHADED; else return META_FRAME_STATE_LAST; } @@ -6281,10 +6332,18 @@ meta_frame_state_to_string (MetaFrameState state) return "normal"; case META_FRAME_STATE_MAXIMIZED: return "maximized"; + case META_FRAME_STATE_TILED_LEFT: + return "tiled_left"; + case META_FRAME_STATE_TILED_RIGHT: + return "tiled_right"; case META_FRAME_STATE_SHADED: return "shaded"; case META_FRAME_STATE_MAXIMIZED_AND_SHADED: return "maximized_and_shaded"; + case META_FRAME_STATE_TILED_LEFT_AND_SHADED: + return "tiled_left_and_shaded"; + case META_FRAME_STATE_TILED_RIGHT_AND_SHADED: + return "tiled_right_and_shaded"; case META_FRAME_STATE_LAST: break; } diff --git a/src/ui/theme.h b/src/ui/theme.h index 89d41efe..c7437bdf 100644 --- a/src/ui/theme.h +++ b/src/ui/theme.h @@ -716,8 +716,12 @@ typedef enum { META_FRAME_STATE_NORMAL, META_FRAME_STATE_MAXIMIZED, + META_FRAME_STATE_TILED_LEFT, + META_FRAME_STATE_TILED_RIGHT, META_FRAME_STATE_SHADED, META_FRAME_STATE_MAXIMIZED_AND_SHADED, + META_FRAME_STATE_TILED_LEFT_AND_SHADED, + META_FRAME_STATE_TILED_RIGHT_AND_SHADED, META_FRAME_STATE_LAST } MetaFrameState; @@ -754,8 +758,12 @@ struct _MetaFrameStyleSet MetaFrameStyleSet *parent; MetaFrameStyle *normal_styles[META_FRAME_RESIZE_LAST][META_FRAME_FOCUS_LAST]; MetaFrameStyle *maximized_styles[META_FRAME_FOCUS_LAST]; + MetaFrameStyle *tiled_left_styles[META_FRAME_FOCUS_LAST]; + MetaFrameStyle *tiled_right_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *shaded_styles[META_FRAME_RESIZE_LAST][META_FRAME_FOCUS_LAST]; MetaFrameStyle *maximized_and_shaded_styles[META_FRAME_FOCUS_LAST]; + MetaFrameStyle *tiled_left_and_shaded_styles[META_FRAME_FOCUS_LAST]; + MetaFrameStyle *tiled_right_and_shaded_styles[META_FRAME_FOCUS_LAST]; }; /** -- cgit v1.2.1