Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
MetaWindow*
meta_stack_get_top (MetaStack *stack)
{
  stack_ensure_sorted (stack);

  if (stack->sorted)
    return stack->sorted->data;
  else
    return NULL;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
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 */
}
Ejemplo n.º 8
0
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);
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
/**
 * 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);
}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
0
/*
 * 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... */
}