Blame SOURCES/0001-shell-screenshot-Only-allow-one-screenshot-request-a.patch

13bb5b
From a13c4a9a6e26b4446d9233637dc88ced61858f35 Mon Sep 17 00:00:00 2001
13bb5b
From: Adel Gadllah <adel.gadllah@gmail.com>
13bb5b
Date: Sat, 27 Sep 2014 13:35:22 +0200
13bb5b
Subject: [PATCH] shell-screenshot: Only allow one screenshot request at a time
13bb5b
 per sender
13bb5b
13bb5b
We currently allow infinite number of screenshot requests to be active at
13bb5b
the same time, which can "dos" the system and cause OOM.
13bb5b
13bb5b
So fail subsequent requests for the same sender when a screenshot operation
13bb5b
is already running.
13bb5b
13bb5b
https://bugzilla.gnome.org/show_bug.cgi?id=737456
13bb5b
---
13bb5b
 js/ui/screenshot.js    |  61 +++++++++++++--
13bb5b
 src/shell-screenshot.c | 203 ++++++++++++++++++++++++++-----------------------
13bb5b
 src/shell-screenshot.h |   5 +-
13bb5b
 3 files changed, 165 insertions(+), 104 deletions(-)
13bb5b
13bb5b
diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js
13bb5b
index f85c62e..dd6448e 100644
13bb5b
--- a/js/ui/screenshot.js
13bb5b
+++ b/js/ui/screenshot.js
13bb5b
@@ -10,6 +10,7 @@ const Shell = imports.gi.Shell;
13bb5b
 const Signals = imports.signals;
13bb5b
 const St = imports.gi.St;
13bb5b
 
13bb5b
+const Hash = imports.misc.hash;
13bb5b
 const Lightbox = imports.ui.lightbox;
13bb5b
 const Main = imports.ui.main;
13bb5b
 const Tweener = imports.ui.tweener;
13bb5b
@@ -61,9 +62,41 @@ const ScreenshotService = new Lang.Class({
13bb5b
         this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenshotIface, this);
13bb5b
         this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screenshot');
13bb5b
 
13bb5b
+        this._screenShooter = new Hash.Map();
13bb5b
+
13bb5b
         Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null);
13bb5b
     },
13bb5b
 
13bb5b
+    _createScreenshot: function(invocation) {
13bb5b
+        let sender = invocation.get_sender();
13bb5b
+        if (this._screenShooter.has(sender)) {
13bb5b
+            invocation.return_value(GLib.Variant.new('(bs)', [false, '']));
13bb5b
+            return null;
13bb5b
+        }
13bb5b
+
13bb5b
+        let shooter = new Shell.Screenshot();
13bb5b
+        shooter._watchNameId =
13bb5b
+                        Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
13bb5b
+                                           Lang.bind(this, this._onNameVanished));
13bb5b
+
13bb5b
+        this._screenShooter.set(sender, shooter);
13bb5b
+
13bb5b
+        return shooter;
13bb5b
+    },
13bb5b
+
13bb5b
+    _onNameVanished: function(connection, name) {
13bb5b
+        this._removeShooterForSender(name);
13bb5b
+    },
13bb5b
+
13bb5b
+    _removeShooterForSender: function(sender) {
13bb5b
+        let shooter = this._screenShooter.get(sender);
13bb5b
+        if (!shooter)
13bb5b
+            return;
13bb5b
+
13bb5b
+        Gio.bus_unwatch_name(shooter._watchNameId);
13bb5b
+        this._screenShooter.delete(sender);
13bb5b
+    },
13bb5b
+
13bb5b
     _checkArea: function(x, y, width, height) {
13bb5b
         return x >= 0 && y >= 0 &&
13bb5b
                width > 0 && height > 0 &&
13bb5b
@@ -72,9 +105,15 @@ const ScreenshotService = new Lang.Class({
13bb5b
     },
13bb5b
 
13bb5b
     _onScreenshotComplete: function(obj, result, area, filenameUsed, flash, invocation) {
13bb5b
-        if (flash && result) {
13bb5b
-            let flashspot = new Flashspot(area);
13bb5b
-            flashspot.fire();
13bb5b
+        if (result) {
13bb5b
+            if (flash) {
13bb5b
+                let flashspot = new Flashspot(area);
13bb5b
+                flashspot.fire(Lang.bind(this, function() {
13bb5b
+                    this._removeShooterForSender(invocation.get_sender());
13bb5b
+                }));
13bb5b
+            }
13bb5b
+            else
13bb5b
+                this._removeShooterForSender(invocation.get_sender());
13bb5b
         }
13bb5b
 
13bb5b
         let retval = GLib.Variant.new('(bs)', [result, filenameUsed]);
13bb5b
@@ -89,7 +128,9 @@ const ScreenshotService = new Lang.Class({
13bb5b
                                             "Invalid params");
13bb5b
             return;
13bb5b
         }
13bb5b
-        let screenshot = new Shell.Screenshot();
13bb5b
+        let screenshot = this._createScreenshot(invocation);
13bb5b
+        if (!screenshot)
13bb5b
+            return;
13bb5b
         screenshot.screenshot_area (x, y, width, height, filename,
13bb5b
                                 Lang.bind(this, this._onScreenshotComplete,
13bb5b
                                           flash, invocation));
13bb5b
@@ -97,7 +138,9 @@ const ScreenshotService = new Lang.Class({
13bb5b
 
13bb5b
     ScreenshotWindowAsync : function (params, invocation) {
13bb5b
         let [include_frame, include_cursor, flash, filename] = params;
13bb5b
-        let screenshot = new Shell.Screenshot();
13bb5b
+        let screenshot = this._createScreenshot(invocation);
13bb5b
+        if (!screenshot)
13bb5b
+            return;
13bb5b
         screenshot.screenshot_window (include_frame, include_cursor, filename,
13bb5b
                                   Lang.bind(this, this._onScreenshotComplete,
13bb5b
                                             flash, invocation));
13bb5b
@@ -105,7 +148,9 @@ const ScreenshotService = new Lang.Class({
13bb5b
 
13bb5b
     ScreenshotAsync : function (params, invocation) {
13bb5b
         let [include_cursor, flash, filename] = params;
13bb5b
-        let screenshot = new Shell.Screenshot();
13bb5b
+        let screenshot = this._createScreenshot(invocation);
13bb5b
+        if (!screenshot)
13bb5b
+            return;
13bb5b
         screenshot.screenshot(include_cursor, filename,
13bb5b
                           Lang.bind(this, this._onScreenshotComplete,
13bb5b
                                     flash, invocation));
13bb5b
@@ -278,7 +323,7 @@ const Flashspot = new Lang.Class({
13bb5b
         this.actor.set_position(area.x, area.y);
13bb5b
     },
13bb5b
 
13bb5b
-    fire: function() {
13bb5b
+    fire: function(doneCallback) {
13bb5b
         this.actor.show();
13bb5b
         this.actor.opacity = 255;
13bb5b
         Tweener.addTween(this.actor,
13bb5b
@@ -286,6 +331,8 @@ const Flashspot = new Lang.Class({
13bb5b
                            time: FLASHSPOT_ANIMATION_OUT_TIME,
13bb5b
                            transition: 'easeOutQuad',
13bb5b
                            onComplete: Lang.bind(this, function() {
13bb5b
+                               if (doneCallback)
13bb5b
+                                   doneCallback();
13bb5b
                                this.destroy();
13bb5b
                            })
13bb5b
                          });
13bb5b
diff --git a/src/shell-screenshot.c b/src/shell-screenshot.c
13bb5b
index b68c3b0..5630726 100644
13bb5b
--- a/src/shell-screenshot.c
13bb5b
+++ b/src/shell-screenshot.c
13bb5b
@@ -27,12 +27,12 @@ struct _ShellScreenshot
13bb5b
 {
13bb5b
   GObject parent_instance;
13bb5b
 
13bb5b
-  ShellGlobal *global;
13bb5b
+  ShellScreenshotPrivate *priv;
13bb5b
 };
13bb5b
 
13bb5b
-/* Used for async screenshot grabbing */
13bb5b
-typedef struct _screenshot_data {
13bb5b
-  ShellScreenshot  *screenshot;
13bb5b
+struct _ShellScreenshotPrivate
13bb5b
+{
13bb5b
+  ShellGlobal *global;
13bb5b
 
13bb5b
   char *filename;
13bb5b
   char *filename_used;
13bb5b
@@ -43,20 +43,23 @@ typedef struct _screenshot_data {
13bb5b
   gboolean include_cursor;
13bb5b
 
13bb5b
   ShellScreenshotCallback callback;
13bb5b
-} _screenshot_data;
13bb5b
+};
13bb5b
 
13bb5b
-G_DEFINE_TYPE(ShellScreenshot, shell_screenshot, G_TYPE_OBJECT);
13bb5b
+G_DEFINE_TYPE (ShellScreenshot, shell_screenshot, G_TYPE_OBJECT);
13bb5b
+
13bb5b
+#define SHELL_SCREENSHOT_GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SHELL_TYPE_SCREENSHOT, ShellScreenshotPrivate))
13bb5b
 
13bb5b
 static void
13bb5b
 shell_screenshot_class_init (ShellScreenshotClass *screenshot_class)
13bb5b
 {
13bb5b
-  (void) screenshot_class;
13bb5b
+  g_type_class_add_private (screenshot_class, sizeof (ShellScreenshotPrivate));
13bb5b
 }
13bb5b
 
13bb5b
 static void
13bb5b
 shell_screenshot_init (ShellScreenshot *screenshot)
13bb5b
 {
13bb5b
-  screenshot->global = shell_global_get ();
13bb5b
+  screenshot->priv = SHELL_SCREENSHOT_GET_PRIVATE (screenshot);
13bb5b
+  screenshot->priv->global = shell_global_get ();
13bb5b
 }
13bb5b
 
13bb5b
 static void
13bb5b
@@ -64,18 +67,18 @@ on_screenshot_written (GObject *source,
13bb5b
                        GAsyncResult *result,
13bb5b
                        gpointer user_data)
13bb5b
 {
13bb5b
-  _screenshot_data *screenshot_data = (_screenshot_data*) user_data;
13bb5b
-  if (screenshot_data->callback)
13bb5b
-    screenshot_data->callback (screenshot_data->screenshot,
13bb5b
-                               g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)),
13bb5b
-                               &screenshot_data->screenshot_area,
13bb5b
-                               screenshot_data->filename_used);
13bb5b
-
13bb5b
-  cairo_surface_destroy (screenshot_data->image);
13bb5b
-  g_object_unref (screenshot_data->screenshot);
13bb5b
-  g_free (screenshot_data->filename);
13bb5b
-  g_free (screenshot_data->filename_used);
13bb5b
-  g_free (screenshot_data);
13bb5b
+  ShellScreenshot *screenshot = SHELL_SCREENSHOT (source);
13bb5b
+  ShellScreenshotPrivate *priv = screenshot->priv;
13bb5b
+
13bb5b
+  if (priv->callback)
13bb5b
+    priv->callback (screenshot,
13bb5b
+                    g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)),
13bb5b
+                    &priv->screenshot_area,
13bb5b
+                    priv->filename_used);
13bb5b
+
13bb5b
+  g_clear_pointer (&priv->image, cairo_surface_destroy);
13bb5b
+  g_clear_pointer (&priv->filename, g_free);
13bb5b
+  g_clear_pointer (&priv->filename_used, g_free);
13bb5b
 }
13bb5b
 
13bb5b
 /* called in an I/O thread */
13bb5b
@@ -174,12 +177,15 @@ write_screenshot_thread (GSimpleAsyncResult *result,
13bb5b
 {
13bb5b
   cairo_status_t status;
13bb5b
   GOutputStream *stream;
13bb5b
-  _screenshot_data *screenshot_data = g_async_result_get_user_data (G_ASYNC_RESULT (result));
13bb5b
+  ShellScreenshot *screenshot = SHELL_SCREENSHOT (object);
13bb5b
+  ShellScreenshotPrivate *priv;
13bb5b
+
13bb5b
+  g_assert (screenshot != NULL);
13bb5b
 
13bb5b
-  g_assert (screenshot_data != NULL);
13bb5b
+  priv = screenshot->priv;
13bb5b
 
13bb5b
-  stream = prepare_write_stream (screenshot_data->filename,
13bb5b
-                                 &screenshot_data->filename_used);
13bb5b
+  stream = prepare_write_stream (priv->filename,
13bb5b
+                                 &priv->filename_used);
13bb5b
 
13bb5b
   if (stream == NULL)
13bb5b
     status = CAIRO_STATUS_FILE_NOT_FOUND;
13bb5b
@@ -187,10 +193,10 @@ write_screenshot_thread (GSimpleAsyncResult *result,
13bb5b
     {
13bb5b
       GdkPixbuf *pixbuf;
13bb5b
 
13bb5b
-      pixbuf = gdk_pixbuf_get_from_surface (screenshot_data->image,
13bb5b
+      pixbuf = gdk_pixbuf_get_from_surface (priv->image,
13bb5b
                                             0, 0,
13bb5b
-                                            cairo_image_surface_get_width (screenshot_data->image),
13bb5b
-                                            cairo_image_surface_get_height (screenshot_data->image));
13bb5b
+                                            cairo_image_surface_get_width (priv->image),
13bb5b
+                                            cairo_image_surface_get_height (priv->image));
13bb5b
 
13bb5b
       if (gdk_pixbuf_save_to_stream (pixbuf, stream, "png", NULL, NULL,
13bb5b
                                     "tEXt::Software", "gnome-screenshot", NULL))
13bb5b
@@ -208,7 +214,7 @@ write_screenshot_thread (GSimpleAsyncResult *result,
13bb5b
 }
13bb5b
 
13bb5b
 static void
13bb5b
-do_grab_screenshot (_screenshot_data *screenshot_data,
13bb5b
+do_grab_screenshot (ShellScreenshot *screenshot,
13bb5b
                     int               x,
13bb5b
                     int               y,
13bb5b
                     int               width,
13bb5b
@@ -219,16 +225,17 @@ do_grab_screenshot (_screenshot_data *screenshot_data,
13bb5b
   CoglContext *context;
13bb5b
   int stride;
13bb5b
   guchar *data;
13bb5b
+  ShellScreenshotPrivate *priv = screenshot->priv;
13bb5b
 
13bb5b
   backend = clutter_get_default_backend ();
13bb5b
   context = clutter_backend_get_cogl_context (backend);
13bb5b
 
13bb5b
-  screenshot_data->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
13bb5b
-                                                       width, height);
13bb5b
+  priv->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
13bb5b
+                                            width, height);
13bb5b
 
13bb5b
 
13bb5b
-  data = cairo_image_surface_get_data (screenshot_data->image);
13bb5b
-  stride = cairo_image_surface_get_stride (screenshot_data->image);
13bb5b
+  data = cairo_image_surface_get_data (priv->image);
13bb5b
+  stride = cairo_image_surface_get_stride (priv->image);
13bb5b
 
13bb5b
   bitmap = cogl_bitmap_new_for_data (context,
13bb5b
                                      width,
13bb5b
@@ -241,7 +248,7 @@ do_grab_screenshot (_screenshot_data *screenshot_data,
13bb5b
                                             COGL_READ_PIXELS_COLOR_BUFFER,
13bb5b
                                             bitmap);
13bb5b
 
13bb5b
-  cairo_surface_mark_dirty (screenshot_data->image);
13bb5b
+  cairo_surface_mark_dirty (priv->image);
13bb5b
   cogl_object_unref (bitmap);
13bb5b
 }
13bb5b
 
13bb5b
@@ -302,16 +309,18 @@ _draw_cursor_image (cairo_surface_t *surface,
13bb5b
 
13bb5b
 static void
13bb5b
 grab_screenshot (ClutterActor *stage,
13bb5b
-                 _screenshot_data *screenshot_data)
13bb5b
+                 ShellScreenshot *screenshot)
13bb5b
 {
13bb5b
-  MetaScreen *screen = shell_global_get_screen (screenshot_data->screenshot->global);
13bb5b
+  MetaScreen *screen;
13bb5b
   int width, height;
13bb5b
   GSimpleAsyncResult *result;
13bb5b
   GSettings *settings;
13bb5b
+  ShellScreenshotPrivate *priv = screenshot->priv;
13bb5b
 
13bb5b
+  screen = shell_global_get_screen (priv->global);
13bb5b
   meta_screen_get_size (screen, &width, &height);
13bb5b
 
13bb5b
-  do_grab_screenshot (screenshot_data, 0, 0, width, height);
13bb5b
+  do_grab_screenshot (screenshot, 0, 0, width, height);
13bb5b
 
13bb5b
   if (meta_screen_get_n_monitors (screen) > 1)
13bb5b
     {
13bb5b
@@ -337,7 +346,7 @@ grab_screenshot (ClutterActor *stage,
13bb5b
       cairo_region_xor (stage_region, screen_region);
13bb5b
       cairo_region_destroy (screen_region);
13bb5b
 
13bb5b
-      cr = cairo_create (screenshot_data->image);
13bb5b
+      cr = cairo_create (priv->image);
13bb5b
 
13bb5b
       for (i = 0; i < cairo_region_num_rectangles (stage_region); i++)
13bb5b
         {
13bb5b
@@ -351,38 +360,39 @@ grab_screenshot (ClutterActor *stage,
13bb5b
       cairo_region_destroy (stage_region);
13bb5b
     }
13bb5b
 
13bb5b
-  screenshot_data->screenshot_area.x = 0;
13bb5b
-  screenshot_data->screenshot_area.y = 0;
13bb5b
-  screenshot_data->screenshot_area.width = width;
13bb5b
-  screenshot_data->screenshot_area.height = height;
13bb5b
+  priv->screenshot_area.x = 0;
13bb5b
+  priv->screenshot_area.y = 0;
13bb5b
+  priv->screenshot_area.width = width;
13bb5b
+  priv->screenshot_area.height = height;
13bb5b
 
13bb5b
   settings = g_settings_new (A11Y_APPS_SCHEMA);
13bb5b
-  if (screenshot_data->include_cursor &&
13bb5b
+  if (priv->include_cursor &&
13bb5b
       !g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
13bb5b
-    _draw_cursor_image (screenshot_data->image, screenshot_data->screenshot_area);
13bb5b
+    _draw_cursor_image (priv->image, priv->screenshot_area);
13bb5b
   g_object_unref (settings);
13bb5b
 
13bb5b
-  g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot_data);
13bb5b
+  g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot);
13bb5b
 
13bb5b
-  result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, grab_screenshot);
13bb5b
+  result = g_simple_async_result_new (G_OBJECT (screenshot), on_screenshot_written, NULL, grab_screenshot);
13bb5b
   g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
13bb5b
   g_object_unref (result);
13bb5b
 }
13bb5b
 
13bb5b
 static void
13bb5b
 grab_area_screenshot (ClutterActor *stage,
13bb5b
-                      _screenshot_data *screenshot_data)
13bb5b
+                      ShellScreenshot *screenshot)
13bb5b
 {
13bb5b
   GSimpleAsyncResult *result;
13bb5b
+  ShellScreenshotPrivate *priv = screenshot->priv;
13bb5b
 
13bb5b
-  do_grab_screenshot (screenshot_data,
13bb5b
-                      screenshot_data->screenshot_area.x,
13bb5b
-                      screenshot_data->screenshot_area.y,
13bb5b
-                      screenshot_data->screenshot_area.width,
13bb5b
-                      screenshot_data->screenshot_area.height);
13bb5b
+  do_grab_screenshot (screenshot,
13bb5b
+                      priv->screenshot_area.x,
13bb5b
+                      priv->screenshot_area.y,
13bb5b
+                      priv->screenshot_area.width,
13bb5b
+                      priv->screenshot_area.height);
13bb5b
 
13bb5b
-  g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot_data);
13bb5b
-  result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, grab_area_screenshot);
13bb5b
+  g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot);
13bb5b
+  result = g_simple_async_result_new (G_OBJECT (screenshot), on_screenshot_written, NULL, grab_area_screenshot);
13bb5b
   g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
13bb5b
   g_object_unref (result);
13bb5b
 }
13bb5b
@@ -406,16 +416,21 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot,
13bb5b
                              ShellScreenshotCallback callback)
13bb5b
 {
13bb5b
   ClutterActor *stage;
13bb5b
-  _screenshot_data *data = g_new0 (_screenshot_data, 1);
13bb5b
+  ShellScreenshotPrivate *priv = screenshot->priv;
13bb5b
+
13bb5b
+  if (priv->filename != NULL) {
13bb5b
+    if (callback)
13bb5b
+      callback (screenshot, FALSE, NULL, "");
13bb5b
+    return;
13bb5b
+  }
13bb5b
 
13bb5b
-  data->screenshot = g_object_ref (screenshot);
13bb5b
-  data->filename = g_strdup (filename);
13bb5b
-  data->callback = callback;
13bb5b
-  data->include_cursor = include_cursor;
13bb5b
+  priv->filename = g_strdup (filename);
13bb5b
+  priv->callback = callback;
13bb5b
+  priv->include_cursor = include_cursor;
13bb5b
 
13bb5b
-  stage = CLUTTER_ACTOR (shell_global_get_stage (screenshot->global));
13bb5b
+  stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
13bb5b
 
13bb5b
-  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), (gpointer)data);
13bb5b
+  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), (gpointer)screenshot);
13bb5b
 
13bb5b
   clutter_actor_queue_redraw (stage);
13bb5b
 }
13bb5b
@@ -445,19 +460,24 @@ shell_screenshot_screenshot_area (ShellScreenshot *screenshot,
13bb5b
                                   ShellScreenshotCallback callback)
13bb5b
 {
13bb5b
   ClutterActor *stage;
13bb5b
-  _screenshot_data *data = g_new0 (_screenshot_data, 1);
13bb5b
+  ShellScreenshotPrivate *priv = screenshot->priv;
13bb5b
 
13bb5b
-  data->screenshot = g_object_ref (screenshot);
13bb5b
-  data->filename = g_strdup (filename);
13bb5b
-  data->screenshot_area.x = x;
13bb5b
-  data->screenshot_area.y = y;
13bb5b
-  data->screenshot_area.width = width;
13bb5b
-  data->screenshot_area.height = height;
13bb5b
-  data->callback = callback;
13bb5b
+  if (priv->filename != NULL) {
13bb5b
+    if (callback)
13bb5b
+      callback (screenshot, FALSE, NULL, "");
13bb5b
+    return;
13bb5b
+  }
13bb5b
+
13bb5b
+  priv->filename = g_strdup (filename);
13bb5b
+  priv->screenshot_area.x = x;
13bb5b
+  priv->screenshot_area.y = y;
13bb5b
+  priv->screenshot_area.width = width;
13bb5b
+  priv->screenshot_area.height = height;
13bb5b
+  priv->callback = callback;
13bb5b
 
13bb5b
-  stage = CLUTTER_ACTOR (shell_global_get_stage (screenshot->global));
13bb5b
+  stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
13bb5b
 
13bb5b
-  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), (gpointer)data);
13bb5b
+  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), (gpointer)screenshot);
13bb5b
 
13bb5b
   clutter_actor_queue_redraw (stage);
13bb5b
 }
13bb5b
@@ -484,10 +504,9 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
13bb5b
 {
13bb5b
   GSimpleAsyncResult *result;
13bb5b
   GSettings *settings;
13bb5b
+  ShellScreenshotPrivate *priv = screenshot->priv;
13bb5b
 
13bb5b
-  _screenshot_data *screenshot_data = g_new0 (_screenshot_data, 1);
13bb5b
-
13bb5b
-  MetaScreen *screen = shell_global_get_screen (screenshot->global);
13bb5b
+  MetaScreen *screen = shell_global_get_screen (priv->global);
13bb5b
   MetaDisplay *display = meta_screen_get_display (screen);
13bb5b
   MetaWindow *window = meta_display_get_focus_window (display);
13bb5b
   ClutterActor *window_actor;
13bb5b
@@ -496,20 +515,14 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
13bb5b
   MetaRectangle rect;
13bb5b
   cairo_rectangle_int_t clip;
13bb5b
 
13bb5b
-  screenshot_data->screenshot = g_object_ref (screenshot);
13bb5b
-  screenshot_data->filename = g_strdup (filename);
13bb5b
-  screenshot_data->callback = callback;
13bb5b
-
13bb5b
-  if (!window)
13bb5b
-    {
13bb5b
-      screenshot_data->filename_used = g_strdup ("");
13bb5b
-      result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window);
13bb5b
-      g_simple_async_result_set_op_res_gboolean (result, FALSE);
13bb5b
-      g_simple_async_result_complete (result);
13bb5b
-      g_object_unref (result);
13bb5b
+  if (priv->filename != NULL || !window) {
13bb5b
+    if (callback)
13bb5b
+      callback (screenshot, FALSE, NULL, "");
13bb5b
+    return;
13bb5b
+  }
13bb5b
 
13bb5b
-      return;
13bb5b
-    }
13bb5b
+  priv->filename = g_strdup (filename);
13bb5b
+  priv->callback = callback;
13bb5b
 
13bb5b
   window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
13bb5b
   clutter_actor_get_position (window_actor, &actor_x, &actor_y);
13bb5b
@@ -518,8 +531,8 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
13bb5b
     {
13bb5b
       meta_window_get_outer_rect (window, &rect);
13bb5b
 
13bb5b
-      screenshot_data->screenshot_area.x = rect.x;
13bb5b
-      screenshot_data->screenshot_area.y = rect.y;
13bb5b
+      priv->screenshot_area.x = rect.x;
13bb5b
+      priv->screenshot_area.y = rect.y;
13bb5b
 
13bb5b
       clip.x = rect.x - (gint) actor_x;
13bb5b
       clip.y = rect.y - (gint) actor_y;
13bb5b
@@ -528,25 +541,25 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
13bb5b
     {
13bb5b
       rect = *meta_window_get_rect (window);
13bb5b
 
13bb5b
-      screenshot_data->screenshot_area.x = (gint) actor_x + rect.x;
13bb5b
-      screenshot_data->screenshot_area.y = (gint) actor_y + rect.y;
13bb5b
+      priv->screenshot_area.x = (gint) actor_x + rect.x;
13bb5b
+      priv->screenshot_area.y = (gint) actor_y + rect.y;
13bb5b
 
13bb5b
       clip.x = rect.x;
13bb5b
       clip.y = rect.y;
13bb5b
     }
13bb5b
 
13bb5b
-  clip.width = screenshot_data->screenshot_area.width = rect.width;
13bb5b
-  clip.height = screenshot_data->screenshot_area.height = rect.height;
13bb5b
+  clip.width = priv->screenshot_area.width = rect.width;
13bb5b
+  clip.height = priv->screenshot_area.height = rect.height;
13bb5b
 
13bb5b
   stex = META_SHAPED_TEXTURE (meta_window_actor_get_texture (META_WINDOW_ACTOR (window_actor)));
13bb5b
-  screenshot_data->image = meta_shaped_texture_get_image (stex, &clip);
13bb5b
+  priv->image = meta_shaped_texture_get_image (stex, &clip);
13bb5b
 
13bb5b
   settings = g_settings_new (A11Y_APPS_SCHEMA);
13bb5b
   if (include_cursor && !g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
13bb5b
-    _draw_cursor_image (screenshot_data->image, screenshot_data->screenshot_area);
13bb5b
+    _draw_cursor_image (priv->image, priv->screenshot_area);
13bb5b
   g_object_unref (settings);
13bb5b
 
13bb5b
-  result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window);
13bb5b
+  result = g_simple_async_result_new (G_OBJECT (screenshot), on_screenshot_written, NULL, shell_screenshot_screenshot_window);
13bb5b
   g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
13bb5b
   g_object_unref (result);
13bb5b
 }
13bb5b
diff --git a/src/shell-screenshot.h b/src/shell-screenshot.h
13bb5b
index 76925f3..0b8ab1c 100644
13bb5b
--- a/src/shell-screenshot.h
13bb5b
+++ b/src/shell-screenshot.h
13bb5b
@@ -11,8 +11,9 @@
13bb5b
  *
13bb5b
  */
13bb5b
 
13bb5b
-typedef struct _ShellScreenshot      ShellScreenshot;
13bb5b
-typedef struct _ShellScreenshotClass ShellScreenshotClass;
13bb5b
+typedef struct _ShellScreenshot         ShellScreenshot;
13bb5b
+typedef struct _ShellScreenshotPrivate  ShellScreenshotPrivate;
13bb5b
+typedef struct _ShellScreenshotClass    ShellScreenshotClass;
13bb5b
 
13bb5b
 #define SHELL_TYPE_SCREENSHOT              (shell_screenshot_get_type ())
13bb5b
 #define SHELL_SCREENSHOT(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_SCREENSHOT, ShellScreenshot))
13bb5b
-- 
13bb5b
2.1.0
13bb5b