MetaWindow* meta_stack_get_below (MetaStack *stack, MetaWindow *window, gboolean only_within_layer) { GList *link; MetaWindow *below; stack_ensure_sorted (stack); link = g_list_find (stack->sorted, window); if (link == NULL) return NULL; if (link->next == NULL) return NULL; below = link->next->data; if (only_within_layer && below->layer != window->layer) return NULL; else return below; }
void meta_stack_lower (MetaStack *stack, MetaWindow *window) { GList *l; int min_stack_position = window->stack_position; MetaWorkspace *workspace; stack_ensure_sorted (stack); workspace = meta_window_get_workspace (window); for (l = stack->sorted; l; l = l->next) { MetaWindow *w = (MetaWindow *) l->data; if (meta_window_located_on_workspace (w, workspace) && w->stack_position < min_stack_position) min_stack_position = w->stack_position; } if (min_stack_position == window->stack_position) return; meta_window_set_stack_position_no_sync (window, min_stack_position); stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); }
GList* meta_stack_list_windows (MetaStack *stack, MetaWorkspace *workspace) { GList *workspace_windows = NULL; GList *link; stack_ensure_sorted (stack); /* do adds/removes */ link = stack->sorted; while (link) { MetaWindow *window = link->data; if (window && (workspace == NULL || meta_window_located_on_workspace (window, workspace))) { workspace_windows = g_list_prepend (workspace_windows, window); } link = link->next; } return workspace_windows; }
MetaWindow* meta_stack_get_top (MetaStack *stack) { stack_ensure_sorted (stack); if (stack->sorted) return stack->sorted->data; else return NULL; }
GList* meta_stack_get_positions (MetaStack *stack) { GList *tmp; /* Make sure to handle any adds or removes */ stack_ensure_sorted (stack); tmp = g_list_copy (stack->sorted); tmp = g_list_sort (tmp, (GCompareFunc) compare_just_window_stack_position); return tmp; }
MetaWindow* meta_stack_get_bottom (MetaStack *stack) { GList *link; stack_ensure_sorted (stack); link = g_list_last (stack->sorted); if (link != NULL) return link->data; else return NULL; }
int meta_stack_windows_cmp (MetaStack *stack, MetaWindow *window_a, MetaWindow *window_b) { g_return_val_if_fail (window_a->screen == window_b->screen, 0); /* -1 means a below b */ stack_ensure_sorted (stack); /* update constraints, layers */ if (window_a->layer < window_b->layer) return -1; else if (window_a->layer > window_b->layer) return 1; else if (window_a->stack_position < window_b->stack_position) return -1; else if (window_a->stack_position > window_b->stack_position) return 1; else return 0; /* not reached */ }
void meta_stack_set_positions (MetaStack *stack, GList *windows) { int i; GList *tmp; /* Make sure any adds or removes aren't in limbo -- is this needed? */ stack_ensure_sorted (stack); if (!lists_contain_same_windows (windows, stack->sorted)) { meta_warning ("This list of windows has somehow changed; not resetting " "positions of the windows.\n"); return; } g_list_free (stack->sorted); stack->sorted = g_list_copy (windows); stack->need_resort = TRUE; stack->need_constrain = TRUE; i = 0; tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; w->stack_position = i++; tmp = tmp->next; } meta_topic (META_DEBUG_STACK, "Reset the stack positions of (nearly) all windows\n"); stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, NULL); }
MetaWindow* meta_stack_get_above (MetaStack *stack, MetaWindow *window, gboolean only_within_layer) { GList *link; MetaWindow *above; stack_ensure_sorted (stack); link = g_list_find (stack->sorted, window); if (link == NULL) return NULL; if (link->prev == NULL) return NULL; above = link->prev->data; if (only_within_layer && above->layer != window->layer) return NULL; else return above; }
static MetaWindow* get_default_focus_window (MetaStack *stack, MetaWorkspace *workspace, MetaWindow *not_this_one, gboolean must_be_at_point, int root_x, int root_y) { /* Find the topmost, focusable, mapped, window. * not_this_one is being unfocused or going away, so exclude it. * Also, prefer to focus transient parent of not_this_one, * or top window in same group as not_this_one. */ MetaWindow *transient_parent; MetaWindow *topmost_in_group; MetaWindow *topmost_overall; MetaGroup *not_this_one_group; GList *l; transient_parent = NULL; topmost_in_group = NULL; topmost_overall = NULL; if (not_this_one) not_this_one_group = meta_window_get_group (not_this_one); else not_this_one_group = NULL; stack_ensure_sorted (stack); /* top of this layer is at the front of the list */ for (l = stack->sorted; l != NULL; l = l->next) { MetaWindow *window = l->data; if (!window) continue; if (window == not_this_one) continue; if (window->unmaps_pending > 0) continue; if (window->minimized) continue; if (window->unmanaging) continue; if (!(window->input || window->take_focus)) continue; if (workspace != NULL && !meta_window_located_on_workspace (window, workspace)) continue; if (must_be_at_point && !window_contains_point (window, root_x, root_y)) continue; if (not_this_one != NULL) { if (transient_parent == NULL && meta_window_get_transient_for (not_this_one) == window) transient_parent = window; if (topmost_in_group == NULL && not_this_one_group != NULL && not_this_one_group == meta_window_get_group (window)) topmost_in_group = window; } if (topmost_overall == NULL && window->type != META_WINDOW_DOCK) topmost_overall = window; /* We could try to bail out early here for efficiency in * some cases, but it's just not worth the code. */ } if (transient_parent) return transient_parent; else if (topmost_in_group) return topmost_in_group; else if (topmost_overall) return topmost_overall; else return NULL; }
/** * 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); }
static MetaWindow* get_default_focus_window (MetaStack *stack, MetaWorkspace *workspace, MetaWindow *not_this_one, gboolean must_be_at_point, int root_x, int root_y) { /* Find the topmost, focusable, mapped, window. * not_this_one is being unfocused or going away, so exclude it. * Also, prefer to focus transient parent of not_this_one, * or top window in same group as not_this_one. */ MetaWindow *topmost_dock; MetaWindow *transient_parent; MetaWindow *topmost_in_group; MetaWindow *topmost_overall; MetaGroup *not_this_one_group; GList *link; topmost_dock = NULL; transient_parent = NULL; topmost_in_group = NULL; topmost_overall = NULL; if (not_this_one) not_this_one_group = meta_window_get_group (not_this_one); else not_this_one_group = NULL; stack_ensure_sorted (stack); /* top of this layer is at the front of the list */ link = stack->sorted; while (link) { MetaWindow *window = link->data; if (window && window != not_this_one && (window->unmaps_pending == 0) && !window->minimized && (window->input || window->take_focus) && (workspace == NULL || meta_window_located_on_workspace (window, workspace))) { if (topmost_dock == NULL && window->type == META_WINDOW_DOCK) topmost_dock = window; if (not_this_one != NULL) { if (transient_parent == NULL && not_this_one->xtransient_for != None && not_this_one->xtransient_for == window->xwindow && (!must_be_at_point || window_contains_point (window, root_x, root_y))) transient_parent = window; if (topmost_in_group == NULL && not_this_one_group != NULL && not_this_one_group == meta_window_get_group (window) && (!must_be_at_point || window_contains_point (window, root_x, root_y))) topmost_in_group = window; } /* Note that DESKTOP windows can be topmost_overall so * we prefer focusing desktop or other windows over * focusing dock, even though docks are stacked higher. */ if (topmost_overall == NULL && window->type != META_WINDOW_DOCK && (!must_be_at_point || window_contains_point (window, root_x, root_y))) topmost_overall = window; /* We could try to bail out early here for efficiency in * some cases, but it's just not worth the code. */ } link = link->next; } if (transient_parent) return transient_parent; else if (topmost_in_group) return topmost_in_group; else if (topmost_overall) return topmost_overall; else return topmost_dock; }
/* * 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... */ }