[stacking] Simplifies the way compositor code has to handle stacking

The compositor now gets handed a GList of MetaWindows when the stacking
gets syncd with the X server.
This commit is contained in:
Robert Bragg 2008-10-30 22:09:48 +00:00
parent 7ec7a8fa44
commit 6d8baea4c2
7 changed files with 46 additions and 252 deletions

View File

@ -79,8 +79,8 @@ struct _MetaCompositor
MetaWorkspace *to,
MetaMotionDirection direction);
void (*ensure_stack_order) (MetaCompositor *compositor,
MetaScreen *screen);
void (*sync_stack) (MetaCompositor *compositor,
GList *stack);
};
#endif

View File

@ -243,11 +243,12 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
}
void
meta_compositor_ensure_stack_order (MetaCompositor *compositor,
MetaScreen *screen)
meta_compositor_sync_stack (MetaCompositor *compositor,
GList *stack)
{
#ifdef HAVE_COMPOSITE_EXTENSIONS
if (compositor && compositor->ensure_stack_order)
compositor->ensure_stack_order (compositor, screen);
if (compositor && compositor->sync_stack)
compositor->sync_stack (compositor, stack);
#endif
}

View File

@ -1073,157 +1073,6 @@ destroy_win (MutterWindow *cw, gboolean no_effect)
}
}
static void
restack_win (MutterWindow *cw, Window above)
{
MutterWindowPrivate *priv = cw->priv;
MetaScreen *screen = priv->screen;
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
Window previous_above;
GList *sibling, *next;
gboolean hide = FALSE;
gboolean live_mode;
live_mode = meta_prefs_get_live_hidden_windows ();
if (priv->window && meta_window_is_hidden (priv->window))
hide = TRUE;
sibling = g_list_find (info->windows, (gconstpointer) cw);
next = g_list_next (sibling);
previous_above = None;
if (next)
{
MutterWindow *ncw = next->data;
previous_above = ncw->priv->xwindow;
}
/* If above is set to None, the window whose state was changed is on
* the bottom of the stack with respect to sibling.
*/
if (above == None)
{
#if 0
printf ("Raising to top %p [0x%x] (%s)\n",
cw, (guint) priv->xwindow,
priv->window ? priv->window->desc : "unknown");
#endif
/* Insert at bottom of window stack */
CHECK_LIST_INTEGRITY_START(info->windows)
info->windows = g_list_delete_link (info->windows, sibling);
info->windows = g_list_append (info->windows, cw);
CHECK_LIST_INTEGRITY_END(info->windows)
if (!info->switch_workspace_in_progress)
{
clutter_actor_raise_top (CLUTTER_ACTOR (cw));
}
}
else if (previous_above != above)
{
GList *index;
/* Find the window that matches 'above'; if the window is hidden (i.e.,
* minimized, on a different desktop) find the first window above it tha
* is not and use it instead; if we cannot find any such window then
* fallback to raise to top (without this, we end up stacking up the act
* in the wrong place, and it probably will not be visible at all).
*/
for (index = info->windows; index; index = index->next)
{
MutterWindow *cw2 = (MutterWindow *) index->data;
if (cw2->priv->xwindow == above)
{
if (live_mode && !hide && cw2->priv->window &&
meta_window_is_hidden (cw2->priv->window))
{
index = index->prev;
while (index)
{
MutterWindow *prev = index->data;
if (!prev->priv->window ||
!meta_window_is_hidden (prev->priv->window))
{
break;
}
index = index->prev;
}
}
break;
}
}
if (index != NULL)
{
if (index != sibling)
{
ClutterActor *above_win = index->data;
CHECK_LIST_INTEGRITY_START(info->windows)
info->windows = g_list_delete_link (info->windows, sibling);
info->windows = g_list_insert_before (info->windows, index, cw);
CHECK_LIST_INTEGRITY_END(info->windows)
#if 0
printf ("Raising %p [0x%x] (%s) hidden %d, above %p [0x%x] (%s)\n",
cw, (guint) priv->xwindow,
priv->window ? priv->window->desc : "unknown", hide,
cw2, (guint) cw2->priv->xwindow,
cw2->priv->window ? cw2->priv->window->desc : "unknown");
#endif
if (!info->switch_workspace_in_progress)
{
clutter_actor_raise (CLUTTER_ACTOR (cw), above_win);
}
}
}
else if (live_mode)
{
if (!hide)
{
#if 0
printf ("Raising to top as fallback %p [0x%x] (%s)\n",
cw, (guint) priv->xwindow,
priv->window ? priv->window->desc : "unknown");
#endif
/* Insert at bottom of window stack */
CHECK_LIST_INTEGRITY_START(info->windows)
info->windows = g_list_delete_link (info->windows, sibling);
info->windows = g_list_append (info->windows, cw);
CHECK_LIST_INTEGRITY_END(info->windows)
if (!info->switch_workspace_in_progress)
{
clutter_actor_raise_top (CLUTTER_ACTOR (cw));
}
}
else
{
#if 0
printf ("Lowering to bottom as fallback %p [0x%x] (%s)\n",
cw, (guint) priv->xwindow,
priv->window ? priv->window->desc : "unknown");
#endif
/* Insert at bottom of window stack */
CHECK_LIST_INTEGRITY_START(info->windows)
info->windows = g_list_delete_link (info->windows, sibling);
info->windows = g_list_prepend (info->windows, cw);
CHECK_LIST_INTEGRITY_END(info->windows)
if (!info->switch_workspace_in_progress)
{
clutter_actor_lower_bottom (CLUTTER_ACTOR (cw));
}
}
}
}
}
static void
resize_win (MutterWindow *cw,
int x,
@ -1793,7 +1642,6 @@ process_configure_notify (Mutter *compositor,
if (cw)
{
restack_win (cw, event->above);
resize_win (cw,
event->x, event->y, event->width, event->height,
event->border_width, event->override_redirect);
@ -1830,33 +1678,6 @@ process_configure_notify (Mutter *compositor,
}
}
static void
process_circulate_notify (Mutter *compositor,
XCirculateEvent *event)
{
MutterWindow *cw = find_window_in_display (compositor->display,
event->window);
MutterWindow *top;
MetaCompScreen *info;
Window above;
MutterWindowPrivate *priv;
if (!cw)
return;
priv = cw->priv;
info = meta_screen_get_compositor_data (priv->screen);
top = info->windows->data;
if ((event->place == PlaceOnTop) && top)
above = top->priv->xwindow;
else
above = None;
restack_win (cw, above);
}
static void
process_unmap (Mutter *compositor,
XUnmapEvent *event)
@ -2224,10 +2045,6 @@ clutter_cmp_process_event (MetaCompositor *compositor,
meta_error_trap_push (xrc->display);
switch (event->type)
{
case CirculateNotify:
process_circulate_notify (xrc, (XCirculateEvent *) event);
break;
case ConfigureNotify:
process_configure_notify (xrc, (XConfigureEvent *) event);
break;
@ -2529,33 +2346,45 @@ clutter_cmp_switch_workspace (MetaCompositor *compositor,
}
static void
clutter_cmp_ensure_stack_order (MetaCompositor *compositor,
MetaScreen *screen)
clutter_cmp_sync_stack (MetaCompositor *compositor,
GList *stack)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
GList *l = g_list_last (info->windows);
GList *tmp;
while (l)
for (tmp = stack; tmp != NULL; tmp = tmp->next)
{
ClutterActor *a = l->data;
MutterWindow *mw = l->data;
MetaWindow *window = mw->priv->window;
MetaWindow *window = tmp->data;
MutterWindow *cw;
MetaCompScreen *info;
MetaScreen *screen;
MetaFrame *f = meta_window_get_frame (window);
Window xwindow;
/*
* If this window is not marked as hidden, we raise it.
* If it has no MetaWindow associated (i.e., override redirect), we
* raise it too. Everything else we push to the bottom.
*/
if (!window || !meta_window_is_hidden (window))
screen = meta_window_get_screen (window);
info = meta_screen_get_compositor_data (screen);
/* Chances are we actually get the window frame here */
xwindow = f ? meta_frame_get_xwindow (f) :
meta_window_get_xwindow (window);
cw = find_window_for_screen (screen, xwindow);
if (!cw)
{
clutter_actor_raise_top (a);
}
else
{
clutter_actor_lower_bottom (a);
meta_verbose ("Failed to find corresponding MutterWindow "
"for window 0x%08x\n", (unsigned int)xwindow);
continue;
}
l = l->prev;
/* TODO: cw = window->compositor_priv; */
#if 0
/* FIXME: There should be a seperate composite manager hook
* for hiding/unhiding the actor when the window becomes
* hidden or not */
if (meta_window_is_hidden (window))
clutter_actor_hide (CLUTTER_ACTOR (cw));
#endif
clutter_actor_lower_bottom (CLUTTER_ACTOR (cw));
}
}
@ -2575,7 +2404,7 @@ static MetaCompositor comp_info = {
clutter_cmp_unmaximize_window,
clutter_cmp_update_workspace_geometry,
clutter_cmp_switch_workspace,
clutter_cmp_ensure_stack_order,
clutter_cmp_sync_stack
};
MetaCompositor *

View File

@ -772,17 +772,6 @@ meta_screen_manage_all_windows (MetaScreen *screen)
}
meta_stack_thaw (screen->stack);
/*
* Because the windows have already been created/mapped/etc, if the compositor
* maintains a separate stack based on ConfigureNotify restack messages, it
* will not necessarily get what it needs; we explicitely notify the
* compositor to fix up its stacking order.
*
* For more on this issue, see comments in meta_window_hide().
*/
if (screen->display->compositor)
meta_compositor_ensure_stack_order (screen->display->compositor, screen);
g_list_foreach (windows, (GFunc)g_free, NULL);
g_list_free (windows);

View File

@ -1066,6 +1066,9 @@ stack_sync_to_server (MetaStack *stack)
stack_ensure_sorted (stack);
meta_compositor_sync_stack (stack->screen->display->compositor,
stack->sorted);
/* 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

View File

@ -2348,33 +2348,6 @@ meta_window_hide (MetaWindow *window)
meta_window_update_layer (window);
meta_window_lower (window);
meta_stack_thaw (window->screen->stack);
/*
* The X server does not implement lower-below semantics for restacking
* windows, only raise-above; consequently each single lower-bottom call
* gets translated to a bunch of raise-above moves, and often there will
* be no ConfigureNotify at all for the window we are lowering (only for
* its siblings). If we mix the lower-bottom sequence of calls with
* mapping of windows, the batch of ConfigureNotify events that is
* generated does not correctly reflect the stack order, and if the
* Compositor relies on these for its own internal stack, it will
* invariably end up with wrong stacking order.
*
* I have not been able to find a way to get this just work so that the
* resulting ConfigureNotify messages would reflect the actual state of
* the stack, so in the special case we map a window while hiding it, we
* explitely notify the compositor that it should ensure its stacking
* matches the cannonical stack of the WM.
*
* NB: this is uncommon, and generally only happens on the WM start up,
* when we are taking over pre-existing windows, so this brute-force
* fix is OK performance wise.
*/
if (!was_mapped && window->display->compositor)
{
meta_compositor_ensure_stack_order (window->display->compositor,
window->screen);
}
}
else
{

View File

@ -129,9 +129,8 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
MetaMotionDirection direction);
void
meta_compositor_ensure_stack_order (MetaCompositor *compositor,
MetaScreen *screen);
meta_compositor_sync_stack (MetaCompositor *compositor,
GList *stack);
#endif