static void meta_stack_tracker_dump (MetaStackTracker *tracker) { guint i; GList *l; 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, "\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 queued_requests: ["); for (l = tracker->queued_requests->head; l; l = l->next) { MetaStackOp *op = l->data; meta_stack_op_dump (op, "", l->next ? ", " : ""); } meta_topic (META_DEBUG_STACK, "]\n"); meta_pop_no_msg_prefix (); }
/** * stack_sync_to_server: * * Order the windows on the X server to be the same as in our structure. * We do this using XRestackWindows if we don't know the previous order, * or XConfigureWindow on a few particular windows if we do and can figure * out the minimum set of changes. After that, we set __NET_CLIENT_LIST * and __NET_CLIENT_LIST_STACKING. * * FIXME: Now that we have a good view of the stacking order on the server * with MetaStackTracker it should be possible to do a simpler and better * job of computing the minimal set of stacking requests needed. */ static void stack_sync_to_xserver (MetaStack *stack) { GArray *x11_stacked; GArray *all_root_children_stacked; /* wayland OR x11 */ GList *tmp; GArray *x11_hidden_stack_ids; /* Bail out if frozen */ if (stack->freeze_count > 0) return; meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n"); stack_ensure_sorted (stack); /* Create stacked xwindow arrays, in bottom-to-top order */ x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64)); x11_hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64)); meta_topic (META_DEBUG_STACK, "Top to bottom: "); meta_push_no_msg_prefix (); for (tmp = g_list_last(stack->sorted); tmp != NULL; tmp = tmp->prev) { MetaWindow *w = tmp->data; Window top_level_window; guint64 stack_id; if (w->unmanaging) continue; meta_topic (META_DEBUG_STACK, "%u:%d - %s ", w->layer, w->stack_position, w->desc); g_array_append_val (x11_stacked, w->xwindow); if (w->frame) top_level_window = w->frame->xwindow; else top_level_window = w->xwindow; if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) stack_id = top_level_window; else stack_id = w->stamp; /* We don't restack hidden windows along with the rest, though they are * reflected in the _NET hints. Hidden windows all get pushed below * the screens fullscreen guard_window. */ if (w->hidden) { if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) { guint64 stack_id = top_level_window; g_array_append_val (x11_hidden_stack_ids, stack_id); } continue; } g_array_append_val (all_root_children_stacked, stack_id); } meta_topic (META_DEBUG_STACK, "\n"); meta_pop_no_msg_prefix (); /* The screen guard window sits above all hidden windows and acts as * a barrier to input reaching these windows. */ g_array_append_val (x11_hidden_stack_ids, stack->screen->guard_window); /* Sync to server */ meta_topic (META_DEBUG_STACK, "Restacking %u windows\n", all_root_children_stacked->len); meta_stack_tracker_restack_managed (stack->screen->stack_tracker, (guint64 *)all_root_children_stacked->data, all_root_children_stacked->len); meta_stack_tracker_restack_at_bottom (stack->screen->stack_tracker, (guint64 *)x11_hidden_stack_ids->data, x11_hidden_stack_ids->len); /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */ XChangeProperty (stack->screen->display->xdisplay, stack->screen->xroot, stack->screen->display->atom__NET_CLIENT_LIST, XA_WINDOW, 32, PropModeReplace, (unsigned char *)stack->xwindows->data, stack->xwindows->len); XChangeProperty (stack->screen->display->xdisplay, stack->screen->xroot, stack->screen->display->atom__NET_CLIENT_LIST_STACKING, XA_WINDOW, 32, PropModeReplace, (unsigned char *)x11_stacked->data, x11_stacked->len); g_array_free (x11_stacked, TRUE); g_array_free (all_root_children_stacked, TRUE); }
/* * Order the windows on the X server to be the same as in our structure. * We do this using XRestackWindows if we don't know the previous order, * or XConfigureWindow on a few particular windows if we do and can figure * out the minimum set of changes. After that, we set __NET_CLIENT_LIST * and __NET_CLIENT_LIST_STACKING. * * FIXME: Now that we have a good view of the stacking order on the server * with MetaStackTracker it should be possible to do a simpler and better * job of computing the minimal set of stacking requests needed. */ static void stack_sync_to_server (MetaStack *stack) { GArray *stacked; GArray *root_children_stacked; GList *tmp; GArray *all_hidden; int n_override_redirect = 0; int n_unmanaging = 0; /* Bail out if frozen */ if (stack->freeze_count > 0) return; meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n"); stack_ensure_sorted (stack); /* 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 * order for XRestackWindows() */ stacked = g_array_new (FALSE, FALSE, sizeof (Window)); root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); all_hidden = g_array_new (FALSE, FALSE, sizeof (Window)); /* The screen guard window sits above all hidden windows and acts as * a barrier to input reaching these windows. */ g_array_append_val (all_hidden, stack->screen->guard_window); meta_topic (META_DEBUG_STACK, "Top to bottom: "); meta_push_no_msg_prefix (); for (tmp = stack->sorted; tmp != NULL; tmp = tmp->next) { MetaWindow *w = tmp->data; Window top_level_window; if (w->unmanaging) { n_unmanaging ++; continue; } meta_topic (META_DEBUG_STACK, "%u:%d - %s ", w->layer, w->stack_position, w->desc); /* remember, stacked is in reverse order (bottom to top) */ if (w->override_redirect) n_override_redirect++; else g_array_prepend_val (stacked, w->xwindow); if (w->frame) top_level_window = w->frame->xwindow; else top_level_window = w->xwindow; /* We don't restack hidden windows along with the rest, though they are * reflected in the _NET hints. Hidden windows all get pushed below * the screens fullscreen guard_window. */ if (w->hidden) { g_array_append_val (all_hidden, top_level_window); continue; } /* build XRestackWindows() array from top to bottom */ g_array_append_val (root_children_stacked, top_level_window); } meta_topic (META_DEBUG_STACK, "\n"); meta_pop_no_msg_prefix (); /* All windows should be in some stacking order */ if (stacked->len != stack->windows->len - n_override_redirect - n_unmanaging) meta_bug ("%u windows stacked, %u windows exist in stack\n", stacked->len, stack->windows->len); /* Sync to server */ meta_topic (META_DEBUG_STACK, "Restacking %u windows\n", root_children_stacked->len); meta_error_trap_push (stack->screen->display); if (stack->last_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. */ meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n"); if (root_children_stacked->len > 0) { meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, (Window *) root_children_stacked->data, root_children_stacked->len, XNextRequest (stack->screen->display->xdisplay)); XRestackWindows (stack->screen->display->xdisplay, (Window *) root_children_stacked->data, root_children_stacked->len); } } else if (root_children_stacked->len > 0) { /* 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 * 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 *new_stack = (Window *) root_children_stacked->data; const int old_len = stack->last_root_children_stacked->len; const int new_len = root_children_stacked->len; const Window *oldp = old_stack; const Window *newp = new_stack; const Window *old_end = old_stack + old_len; const Window *new_end = new_stack + new_len; Window last_window = None; while (oldp != old_end && newp != new_end) { if (*oldp == *newp) { /* Stacks are the same here, move on */ ++oldp; last_window = *newp; ++newp; } else if (meta_display_lookup_x_window (stack->screen->display, *oldp) == NULL) { /* *oldp is no longer known to us (probably destroyed), * so we can just skip it */ ++oldp; } else { /* Move *newp below last_window */ if (last_window == None) { meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp); raise_window_relative_to_managed_windows (stack->screen, *newp); } else { /* This means that if last_window is dead, but not * *newp, then we fail to restack *newp; but on * unmanaging last_window, we'll fix it up. */ XWindowChanges changes; changes.sibling = last_window; changes.stack_mode = Below; meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n", *newp, last_window); meta_stack_tracker_record_lower_below (stack->screen->stack_tracker, *newp, last_window, XNextRequest (stack->screen->display->xdisplay)); XConfigureWindow (stack->screen->display->xdisplay, *newp, CWSibling | CWStackMode, &changes); } last_window = *newp; ++newp; } } if (newp != new_end) { /* Restack remaining windows */ meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n", (int) (new_end - newp)); /* We need to include an already-stacked window * in the restack call, so we get in the proper position * with respect to it. */ if (newp != new_stack) --newp; meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, (Window *) newp, new_end - newp, XNextRequest (stack->screen->display->xdisplay)); XRestackWindows (stack->screen->display->xdisplay, (Window *) newp, new_end - newp); } } /* Push hidden windows to the bottom of the stack under the guard window */ meta_stack_tracker_record_lower (stack->screen->stack_tracker, stack->screen->guard_window, XNextRequest (stack->screen->display->xdisplay)); XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window); meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, (Window *)all_hidden->data, all_hidden->len, XNextRequest (stack->screen->display->xdisplay)); XRestackWindows (stack->screen->display->xdisplay, (Window *)all_hidden->data, all_hidden->len); g_array_free (all_hidden, TRUE); meta_error_trap_pop (stack->screen->display); /* on error, a window was destroyed; it should eventually * get removed from the stacking list when we unmanage it * and we'll fix stacking at that time. */ /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */ XChangeProperty (stack->screen->display->xdisplay, stack->screen->xroot, stack->screen->display->atom__NET_CLIENT_LIST, XA_WINDOW, 32, PropModeReplace, (unsigned char *)stack->windows->data, stack->windows->len); XChangeProperty (stack->screen->display->xdisplay, stack->screen->xroot, stack->screen->display->atom__NET_CLIENT_LIST_STACKING, XA_WINDOW, 32, PropModeReplace, (unsigned char *)stacked->data, stacked->len); 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; /* That was scary... */ }