mirror of
https://github.com/brl/mutter.git
synced 2025-03-29 14:43:47 +00:00
[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:
parent
7ec7a8fa44
commit
6d8baea4c2
@ -79,8 +79,8 @@ struct _MetaCompositor
|
|||||||
MetaWorkspace *to,
|
MetaWorkspace *to,
|
||||||
MetaMotionDirection direction);
|
MetaMotionDirection direction);
|
||||||
|
|
||||||
void (*ensure_stack_order) (MetaCompositor *compositor,
|
void (*sync_stack) (MetaCompositor *compositor,
|
||||||
MetaScreen *screen);
|
GList *stack);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -243,11 +243,12 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_compositor_ensure_stack_order (MetaCompositor *compositor,
|
meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||||
MetaScreen *screen)
|
GList *stack)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_COMPOSITE_EXTENSIONS
|
#ifdef HAVE_COMPOSITE_EXTENSIONS
|
||||||
if (compositor && compositor->ensure_stack_order)
|
if (compositor && compositor->sync_stack)
|
||||||
compositor->ensure_stack_order (compositor, screen);
|
compositor->sync_stack (compositor, stack);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
static void
|
||||||
resize_win (MutterWindow *cw,
|
resize_win (MutterWindow *cw,
|
||||||
int x,
|
int x,
|
||||||
@ -1793,7 +1642,6 @@ process_configure_notify (Mutter *compositor,
|
|||||||
|
|
||||||
if (cw)
|
if (cw)
|
||||||
{
|
{
|
||||||
restack_win (cw, event->above);
|
|
||||||
resize_win (cw,
|
resize_win (cw,
|
||||||
event->x, event->y, event->width, event->height,
|
event->x, event->y, event->width, event->height,
|
||||||
event->border_width, event->override_redirect);
|
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
|
static void
|
||||||
process_unmap (Mutter *compositor,
|
process_unmap (Mutter *compositor,
|
||||||
XUnmapEvent *event)
|
XUnmapEvent *event)
|
||||||
@ -2224,10 +2045,6 @@ clutter_cmp_process_event (MetaCompositor *compositor,
|
|||||||
meta_error_trap_push (xrc->display);
|
meta_error_trap_push (xrc->display);
|
||||||
switch (event->type)
|
switch (event->type)
|
||||||
{
|
{
|
||||||
case CirculateNotify:
|
|
||||||
process_circulate_notify (xrc, (XCirculateEvent *) event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ConfigureNotify:
|
case ConfigureNotify:
|
||||||
process_configure_notify (xrc, (XConfigureEvent *) event);
|
process_configure_notify (xrc, (XConfigureEvent *) event);
|
||||||
break;
|
break;
|
||||||
@ -2529,33 +2346,45 @@ clutter_cmp_switch_workspace (MetaCompositor *compositor,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_cmp_ensure_stack_order (MetaCompositor *compositor,
|
clutter_cmp_sync_stack (MetaCompositor *compositor,
|
||||||
MetaScreen *screen)
|
GList *stack)
|
||||||
{
|
{
|
||||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
GList *tmp;
|
||||||
GList *l = g_list_last (info->windows);
|
|
||||||
|
for (tmp = stack; tmp != NULL; tmp = tmp->next)
|
||||||
while (l)
|
|
||||||
{
|
{
|
||||||
ClutterActor *a = l->data;
|
MetaWindow *window = tmp->data;
|
||||||
MutterWindow *mw = l->data;
|
MutterWindow *cw;
|
||||||
MetaWindow *window = mw->priv->window;
|
MetaCompScreen *info;
|
||||||
|
MetaScreen *screen;
|
||||||
|
MetaFrame *f = meta_window_get_frame (window);
|
||||||
|
Window xwindow;
|
||||||
|
|
||||||
/*
|
screen = meta_window_get_screen (window);
|
||||||
* If this window is not marked as hidden, we raise it.
|
info = meta_screen_get_compositor_data (screen);
|
||||||
* If it has no MetaWindow associated (i.e., override redirect), we
|
|
||||||
* raise it too. Everything else we push to the bottom.
|
/* Chances are we actually get the window frame here */
|
||||||
*/
|
xwindow = f ? meta_frame_get_xwindow (f) :
|
||||||
if (!window || !meta_window_is_hidden (window))
|
meta_window_get_xwindow (window);
|
||||||
|
cw = find_window_for_screen (screen, xwindow);
|
||||||
|
if (!cw)
|
||||||
{
|
{
|
||||||
clutter_actor_raise_top (a);
|
meta_verbose ("Failed to find corresponding MutterWindow "
|
||||||
}
|
"for window 0x%08x\n", (unsigned int)xwindow);
|
||||||
else
|
continue;
|
||||||
{
|
|
||||||
clutter_actor_lower_bottom (a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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_unmaximize_window,
|
||||||
clutter_cmp_update_workspace_geometry,
|
clutter_cmp_update_workspace_geometry,
|
||||||
clutter_cmp_switch_workspace,
|
clutter_cmp_switch_workspace,
|
||||||
clutter_cmp_ensure_stack_order,
|
clutter_cmp_sync_stack
|
||||||
};
|
};
|
||||||
|
|
||||||
MetaCompositor *
|
MetaCompositor *
|
||||||
|
@ -772,17 +772,6 @@ meta_screen_manage_all_windows (MetaScreen *screen)
|
|||||||
}
|
}
|
||||||
meta_stack_thaw (screen->stack);
|
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_foreach (windows, (GFunc)g_free, NULL);
|
||||||
g_list_free (windows);
|
g_list_free (windows);
|
||||||
|
|
||||||
|
@ -1065,6 +1065,9 @@ stack_sync_to_server (MetaStack *stack)
|
|||||||
meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");
|
meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");
|
||||||
|
|
||||||
stack_ensure_sorted (stack);
|
stack_ensure_sorted (stack);
|
||||||
|
|
||||||
|
meta_compositor_sync_stack (stack->screen->display->compositor,
|
||||||
|
stack->sorted);
|
||||||
|
|
||||||
/* Create stacked xwindow arrays.
|
/* Create stacked xwindow arrays.
|
||||||
* Painfully, "stacked" is in bottom-to-top order for the
|
* Painfully, "stacked" is in bottom-to-top order for the
|
||||||
|
@ -2348,33 +2348,6 @@ meta_window_hide (MetaWindow *window)
|
|||||||
meta_window_update_layer (window);
|
meta_window_update_layer (window);
|
||||||
meta_window_lower (window);
|
meta_window_lower (window);
|
||||||
meta_stack_thaw (window->screen->stack);
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -129,9 +129,8 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
|
|||||||
MetaMotionDirection direction);
|
MetaMotionDirection direction);
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_compositor_ensure_stack_order (MetaCompositor *compositor,
|
meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||||
MetaScreen *screen);
|
GList *stack);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user