[metacity] move logic for syncing the stack to the X server into MetaStackTracker
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [metacity] move logic for syncing the stack to the X server into MetaStackTracker
- Date: Sat, 1 Apr 2017 16:24:22 +0000 (UTC)
commit 0eb69c9d1b40128e547c898d40d8963171470f98
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Sat Apr 1 14:39:13 2017 +0300
move logic for syncing the stack to the X server into MetaStackTracker
https://git.gnome.org/browse/mutter/commit/?id=04bc846ef366964505abbb016c383becfb5fca88
src/core/stack-tracker.c | 120 ++++++++++++++++++++++---
src/core/stack-tracker.h | 25 +++---
src/core/stack.c | 226 ++--------------------------------------------
3 files changed, 130 insertions(+), 241 deletions(-)
---
diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c
index 7f1c7fc..ea66576 100644
--- a/src/core/stack-tracker.c
+++ b/src/core/stack-tracker.c
@@ -749,9 +749,6 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker,
stack = tracker->predicted_stack;
}
- meta_topic (META_DEBUG_STACK, "Get Stack\n");
- meta_stack_tracker_dump (tracker);
-
if (windows)
*windows = (Window *)stack->data;
if (n_windows)
@@ -903,18 +900,113 @@ meta_stack_tracker_raise_above (MetaStackTracker *tracker,
}
void
-meta_stack_tracker_restack_windows (MetaStackTracker *tracker,
- const Window *windows,
- int n_windows)
+meta_stack_tracker_restack_managed (MetaStackTracker *tracker,
+ const Window *managed,
+ int n_managed)
{
- int i;
+ MetaDisplay *display;
+ Window *windows;
+ int n_windows;
+ int old_pos;
+ int new_pos;
- /* XRestackWindows() isn't actually a X requests - it's broken down
- * by XLib into a series of XConfigureWindow(StackMode=below); we
- * just do the same here directly. The main disadvantage of is that
- * we allocate individual ops for each lower, and also that we are
- * grabbing the libX11 lock separately for individual component.
+ if (n_managed == 0)
+ return;
+
+ display = tracker->screen->display;
+
+ meta_stack_tracker_get_stack (tracker, &windows, &n_windows);
+
+ /* If the top window has to be restacked, we don't want to move it to the very
+ * top of the stack, since apps expect override-redirect windows to stay near
+ * the top of the X stack; we instead move it above all managed windows (or
+ * above the guard window if there are no non-hidden managed windows.)
*/
- for (i = 0; i < n_windows - 1; i++)
- meta_stack_tracker_lower_below (tracker, windows[i + 1], windows[i]);
+ old_pos = n_windows - 1;
+ for (old_pos = n_windows - 1; old_pos >= 0; old_pos--)
+ {
+ MetaWindow *old_window;
+
+ old_window = meta_display_lookup_x_window (display, windows[old_pos]);
+
+ if (old_window && !old_window->override_redirect)
+ break;
+ }
+
+ g_assert (old_pos >= 0);
+
+ new_pos = n_managed - 1;
+ if (managed[new_pos] != windows[old_pos])
+ {
+ /* Move the first managed window in the new stack above
+ * all managed windows
+ */
+ meta_stack_tracker_raise_above (tracker, managed[new_pos], windows[old_pos]);
+ meta_stack_tracker_get_stack (tracker, &windows, &n_windows);
+ /* Moving managed[new_pos] above windows[old_pos], moves
+ * the window at old_pos down by one
+ */
+ }
+
+ old_pos--;
+ new_pos--;
+
+ while (old_pos >= 0 && new_pos >= 0)
+ {
+ MetaWindow *old_window;
+
+ if (windows[old_pos] == managed[new_pos])
+ {
+ old_pos--;
+ new_pos--;
+ continue;
+ }
+
+ old_window = meta_display_lookup_x_window (display, windows[old_pos]);
+ if (!old_window || old_window->override_redirect)
+ {
+ old_pos--;
+ continue;
+ }
+
+ meta_stack_tracker_lower_below (tracker, managed[new_pos], managed[new_pos + 1]);
+ meta_stack_tracker_get_stack (tracker, &windows, &n_windows);
+ /* Moving managed[new_pos] above windows[old_pos] moves the window
+ * at old_pos down by one, we'll examine it again to see if it
+ * matches the next new window
+ */
+ old_pos--;
+ new_pos--;
+ }
+
+ while (new_pos >= 0)
+ {
+ meta_stack_tracker_lower_below (tracker, managed[new_pos], managed[new_pos - 1]);
+ new_pos--;
+ }
+}
+
+void
+meta_stack_tracker_restack_at_bottom (MetaStackTracker *tracker,
+ const Window *new_order,
+ int n_new_order)
+{
+ Window *windows;
+ int n_windows;
+ int pos;
+
+ meta_stack_tracker_get_stack (tracker, &windows, &n_windows);
+
+ for (pos = 0; pos < n_new_order; pos++)
+ {
+ if (pos >= n_windows || windows[pos] != new_order[pos])
+ {
+ if (pos == 0)
+ meta_stack_tracker_lower (tracker, new_order[pos]);
+ else
+ meta_stack_tracker_raise_above (tracker, new_order[pos], new_order[pos - 1]);
+
+ meta_stack_tracker_get_stack (tracker, &windows, &n_windows);
+ }
+ }
}
diff --git a/src/core/stack-tracker.h b/src/core/stack-tracker.h
index 6947301..0e6c5a1 100644
--- a/src/core/stack-tracker.h
+++ b/src/core/stack-tracker.h
@@ -64,17 +64,20 @@ void meta_stack_tracker_record_lower (MetaStackTracker *tracker,
/* We also have functions that also go ahead and do the work
*/
-void meta_stack_tracker_raise_above (MetaStackTracker *tracker,
- Window window,
- Window sibling);
-void meta_stack_tracker_lower_below (MetaStackTracker *tracker,
- Window window,
- Window sibling);
-void meta_stack_tracker_lower (MetaStackTracker *tracker,
- Window window);
-void meta_stack_tracker_restack_windows (MetaStackTracker *tracker,
- const Window *windows,
- int n_windows);
+void meta_stack_tracker_raise_above (MetaStackTracker *tracker,
+ Window window,
+ Window sibling);
+void meta_stack_tracker_lower_below (MetaStackTracker *tracker,
+ Window window,
+ Window sibling);
+void meta_stack_tracker_lower (MetaStackTracker *tracker,
+ Window window);
+void meta_stack_tracker_restack_managed (MetaStackTracker *tracker,
+ const Window *windows,
+ int n_windows);
+void meta_stack_tracker_restack_at_bottom (MetaStackTracker *tracker,
+ const Window *new_order,
+ int n_new_order);
/* These functions are used to update the stack when we get events
* reflecting changes to the stacking order */
diff --git a/src/core/stack.c b/src/core/stack.c
index 5e1db12..8baa385 100644
--- a/src/core/stack.c
+++ b/src/core/stack.c
@@ -981,94 +981,6 @@ stack_ensure_sorted (MetaStack *stack)
stack_do_resort (stack);
}
-static Window
-find_top_most_managed_window (MetaScreen *screen,
- Window ignore)
-{
- Window *windows;
- int n_windows;
- int i;
-
- meta_stack_tracker_get_stack (screen->stack_tracker, &windows, &n_windows);
-
- /* Children are in order from bottom to top. We want to
- * find the topmost managed child, then configure
- * our window to be above it.
- */
- for (i = n_windows - 1; i >= 0; i--)
- {
- if (windows[i] == ignore)
- {
- /* Do nothing. This means we're already the topmost managed
- * window, but it DOES NOT mean we are already just above
- * the topmost managed window. This is important because if
- * an override redirect window is up, and we map a new
- * managed window, the new window is probably above the old
- * popup by default, and we want to push it below that
- * popup. So keep looking for a sibling managed window
- * to be moved below.
- */
- }
- else
- {
- MetaWindow *other;
-
- other = meta_display_lookup_x_window (screen->display, windows[i]);
-
- if (other != NULL && !other->override_redirect)
- return windows[i];
- }
- }
-
- return None;
-}
-
-/**
- * This function is used to avoid raising a window above popup
- * menus and other such things.
- *
- * The key to the operation of this function is that we are expecting
- * at most one window to be added at a time. If xwindow is newly added,
- * then its own stack position will be too high (the frame window
- * is created at the top of the stack), but if we ignore xwindow,
- * then the *next* managed window in the stack will be a window that
- * we've already stacked.
- *
- * We could generalize this and remove the assumption that windows
- * are added one at a time by keeping an explicit ->stacked flag in
- * MetaWindow.
- *
- * An alternate approach would be to reverse the stacking algorithm to
- * work by placing each window above the others, and start by lowering
- * a window to the bottom (instead of the current way, which works by
- * placing each window below another and starting with a raise)
- */
-static void
-raise_window_relative_to_managed_windows (MetaScreen *screen,
- Window xwindow)
-{
- Window sibling;
-
- sibling = find_top_most_managed_window (screen, xwindow);
-
- if (sibling == None)
- {
- /* No sibling to use, just lower ourselves to the bottom
- * to be sure we're below any override redirect windows.
- */
- meta_stack_tracker_lower (screen->stack_tracker, xwindow);
- }
- else
- {
- /* sibling is the topmost managed child */
- meta_topic (META_DEBUG_STACK,
- "Moving 0x%lx above topmost managed child window 0x%lx\n",
- xwindow, sibling);
-
- meta_stack_tracker_raise_above (screen->stack_tracker, xwindow, sibling);
- }
-}
-
/**
* Order the windows on the X server to be the same as in our structure.
* We do this using XRestackWindows if we don't know the previous order,
@@ -1095,42 +1007,31 @@ stack_sync_to_xserver (MetaStack *stack)
stack_ensure_sorted (stack);
- /* Create stacked xwindow arrays.
- * Painfully, "stacked" is in bottom-to-top order for the
- * _NET hints, and "root_children_stacked" is in top-to-bottom
- * order for XRestackWindows()
- */
+ /* Create stacked xwindow arrays, in bottom-to-top order */
stacked = g_array_new (FALSE, FALSE, sizeof (Window));
root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
meta_topic (META_DEBUG_STACK, "Top to bottom: ");
meta_push_no_msg_prefix ();
- tmp = stack->sorted;
- while (tmp != NULL)
+ for (tmp = g_list_last (stack->sorted); tmp != NULL; tmp = tmp->prev)
{
MetaWindow *w;
w = tmp->data;
if (w->unmanaging)
- {
- tmp = tmp->next;
- continue;
- }
+ continue;
+
+ meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
+ w->layer, w->stack_position, w->desc);
- /* remember, stacked is in reverse order (bottom to top) */
g_array_prepend_val (stacked, w->xwindow);
- /* build XRestackWindows() array from top to bottom */
if (w->frame)
g_array_append_val (root_children_stacked, w->frame->xwindow);
else
g_array_append_val (root_children_stacked, w->xwindow);
-
- meta_topic (META_DEBUG_STACK, "%u:%d - %s ", w->layer, w->stack_position, w->desc);
-
- tmp = tmp->next;
}
meta_topic (META_DEBUG_STACK, "\n");
@@ -1141,115 +1042,9 @@ stack_sync_to_xserver (MetaStack *stack)
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
root_children_stacked->len);
- meta_error_trap_push (stack->screen->display);
-
- if (root_children_stacked->len > 0)
- {
- /* Try to do minimal window moves to get the stack in order */
- /* A point of note: these arrays include frames not client windows,
- * so if a client window has changed frame since last_all_root_children_stacked
- * was saved, then we may have inefficiency, but I don't think things
- * break...
- */
- Window *old_stack;
- int old_len;
- Window *new_stack;
- int new_len;
- const Window *oldp;
- const Window *newp;
- const Window *old_end;
- const Window *new_end;
- Window last_window;
-
- meta_stack_tracker_get_stack (stack->screen->stack_tracker,
- &old_stack, &old_len);
-
- new_stack = (Window *) root_children_stacked->data;
- new_len = root_children_stacked->len;
-
- oldp = old_stack;
- newp = new_stack;
-
- old_end = old_stack + old_len;
- new_end = new_stack + new_len;
-
- last_window = None;
-
- while (oldp != old_end &&
- newp != new_end)
- {
- MetaWindow *old_window;
-
- if (*oldp == *newp)
- {
- /* Stacks are the same here, move on */
- ++oldp;
- last_window = *newp;
- ++newp;
-
- continue;
- }
-
- old_window = meta_display_lookup_x_window (stack->screen->display, *oldp);
-
- if (old_window == NULL || old_window->override_redirect)
- {
- /* *oldp is not known to us (probably unmanaged), or
- * override_redirect, so we should skip it.
- */
- ++oldp;
- }
- else
- {
- /* Move *newp below last_window */
- if (last_window == None)
- {
- meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n",
*newp);
-
- raise_window_relative_to_managed_windows (stack->screen,
- *newp);
- }
- else
- {
- /* This means that if last_window is dead, but not
- * *newp, then we fail to restack *newp; but on
- * unmanaging last_window, we'll fix it up.
- */
-
- meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
- *newp, last_window);
-
- meta_stack_tracker_lower_below (stack->screen->stack_tracker,
- *newp, last_window);
- }
-
- last_window = *newp;
- ++newp;
- }
- }
-
- if (newp != new_end)
- {
- /* Restack remaining windows */
- meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n",
- (int) (new_end - newp));
-
- /* We need to include an already-stacked window
- * in the restack call, so we get in the proper position
- * with respect to it.
- */
- if (newp != new_stack)
- --newp;
- meta_stack_tracker_restack_windows (stack->screen->stack_tracker,
- newp, new_end - newp);
- }
- }
-
- meta_error_trap_pop (stack->screen->display);
- /* on error, a window was destroyed; it should eventually
- * get removed from the stacking list when we unmanage it
- * and we'll fix stacking at that time.
- */
+ meta_stack_tracker_restack_managed (stack->screen->stack_tracker,
+ (Window *)root_children_stacked->data,
+ root_children_stacked->len);
/* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */
@@ -1269,8 +1064,7 @@ stack_sync_to_xserver (MetaStack *stack)
stacked->len);
g_array_free (stacked, TRUE);
-
- /* That was scary... */
+ g_array_free (root_children_stacked, TRUE);
}
MetaWindow*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]