[metacity] stack-tracker: apply some changes from mutter
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [metacity] stack-tracker: apply some changes from mutter
- Date: Sat, 1 Apr 2017 16:23:41 +0000 (UTC)
commit 273b9c498d69ee5e79d4dc8ce47c4391ed0ccfd0
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Sat Apr 1 12:26:14 2017 +0300
stack-tracker: apply some changes from mutter
https://git.gnome.org/browse/mutter/commit/?id=40e820f551e5d02dc8d9eecb55419fe00558c670
https://git.gnome.org/browse/mutter/commit/?id=b53bf0e8c2f84c93acbef5cb9d08fedce80b8013
https://git.gnome.org/browse/mutter/commit/?id=0be4622e14af0625472123dadb0648e25501f764
https://git.gnome.org/browse/mutter/commit/?id=a378faf495351244189ba893e8e7c2733e7311a6
https://git.gnome.org/browse/mutter/commit/?id=098c8908edf01a515d862bff1e8d37cd227370a9
https://git.gnome.org/browse/mutter/commit/?id=9711d95996c9ae3f0ccf5f82d2bb9aa7a5dda00f
https://git.gnome.org/browse/mutter/commit/?id=01b6d9bfe2dcb8c806c13877d2816edd7876ceec
https://git.gnome.org/browse/mutter/commit/?id=d1a588a94fba75c21a6b26b30a73c2087ad0c4e5
src/core/stack-tracker.c | 473 +++++++++++++++++++++++++++++++++++++++-------
src/core/stack.c | 199 +++++++++++---------
src/core/stack.h | 4 +-
3 files changed, 514 insertions(+), 162 deletions(-)
---
diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c
index ba64666..0fdb049 100644
--- a/src/core/stack-tracker.c
+++ b/src/core/stack-tracker.c
@@ -112,20 +112,25 @@ struct _MetaStackTracker
/* This is the last state of the stack as based on events received
* from the X server.
*/
- GArray *server_stack;
+ GArray *xserver_stack;
/* This is the serial of the last request we made that was reflected
- * in server_stack
+ * in xserver_stack.
*/
- gulong server_serial;
+ gulong xserver_serial;
+
+ /* A stack without any unverified operations applied.
+ */
+ GArray *verified_stack;
/* This is a queue of requests we've made to change the stacking order,
* where we haven't yet gotten a reply back from the server.
*/
- GQueue *queued_requests;
+ GQueue *unverified_predictions;
- /* This is how we think the stack is, based on server_stack, and
- * on requests we've made subsequent to server_stack
+ /* This is how we think the stack is, based on verified_stack, and
+ * on the unverified_predictions we've made subsequent to
+ * verified_stack.
*/
GArray *predicted_stack;
@@ -177,23 +182,33 @@ meta_stack_tracker_dump (MetaStackTracker *tracker)
meta_topic (META_DEBUG_STACK, "MetaStackTracker state (screen=%d)\n", tracker->screen->number);
meta_push_no_msg_prefix ();
- meta_topic (META_DEBUG_STACK, " server_serial: %ld\n", tracker->server_serial);
- meta_topic (META_DEBUG_STACK, " server_stack: ");
- for (i = 0; i < tracker->server_stack->len; i++)
- meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->server_stack, Window, i));
- if (tracker->predicted_stack)
+ meta_topic (META_DEBUG_STACK, " xserver_serial: %ld\n", tracker->xserver_serial);
+ meta_topic (META_DEBUG_STACK, " xserver_stack: ");
+ for (i = 0; i < tracker->xserver_stack->len; i++)
{
- meta_topic (META_DEBUG_STACK, "\n predicted_stack: ");
- for (i = 0; i < tracker->predicted_stack->len; i++)
- meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->predicted_stack, Window, i));
+ meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->xserver_stack, Window, i));
+ }
+ meta_topic (META_DEBUG_STACK, "\n verfied_stack: ");
+ for (i = 0; i < tracker->verified_stack->len; i++)
+ {
+ meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->verified_stack, Window, i));
}
- meta_topic (META_DEBUG_STACK, "\n queued_requests: [");
- for (l = tracker->queued_requests->head; l; l = l->next)
+ meta_topic (META_DEBUG_STACK, "\n unverified_predictions: [");
+ for (l = tracker->unverified_predictions->head; l; l = l->next)
{
MetaStackOp *op = l->data;
meta_stack_op_dump (op, "", l->next ? ", " : "");
}
meta_topic (META_DEBUG_STACK, "]\n");
+ if (tracker->predicted_stack)
+ {
+ meta_topic (META_DEBUG_STACK, "\n predicted_stack: ");
+ for (i = 0; i < tracker->predicted_stack->len; i++)
+ {
+ meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->predicted_stack, Window, i));
+ }
+ }
+ meta_topic (META_DEBUG_STACK, "\n");
meta_pop_no_msg_prefix ();
}
@@ -204,14 +219,16 @@ meta_stack_op_free (MetaStackOp *op)
}
static int
-find_window (GArray *stack,
+find_window (GArray *window_stack,
Window window)
{
guint i;
- for (i = 0; i < stack->len; i++)
- if (g_array_index (stack, Window, i) == window)
- return i;
+ for (i = 0; i < window_stack->len; i++)
+ {
+ if (g_array_index (window_stack, Window, i) == window)
+ return i;
+ }
return -1;
}
@@ -351,37 +368,61 @@ meta_stack_op_apply (MetaStackOp *op,
}
static GArray *
-copy_stack (Window *windows,
- guint n_windows)
+copy_stack (GArray *stack)
{
- GArray *stack = g_array_new (FALSE, FALSE, sizeof (Window));
+ GArray *copy = g_array_sized_new (FALSE, FALSE, sizeof (Window), stack->len);
+
+ g_array_set_size (copy, stack->len);
- g_array_set_size (stack, n_windows);
- memcpy (stack->data, windows, sizeof (Window) * n_windows);
+ memcpy (copy->data, stack->data, sizeof (Window) * stack->len);
- return stack;
+ return copy;
}
-MetaStackTracker *
-meta_stack_tracker_new (MetaScreen *screen)
+static void
+requery_xserver_stack (MetaStackTracker *tracker)
{
- MetaStackTracker *tracker;
+ MetaScreen *screen = tracker->screen;
Window ignored1, ignored2;
Window *children;
guint n_children;
+ guint i;
- tracker = g_new0 (MetaStackTracker, 1);
- tracker->screen = screen;
+ if (tracker->xserver_stack)
+ g_array_free (tracker->xserver_stack, TRUE);
- tracker->server_serial = XNextRequest (screen->display->xdisplay);
+ tracker->xserver_serial = XNextRequest (screen->display->xdisplay);
XQueryTree (screen->display->xdisplay,
screen->xroot,
&ignored1, &ignored2, &children, &n_children);
- tracker->server_stack = copy_stack (children, n_children);
+
+ tracker->xserver_stack = g_array_sized_new (FALSE, FALSE, sizeof (Window), n_children);
+ g_array_set_size (tracker->xserver_stack, n_children);
+
+ for (i = 0; i < n_children; i++)
+ {
+ g_array_index (tracker->xserver_stack, Window, i) = children[i];
+ }
+
XFree (children);
+}
+
+MetaStackTracker *
+meta_stack_tracker_new (MetaScreen *screen)
+{
+ MetaStackTracker *tracker;
+
+ tracker = g_new0 (MetaStackTracker, 1);
+ tracker->screen = screen;
+
+ requery_xserver_stack (tracker);
+
+ tracker->verified_stack = copy_stack (tracker->xserver_stack);
- tracker->queued_requests = g_queue_new ();
+ tracker->unverified_predictions = g_queue_new ();
+
+ meta_stack_tracker_dump (tracker);
return tracker;
}
@@ -392,23 +433,25 @@ meta_stack_tracker_free (MetaStackTracker *tracker)
if (tracker->sync_stack_idle)
g_source_remove (tracker->sync_stack_idle);
- g_array_free (tracker->server_stack, TRUE);
+ g_array_free (tracker->xserver_stack, TRUE);
+ g_array_free (tracker->verified_stack, TRUE);
if (tracker->predicted_stack)
g_array_free (tracker->predicted_stack, TRUE);
- g_queue_foreach (tracker->queued_requests, (GFunc)meta_stack_op_free, NULL);
- g_queue_free (tracker->queued_requests);
- tracker->queued_requests = NULL;
+ g_queue_foreach (tracker->unverified_predictions, (GFunc)meta_stack_op_free, NULL);
+ g_queue_free (tracker->unverified_predictions);
+ tracker->unverified_predictions = NULL;
g_free (tracker);
}
static void
-stack_tracker_queue_request (MetaStackTracker *tracker,
- MetaStackOp *op)
+stack_tracker_apply_prediction (MetaStackTracker *tracker,
+ MetaStackOp *op)
{
- meta_stack_op_dump (op, "Queueing: ", "\n");
- g_queue_push_tail (tracker->queued_requests, op);
+ meta_stack_op_dump (op, "Predicting: ", "\n");
+ g_queue_push_tail (tracker->unverified_predictions, op);
+
if (!tracker->predicted_stack ||
meta_stack_op_apply (op, tracker->predicted_stack))
meta_stack_tracker_queue_sync_stack (tracker);
@@ -427,7 +470,7 @@ meta_stack_tracker_record_add (MetaStackTracker *tracker,
op->any.serial = serial;
op->add.window = window;
- stack_tracker_queue_request (tracker, op);
+ stack_tracker_apply_prediction (tracker, op);
}
void
@@ -441,7 +484,7 @@ meta_stack_tracker_record_remove (MetaStackTracker *tracker,
op->any.serial = serial;
op->remove.window = window;
- stack_tracker_queue_request (tracker, op);
+ stack_tracker_apply_prediction (tracker, op);
}
void
@@ -454,7 +497,7 @@ meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
/* XRestackWindows() isn't actually a X requests - it's broken down
* by XLib into a series of XConfigureWindow(StackMode=below); we
- * mirror that exactly here.
+ * mirror that here.
*
* Aside: Having a separate StackOp for this would be possible to
* get some extra efficiency in memory allocation and in applying
@@ -481,7 +524,7 @@ meta_stack_tracker_record_raise_above (MetaStackTracker *tracker,
op->raise_above.window = window;
op->raise_above.sibling = sibling;
- stack_tracker_queue_request (tracker, op);
+ stack_tracker_apply_prediction (tracker, op);
}
void
@@ -497,7 +540,7 @@ meta_stack_tracker_record_lower_below (MetaStackTracker *tracker,
op->lower_below.window = window;
op->lower_below.sibling = sibling;
- stack_tracker_queue_request (tracker, op);
+ stack_tracker_apply_prediction (tracker, op);
}
void
@@ -508,34 +551,289 @@ meta_stack_tracker_record_lower (MetaStackTracker *tracker,
meta_stack_tracker_record_raise_above (tracker, window, None, serial);
}
-static void
-stack_tracker_event_received (MetaStackTracker *tracker,
- MetaStackOp *op)
+/* @op is an operation derived from an X event from the server and we
+ * want to verify that our predicted operations are consistent with
+ * what's being reported by the X server.
+ *
+ * This function applies all the unverified predicted operations up to
+ * the given @serial onto the verified_stack so that we can check the
+ * stack for consistency with the given X operation.
+ *
+ * Return value: %TRUE if the predicted state is consistent with
+ * receiving the given @op from X, else %FALSE.
+ *
+ * @modified will be set to %TRUE if tracker->verified_stack is
+ * changed by applying any newly validated operations, else %FALSE.
+ */
+static gboolean
+stack_tracker_verify_predictions (MetaStackTracker *tracker,
+ MetaStackOp *op,
+ gboolean *modified)
{
- gboolean need_sync = FALSE;
+ GArray *tmp_predicted_stack = NULL;
+ GArray *predicted_stack;
+ gboolean modified_stack = FALSE;
- meta_stack_op_dump (op, "Stack op event received: ", "\n");
+ if (tracker->unverified_predictions->length)
+ {
+ GList *l;
- if (op->any.serial < tracker->server_serial)
- return;
+ tmp_predicted_stack = predicted_stack = copy_stack (tracker->verified_stack);
- tracker->server_serial = op->any.serial;
+ for (l = tracker->unverified_predictions->head; l; l = l->next)
+ {
+ MetaStackOp *current_op = l->data;
+
+ if (current_op->any.serial > op->any.serial)
+ break;
+
+ modified_stack |= meta_stack_op_apply (current_op, predicted_stack);
+ }
+ }
+ else
+ predicted_stack = tracker->verified_stack;
+
+ switch (op->any.type)
+ {
+ case STACK_OP_ADD:
+ if (!find_window (predicted_stack, op->add.window))
+ {
+ meta_topic (META_DEBUG_STACK, "Verify STACK_OP_ADD: window %#lx not found\n", op->add.window);
+ goto not_verified;
+ }
+ break;
+ case STACK_OP_REMOVE:
+ if (!find_window (predicted_stack, op->remove.window))
+ {
+ meta_topic (META_DEBUG_STACK, "Verify STACK_OP_REMOVE: window %#lx not found\n",
op->remove.window);
+ goto not_verified;
+ }
+ break;
+ case STACK_OP_RAISE_ABOVE:
+ {
+ Window last_xwindow = None;
+ guint i;
+
+ for (i = 0; i < predicted_stack->len; i++)
+ {
+ Window xwindow = g_array_index (predicted_stack, Window, i);
+
+ if (xwindow == op->raise_above.window)
+ {
+ if (last_xwindow == op->raise_above.sibling)
+ goto verified;
+ else
+ goto not_verified;
+ }
+
+ last_xwindow = xwindow;
+ }
+
+ meta_topic (META_DEBUG_STACK, "Verify STACK_OP_RAISE_ABOVE: window %#lx not found\n",
op->raise_above.window);
+ goto not_verified;
+ }
+ break;
+ case STACK_OP_LOWER_BELOW:
+ g_warn_if_reached (); /* No X events currently lead to this path */
+ goto not_verified;
+ break;
+ default:
+ g_warn_if_reached ();
+ goto not_verified;
+ break;
+ }
- if (meta_stack_op_apply (op, tracker->server_stack))
- need_sync = TRUE;
+verified:
- while (tracker->queued_requests->head)
+ /* We can free the operations which we have now verified... */
+ while (tracker->unverified_predictions->head)
{
- MetaStackOp *queued_op = tracker->queued_requests->head->data;
+ MetaStackOp *queued_op = tracker->unverified_predictions->head->data;
+
if (queued_op->any.serial > op->any.serial)
break;
- g_queue_pop_head (tracker->queued_requests);
+ g_queue_pop_head (tracker->unverified_predictions);
meta_stack_op_free (queued_op);
- need_sync = TRUE;
}
- if (need_sync)
+ *modified = modified_stack;
+ if (modified_stack)
+ {
+ g_array_free (tracker->verified_stack, TRUE);
+ tracker->verified_stack = predicted_stack;
+ }
+ else if (tmp_predicted_stack)
+ g_array_free (tmp_predicted_stack, TRUE);
+
+ return TRUE;
+
+not_verified:
+
+ if (tmp_predicted_stack)
+ g_array_free (tmp_predicted_stack, TRUE);
+
+ if (tracker->predicted_stack)
+ {
+ g_array_free (tracker->predicted_stack, TRUE);
+ tracker->predicted_stack = NULL;
+ }
+
+ *modified = FALSE;
+
+ return FALSE;
+}
+
+/* If we find that our predicted state is not consistent with what the
+ * X server is reporting to us then this function can re-query and
+ * re-synchronize verified_stack with the X server stack.
+ *
+ * Return value: %TRUE if the verified stack was modified with respect
+ * to the predicted stack else %FALSE.
+ *
+ * Note: ->predicted_stack will be cleared by this function if
+ * ->verified_stack had to be modified when re-synchronizing.
+ */
+static gboolean
+resync_verified_stack_with_xserver_stack (MetaStackTracker *tracker)
+{
+ GList *l;
+ unsigned int i, j;
+ Window expected_xwindow;
+ gboolean modified_stack = FALSE;
+
+ /* Overview of the algorithm:
+ *
+ * - Re-query the complete X window stack from the X server via
+ * XQueryTree() and update xserver_stack.
+ *
+ * - Apply all operations in unverified_predictions to
+ * verified_stack so we have a predicted stack and free the
+ * queue of unverified_predictions.
+ *
+ * - Iterate through the x windows listed in verified_stack at the
+ * same time as iterating the windows in xserver_stack. (Stop
+ * when we reach the end of the xserver_stack)
+ * - If the window found doesn't match the window expected
+ * according to the order of xserver_stack then:
+ * - Look ahead for the window we were expecting and restack
+ * that above the previous X window. If we fail to find the
+ * expected window then create a new entry for it and stack
+ * that.
+ *
+ * - Continue to iterate through verified_stack for any remaining
+ * X windows that we now know aren't in the xserver_stack and
+ * remove them.
+ *
+ * - Free ->predicted_stack if any.
+ */
+
+ meta_topic (META_DEBUG_STACK, "Fully re-synchronizing X stack with verified stack\n");
+
+ requery_xserver_stack (tracker);
+
+ for (l = tracker->unverified_predictions->head; l; l = l->next)
+ {
+ meta_stack_op_apply (l->data, tracker->verified_stack);
+ meta_stack_op_free (l->data);
+ }
+ g_queue_clear (tracker->unverified_predictions);
+
+ j = 0;
+ expected_xwindow = g_array_index (tracker->xserver_stack, Window, j);
+
+ for (i = 0; i < tracker->verified_stack->len; )
+ {
+ Window current = g_array_index (tracker->verified_stack, Window, i);
+
+ if (current != expected_xwindow)
+ {
+ Window new;
+ Window expected;
+ int expected_index;
+
+ /* If the current window corresponds to a window that's not
+ * in xserver_stack any more then the least disruptive thing
+ * we can do is to simply remove it and take another look at
+ * the same index.
+ *
+ * Technically we only need to look forward from j if we
+ * wanted to optimize this a bit...
+ */
+ if (find_window (tracker->xserver_stack, current) < 0)
+ {
+ g_array_remove_index (tracker->verified_stack, i);
+ continue;
+ }
+
+ /* Technically we only need to look forward from i if we
+ * wanted to optimize this a bit...
+ */
+ expected_index = find_window (tracker->verified_stack, expected_xwindow);
+
+ if (expected_index >= 0)
+ {
+ expected = g_array_index (tracker->verified_stack, Window, expected_index);
+ }
+ else
+ {
+ new = expected_xwindow;
+
+ g_array_append_val (tracker->verified_stack, new);
+
+ expected = new;
+ expected_index = tracker->verified_stack->len - 1;
+ }
+
+ /* Note: that this move will effectively bump the index of
+ * the current window.
+ *
+ * We want to continue by re-checking this window against
+ * the next expected window though so we don't have to
+ * update i to compensate here.
+ */
+ move_window_above (tracker->verified_stack, expected,
+ expected_index, /* current index */
+ i - 1); /* above */
+ modified_stack = TRUE;
+ }
+
+ /* NB: we want to make sure that if we break the loop because j
+ * reaches the end of xserver_stack that i has also been
+ * incremented already so that we can run a final loop to remove
+ * remaining windows based on the i index.
+ */
+ i++;
+
+ j++;
+ expected_xwindow = g_array_index (tracker->xserver_stack, Window, j);
+
+ if (j >= tracker->xserver_stack->len)
+ break;
+ }
+
+ /* We now know that any remaining X windows aren't listed in the
+ * xserver_stack and so we can remove them.
+ */
+ while (i < tracker->verified_stack->len)
+ {
+ g_array_remove_index (tracker->verified_stack, i);
+
+ modified_stack = TRUE;
+ }
+
+ /* If we get to the end of verified_list and there are any remaining
+ * entries in xserver_stack then append them all to the end
+ */
+ for (; j < tracker->xserver_stack->len; j++)
+ {
+ Window current = g_array_index (tracker->xserver_stack, Window, j);
+ g_array_append_val (tracker->verified_stack, current);
+
+ modified_stack = TRUE;
+ }
+
+ if (modified_stack)
{
if (tracker->predicted_stack)
{
@@ -546,6 +844,45 @@ stack_tracker_event_received (MetaStackTracker *tracker,
meta_stack_tracker_queue_sync_stack (tracker);
}
+ return modified_stack;
+}
+
+static void
+stack_tracker_event_received (MetaStackTracker *tracker,
+ MetaStackOp *op)
+{
+ gboolean need_sync = FALSE;
+ gboolean verified;
+
+ /* If the event is older than our latest requery, then it's
+ * already included in our tree. Just ignore it.
+ */
+ if (op->any.serial < tracker->xserver_serial)
+ return;
+
+ meta_stack_op_dump (op, "Stack op event received: ", "\n");
+
+ tracker->xserver_serial = op->any.serial;
+
+ /* XXX: With the design we have ended up with it looks like we've
+ * ended up making it unnecessary to maintain tracker->xserver_stack
+ * since we only need an xserver_stack during the
+ * resync_verified_stack_with_xserver_stack() at which point we are
+ * going to query the full stack from the X server using
+ * XQueryTree() anyway.
+ *
+ * TODO: remove tracker->xserver_stack.
+ */
+ meta_stack_op_apply (op, tracker->xserver_stack);
+
+ verified = stack_tracker_verify_predictions (tracker, op, &need_sync);
+ if (!verified)
+ {
+ resync_verified_stack_with_xserver_stack (tracker);
+ meta_stack_tracker_dump (tracker);
+ return;
+ }
+
meta_stack_tracker_dump (tracker);
}
@@ -639,9 +976,9 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker,
{
GArray *stack;
- if (tracker->queued_requests->length == 0)
+ if (tracker->unverified_predictions->length == 0)
{
- stack = tracker->server_stack;
+ stack = tracker->verified_stack;
}
else
{
@@ -649,9 +986,8 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker,
{
GList *l;
- tracker->predicted_stack = copy_stack ((Window *)tracker->server_stack->data,
- tracker->server_stack->len);
- for (l = tracker->queued_requests->head; l; l = l->next)
+ tracker->predicted_stack = copy_stack (tracker->verified_stack);
+ for (l = tracker->unverified_predictions->head; l; l = l->next)
{
MetaStackOp *op = l->data;
meta_stack_op_apply (op, tracker->predicted_stack);
@@ -661,6 +997,9 @@ 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)
diff --git a/src/core/stack.c b/src/core/stack.c
index c0fcdbd..01fedb3 100644
--- a/src/core/stack.c
+++ b/src/core/stack.c
@@ -49,7 +49,7 @@
#define WINDOW_IN_STACK(w) (w->stack_position >= 0)
-static void stack_sync_to_server (MetaStack *stack);
+static void stack_sync_to_xserver (MetaStack *stack);
static void meta_window_set_stack_position_no_sync (MetaWindow *window,
int position);
static void stack_do_window_deletions (MetaStack *stack);
@@ -68,14 +68,14 @@ meta_stack_new (MetaScreen *screen)
stack = g_new (MetaStack, 1);
stack->screen = screen;
- stack->windows = g_array_new (FALSE, FALSE, sizeof (Window));
+ stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
stack->sorted = NULL;
stack->added = NULL;
stack->removed = NULL;
stack->freeze_count = 0;
- stack->last_root_children_stacked = NULL;
+ stack->last_all_root_children_stacked = NULL;
stack->n_positions = 0;
@@ -86,17 +86,24 @@ meta_stack_new (MetaScreen *screen)
return stack;
}
+static void
+free_last_all_root_children_stacked_cache (MetaStack *stack)
+{
+ g_array_free (stack->last_all_root_children_stacked, TRUE);
+ stack->last_all_root_children_stacked = NULL;
+}
+
void
meta_stack_free (MetaStack *stack)
{
- g_array_free (stack->windows, TRUE);
+ g_array_free (stack->xwindows, TRUE);
g_list_free (stack->sorted);
g_list_free (stack->added);
g_list_free (stack->removed);
- if (stack->last_root_children_stacked)
- g_array_free (stack->last_root_children_stacked, TRUE);
+ if (stack->last_all_root_children_stacked)
+ free_last_all_root_children_stacked_cache (stack);
g_free (stack);
}
@@ -120,7 +127,7 @@ meta_stack_add (MetaStack *stack,
"Window %s has stack_position initialized to %d\n",
window->desc, window->stack_position);
- stack_sync_to_server (stack);
+ stack_sync_to_xserver (stack);
}
void
@@ -155,7 +162,7 @@ meta_stack_remove (MetaStack *stack,
stack->removed = g_list_prepend (stack->removed,
GUINT_TO_POINTER (window->frame->xwindow));
- stack_sync_to_server (stack);
+ stack_sync_to_xserver (stack);
}
void
@@ -164,7 +171,7 @@ meta_stack_update_layer (MetaStack *stack,
{
stack->need_relayer = TRUE;
- stack_sync_to_server (stack);
+ stack_sync_to_xserver (stack);
}
void
@@ -173,7 +180,7 @@ meta_stack_update_transient (MetaStack *stack,
{
stack->need_constrain = TRUE;
- stack_sync_to_server (stack);
+ stack_sync_to_xserver (stack);
}
/* raise/lower within a layer */
@@ -201,7 +208,7 @@ meta_stack_raise (MetaStack *stack,
meta_window_set_stack_position_no_sync (window, max_stack_position);
- stack_sync_to_server (stack);
+ stack_sync_to_xserver (stack);
}
void
@@ -228,7 +235,7 @@ meta_stack_lower (MetaStack *stack,
meta_window_set_stack_position_no_sync (window, min_stack_position);
- stack_sync_to_server (stack);
+ stack_sync_to_xserver (stack);
}
void
@@ -243,7 +250,7 @@ meta_stack_thaw (MetaStack *stack)
g_return_if_fail (stack->freeze_count > 0);
stack->freeze_count -= 1;
- stack_sync_to_server (stack);
+ stack_sync_to_xserver (stack);
}
static gboolean
@@ -792,7 +799,7 @@ stack_do_window_deletions (MetaStack *stack)
/* We go from the end figuring removals are more
* likely to be recent.
*/
- i = stack->windows->len;
+ i = stack->xwindows->len;
while (i > 0)
{
--i;
@@ -803,9 +810,9 @@ stack_do_window_deletions (MetaStack *stack)
* both the window->xwindow and window->frame->xwindow
* in the removal list.
*/
- if (xwindow == g_array_index (stack->windows, Window, i))
+ if (xwindow == g_array_index (stack->xwindows, Window, i))
{
- g_array_remove_index (stack->windows, i);
+ g_array_remove_index (stack->xwindows, i);
goto next;
}
}
@@ -834,10 +841,10 @@ stack_do_window_additions (MetaStack *stack)
"Adding %d windows to sorted list\n",
n_added);
- old_size = stack->windows->len;
- g_array_set_size (stack->windows, old_size + n_added);
+ old_size = stack->xwindows->len;
+ g_array_set_size (stack->xwindows, old_size + n_added);
- end = &g_array_index (stack->windows, Window, old_size);
+ end = &g_array_index (stack->xwindows, Window, old_size);
/* stack->added has the most recent additions at the
* front of the list, so we need to reverse it
@@ -985,44 +992,23 @@ stack_ensure_sorted (MetaStack *stack)
stack_do_resort (stack);
}
-/**
- * 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)
+static Window
+find_top_most_managed_window (MetaScreen *screen,
+ Window ignore)
{
- Window *children;
- int n_children;
+ Window *windows;
+ int n_windows;
int i;
- meta_stack_tracker_get_stack (screen->stack_tracker, &children, &n_children);
+ 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.
*/
- i = n_children - 1;
- while (i >= 0)
+ for (i = n_windows - 1; i >= 0; i--)
{
- if (children[i] == xwindow)
+ 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
@@ -1038,50 +1024,77 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
{
MetaWindow *other;
- other = meta_display_lookup_x_window (screen->display, children[i]);
+ other = meta_display_lookup_x_window (screen->display, windows[i]);
if (other != NULL && !other->override_redirect)
- {
- XWindowChanges changes;
-
- /* children[i] is the topmost managed child */
- meta_topic (META_DEBUG_STACK,
- "Moving 0x%lx above topmost managed child window 0x%lx\n",
- xwindow, children[i]);
-
- changes.sibling = children[i];
- changes.stack_mode = Above;
-
- meta_error_trap_push (screen->display);
- meta_stack_tracker_record_raise_above (screen->stack_tracker,
- xwindow,
- children[i],
- XNextRequest (screen->display->xdisplay));
- XConfigureWindow (screen->display->xdisplay,
- xwindow,
- CWSibling | CWStackMode,
- &changes);
- meta_error_trap_pop (screen->display);
-
- break;
- }
+ return windows[i];
}
-
- --i;
}
- if (i < 0)
+ 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;
+ gulong serial;
+
+ sibling = find_top_most_managed_window (screen, xwindow);
+
+ if (sibling == None)
{
+ meta_error_trap_push (screen->display);
+ serial = XNextRequest (screen->display->xdisplay);
+ XLowerWindow (screen->display->xdisplay, xwindow);
+ meta_error_trap_pop (screen->display);
+
/* No sibling to use, just lower ourselves to the bottom
* to be sure we're below any override redirect windows.
*/
+ meta_stack_tracker_record_lower (screen->stack_tracker, xwindow, serial);
+ }
+ else
+ {
+ XWindowChanges changes;
+
+ /* sibling is the topmost managed child */
+ meta_topic (META_DEBUG_STACK,
+ "Moving 0x%lx above topmost managed child window 0x%lx\n",
+ xwindow, sibling);
+
+ changes.sibling = sibling;
+ changes.stack_mode = Above;
+
meta_error_trap_push (screen->display);
- meta_stack_tracker_record_lower (screen->stack_tracker,
- xwindow,
- XNextRequest (screen->display->xdisplay));
- XLowerWindow (screen->display->xdisplay,
- xwindow);
+ serial = XNextRequest (screen->display->xdisplay);
+ XConfigureWindow (screen->display->xdisplay, xwindow,
+ CWSibling | CWStackMode, &changes);
meta_error_trap_pop (screen->display);
+
+ meta_stack_tracker_record_raise_above (screen->stack_tracker,
+ xwindow, sibling, serial);
}
}
@@ -1097,7 +1110,7 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
* job of computing the minimal set of stacking requests needed.
*/
static void
-stack_sync_to_server (MetaStack *stack)
+stack_sync_to_xserver (MetaStack *stack)
{
GArray *stacked;
GArray *root_children_stacked;
@@ -1159,7 +1172,7 @@ stack_sync_to_server (MetaStack *stack)
meta_error_trap_push (stack->screen->display);
- if (stack->last_root_children_stacked == NULL)
+ if (stack->last_all_root_children_stacked == NULL)
{
/* Just impose our stack, we don't know the previous state.
* This involves a ton of circulate requests and may flicker.
@@ -1181,13 +1194,13 @@ stack_sync_to_server (MetaStack *stack)
{
/* 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_root_children_stacked
+ * 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...
*/
- const Window *old_stack = (Window *) stack->last_root_children_stacked->data;
+ const Window *old_stack = (Window *) stack->last_all_root_children_stacked->data;
const Window *new_stack = (Window *) root_children_stacked->data;
- const int old_len = stack->last_root_children_stacked->len;
+ const int old_len = stack->last_all_root_children_stacked->len;
const int new_len = root_children_stacked->len;
const Window *oldp = old_stack;
const Window *newp = new_stack;
@@ -1284,8 +1297,8 @@ stack_sync_to_server (MetaStack *stack)
stack->screen->display->atom__NET_CLIENT_LIST,
XA_WINDOW,
32, PropModeReplace,
- (unsigned char *)stack->windows->data,
- stack->windows->len);
+ (unsigned char *)stack->xwindows->data,
+ stack->xwindows->len);
XChangeProperty (stack->screen->display->xdisplay,
stack->screen->xroot,
stack->screen->display->atom__NET_CLIENT_LIST_STACKING,
@@ -1296,9 +1309,9 @@ stack_sync_to_server (MetaStack *stack)
g_array_free (stacked, TRUE);
- if (stack->last_root_children_stacked)
- g_array_free (stack->last_root_children_stacked, TRUE);
- stack->last_root_children_stacked = root_children_stacked;
+ if (stack->last_all_root_children_stacked)
+ free_last_all_root_children_stacked_cache (stack);
+ stack->last_all_root_children_stacked = root_children_stacked;
/* That was scary... */
}
@@ -1614,7 +1627,7 @@ meta_stack_set_positions (MetaStack *stack,
meta_topic (META_DEBUG_STACK,
"Reset the stack positions of (nearly) all windows\n");
- stack_sync_to_server (stack);
+ stack_sync_to_xserver (stack);
}
void
@@ -1676,5 +1689,5 @@ meta_window_set_stack_position (MetaWindow *window,
int position)
{
meta_window_set_stack_position_no_sync (window, position);
- stack_sync_to_server (window->screen->stack);
+ stack_sync_to_xserver (window->screen->stack);
}
diff --git a/src/core/stack.h b/src/core/stack.h
index 43e0f67..fcce679 100644
--- a/src/core/stack.h
+++ b/src/core/stack.h
@@ -74,7 +74,7 @@ struct _MetaStack
* A sequence of all the Windows (X handles, not MetaWindows) of the windows
* we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST.
*/
- GArray *windows;
+ GArray *xwindows;
/** The MetaWindows of the windows we manage, sorted in order. */
GList *sorted;
@@ -113,7 +113,7 @@ struct _MetaStack
* The last-known stack of all windows, bottom to top. We cache it here
* so that subsequent times we'll be able to do incremental moves.
*/
- GArray *last_root_children_stacked;
+ GArray *last_all_root_children_stacked;
/**
* Number of stack positions; same as the length of added, but
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]