Move compositor-stack handling to MetaStackTracker

In order to properly track the stacking order for override-redirect
windows, move meta_compositor_sync_stack() call into MetaStackTracker.
In the new location, we sync the stack as a before-redraw idle function,
rather then using the freeze-thaw facilities of MetaStack. This is
simpler, and also properly compresses multiple stack changes on
notifications received from the X server.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
This commit is contained in:
Owen W. Taylor
2009-06-14 08:04:28 -04:00
parent a4cd66f599
commit 6314ee8780
5 changed files with 135 additions and 32 deletions

View File

@@ -27,6 +27,8 @@
#include "stack-tracker.h"
#include "util.h"
#include "compositor.h"
/* The complexity here comes from resolving two competing factors:
*
* - We need to have a view of the stacking order that takes into
@@ -128,6 +130,11 @@ struct _MetaStackTracker
* on requests we've made subsequent to server_stack
*/
GArray *predicted_stack;
/* Idle function used to sync the compositor's view of the window
* stack up with our best guess before a frame is drawn.
*/
guint sync_stack_idle;
};
static void
@@ -209,7 +216,8 @@ find_window (GArray *stack,
return -1;
}
static void
/* Returns TRUE if stack was changed */
static gboolean
move_window_above (GArray *stack,
Window window,
int old_pos,
@@ -223,6 +231,8 @@ move_window_above (GArray *stack,
g_array_index (stack, Window, i) = g_array_index (stack, Window, i + 1);
g_array_index (stack, Window, above_pos) = window;
return TRUE;
}
else if (old_pos > above_pos + 1)
{
@@ -230,10 +240,15 @@ move_window_above (GArray *stack,
g_array_index (stack, Window, i) = g_array_index (stack, Window, i - 1);
g_array_index (stack, Window, above_pos + 1) = window;
return TRUE;
}
else
return FALSE;
}
static void
/* Returns TRUE if stack was changed */
static gboolean
meta_stack_op_apply (MetaStackOp *op,
GArray *stack)
{
@@ -246,11 +261,11 @@ meta_stack_op_apply (MetaStackOp *op,
{
g_warning ("STACK_OP_ADD: window %#lx already in stack",
op->add.window);
return;
return FALSE;
}
g_array_append_val (stack, op->add.window);
break;
return TRUE;
}
case STACK_OP_REMOVE:
{
@@ -259,11 +274,11 @@ meta_stack_op_apply (MetaStackOp *op,
{
g_warning ("STACK_OP_REMOVE: window %#lx not in stack",
op->remove.window);
return;
return FALSE;
}
g_array_remove_index (stack, old_pos);
break;
return TRUE;
}
case STACK_OP_RAISE_ABOVE:
{
@@ -273,7 +288,7 @@ meta_stack_op_apply (MetaStackOp *op,
{
g_warning ("STACK_OP_RAISE_ABOVE: window %#lx not in stack",
op->raise_above.window);
return;
return FALSE;
}
if (op->raise_above.sibling != None)
@@ -283,7 +298,7 @@ meta_stack_op_apply (MetaStackOp *op,
{
g_warning ("STACK_OP_RAISE_ABOVE: sibling window %#lx not in stack",
op->raise_above.sibling);
return;
return FALSE;
}
}
else
@@ -291,8 +306,7 @@ meta_stack_op_apply (MetaStackOp *op,
above_pos = -1;
}
move_window_above (stack, op->raise_above.window, old_pos, above_pos);
break;
return move_window_above (stack, op->raise_above.window, old_pos, above_pos);
}
case STACK_OP_LOWER_BELOW:
{
@@ -302,7 +316,7 @@ meta_stack_op_apply (MetaStackOp *op,
{
g_warning ("STACK_OP_LOWER_BELOW: window %#lx not in stack",
op->lower_below.window);
return;
return FALSE;
}
if (op->lower_below.sibling != None)
@@ -312,7 +326,7 @@ meta_stack_op_apply (MetaStackOp *op,
{
g_warning ("STACK_OP_LOWER_BELOW: sibling window %#lx not in stack",
op->lower_below.sibling);
return;
return FALSE;
}
above_pos = below_pos - 1;
@@ -322,10 +336,12 @@ meta_stack_op_apply (MetaStackOp *op,
above_pos = stack->len - 1;
}
move_window_above (stack, op->lower_below.window, old_pos, above_pos);
break;
return move_window_above (stack, op->lower_below.window, old_pos, above_pos);
}
}
g_assert_not_reached ();
return FALSE;
}
static GArray *
@@ -367,6 +383,9 @@ meta_stack_tracker_new (MetaScreen *screen)
void
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);
if (tracker->predicted_stack)
g_array_free (tracker->predicted_stack, TRUE);
@@ -382,8 +401,10 @@ stack_tracker_queue_request (MetaStackTracker *tracker,
{
meta_stack_op_dump (op, "Queueing: ", "\n");
g_queue_push_tail (tracker->queued_requests, op);
if (tracker->predicted_stack)
meta_stack_op_apply (op, tracker->predicted_stack);
if (!tracker->predicted_stack ||
meta_stack_op_apply (op, tracker->predicted_stack))
meta_stack_tracker_queue_sync_stack (tracker);
meta_stack_tracker_dump (tracker);
}
@@ -509,6 +530,8 @@ stack_tracker_event_received (MetaStackTracker *tracker,
}
meta_stack_tracker_dump (tracker);
meta_stack_tracker_queue_sync_stack (tracker);
}
void
@@ -628,3 +651,78 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker,
if (n_windows)
*n_windows = stack->len;
}
/**
* meta_stack_tracker_sync_stack:
* @tracker: a #MetaStackTracker
*
* Informs the compositor of the current stacking order of windows,
* based on the predicted view maintained by the #MetaStackTracker.
*/
void
meta_stack_tracker_sync_stack (MetaStackTracker *tracker)
{
GList *meta_windows;
Window *windows;
int n_windows;
int i;
if (tracker->sync_stack_idle)
{
g_source_remove (tracker->sync_stack_idle);
tracker->sync_stack_idle = 0;
}
meta_stack_tracker_get_stack (tracker, &windows, &n_windows);
meta_windows = NULL;
for (i = 0; i < n_windows; i++)
{
MetaWindow *meta_window;
meta_window = meta_display_lookup_x_window (tracker->screen->display,
windows[i]);
if (meta_window)
meta_windows = g_list_prepend (meta_windows, meta_window);
}
meta_compositor_sync_stack (tracker->screen->display->compositor,
tracker->screen,
meta_windows);
g_list_free (meta_windows);
meta_screen_restacked (tracker->screen);
}
static gboolean
stack_tracker_sync_stack_idle (gpointer data)
{
meta_stack_tracker_sync_stack (data);
return FALSE;
}
/**
* meta_stack_tracker_queue_sync_stack:
* @tracker: a #MetaStackTracker
*
* Queue informing the compositor of the new stacking order before the
* next redraw. (See meta_stack_tracker_sync_stack()). This is called
* internally when the stack of X windows changes, but also needs be
* called directly when we an undecorated window is first shown or
* withdrawn since the compositor's stacking order (which contains only
* the windows that have a corresponding MetaWindow) will change without
* any change to the stacking order of the X windows, if we are creating
* or destroying MetaWindows.
*/
void
meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker)
{
if (tracker->sync_stack_idle == 0)
{
tracker->sync_stack_idle = g_idle_add_full (META_PRIORITY_BEFORE_REDRAW,
stack_tracker_sync_stack_idle,
tracker, NULL);
}
}