diff --git a/src/core/screen.c b/src/core/screen.c index 3560e11ad..24ed8de60 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -945,9 +945,8 @@ meta_screen_composite_all_windows (MetaScreen *screen) meta_compositor_add_window (display->compositor, tmp->data); g_slist_free (windows); - /* trigger a stack_sync_to_server: */ - meta_stack_freeze (screen->stack); - meta_stack_thaw (screen->stack); + /* initialize the compositor's view of the stacking order */ + meta_stack_tracker_sync_stack (screen->stack_tracker); #endif } diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c index 3b753e0c1..98673cbb9 100644 --- a/src/core/stack-tracker.c +++ b/src/core/stack-tracker.c @@ -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); + } +} + diff --git a/src/core/stack-tracker.h b/src/core/stack-tracker.h index 6df329977..557c459a0 100644 --- a/src/core/stack-tracker.h +++ b/src/core/stack-tracker.h @@ -79,8 +79,11 @@ void meta_stack_tracker_reparent_event (MetaStackTracker *tracker, void meta_stack_tracker_configure_event (MetaStackTracker *tracker, XConfigureEvent *event); -void meta_stack_tracker_get_stack (MetaStackTracker *tracker, - Window **windows, - int *n_windows); +void meta_stack_tracker_get_stack (MetaStackTracker *tracker, + Window **windows, + int *n_windows); + +void meta_stack_tracker_sync_stack (MetaStackTracker *tracker); +void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker); #endif /* META_STACK_TRACKER_H */ diff --git a/src/core/stack.c b/src/core/stack.c index f2f36f07f..de70fb854 100644 --- a/src/core/stack.c +++ b/src/core/stack.c @@ -35,10 +35,6 @@ #include "prefs.h" #include "workspace.h" -#ifdef HAVE_COMPOSITE_EXTENSIONS -#include "compositor.h" -#endif - #include #define WINDOW_HAS_TRANSIENT_TYPE(w) \ @@ -1091,10 +1087,6 @@ stack_sync_to_server (MetaStack *stack) stack_ensure_sorted (stack); - meta_compositor_sync_stack (stack->screen->display->compositor, - stack->screen, - 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 @@ -1312,8 +1304,6 @@ stack_sync_to_server (MetaStack *stack) if (stack->last_root_children_stacked) g_array_free (stack->last_root_children_stacked, TRUE); stack->last_root_children_stacked = root_children_stacked; - - meta_screen_restacked (stack->screen); /* That was scary... */ } diff --git a/src/core/window.c b/src/core/window.c index 4fab34aa8..cca089a69 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -1001,6 +1001,13 @@ meta_window_new_with_attrs (MetaDisplay *display, /* Sync stack changes */ meta_stack_thaw (window->screen->stack); + /* Usually the we'll have queued a stack sync anyways, because we've + * added a new frame window or restacked. But if an undecorated + * window is mapped, already stacked in the right place, then we + * might need to do this explicitly. + */ + meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker); + /* disable show desktop mode unless we're a desktop component */ maybe_leave_show_desktop_mode (window); @@ -1309,6 +1316,12 @@ meta_window_unmanage (MetaWindow *window, if (window->frame) meta_window_destroy_frame (window); + /* If an undecorated window is being withdrawn, that will change the + * stack as presented to the compositing manager, without actually + * changing the stacking order of X windows. + */ + meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker); + if (window->withdrawn) { /* We need to clean off the window's state so it