From abedce08727b9993e0365c9b925bbcab9110feb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 13 Jun 2014 22:28:26 +0200 Subject: [PATCH 1/2] window: Keep track of preferred output Remember the last monitor a window was moved to by user action and try to move it back on monitor changes; this should match user expectations much better when a monitor is unplugged temporarily. https://bugzilla.gnome.org/show_bug.cgi?id=731760 --- src/core/window-private.h | 1 + src/core/window.c | 47 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/core/window-private.h b/src/core/window-private.h index e9f935f..9a0c760 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -148,6 +148,7 @@ struct _MetaWindow * that to toggle between normal/tiled or maximized/tiled states. */ guint saved_maximize : 1; int tile_monitor_number; + XID preferred_output; /* Whether we're shaded */ guint shaded : 1; diff --git a/src/core/window.c b/src/core/window.c index 60347ef..8b8fbe7 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -1198,6 +1198,7 @@ meta_window_new_with_attrs (MetaDisplay *display, window->compositor_private = NULL; window->monitor = meta_screen_get_monitor_for_window (window->screen, window); + window->preferred_output = window->monitor->output; window->tile_match = NULL; @@ -4779,13 +4780,29 @@ meta_window_get_monitor (MetaWindow *window) return window->monitor->number; } +static MetaMonitorInfo * +find_monitor_by_id (MetaWindow *window, + guint id) +{ + int i; + + for (i = 0; i < window->screen->n_monitor_infos; i++) + { + MetaMonitorInfo *info = &window->screen->monitor_infos[i]; + + if (info->output != 0 && info->output == id) + return info; + } + + return NULL; +} + /* This is called when the monitor setup has changed. The window->monitor * reference is still "valid", but refer to the previous monitor setup */ void meta_window_update_for_monitors_changed (MetaWindow *window) { const MetaMonitorInfo *old, *new; - int i; if (window->type == META_WINDOW_DESKTOP) return; @@ -4798,20 +4815,16 @@ meta_window_update_for_monitors_changed (MetaWindow *window) old = window->monitor; - /* Start on primary */ - new = &window->screen->monitor_infos[window->screen->primary_monitor_index]; + /* Try the preferred output first */ + new = find_monitor_by_id (window, window->preferred_output); - /* But, if we can find the old output on a new monitor, use that */ - for (i = 0; i < window->screen->n_monitor_infos; i++) - { - MetaMonitorInfo *info = &window->screen->monitor_infos[i]; + /* Otherwise, try to find the old output on a new monitor */ + if (!new) + new = find_monitor_by_id (window, old->output); - if (info->output == old->output) - { - new = info; - break; - } - } + /* Fall back to primary if everything else failed */ + if (!new) + new = &window->screen->monitor_infos[window->screen->primary_monitor_index]; if (window->tile_mode != META_TILE_NONE) window->tile_monitor_number = new->number; @@ -4934,6 +4947,7 @@ meta_window_move_resize_internal (MetaWindow *window, int client_move_y; MetaRectangle new_rect; MetaRectangle old_rect; + guint old_output_id; g_return_if_fail (!window->override_redirect); @@ -5332,8 +5346,14 @@ meta_window_move_resize_internal (MetaWindow *window, meta_window_refresh_resize_popup (window); + old_output_id = window->monitor->output; + meta_window_update_monitor (window); + if (old_output_id != window->monitor->output && + flags & META_IS_MOVE_ACTION && flags & META_IS_USER_ACTION) + window->preferred_output = window->monitor->output; + /* Invariants leaving this function are: * a) window->rect and frame->rect reflect the actual * server-side size/pos of window->xwindow and frame->xwindow @@ -5536,6 +5556,7 @@ meta_window_move_to_monitor (MetaWindow *window, window->tile_monitor_number = monitor; meta_window_move_between_rects (window, &old_area, &new_area); + window->preferred_output = window->monitor->output; } void -- 2.1.0 From 6d39e1a72f8914d6a021d801940ab8a6c13d16f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 20 Jun 2014 18:06:40 +0200 Subject: [PATCH 2/2] window: Add user_op parameter to update_monitor() When workspaces-only-on-primary is set and a window is moved back to the primary, we also move it to the active workspace to avoid the confusion of a visible window suddenly disappearing when crossing the monitor border. However when the window is not actually moved by the user, preserving the workspace makes more sense - we already do this in some cases (e.g. when moving between primary monitors), but miss others (unplugging the previous monitor); just add an explicit user_op parameter as used elsewhere to cover all exceptions. https://bugzilla.gnome.org/show_bug.cgi?id=731760 --- src/core/window-private.h | 1 - src/core/window.c | 30 ++++++++++++++---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/core/window-private.h b/src/core/window-private.h index 9a0c760..1a39a4b 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -677,5 +677,4 @@ gboolean meta_window_can_tile_side_by_side (MetaWindow *window); void meta_window_compute_tile_match (MetaWindow *window); gboolean meta_window_updates_are_frozen (MetaWindow *window); - #endif diff --git a/src/core/window.c b/src/core/window.c index 8b8fbe7..f376ea0 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -145,7 +145,8 @@ static void meta_window_move_between_rects (MetaWindow *window, static void unmaximize_window_before_freeing (MetaWindow *window); static void unminimize_window_and_all_transient_parents (MetaWindow *window); -static void meta_window_update_monitor (MetaWindow *window); +static void meta_window_update_monitor (MetaWindow *window, + gboolean user_op); /* Idle handlers for the three queues (run with meta_later_add()). The * "data" parameter in each case will be a GINT_TO_POINTER of the @@ -4809,7 +4810,7 @@ meta_window_update_for_monitors_changed (MetaWindow *window) if (window->override_redirect) { - meta_window_update_monitor (window); + meta_window_update_monitor (window, FALSE); return; } @@ -4842,7 +4843,8 @@ meta_window_update_for_monitors_changed (MetaWindow *window) } static void -meta_window_update_monitor (MetaWindow *window) +meta_window_update_monitor (MetaWindow *window, + gboolean user_op) { const MetaMonitorInfo *old; @@ -4852,22 +4854,17 @@ meta_window_update_monitor (MetaWindow *window) { meta_window_update_on_all_workspaces (window); - /* If workspaces only on primary and we moved back to primary, ensure that the - * window is now in that workspace. We do this because while the window is on a - * non-primary monitor it is always visible, so it would be very jarring if it - * disappeared when it crossed the monitor border. + /* If workspaces only on primary and we moved back to primary due to a user action, + * ensure that the window is now in that workspace. We do this because while + * the window is on a non-primary monitor it is always visible, so it would be + * very jarring if it disappeared when it crossed the monitor border. * The one time we want it to both change to the primary monitor and a non-active * workspace is when dropping the window on some other workspace thumbnail directly. * That should be handled by explicitly moving the window before changing the - * workspace - * Don't do this if old == NULL, because thats what happens when starting up, and - * we don't want to move all windows around from a previous WM instance. Nor do - * we want it when moving from one primary monitor to another (can happen during - * screen reconfiguration. + * workspace. */ - if (meta_prefs_get_workspaces_only_on_primary () && + if (meta_prefs_get_workspaces_only_on_primary () && user_op && meta_window_is_on_primary_monitor (window) && - old != NULL && !old->is_primary && window->screen->active_workspace != window->workspace) meta_window_change_workspace (window, window->screen->active_workspace); @@ -4878,6 +4875,7 @@ meta_window_update_monitor (MetaWindow *window) /* If we're changing monitors, we need to update the has_maximize_func flag, * as the working area has changed. */ recalc_window_features (window); + meta_window_queue (window, META_QUEUE_CALC_SHOWING); } } @@ -5348,7 +5346,7 @@ meta_window_move_resize_internal (MetaWindow *window, old_output_id = window->monitor->output; - meta_window_update_monitor (window); + meta_window_update_monitor (window, flags & META_IS_USER_ACTION); if (old_output_id != window->monitor->output && flags & META_IS_MOVE_ACTION && flags & META_IS_USER_ACTION) @@ -5672,7 +5670,7 @@ meta_window_configure_notify (MetaWindow *window, window->rect.y = event->y; window->rect.width = event->width; window->rect.height = event->height; - meta_window_update_monitor (window); + meta_window_update_monitor (window, FALSE); /* Whether an override-redirect window is considered fullscreen depends * on its geometry. -- 2.1.0