Ejemplo n.º 1
0
/*
 * Minimize effect completion callback; this function restores actor state, and
 * calls the manager callback function.
 */
static void
on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
{
  /*
   * Must reverse the effect of the effect; must hide it first to ensure
   * that the restoration will not be visible.
   */
  MetaPlugin *plugin = data->plugin;
  ActorPrivate *apriv;
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);

  apriv = get_actor_private (META_WINDOW_ACTOR (data->actor));
  apriv->tml_minimize = NULL;

  clutter_actor_hide (data->actor);

  /* FIXME - we shouldn't assume the original scale, it should be saved
   * at the start of the effect */
  clutter_actor_set_scale (data->actor, 1.0, 1.0);
  clutter_actor_move_anchor_point_from_gravity (data->actor,
                                                CLUTTER_GRAVITY_NORTH_WEST);

  /* Now notify the manager that we are done with this effect */
  meta_plugin_minimize_completed (plugin, window_actor);

  g_free (data);
}
Ejemplo n.º 2
0
static gint window_compare(gconstpointer a, gconstpointer b)
{
    ClutterActor* aa = *(ClutterActor**)a;
    ClutterActor* bb = *(ClutterActor**)b;

    MetaWindowActor* a1 = META_WINDOW_ACTOR(clutter_clone_get_source(CLUTTER_CLONE(aa)));
    MetaWindowActor* b1 = META_WINDOW_ACTOR(clutter_clone_get_source(CLUTTER_CLONE(bb)));

    MetaWindow* w1 = meta_window_actor_get_meta_window(a1);
    MetaWindow* w2 = meta_window_actor_get_meta_window(b1);
    return meta_window_get_stable_sequence(w1) - meta_window_get_stable_sequence(w2);
}
Ejemplo n.º 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);
}
Ejemplo n.º 4
0
void
meta_compositor_sync_updates_frozen (MetaCompositor *compositor,
                                     MetaWindow     *window)
{
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  meta_window_actor_sync_updates_frozen (window_actor);
}
Ejemplo n.º 5
0
/**
 * Simply restore pivot point and complete the effect within mutter
 */
static void map_done(ClutterActor *actor, MetaPlugin *plugin)
{
        clutter_actor_remove_all_transitions(actor);
        g_signal_handlers_disconnect_by_func(actor, G_CALLBACK(map_done), plugin);
        g_object_set(actor, "pivot-point", &PV_NORM, NULL);
        meta_plugin_map_completed(plugin, META_WINDOW_ACTOR(actor));
}
Ejemplo n.º 6
0
static void
meta_window_group_reset_culling (MetaWindowGroup *group)
{
  ClutterActor *actor = CLUTTER_ACTOR (group);
  ClutterActor *child;
  ClutterActorIter iter;

  /* Now that we are done painting, unset the visible regions (they will
   * mess up painting clones of our actors)
   */
  clutter_actor_iter_init (&iter, actor);
  while (clutter_actor_iter_next (&iter, &child))
    {
      if (META_IS_WINDOW_ACTOR (child))
        {
          MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
          meta_window_actor_reset_visible_regions (window_actor);
        }
      else if (META_IS_BACKGROUND_ACTOR (child))
        {
          MetaBackgroundActor *background_actor = META_BACKGROUND_ACTOR (child);
          meta_background_actor_set_visible_region (background_actor, NULL);
        }
    }
}
Ejemplo n.º 7
0
static void
on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data)
{
  MetaPlugin               *plugin  = META_PLUGIN (data);
  MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
  MetaScreen *screen = meta_plugin_get_screen (plugin);
  GList *l = meta_get_window_actors (screen);

  while (l)
    {
      ClutterActor *a = l->data;
      MetaWindowActor *window_actor = META_WINDOW_ACTOR (a);
      ActorPrivate *apriv = get_actor_private (window_actor);

      if (apriv->orig_parent)
        {
          clutter_actor_reparent (a, apriv->orig_parent);
          apriv->orig_parent = NULL;
        }

      l = l->next;
    }

  clutter_actor_destroy (priv->desktop1);
  clutter_actor_destroy (priv->desktop2);

  priv->tml_switch_workspace1 = NULL;
  priv->tml_switch_workspace2 = NULL;
  priv->desktop1 = NULL;
  priv->desktop2 = NULL;

  meta_plugin_switch_workspace_completed (plugin);
}
Ejemplo n.º 8
0
void
meta_compositor_hide_window (MetaCompositor *compositor,
                             MetaWindow     *window,
                             MetaCompEffect  effect)
{
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  meta_window_actor_hide (window_actor, effect);
}
Ejemplo n.º 9
0
void
meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
                                   MetaWindow     *window,
                                   gboolean        no_delay_frame)
{
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
}
Ejemplo n.º 10
0
void
meta_compositor_sync_window_geometry (MetaCompositor *compositor,
				      MetaWindow *window,
                                      gboolean did_placement)
{
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  meta_window_actor_sync_actor_geometry (window_actor, did_placement);
}
Ejemplo n.º 11
0
void
meta_compositor_window_shape_changed (MetaCompositor *compositor,
                                      MetaWindow     *window)
{
    MetaWindowActor *window_actor;
    window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
    meta_window_actor_update_shape (window_actor);
}
Ejemplo n.º 12
0
void
meta_compositor_unmaximize_window (MetaCompositor    *compositor,
                                   MetaWindow        *window,
				   MetaRectangle     *old_rect,
				   MetaRectangle     *new_rect)
{
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  meta_window_actor_unmaximize (window_actor, old_rect, new_rect);
}
Ejemplo n.º 13
0
static void prepare_workspace_content(MosesOverview *self, MetaWorkspace *ws)
{
    MosesOverviewPrivate* priv = self->priv;
    GList* l = meta_workspace_list_windows(ws);
    if (!priv->clones) { priv->clones = g_ptr_array_new(); }

    while (l) {
        MetaWindow* win = l->data;
        MetaWindowActor* win_actor = META_WINDOW_ACTOR(meta_window_get_compositor_private(win));

        if (meta_window_get_window_type(win) == META_WINDOW_DESKTOP) {
            g_debug("%s: got desktop actor", __func__);
            priv->background_actor = clutter_clone_new(CLUTTER_ACTOR(win_actor));

        } else if (meta_window_get_window_type(win) == META_WINDOW_NORMAL &&
                !meta_window_is_hidden(win)) {
            ClutterActor* clone = clutter_clone_new(CLUTTER_ACTOR(win_actor));
            clutter_actor_set_reactive(clone, TRUE);

            float x = 0.0, y = 0.0;
            clutter_actor_get_position(CLUTTER_ACTOR(win_actor), &x, &y);
            clutter_actor_set_position(clone, x, y);

            clutter_actor_hide(CLUTTER_ACTOR(win_actor));

            g_ptr_array_add(priv->clones, clone);
            clutter_actor_add_child(CLUTTER_ACTOR(self), clone);

            g_object_connect(clone,
                    "signal::transitions-completed", G_CALLBACK(on_effect_complete), self,
                    "signal::button-press-event", on_thumb_button_press, self,
                    "signal::enter-event", on_thumb_enter, self,
                    "signal::leave-event", on_thumb_leave, self,
                    NULL);
        }

        l = l->next;
    }

    ClutterColor clr = CLUTTER_COLOR_INIT(0xff, 0xff, 0xff, 0xff);
    clutter_actor_set_background_color(CLUTTER_ACTOR(self), &clr);

    if (priv->background_actor) {
#if 0
        ClutterEffect* blur = moses_blur_effect_new();
        clutter_actor_add_effect_with_name(priv->background_actor, "blur", blur);
        clutter_actor_insert_child_below(CLUTTER_ACTOR(self), priv->background_actor, NULL);
        clutter_actor_hide(clutter_clone_get_source(CLUTTER_CLONE(priv->background_actor)));
        clutter_actor_set_reactive(priv->background_actor, TRUE);
#endif
    }

    g_object_connect(priv->background_actor ? priv->background_actor: CLUTTER_ACTOR(self),
            "signal::button-press-event", on_bg_button_press, self,
            NULL);
}
Ejemplo n.º 14
0
void
meta_compositor_size_change_window (MetaCompositor    *compositor,
                                    MetaWindow        *window,
                                    MetaSizeChange     which_change,
                                    MetaRectangle     *old_frame_rect,
                                    MetaRectangle     *old_buffer_rect)
{
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  meta_window_actor_size_change (window_actor, which_change, old_frame_rect, old_buffer_rect);
}
Ejemplo n.º 15
0
static void
process_damage (MetaCompositor     *compositor,
                XDamageNotifyEvent *event,
                MetaWindow         *window)
{
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  meta_window_actor_process_x11_damage (window_actor, event);

  compositor->frame_has_updated_xsurfaces = TRUE;
}
Ejemplo n.º 16
0
void
meta_compositor_window_unmapped (MetaCompositor *compositor,
                                 MetaWindow     *window)
{
    MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
    DEBUG_TRACE ("meta_compositor_window_unmapped\n");
    if (!window_actor)
        return;

    meta_window_actor_unmapped (window_actor);
}
Ejemplo n.º 17
0
/*
 * Destroy effect completion callback; this is a simple effect that requires no
 * further action than notifying the manager that the effect is completed.
 */
static void
on_destroy_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
{
  MetaPlugin *plugin = data->plugin;
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
  ActorPrivate *apriv = get_actor_private (window_actor);

  apriv->tml_destroy = NULL;

  meta_plugin_destroy_completed (plugin, window_actor);
}
Ejemplo n.º 18
0
void
meta_compositor_remove_window (MetaCompositor *compositor,
                               MetaWindow     *window)
{
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));

  if (compositor->unredirected_window == window)
    set_unredirected_window (compositor, NULL);

  meta_window_actor_destroy (window_actor);
}
Ejemplo n.º 19
0
void
meta_compositor_window_opacity_changed (MetaCompositor *compositor,
                                        MetaWindow     *window)
{
  MetaWindowActor *window_actor;
  window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  if (!window_actor)
    return;

  meta_window_actor_update_opacity (window_actor);
}
Ejemplo n.º 20
0
void
meta_compositor_hide_window (MetaCompositor *compositor,
                             MetaWindow     *window,
                             MetaCompEffect  effect)
{
    MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
    DEBUG_TRACE ("meta_compositor_hide_window\n");
    if (!window_actor)
        return;

    meta_window_actor_hide (window_actor, effect);
}
Ejemplo n.º 21
0
void
meta_compositor_unmaximize_window (MetaCompositor    *compositor,
                                   MetaWindow        *window,
                                   MetaRectangle     *old_rect,
                                   MetaRectangle     *new_rect)
{
    MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
    DEBUG_TRACE ("meta_compositor_unmaximize_window\n");
    if (!window_actor)
        return;

    meta_window_actor_unmaximize (window_actor, old_rect, new_rect);
}
Ejemplo n.º 22
0
static void
set_unredirected_window (MetaCompositor *compositor,
                         MetaWindow     *window)
{
  if (compositor->unredirected_window == window)
    return;

  if (compositor->unredirected_window != NULL)
    {
      MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window));
      meta_window_actor_set_unredirected (window_actor, FALSE);
    }

  meta_shape_cow_for_window (compositor, window);
  compositor->unredirected_window = window;

  if (compositor->unredirected_window != NULL)
    {
      MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window));
      meta_window_actor_set_unredirected (window_actor, TRUE);
    }
}
Ejemplo n.º 23
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);
}
Ejemplo n.º 24
0
static void
process_damage (MetaCompositor     *compositor,
                XDamageNotifyEvent *event,
                MetaWindow         *window)
{
    MetaWindowActor *window_actor;

    if (window == NULL)
        return;

    window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
    if (window_actor == NULL)
        return;

    meta_window_actor_process_damage (window_actor, event);
}
Ejemplo n.º 25
0
static void
on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
{
  /*
   * Must reverse the effect of the effect.
   */
  MetaPlugin *plugin = data->plugin;
  MetaWindowActor  *window_actor = META_WINDOW_ACTOR (data->actor);
  ActorPrivate  *apriv = get_actor_private (window_actor);

  apriv->tml_map = NULL;

  /* Now notify the manager that we are done with this effect */
  meta_plugin_map_completed (plugin, window_actor);

  g_free (data);
}
Ejemplo n.º 26
0
/*
 * Minimize effect completion callback; this function restores actor state, and
 * calls the manager callback function.
 */
static void
on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
{
  /*
   * Must reverse the effect of the effect.
   */
  MetaPlugin *plugin = data->plugin;
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
  ActorPrivate *apriv = get_actor_private (window_actor);

  apriv->tml_maximize = NULL;

  /* FIXME - don't assume the original scale was 1.0 */
  clutter_actor_set_scale (data->actor, 1.0, 1.0);
  clutter_actor_move_anchor_point_from_gravity (data->actor,
                                                CLUTTER_GRAVITY_NORTH_WEST);

  /* Now notify the manager that we are done with this effect */
  meta_plugin_maximize_completed (plugin, window_actor);

  g_free (data);
}
Ejemplo n.º 27
0
static void
process_property_notify (MetaCompositor	*compositor,
                         XPropertyEvent *event,
                         MetaWindow     *window)
{
    MetaWindowActor *window_actor;

    if (event->atom == compositor->atom_x_root_pixmap)
    {
        GSList *l;

        for (l = meta_display_get_screens (compositor->display); l; l = l->next)
        {
            MetaScreen  *screen = l->data;
            if (event->window == meta_screen_get_xroot (screen))
            {
                meta_background_actor_update (screen);
                return;
            }
        }
    }

    if (window == NULL)
        return;

    window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
    if (window_actor == NULL)
        return;

    /* Check for the opacity changing */
    if (event->atom == compositor->atom_net_wm_window_opacity)
    {
        meta_window_actor_update_opacity (window_actor);
        DEBUG_TRACE ("process_property_notify: net_wm_window_opacity\n");
        return;
    }

    DEBUG_TRACE ("process_property_notify: unknown\n");
}
Ejemplo n.º 28
0
static void
meta_window_group_paint (ClutterActor *actor)
{
  cairo_region_t *clip_region;
  cairo_region_t *unobscured_region;
  ClutterActorIter iter;
  ClutterActor *child;
  cairo_rectangle_int_t visible_rect, clip_rect;
  int paint_x_offset, paint_y_offset;
  int paint_x_origin, paint_y_origin;
  int actor_x_origin, actor_y_origin;

  MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
  MetaCompositor *compositor = window_group->screen->display->compositor;
  ClutterActor *stage = CLUTTER_STAGE (compositor->stage);

  /* Start off by treating all windows as completely unobscured, so damage anywhere
   * in a window queues redraws, but confine it more below. */
  clutter_actor_iter_init (&iter, actor);
  while (clutter_actor_iter_next (&iter, &child))
    {
      if (META_IS_WINDOW_ACTOR (child))
        {
          MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
          meta_window_actor_set_unobscured_region (window_actor, NULL);
        }
    }

  /* 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;

  visible_rect.x = visible_rect.y = 0;
  visible_rect.width = clutter_actor_get_width (stage);
  visible_rect.height = clutter_actor_get_height (stage);

  unobscured_region = cairo_region_create_rectangle (&visible_rect);

  /* 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. */
  clutter_stage_get_redraw_clip_bounds (stage, &clip_rect);

  clip_region = cairo_region_create_rectangle (&clip_rect);

  cairo_region_translate (clip_region, -paint_x_offset, -paint_y_offset);

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

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

  meta_window_group_cull_out (window_group,
                              CLUTTER_ACTOR (compositor->unredirected_window),
                              has_unredirected_window,
                              unobscured_region,
                              clip_region);

  cairo_region_destroy (unobscured_region);
  cairo_region_destroy (clip_region);

  CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);

  meta_window_group_reset_culling (window_group);
}
Ejemplo n.º 29
0
static void
meta_window_group_cull_out (MetaWindowGroup *group,
                            ClutterActor    *unredirected_window,
                            gboolean         has_unredirected_window,
                            cairo_region_t  *unobscured_region,
                            cairo_region_t  *clip_region)
{
  ClutterActor *actor = CLUTTER_ACTOR (group);
  ClutterActor *child;
  ClutterActorIter iter;

  /* 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.
   */
  clutter_actor_iter_init (&iter, actor);
  while (clutter_actor_iter_prev (&iter, &child))
    {
      if (!CLUTTER_ACTOR_IS_VISIBLE (child))
        continue;

      if (has_unredirected_window && child == 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 (child))
        continue;

      if (META_IS_WINDOW_ACTOR (child))
        {
          MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
          int x, y;

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

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

          meta_window_actor_set_unobscured_region (window_actor, unobscured_region);
          meta_window_actor_set_visible_region (window_actor, clip_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 (unobscured_region, obscured_region);
                  cairo_region_subtract (clip_region, obscured_region);
                }
            }

          meta_window_actor_set_visible_region_beneath (window_actor, clip_region);

          cairo_region_translate (unobscured_region, x, y);
          cairo_region_translate (clip_region, x, y);
        }
      else if (META_IS_BACKGROUND_ACTOR (child))
        {
          int x, y;

          if (!meta_actor_is_untransformed (child, &x, &y))
            continue;

          cairo_region_translate (clip_region, - x, - y);

          meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (child), clip_region);

          cairo_region_translate (clip_region, x, y);
        }
    }
}
Ejemplo n.º 30
0
/**
 * shell_screenshot_screenshot_window:
 * @screenshot: the #ShellScreenshot
 * @include_frame: Whether to include the frame or not
 * @include_cursor: Whether to include the cursor or not
 * @filename: The filename for the screenshot
 * @callback: (scope async): function to call returning success or failure
 * of the async grabbing
 *
 * Takes a screenshot of the focused window (optionally omitting the frame)
 * in @filename as png image.
 *
 */
void
shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
                                    gboolean include_frame,
                                    gboolean include_cursor,
                                    const char *filename,
                                    ShellScreenshotCallback callback)
{
  GSimpleAsyncResult *result;
  GSettings *settings;

  _screenshot_data *screenshot_data = g_new0 (_screenshot_data, 1);

  MetaScreen *screen = shell_global_get_screen (screenshot->global);
  MetaCursorTracker *tracker;
  MetaDisplay *display = meta_screen_get_display (screen);
  MetaWindow *window = meta_display_get_focus_window (display);
  ClutterActor *window_actor;
  gfloat actor_x, actor_y;
  MetaShapedTexture *stex;
  MetaRectangle rect;
  cairo_rectangle_int_t clip;

  screenshot_data->screenshot = g_object_ref (screenshot);
  screenshot_data->filename = g_strdup (filename);
  screenshot_data->callback = callback;

  if (!window)
    {
      screenshot_data->filename_used = g_strdup ("");
      result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window);
      g_simple_async_result_set_op_res_gboolean (result, FALSE);
      g_simple_async_result_complete (result);
      g_object_unref (result);

      return;
    }

  window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
  clutter_actor_get_position (window_actor, &actor_x, &actor_y);

  if (include_frame || !meta_window_get_frame (window))
    {
      meta_window_get_outer_rect (window, &rect);

      screenshot_data->screenshot_area.x = rect.x;
      screenshot_data->screenshot_area.y = rect.y;

      clip.x = rect.x - (gint) actor_x;
      clip.y = rect.y - (gint) actor_y;
    }
  else
    {
      rect = *meta_window_get_rect (window);

      screenshot_data->screenshot_area.x = (gint) actor_x + rect.x;
      screenshot_data->screenshot_area.y = (gint) actor_y + rect.y;

      clip.x = rect.x;
      clip.y = rect.y;
    }

  clip.width = screenshot_data->screenshot_area.width = rect.width;
  clip.height = screenshot_data->screenshot_area.height = rect.height;

  stex = META_SHAPED_TEXTURE (meta_window_actor_get_texture (META_WINDOW_ACTOR (window_actor)));
  screenshot_data->image = meta_shaped_texture_get_image (stex, &clip);

  settings = g_settings_new (A11Y_APPS_SCHEMA);
  if (include_cursor && !g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
    {
      tracker = meta_cursor_tracker_get_for_screen (screen);
      _draw_cursor_image (tracker, screenshot_data->image, screenshot_data->screenshot_area);
    }
  g_object_unref (settings);

  result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window);
  g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
  g_object_unref (result);
}