Пример #1
0
void
meta_core_lower_beneath_grab_window (Display *xdisplay,
                                     Window   xwindow,
                                     guint32  timestamp)
{
  XWindowChanges changes;
  MetaDisplay *display;
  MetaScreen *screen;
  MetaWindow *grab_window;

  display = meta_display_for_x_display (xdisplay);
  screen = meta_display_screen_for_xwindow (display, xwindow);
  grab_window = display->grab_window;

  if (grab_window == NULL)
    return;

  changes.stack_mode = Below;
  changes.sibling = grab_window->frame ? grab_window->frame->xwindow
                                       : grab_window->xwindow;

  meta_stack_tracker_record_lower_below (screen->stack_tracker,
                                         xwindow,
                                         changes.sibling,
                                         XNextRequest (screen->display->xdisplay));

  meta_error_trap_push (display);
  XConfigureWindow (xdisplay,
                    xwindow,
                    CWSibling | CWStackMode,
                    &changes);
  meta_error_trap_pop (display);
}
Пример #2
0
LOCAL_SYMBOL void
meta_core_lower_beneath_sibling (Display   *xdisplay,
                                 Window     xwindow,
                                 Window     grab_window,
                                 guint32    timestamp)
{
  XWindowChanges changes;
  MetaDisplay *display;
  MetaScreen *screen;

  display = meta_display_for_x_display (xdisplay);
  screen = meta_display_screen_for_xwindow (display, xwindow);

  changes.stack_mode = Below;
  changes.sibling = grab_window;

  meta_stack_tracker_record_lower_below (screen->stack_tracker,
                                         xwindow,
                                         changes.sibling,
                                         XNextRequest (screen->display->xdisplay));

  meta_error_trap_push (display);
  XConfigureWindow (xdisplay,
                    xwindow,
                    CWSibling | CWStackMode,
                    &changes);
  meta_error_trap_pop (display);
}
Пример #3
0
void
meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
					   Window           *windows,
					   int               n_windows,
					   gulong            serial)
{
  int i;

  /* XRestackWindows() isn't actually a X requests - it's broken down
   * by XLib into a series of XConfigureWindow(StackMode=below); we
   * mirror that exactly here.
   *
   * Aside: Having a separate StackOp for this would be possible to
   * get some extra efficiency in memory allocation and in applying
   * the op, at the expense of a code complexity. Implementation hint
   * for that - keep op->restack_window.n_complete, and when receiving
   * events with intermediate serials, set n_complete rather than
   * removing the op from the queue.
   */
  for (i = 0; i < n_windows - 1; i++)
    meta_stack_tracker_record_lower_below (tracker, windows[i + 1], windows[i],
					   serial + i);
}
Пример #4
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... */
}