From 2926323a9a0defc2f9f845d80a5ec6b00a23d78e Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Fri, 24 Feb 2012 17:08:55 +0100 Subject: [PATCH] window: Introduce meta_window_get_tile_match() Returns the matching tiled window. This is the topmost tiled window in a complementary tile mode that is: - on the same monitor; - on the same workspace; - spanning the remaining monitor width; - there is no 3rd window stacked between both tiled windows that's partially visible in the common edge. https://bugzilla.gnome.org/show_bug.cgi?id=643075 --- src/core/stack.c | 29 +++++++++++ src/core/stack.h | 2 + src/core/window-private.h | 5 ++ src/core/window.c | 101 ++++++++++++++++++++++++++++++++++++++ src/meta/window.h | 2 + 5 files changed, 139 insertions(+) diff --git a/src/core/stack.c b/src/core/stack.c index c3917c6d8..de1c9e031 100644 --- a/src/core/stack.c +++ b/src/core/stack.c @@ -121,6 +121,7 @@ meta_stack_add (MetaStack *stack, window->desc, window->stack_position); stack_sync_to_server (stack); + meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } void @@ -156,6 +157,7 @@ meta_stack_remove (MetaStack *stack, GUINT_TO_POINTER (window->frame->xwindow)); stack_sync_to_server (stack); + meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } void @@ -165,6 +167,7 @@ meta_stack_update_layer (MetaStack *stack, stack->need_relayer = TRUE; stack_sync_to_server (stack); + meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } void @@ -174,6 +177,7 @@ meta_stack_update_transient (MetaStack *stack, stack->need_constrain = TRUE; stack_sync_to_server (stack); + meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } /* raise/lower within a layer */ @@ -185,6 +189,7 @@ meta_stack_raise (MetaStack *stack, stack->n_positions - 1); stack_sync_to_server (stack); + meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } void @@ -194,6 +199,7 @@ meta_stack_lower (MetaStack *stack, meta_window_set_stack_position_no_sync (window, 0); stack_sync_to_server (stack); + meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } void @@ -209,6 +215,26 @@ meta_stack_thaw (MetaStack *stack) stack->freeze_count -= 1; stack_sync_to_server (stack); + meta_stack_update_window_tile_matches (stack, NULL); +} + +void +meta_stack_update_window_tile_matches (MetaStack *stack, + MetaWorkspace *workspace) +{ + GList *windows; + + if (stack->freeze_count > 0) + return; + + windows = meta_stack_list_windows (stack, workspace); + while (windows) + { + meta_window_compute_tile_match ((MetaWindow *) windows->data); + windows = windows->next; + } + + g_list_free (windows); } static gboolean @@ -1656,6 +1682,7 @@ meta_stack_set_positions (MetaStack *stack, "Reset the stack positions of (nearly) all windows\n"); stack_sync_to_server (stack); + meta_stack_update_window_tile_matches (stack, NULL); } void @@ -1718,4 +1745,6 @@ meta_window_set_stack_position (MetaWindow *window, { meta_window_set_stack_position_no_sync (window, position); stack_sync_to_server (window->screen->stack); + meta_stack_update_window_tile_matches (window->screen->stack, + window->screen->active_workspace); } diff --git a/src/core/stack.h b/src/core/stack.h index e8b63109b..4102cc609 100644 --- a/src/core/stack.h +++ b/src/core/stack.h @@ -383,4 +383,6 @@ GList* meta_stack_get_positions (MetaStack *stack); void meta_stack_set_positions (MetaStack *stack, GList *windows); +void meta_stack_update_window_tile_matches (MetaStack *stack, + MetaWorkspace *workspace); #endif diff --git a/src/core/window-private.h b/src/core/window-private.h index b425aed7a..d89924c8f 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -410,6 +410,9 @@ struct _MetaWindow /* Focused window that is (directly or indirectly) attached to this one */ MetaWindow *attached_focus_window; + + /* The currently complementary tiled window, if any */ + MetaWindow *tile_match; }; struct _MetaWindowClass @@ -663,4 +666,6 @@ void meta_window_propagate_focus_appearance (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); + #endif diff --git a/src/core/window.c b/src/core/window.c index 8c5483954..ff09914ad 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -1167,6 +1167,8 @@ meta_window_new_with_attrs (MetaDisplay *display, window->monitor = meta_screen_get_monitor_for_window (window->screen, window); + window->tile_match = NULL; + if (window->override_redirect) { window->decorated = FALSE; @@ -5022,6 +5024,9 @@ meta_window_move_resize_internal (MetaWindow *window, } meta_window_foreach_transient (window, maybe_move_attached_dialog, NULL); + + meta_stack_update_window_tile_matches (window->screen->stack, + window->screen->active_workspace); } /** @@ -10712,3 +10717,99 @@ meta_window_is_attached_dialog (MetaWindow *window) { return window->attached; } + +/** + * meta_window_get_tile_match: + * + * Returns the matching tiled window on the same monitor as @window. This is + * the topmost tiled window in a complementary tile mode that is: + * + * - on the same monitor; + * - on the same workspace; + * - spanning the remaining monitor width; + * - there is no 3rd window stacked between both tiled windows that's + * partially visible in the common edge. + * + * Return value: (transfer none) (allow-none): the matching tiled window or + * %NULL if it doesn't exist. + */ +MetaWindow * +meta_window_get_tile_match (MetaWindow *window) +{ + return window->tile_match; +} + +void +meta_window_compute_tile_match (MetaWindow *window) +{ + MetaWindow *match; + MetaTileMode match_tile_mode; + MetaStack *stack; + + window->tile_match = NULL; + + if (window->shaded || + window->minimized || + !META_WINDOW_TILED_SIDE_BY_SIDE (window)) + return; + + if (META_WINDOW_TILED_LEFT (window)) + match_tile_mode = META_TILE_RIGHT; + else if (META_WINDOW_TILED_RIGHT (window)) + match_tile_mode = META_TILE_LEFT; + + stack = window->screen->stack; + + for (match = meta_stack_get_top (stack); + match; + match = meta_stack_get_below (stack, match, FALSE)) + { + if (!match->shaded && + !match->minimized && + match->tile_mode == match_tile_mode && + match->monitor == window->monitor && + meta_window_get_workspace (match) == meta_window_get_workspace (window)) + break; + } + + if (match) + { + MetaWindow *above, *bottommost, *topmost; + MetaRectangle above_rect, bottommost_rect, topmost_rect; + + if (meta_stack_windows_cmp (window->screen->stack, match, window) > 0) + { + topmost = match; + bottommost = window; + } + else + { + topmost = window; + bottommost = match; + } + + meta_window_get_outer_rect (bottommost, &bottommost_rect); + meta_window_get_outer_rect (topmost, &topmost_rect); + /* + * If there's a window stacked in between which is partially visible + * behind the topmost tile we don't consider the tiles to match. + */ + for (above = meta_stack_get_above (stack, bottommost, FALSE); + above && above != topmost; + above = meta_stack_get_above (stack, above, FALSE)) + { + if (above->minimized || + above->monitor != window->monitor || + meta_window_get_workspace (above) != meta_window_get_workspace (window)) + continue; + + meta_window_get_outer_rect (above, &above_rect); + + if (meta_rectangle_overlap (&above_rect, &bottommost_rect) && + meta_rectangle_overlap (&above_rect, &topmost_rect)) + return; + } + + window->tile_match = match; + } +} diff --git a/src/meta/window.h b/src/meta/window.h index 765ef28eb..5e09b598a 100644 --- a/src/meta/window.h +++ b/src/meta/window.h @@ -169,4 +169,6 @@ MetaFrameType meta_window_get_frame_type (MetaWindow *window); cairo_region_t *meta_window_get_frame_bounds (MetaWindow *window); +MetaWindow *meta_window_get_tile_match (MetaWindow *window); + #endif