static gboolean
get_property (MetaDisplay        *display,
              Window              xwindow,
              Atom                xatom,
              Atom                req_type,
              GetPropertyResults *results)
{
  results->display = display;
  results->xwindow = xwindow;
  results->xatom = xatom;
  results->prop = NULL;
  results->n_items = 0;
  results->type = None;
  results->bytes_after = 0;
  results->format = 0;
  
  meta_error_trap_push_with_return (display);
  if (XGetWindowProperty (display->xdisplay, xwindow, xatom,
                          0, G_MAXLONG,
                          False, req_type, &results->type, &results->format,
                          &results->n_items,
                          &results->bytes_after,
                          &results->prop) != Success ||
      results->type == None)
    {
      if (results->prop)
        XFree (results->prop);
      meta_error_trap_pop_with_return (display, TRUE);
      return FALSE;
    }

  if (meta_error_trap_pop_with_return (display, TRUE) != Success)
    {
      if (results->prop)
        XFree (results->prop);
      return FALSE;
    }

  return TRUE;
}
Ejemplo n.º 2
0
/**
 * This function is used to avoid raising a window above popup
 * menus and other such things.
 *
 * FIXME This is sort of an expensive function, should probably
 * do something to avoid it. One approach would be to reverse
 * the stacking algorithm to work by placing each window above
 * the others, and start by lowering a window to the bottom
 * (instead of the current way, which works by placing each
 * window below another and starting with a raise)
 */
static void
raise_window_relative_to_managed_windows (MetaScreen *screen,
                                          Window      xwindow)
{

  Window ignored1, ignored2;
  Window *children;
  unsigned int n_children;
  int i;

  /* Normally XQueryTree() means "must grab server" but here
   * we don't, since we know we won't manage any new windows
   * or restack any windows before using the XQueryTree results.
   */
  
  meta_error_trap_push_with_return (screen->display);
  
  XQueryTree (screen->display->xdisplay,
              screen->xroot,
              &ignored1, &ignored2, &children, &n_children);

  if (meta_error_trap_pop_with_return (screen->display, TRUE) != Success)
    {
      meta_topic (META_DEBUG_STACK,
                  "Error querying root children to raise window 0x%lx\n",
                  xwindow);
      return;
    }

  /* Children are in order from bottom to top. We want to
   * find the topmost managed child, then configure
   * our window to be above it.
   */
  i = n_children - 1;
  while (i >= 0)
    {
      if (children[i] == xwindow)
        {
          /* Do nothing. This means we're already the topmost managed
           * window, but it DOES NOT mean we are already just above
           * the topmost managed window. This is important because if
           * an override redirect window is up, and we map a new
           * managed window, the new window is probably above the old
           * popup by default, and we want to push it below that
           * popup. So keep looking for a sibling managed window
           * to be moved below.
           */
        }
      else if (meta_display_lookup_x_window (screen->display,
                                             children[i]) != NULL)
        {
          XWindowChanges changes;
          
          /* children[i] is the topmost managed child */
          meta_topic (META_DEBUG_STACK,
                      "Moving 0x%lx above topmost managed child window 0x%lx\n",
                      xwindow, children[i]);

          changes.sibling = children[i];
          changes.stack_mode = Above;

          meta_error_trap_push (screen->display);
          XConfigureWindow (screen->display->xdisplay,
                            xwindow,
                            CWSibling | CWStackMode,
                            &changes);
          meta_error_trap_pop (screen->display, FALSE);

          break;
        }

      --i;
    }

  if (i < 0)
    {
      /* No sibling to use, just lower ourselves to the bottom
       * to be sure we're below any override redirect windows.
       */
      meta_error_trap_push (screen->display);
      XLowerWindow (screen->display->xdisplay,
                    xwindow);
      meta_error_trap_pop (screen->display, FALSE);
    }
  
  if (children)
    XFree (children);
}
Ejemplo n.º 3
0
void
meta_compositor_manage_screen (MetaCompositor *compositor,
                               MetaScreen     *screen)
{
    MetaCompScreen *info;
    MetaDisplay    *display       = meta_screen_get_display (screen);
    Display        *xdisplay      = meta_display_get_xdisplay (display);
    int             screen_number = meta_screen_get_screen_number (screen);
    Window          xroot         = meta_screen_get_xroot (screen);
    Window          xwin;
    gint            width, height;
    XWindowAttributes attr;
    long            event_mask;
    guint           n_retries;
    guint           max_retries;

    /* Check if the screen is already managed */
    if (meta_screen_get_compositor_data (screen))
        return;

    if (meta_get_replace_current_wm ())
        max_retries = 5;
    else
        max_retries = 1;

    n_retries = 0;

    /* Some compositors (like old versions of Muffin) might not properly unredirect
     * subwindows before destroying the WM selection window; so we wait a while
     * for such a compositor to exit before giving up.
     */
    while (TRUE)
    {
        meta_error_trap_push_with_return (display);
        XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
        XSync (xdisplay, FALSE);

        if (!meta_error_trap_pop_with_return (display))
            break;

        if (n_retries == max_retries)
        {
            /* This probably means that a non-WM compositor like xcompmgr is running;
             * we have no way to get it to exit */
            meta_fatal (_("Another compositing manager is already running on screen %i on display \"%s\"."),
                        screen_number, display->name);
        }

        n_retries++;
        g_usleep (G_USEC_PER_SEC);
    }

    info = g_new0 (MetaCompScreen, 1);
    /*
     * We use an empty input region for Clutter as a default because that allows
     * the user to interact with all the windows displayed on the screen.
     * We have to initialize info->pending_input_region to an empty region explicitly,
     * because None value is used to mean that the whole screen is an input region.
     */
    info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);

    info->screen = screen;

    meta_screen_set_compositor_data (screen, info);

    info->output = None;
    info->windows = NULL;

    meta_screen_set_cm_selection (screen);

    info->stage = clutter_stage_new ();

    meta_screen_get_size (screen, &width, &height);
    clutter_actor_realize (info->stage);

    xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));

    XResizeWindow (xdisplay, xwin, width, height);

    event_mask = FocusChangeMask |
                 ExposureMask |
                 EnterWindowMask | LeaveWindowMask |
                 PointerMotionMask |
                 PropertyChangeMask |
                 ButtonPressMask | ButtonReleaseMask |
                 KeyPressMask | KeyReleaseMask |
                 StructureNotifyMask;

    if (XGetWindowAttributes (xdisplay, xwin, &attr))
    {
        event_mask |= attr.your_event_mask;
    }

    XSelectInput (xdisplay, xwin, event_mask);

    info->window_group = meta_window_group_new (screen);
    info->background_actor = meta_background_actor_new_for_screen (screen);
    info->bottom_window_group = clutter_group_new();
    info->overlay_group = clutter_group_new ();
    info->top_window_group = meta_window_group_new (screen);
    info->hidden_group = clutter_group_new ();

    clutter_container_add (CLUTTER_CONTAINER (info->window_group),
                           info->background_actor,
                           NULL);

    clutter_container_add (CLUTTER_CONTAINER (info->stage),
                           info->window_group,
                           info->overlay_group,
                           info->hidden_group,
                           NULL);

    clutter_actor_hide (info->hidden_group);

    info->plugin_mgr =
        meta_plugin_manager_get (screen);
    meta_plugin_manager_initialize (info->plugin_mgr);

    /*
     * Delay the creation of the overlay window as long as we can, to avoid
     * blanking out the screen. This means that during the plugin loading, the
     * overlay window is not accessible; if the plugin needs to access it
     * directly, it should hook into the "show" signal on stage, and do
     * its stuff there.
     */
    info->output = get_output_window (screen);
    XReparentWindow (xdisplay, xwin, info->output, 0, 0);

    /* Make sure there isn't any left-over output shape on the
     * overlay window by setting the whole screen to be an
     * output region.
     *
     * Note: there doesn't seem to be any real chance of that
     *  because the X server will destroy the overlay window
     *  when the last client using it exits.
     */
    XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);

    do_set_stage_input_region (screen, info->pending_input_region);
    if (info->pending_input_region != None)
    {
        XFixesDestroyRegion (xdisplay, info->pending_input_region);
        info->pending_input_region = None;
    }

    clutter_actor_show (info->overlay_group);
    clutter_actor_show (info->stage);
}