Exemple #1
0
/**
 * meta_get_overlay_window: (skip)
 *
 */
Window
meta_get_overlay_window (MetaScreen *screen)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);

    return info->output;
}
Exemple #2
0
/**
 * meta_enable_unredirect_for_screen:
 * @screen: a #MetaScreen
 *
 * Enables unredirection which reduces the overhead for apps like games.
 *
 */
void
meta_enable_unredirect_for_screen (MetaScreen *screen)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);
    if (info != NULL)
        info->disable_unredirect_count = MAX(0, info->disable_unredirect_count - 1);
}
Exemple #3
0
void
meta_compositor_remove_window (MetaCompositor *compositor,
                               MetaWindow     *window)
{
    MetaWindowActor         *window_actor     = NULL;
    MetaScreen *screen;
    MetaCompScreen *info;

    DEBUG_TRACE ("meta_compositor_remove_window\n");
    window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
    if (!window_actor)
        return;

    screen = meta_window_get_screen (window);
    info = meta_screen_get_compositor_data (screen);

    if (window_actor == info->unredirected_window)
    {
        meta_window_actor_set_redirected (window_actor, TRUE);
        meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
                                   NULL);
        info->unredirected_window = NULL;
    }

    meta_window_actor_destroy (window_actor);
}
Exemple #4
0
void
meta_compositor_sync_screen_size (MetaCompositor  *compositor,
                                  MetaScreen	  *screen,
                                  guint		   width,
                                  guint		   height)
{
    MetaDisplay    *display = meta_screen_get_display (screen);
    MetaCompScreen *info    = meta_screen_get_compositor_data (screen);
    Display        *xdisplay;
    Window          xwin;

    DEBUG_TRACE ("meta_compositor_sync_screen_size\n");
    g_return_if_fail (info);

    xdisplay = meta_display_get_xdisplay (display);
    xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));

    XResizeWindow (xdisplay, xwin, width, height);

    meta_background_actor_screen_size_changed (screen);

    meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
                  meta_screen_get_screen_number (screen),
                  width, height);
}
Exemple #5
0
void
meta_set_stage_input_region (MetaScreen   *screen,
                             XserverRegion region)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);
    MetaDisplay  *display = meta_screen_get_display (screen);
    Display      *xdpy    = meta_display_get_xdisplay (display);

    if (info->stage && info->output)
    {
        do_set_stage_input_region (screen, region);
    }
    else
    {
        /* Reset info->pending_input_region if one existed before and set the new
         * one to use it later. */
        if (info->pending_input_region)
        {
            XFixesDestroyRegion (xdpy, info->pending_input_region);
            info->pending_input_region = None;
        }
        if (region != None)
        {
            info->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0);
            XFixesCopyRegion (xdpy, info->pending_input_region, region);
        }
    }
}
Exemple #6
0
/**
 * meta_get_background_actor_for_screen:
 * @screen: a #MetaScreen
 *
 * Gets the actor that draws the root window background under the windows.
 * The root window background automatically tracks the image or color set
 * by the environment.
 *
 * Returns: (transfer none): The background actor corresponding to @screen
 */
ClutterActor *
meta_get_background_actor_for_screen (MetaScreen *screen)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);

    if (!info)
        return NULL;

    return info->background_actor;
}
Exemple #7
0
/**
 * meta_get_top_window_group_for_screen:
 * @screen: a #MetaScreen
 *
 * Returns: (transfer none): The top window group corresponding to @screen
 */
ClutterActor *
meta_get_top_window_group_for_screen (MetaScreen *screen)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);

    if (!info)
        return NULL;

    return info->top_window_group;
}
Exemple #8
0
/**
 * meta_get_stage_for_screen:
 * @screen: a #MetaScreen
 *
 * Returns: (transfer none): The #ClutterStage for the screen
 */
ClutterActor *
meta_get_stage_for_screen (MetaScreen *screen)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);

    if (!info)
        return NULL;

    return info->stage;
}
Exemple #9
0
/**
 * meta_get_window_actors:
 * @screen: a #MetaScreen
 *
 * Returns: (transfer none) (element-type Clutter.Actor): The set of #MetaWindowActor on @screen
 */
GList *
meta_get_window_actors (MetaScreen *screen)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);

    if (!info)
        return NULL;

    return info->windows;
}
Exemple #10
0
static void
add_win (MetaWindow *window)
{
    MetaScreen		*screen = meta_window_get_screen (window);
    MetaCompScreen        *info = meta_screen_get_compositor_data (screen);

    g_return_if_fail (info != NULL);

    meta_window_actor_new (window);

    sync_actor_stacking (info);
}
Exemple #11
0
void
meta_compositor_sync_window_geometry (MetaCompositor *compositor,
                                      MetaWindow *window)
{
    MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
    MetaScreen      *screen = meta_window_get_screen (window);
    MetaCompScreen  *info = meta_screen_get_compositor_data (screen);

    DEBUG_TRACE ("meta_compositor_sync_window_geometry\n");
    g_return_if_fail (info);

    if (!window_actor)
        return;

    meta_window_actor_sync_actor_position (window_actor);
}
Exemple #12
0
LOCAL_SYMBOL void
meta_switch_workspace_completed (MetaScreen *screen)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);

    /* FIXME -- must redo stacking order */
    info->switch_workspace_in_progress--;
    if (info->switch_workspace_in_progress < 0)
    {
        g_warning ("Error in workspace_switch accounting!");
        info->switch_workspace_in_progress = 0;
    }

    if (!info->switch_workspace_in_progress)
        meta_finish_workspace_switch (info);
}
Exemple #13
0
static void
do_set_stage_input_region (MetaScreen   *screen,
                           XserverRegion region)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);
    MetaDisplay *display = meta_screen_get_display (screen);
    Display        *xdpy = meta_display_get_xdisplay (display);
    Window        xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));

    XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region);

    /* It's generally a good heuristic that when a crossing event is generated because
     * we reshape the overlay, we don't want it to affect focus-follows-mouse focus -
     * it's not the user doing something, it's the environment changing under the user.
     */
    meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy));
    XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region);
}
Exemple #14
0
static gboolean
meta_repaint_func (gpointer data)
{
    MetaCompositor *compositor = data;
    GSList *screens = meta_display_get_screens (compositor->display);
    GSList *l;

    for (l = screens; l; l = l->next)
    {
        MetaScreen *screen = l->data;
        MetaCompScreen *info = meta_screen_get_compositor_data (screen);
        if (!info)
            continue;

        pre_paint_windows (info);
    }

    return TRUE;
}
Exemple #15
0
static void
on_shadow_factory_changed (MetaShadowFactory *factory,
                           MetaCompositor    *compositor)
{
    GSList *screens = meta_display_get_screens (compositor->display);
    GList *l;
    GSList *sl;

    for (sl = screens; sl; sl = sl->next)
    {
        MetaScreen *screen = sl->data;
        MetaCompScreen *info = meta_screen_get_compositor_data (screen);
        if (!info)
            continue;

        for (l = info->windows; l; l = l->next)
            meta_window_actor_invalidate_shadow (l->data);
    }
}
Exemple #16
0
void
meta_compositor_update_workspace_geometry (MetaCompositor *compositor,
        MetaWorkspace  *workspace)
{
#if 0
    /* FIXME -- should do away with this function in favour of MetaWorkspace
     * signal.
     */
    MetaScreen     *screen = meta_workspace_get_screen (workspace);
    MetaCompScreen *info;
    MetaPluginManager *mgr;

    DEBUG_TRACE ("meta_compositor_update_workspace_geometry\n");
    info = meta_screen_get_compositor_data (screen);
    mgr  = info->plugin_mgr;

    if (!mgr || !workspace)
        return;

    meta_plugin_manager_update_workspace (mgr, workspace);
#endif
}
Exemple #17
0
void
meta_compositor_switch_workspace (MetaCompositor     *compositor,
                                  MetaScreen         *screen,
                                  MetaWorkspace      *from,
                                  MetaWorkspace      *to,
                                  MetaMotionDirection direction)
{
    MetaCompScreen *info;
    gint            to_indx, from_indx;

    info      = meta_screen_get_compositor_data (screen);
    to_indx   = meta_workspace_index (to);
    from_indx = meta_workspace_index (from);

    DEBUG_TRACE ("meta_compositor_switch_workspace\n");

    if (!info) /* During startup before manage_screen() */
        return;

    info->switch_workspace_in_progress++;

    if (!info->plugin_mgr ||
            !meta_plugin_manager_switch_workspace (info->plugin_mgr,
                    from_indx,
                    to_indx,
                    direction))
    {
        info->switch_workspace_in_progress--;

        /* We have to explicitely call this to fix up stacking order of the
         * actors; this is because the abs stacking position of actors does not
         * necessarily change during the window hiding/unhiding, only their
         * relative position toward the destkop window.
         */
        meta_finish_workspace_switch (info);
    }
}
Exemple #18
0
/*
 * Shapes the cow so that the given window is exposed,
 * when metaWindow is NULL it clears the shape again
 */
static void
meta_shape_cow_for_window (MetaScreen *screen,
                           MetaWindow *metaWindow)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);
    Display *xdisplay = meta_display_get_xdisplay (meta_screen_get_display (screen));

    if (metaWindow == NULL)
        XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
    else
    {
        XserverRegion output_region;
        XRectangle screen_rect, window_bounds;
        int width, height;
        MetaRectangle rect;

        meta_window_get_outer_rect (metaWindow, &rect);

        window_bounds.x = rect.x;
        window_bounds.y = rect.y;
        window_bounds.width = rect.width;
        window_bounds.height = rect.height;

        meta_screen_get_size (screen, &width, &height);
        screen_rect.x = 0;
        screen_rect.y = 0;
        screen_rect.width = width;
        screen_rect.height = height;

        output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1);

        XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region);
        XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, output_region);
        XFixesDestroyRegion (xdisplay, output_region);
    }
}
Exemple #19
0
/**
 * meta_compositor_process_event: (skip)
 *
 */
gboolean
meta_compositor_process_event (MetaCompositor *compositor,
                               XEvent         *event,
                               MetaWindow     *window)
{
    if (compositor->modal_plugin && is_grabbed_event (event))
    {
        MetaPluginClass *klass = META_PLUGIN_GET_CLASS (compositor->modal_plugin);

        if (klass->xevent_filter)
            klass->xevent_filter (compositor->modal_plugin, event);

        /* We always consume events even if the plugin says it didn't handle them;
         * exclusive is exclusive */
        return TRUE;
    }

    if (window)
    {
        MetaCompScreen *info;
        MetaScreen     *screen;

        screen = meta_window_get_screen (window);
        info = meta_screen_get_compositor_data (screen);

        if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
        {
            DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
            return TRUE;
        }
    }
    else
    {
        GSList *l;

        l = meta_display_get_screens (compositor->display);

        while (l)
        {
            MetaScreen     *screen = l->data;
            MetaCompScreen *info;

            info = meta_screen_get_compositor_data (screen);

            if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
            {
                DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
                return TRUE;
            }

            l = l->next;
        }
    }

    switch (event->type)
    {
    case PropertyNotify:
        process_property_notify (compositor, (XPropertyEvent *) event, window);
        break;

    default:
        if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
        {
            /* Core code doesn't handle damage events, so we need to extract the MetaWindow
             * ourselves
             */
            if (window == NULL)
            {
                Window xwin = ((XDamageNotifyEvent *) event)->drawable;
                window = meta_display_lookup_x_window (compositor->display, xwin);
            }

            DEBUG_TRACE ("meta_compositor_process_event (process_damage)\n");
            process_damage (compositor, (XDamageNotifyEvent *) event, window);
        }
        break;
    }

    /* Clutter needs to know about MapNotify events otherwise it will
       think the stage is invisible */
    if (event->type == MapNotify)
        clutter_x11_handle_event (event);

    /* The above handling is basically just "observing" the events, so we return
     * FALSE to indicate that the event should not be filtered out; if we have
     * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example.
     */
    return FALSE;
}
Exemple #20
0
static void
meta_window_group_paint (ClutterActor *actor)
{
  cairo_region_t *visible_region;
  cairo_region_t *unredirected_window_region = NULL;
  ClutterActor *stage;
  cairo_rectangle_int_t visible_rect, unredirected_rect;
  GList *children, *l;

  MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
  MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
  if (info->unredirected_window != NULL)
    {
      meta_window_actor_get_shape_bounds (META_WINDOW_ACTOR (info->unredirected_window), &unredirected_rect);
      unredirected_window_region = cairo_region_create_rectangle (&unredirected_rect);
    }

  /* We walk the list from top to bottom (opposite of painting order),
   * and subtract the opaque area of each window out of the visible
   * region that we pass to the windows below.
   */
  children = clutter_container_get_children (CLUTTER_CONTAINER (actor));
  children = g_list_reverse (children);

  /* Get the clipped redraw bounds from Clutter so that we can avoid
   * painting shadows on windows that don't need to be painted in this
   * frame. In the case of a multihead setup with mismatched monitor
   * sizes, we could intersect this with an accurate union of the
   * monitors to avoid painting shadows that are visible only in the
   * holes. */
  stage = clutter_actor_get_stage (actor);
  clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage),
                                        &visible_rect);

  visible_region = cairo_region_create_rectangle (&visible_rect);

  if (unredirected_window_region)
    cairo_region_subtract (visible_region, unredirected_window_region);

  for (l = children; l; l = l->next)
    {
      if (!CLUTTER_ACTOR_IS_VISIBLE (l->data))
        continue;

      /* If an actor has effects applied, then that can change the area
       * it paints and the opacity, so we no longer can figure out what
       * portion of the actor is obscured and what portion of the screen
       * it obscures, so we skip the actor.
       *
       * This has a secondary beneficial effect: if a ClutterOffscreenEffect
       * is applied to an actor, then our clipped redraws interfere with the
       * caching of the FBO - even if we only need to draw a small portion
       * of the window right now, ClutterOffscreenEffect may use other portions
       * of the FBO later. So, skipping actors with effects applied also
       * prevents these bugs.
       *
       * Theoretically, we should check clutter_actor_get_offscreen_redirect()
       * as well for the same reason, but omitted for simplicity in the
       * hopes that no-one will do that.
       */
      if (clutter_actor_has_effects (l->data))
        continue;

      if (META_IS_WINDOW_ACTOR (l->data))
        {
          MetaWindowActor *window_actor = l->data;
          int x, y;

          if (!actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
            continue;

          /* Temporarily move to the coordinate system of the actor */
          cairo_region_translate (visible_region, - x, - y);

          meta_window_actor_set_visible_region (window_actor, visible_region);

          if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
            {
              cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
              if (obscured_region)
                cairo_region_subtract (visible_region, obscured_region);
            }

          meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
          cairo_region_translate (visible_region, x, y);
        }
      else if (META_IS_BACKGROUND_ACTOR (l->data))
        {
          MetaBackgroundActor *background_actor = l->data;
          meta_background_actor_set_visible_region (background_actor, visible_region);
        }
    }

  cairo_region_destroy (visible_region);

  if (unredirected_window_region)
    cairo_region_destroy (unredirected_window_region);

  CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);

  /* Now that we are done painting, unset the visible regions (they will
   * mess up painting clones of our actors)
   */
  for (l = children; l; l = l->next)
    {
      if (META_IS_WINDOW_ACTOR (l->data))
        {
          MetaWindowActor *window_actor = l->data;
          window_actor = l->data;
          meta_window_actor_reset_visible_regions (window_actor);
        }
      else if (META_IS_BACKGROUND_ACTOR (l->data))
        {
          MetaBackgroundActor *background_actor = l->data;
          meta_background_actor_set_visible_region (background_actor, NULL);
        }
    }

  g_list_free (children);
}
Exemple #21
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);
}
Exemple #22
0
static void
meta_window_group_paint (ClutterActor *actor)
{
  cairo_region_t *visible_region;
  ClutterActor *stage;
  cairo_rectangle_int_t visible_rect;
  GList *children, *l;
  int paint_x_origin, paint_y_origin;
  int actor_x_origin, actor_y_origin;
  int paint_x_offset, paint_y_offset;

  MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
  MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);

  /* Normally we expect an actor to be drawn at it's position on the screen.
   * However, if we're inside the paint of a ClutterClone, that won't be the
   * case and we need to compensate. We look at the position of the window
   * group under the current model-view matrix and the position of the actor.
   * If they are both simply integer translations, then we can compensate
   * easily, otherwise we give up.
   *
   * Possible cleanup: work entirely in paint space - we can compute the
   * combination of the model-view matrix with the local matrix for each child
   * actor and get a total transformation for that actor for how we are
   * painting currently, and never worry about how actors are positioned
   * on the stage.
   */
  if (!painting_untransformed (window_group, &paint_x_origin, &paint_y_origin) ||
      !meta_actor_is_untransformed (actor, &actor_x_origin, &actor_y_origin))
    {
      CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
      return;
    }

  paint_x_offset = paint_x_origin - actor_x_origin;
  paint_y_offset = paint_y_origin - actor_y_origin;

  /* We walk the list from top to bottom (opposite of painting order),
   * and subtract the opaque area of each window out of the visible
   * region that we pass to the windows below.
   */
  children = clutter_actor_get_children (actor);
  children = g_list_reverse (children);

  /* Get the clipped redraw bounds from Clutter so that we can avoid
   * painting shadows on windows that don't need to be painted in this
   * frame. In the case of a multihead setup with mismatched monitor
   * sizes, we could intersect this with an accurate union of the
   * monitors to avoid painting shadows that are visible only in the
   * holes. */
  stage = clutter_actor_get_stage (actor);
  clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage),
                                        &visible_rect);

  visible_region = cairo_region_create_rectangle (&visible_rect);

  if (info->unredirected_window != NULL)
    {
      cairo_rectangle_int_t unredirected_rect;
      MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);

      meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
      cairo_region_subtract_rectangle (visible_region, &unredirected_rect);
    }

  for (l = children; l; l = l->next)
    {
      if (!CLUTTER_ACTOR_IS_VISIBLE (l->data))
        continue;

      if (l->data == info->unredirected_window)
        continue;

      /* If an actor has effects applied, then that can change the area
       * it paints and the opacity, so we no longer can figure out what
       * portion of the actor is obscured and what portion of the screen
       * it obscures, so we skip the actor.
       *
       * This has a secondary beneficial effect: if a ClutterOffscreenEffect
       * is applied to an actor, then our clipped redraws interfere with the
       * caching of the FBO - even if we only need to draw a small portion
       * of the window right now, ClutterOffscreenEffect may use other portions
       * of the FBO later. So, skipping actors with effects applied also
       * prevents these bugs.
       *
       * Theoretically, we should check clutter_actor_get_offscreen_redirect()
       * as well for the same reason, but omitted for simplicity in the
       * hopes that no-one will do that.
       */
      if (clutter_actor_has_effects (l->data))
        continue;

      if (META_IS_WINDOW_ACTOR (l->data))
        {
          MetaWindowActor *window_actor = l->data;
          int x, y;

          if (!meta_actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
            continue;

          x += paint_x_offset;
          y += paint_y_offset;

          /* Temporarily move to the coordinate system of the actor */
          cairo_region_translate (visible_region, - x, - y);

          meta_window_actor_set_visible_region (window_actor, visible_region);

          if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
            {
              cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
              if (obscured_region)
                cairo_region_subtract (visible_region, obscured_region);
            }

          meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
          cairo_region_translate (visible_region, x, y);
        }
      else if (META_IS_BACKGROUND_ACTOR (l->data) ||
               META_IS_BACKGROUND_GROUP (l->data))
        {
          ClutterActor *background_actor = l->data;
          int x, y;

          if (!meta_actor_is_untransformed (CLUTTER_ACTOR (background_actor), &x, &y))
            continue;

          x += paint_x_offset;
          y += paint_y_offset;

          cairo_region_translate (visible_region, - x, - y);

          if (META_IS_BACKGROUND_GROUP (background_actor))
            meta_background_group_set_visible_region (META_BACKGROUND_GROUP (background_actor), visible_region);
          else
            meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (background_actor), visible_region);
          cairo_region_translate (visible_region, x, y);
        }
    }

  cairo_region_destroy (visible_region);

  CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);

  /* Now that we are done painting, unset the visible regions (they will
   * mess up painting clones of our actors)
   */
  for (l = children; l; l = l->next)
    {
      if (META_IS_WINDOW_ACTOR (l->data))
        {
          MetaWindowActor *window_actor = l->data;
          meta_window_actor_reset_visible_regions (window_actor);
        }
      else if (META_IS_BACKGROUND_ACTOR (l->data))
        {
          MetaBackgroundActor *background_actor = l->data;
          meta_background_actor_set_visible_region (background_actor, NULL);
        }
    }

  g_list_free (children);
}
Exemple #23
0
void
meta_compositor_sync_stack (MetaCompositor  *compositor,
                            MetaScreen	    *screen,
                            GList	    *stack)
{
    GList *old_stack;
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);

    DEBUG_TRACE ("meta_compositor_sync_stack\n");

    /* This is painful because hidden windows that we are in the process
     * of animating out of existence. They'll be at the bottom of the
     * stack of X windows, but we want to leave them in their old position
     * until the animation effect finishes.
     */

    /* Sources: first window is the highest */
    stack = g_list_copy (stack); /* The new stack of MetaWindow */
    old_stack = g_list_reverse (info->windows); /* The old stack of MetaWindowActor */
    info->windows = NULL;

    while (TRUE)
    {
        MetaWindowActor *old_actor = NULL, *stack_actor = NULL, *actor;
        MetaWindow *old_window = NULL, *stack_window = NULL, *window;

        /* Find the remaining top actor in our existing stack (ignoring
         * windows that have been hidden and are no longer animating) */
        while (old_stack)
        {
            old_actor = old_stack->data;
            old_window = meta_window_actor_get_meta_window (old_actor);

            if (old_window->hidden &&
                    !meta_window_actor_effect_in_progress (old_actor))
            {
                old_stack = g_list_delete_link (old_stack, old_stack);
                old_actor = NULL;
            }
            else
                break;
        }

        /* And the remaining top actor in the new stack */
        while (stack)
        {
            stack_window = stack->data;
            stack_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (stack_window));
            if (!stack_actor)
            {
                meta_verbose ("Failed to find corresponding MetaWindowActor "
                              "for window %s\n", meta_window_get_description (stack_window));
                stack = g_list_delete_link (stack, stack);
            }
            else
                break;
        }

        if (!old_actor && !stack_actor) /* Nothing more to stack */
            break;

        /* We usually prefer the window in the new stack, but if if we
         * found a hidden window in the process of being animated out
         * of existence in the old stack we use that instead. We've
         * filtered out non-animating hidden windows above.
         */
        if (old_actor &&
                (!stack_actor || old_window->hidden))
        {
            actor = old_actor;
            window = old_window;
        }
        else
        {
            actor = stack_actor;
            window = stack_window;
        }

        /* OK, we know what actor we want next. Add it to our window
         * list, and remove it from both source lists. (It will
         * be at the front of at least one, hopefully it will be
         * near the front of the other.)
         */
        info->windows = g_list_prepend (info->windows, actor);

        stack = g_list_remove (stack, window);
        old_stack = g_list_remove (old_stack, actor);
    }

    sync_actor_stacking (info);
}