Florian Müllner 2653871
From 0192bf0981c831163a6bbe5b710c424abd901536 Mon Sep 17 00:00:00 2001
Florian Müllner 2653871
From: Adel Gadllah <adel.gadllah@gmail.com>
Florian Müllner 2653871
Date: Sat, 27 Sep 2014 13:35:22 +0200
Florian Müllner 2653871
Subject: [PATCH] shell-screenshot: Only allow one screenshot request at a time
Florian Müllner 2653871
 per sender
Florian Müllner 2653871
Florian Müllner 2653871
We currently allow infinite number of screenshot requests to be active at
Florian Müllner 2653871
the same time, which can "dos" the system and cause OOM.
Florian Müllner 2653871
Florian Müllner 2653871
So fail subsequent requests for the same sender when a screenshot operation
Florian Müllner 2653871
is already running.
Florian Müllner 2653871
Florian Müllner 2653871
https://bugzilla.gnome.org/show_bug.cgi?id=737456
Florian Müllner 2653871
---
Florian Müllner 2653871
 js/ui/screenshot.js    |  61 +++++++++++++--
Florian Müllner 2653871
 src/shell-screenshot.c | 200 ++++++++++++++++++++++++++-----------------------
Florian Müllner 2653871
 src/shell-screenshot.h |   5 +-
Florian Müllner 2653871
 3 files changed, 162 insertions(+), 104 deletions(-)
Florian Müllner 2653871
Florian Müllner 2653871
diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js
Florian Müllner 2653871
index bbeddd0..4b4e35e 100644
Florian Müllner 2653871
--- a/js/ui/screenshot.js
Florian Müllner 2653871
+++ b/js/ui/screenshot.js
Florian Müllner 2653871
@@ -11,6 +11,7 @@ const Shell = imports.gi.Shell;
Florian Müllner 2653871
 const Signals = imports.signals;
Florian Müllner 2653871
 const St = imports.gi.St;
Florian Müllner 2653871
 
Florian Müllner 2653871
+const Hash = imports.misc.hash;
Florian Müllner 2653871
 const Lightbox = imports.ui.lightbox;
Florian Müllner 2653871
 const Main = imports.ui.main;
Florian Müllner 2653871
 const Tweener = imports.ui.tweener;
Florian Müllner 2653871
@@ -62,13 +63,51 @@ const ScreenshotService = new Lang.Class({
Florian Müllner 2653871
         this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenshotIface, this);
Florian Müllner 2653871
         this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screenshot');
Florian Müllner 2653871
 
Florian Müllner 2653871
+        this._screenShooter = new Hash.Map();
Florian Müllner 2653871
+
Florian Müllner 2653871
         Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null);
Florian Müllner 2653871
     },
Florian Müllner 2653871
 
Florian Müllner 2653871
+    _createScreenshot: function(invocation) {
Florian Müllner 2653871
+        let sender = invocation.get_sender();
Florian Müllner 2653871
+        if (this._screenShooter.has(sender)) {
Florian Müllner 2653871
+            invocation.return_value(GLib.Variant.new('(bs)', [false, '']));
Florian Müllner 2653871
+            return null;
Florian Müllner 2653871
+        }
Florian Müllner 2653871
+
Florian Müllner 2653871
+        let shooter = new Shell.Screenshot();
Florian Müllner 2653871
+        shooter._watchNameId =
Florian Müllner 2653871
+                        Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
Florian Müllner 2653871
+                                           Lang.bind(this, this._onNameVanished));
Florian Müllner 2653871
+
Florian Müllner 2653871
+        this._screenShooter.set(sender, shooter);
Florian Müllner 2653871
+
Florian Müllner 2653871
+        return shooter;
Florian Müllner 2653871
+    },
Florian Müllner 2653871
+
Florian Müllner 2653871
+    _onNameVanished: function(connection, name) {
Florian Müllner 2653871
+        this._removeShooterForSender(name);
Florian Müllner 2653871
+    },
Florian Müllner 2653871
+
Florian Müllner 2653871
+    _removeShooterForSender: function(sender) {
Florian Müllner 2653871
+        let shooter = this._screenShooter.get(sender);
Florian Müllner 2653871
+        if (!shooter)
Florian Müllner 2653871
+            return;
Florian Müllner 2653871
+
Florian Müllner 2653871
+        Gio.bus_unwatch_name(shooter._watchNameId);
Florian Müllner 2653871
+        this._screenShooter.delete(sender);
Florian Müllner 2653871
+    },
Florian Müllner 2653871
+
Florian Müllner 2653871
     _onScreenshotComplete: function(obj, result, area, filenameUsed, flash, invocation) {
Florian Müllner 2653871
-        if (flash && result) {
Florian Müllner 2653871
-            let flashspot = new Flashspot(area);
Florian Müllner 2653871
-            flashspot.fire();
Florian Müllner 2653871
+        if (result) {
Florian Müllner 2653871
+            if (flash) {
Florian Müllner 2653871
+                let flashspot = new Flashspot(area);
Florian Müllner 2653871
+                flashspot.fire(Lang.bind(this, function() {
Florian Müllner 2653871
+                    this._removeShooterForSender(invocation.get_sender());
Florian Müllner 2653871
+                }));
Florian Müllner 2653871
+            }
Florian Müllner 2653871
+            else
Florian Müllner 2653871
+                this._removeShooterForSender(invocation.get_sender());
Florian Müllner 2653871
         }
Florian Müllner 2653871
 
Florian Müllner 2653871
         let retval = GLib.Variant.new('(bs)', [result, filenameUsed]);
Florian Müllner 2653871
@@ -84,7 +123,9 @@ const ScreenshotService = new Lang.Class({
Florian Müllner 2653871
                         "Invalid params");
Florian Müllner 2653871
             return;
Florian Müllner 2653871
         }
Florian Müllner 2653871
-        let screenshot = new Shell.Screenshot();
Florian Müllner 2653871
+        let screenshot = this._createScreenshot(invocation);
Florian Müllner 2653871
+        if (!screenshot)
Florian Müllner 2653871
+            return;
Florian Müllner 2653871
         screenshot.screenshot_area (x, y, width, height, filename,
Florian Müllner 2653871
                                 Lang.bind(this, this._onScreenshotComplete,
Florian Müllner 2653871
                                           flash, invocation));
Florian Müllner 2653871
@@ -92,7 +133,9 @@ const ScreenshotService = new Lang.Class({
Florian Müllner 2653871
 
Florian Müllner 2653871
     ScreenshotWindowAsync : function (params, invocation) {
Florian Müllner 2653871
         let [include_frame, include_cursor, flash, filename] = params;
Florian Müllner 2653871
-        let screenshot = new Shell.Screenshot();
Florian Müllner 2653871
+        let screenshot = this._createScreenshot(invocation);
Florian Müllner 2653871
+        if (!screenshot)
Florian Müllner 2653871
+            return;
Florian Müllner 2653871
         screenshot.screenshot_window (include_frame, include_cursor, filename,
Florian Müllner 2653871
                                   Lang.bind(this, this._onScreenshotComplete,
Florian Müllner 2653871
                                             flash, invocation));
Florian Müllner 2653871
@@ -100,7 +143,9 @@ const ScreenshotService = new Lang.Class({
Florian Müllner 2653871
 
Florian Müllner 2653871
     ScreenshotAsync : function (params, invocation) {
Florian Müllner 2653871
         let [include_cursor, flash, filename] = params;
Florian Müllner 2653871
-        let screenshot = new Shell.Screenshot();
Florian Müllner 2653871
+        let screenshot = this._createScreenshot(invocation);
Florian Müllner 2653871
+        if (!screenshot)
Florian Müllner 2653871
+            return;
Florian Müllner 2653871
         screenshot.screenshot(include_cursor, filename,
Florian Müllner 2653871
                           Lang.bind(this, this._onScreenshotComplete,
Florian Müllner 2653871
                                     flash, invocation));
Florian Müllner 2653871
@@ -265,7 +310,7 @@ const Flashspot = new Lang.Class({
Florian Müllner 2653871
         this.actor.set_position(area.x, area.y);
Florian Müllner 2653871
     },
Florian Müllner 2653871
 
Florian Müllner 2653871
-    fire: function() {
Florian Müllner 2653871
+    fire: function(doneCallback) {
Florian Müllner 2653871
         this.actor.show();
Florian Müllner 2653871
         this.actor.opacity = 255;
Florian Müllner 2653871
         Tweener.addTween(this.actor,
Florian Müllner 2653871
@@ -273,6 +318,8 @@ const Flashspot = new Lang.Class({
Florian Müllner 2653871
                            time: FLASHSPOT_ANIMATION_OUT_TIME,
Florian Müllner 2653871
                            transition: 'easeOutQuad',
Florian Müllner 2653871
                            onComplete: Lang.bind(this, function() {
Florian Müllner 2653871
+                               if (doneCallback)
Florian Müllner 2653871
+                                   doneCallback();
Florian Müllner 2653871
                                this.destroy();
Florian Müllner 2653871
                            })
Florian Müllner 2653871
                          });
Florian Müllner 2653871
diff --git a/src/shell-screenshot.c b/src/shell-screenshot.c
Florian Müllner 2653871
index 991a554..77952f9 100644
Florian Müllner 2653871
--- a/src/shell-screenshot.c
Florian Müllner 2653871
+++ b/src/shell-screenshot.c
Florian Müllner 2653871
@@ -26,12 +26,12 @@ struct _ShellScreenshot
Florian Müllner 2653871
 {
Florian Müllner 2653871
   GObject parent_instance;
Florian Müllner 2653871
 
Florian Müllner 2653871
-  ShellGlobal *global;
Florian Müllner 2653871
+  ShellScreenshotPrivate *priv;
Florian Müllner 2653871
 };
Florian Müllner 2653871
 
Florian Müllner 2653871
-/* Used for async screenshot grabbing */
Florian Müllner 2653871
-typedef struct _screenshot_data {
Florian Müllner 2653871
-  ShellScreenshot  *screenshot;
Florian Müllner 2653871
+struct _ShellScreenshotPrivate
Florian Müllner 2653871
+{
Florian Müllner 2653871
+  ShellGlobal *global;
Florian Müllner 2653871
 
Florian Müllner 2653871
   char *filename;
Florian Müllner 2653871
   char *filename_used;
Florian Müllner 2653871
@@ -42,9 +42,9 @@ typedef struct _screenshot_data {
Florian Müllner 2653871
   gboolean include_cursor;
Florian Müllner 2653871
 
Florian Müllner 2653871
   ShellScreenshotCallback callback;
Florian Müllner 2653871
-} _screenshot_data;
Florian Müllner 2653871
+};
Florian Müllner 2653871
 
Florian Müllner 2653871
-G_DEFINE_TYPE(ShellScreenshot, shell_screenshot, G_TYPE_OBJECT);
Florian Müllner 2653871
+G_DEFINE_TYPE_WITH_PRIVATE (ShellScreenshot, shell_screenshot, G_TYPE_OBJECT);
Florian Müllner 2653871
 
Florian Müllner 2653871
 static void
Florian Müllner 2653871
 shell_screenshot_class_init (ShellScreenshotClass *screenshot_class)
Florian Müllner 2653871
@@ -55,7 +55,8 @@ shell_screenshot_class_init (ShellScreenshotClass *screenshot_class)
Florian Müllner 2653871
 static void
Florian Müllner 2653871
 shell_screenshot_init (ShellScreenshot *screenshot)
Florian Müllner 2653871
 {
Florian Müllner 2653871
-  screenshot->global = shell_global_get ();
Florian Müllner 2653871
+  screenshot->priv = shell_screenshot_get_instance_private (screenshot);
Florian Müllner 2653871
+  screenshot->priv->global = shell_global_get ();
Florian Müllner 2653871
 }
Florian Müllner 2653871
 
Florian Müllner 2653871
 static void
Florian Müllner 2653871
@@ -63,18 +64,18 @@ on_screenshot_written (GObject *source,
Florian Müllner 2653871
                        GAsyncResult *result,
Florian Müllner 2653871
                        gpointer user_data)
Florian Müllner 2653871
 {
Florian Müllner 2653871
-  _screenshot_data *screenshot_data = (_screenshot_data*) user_data;
Florian Müllner 2653871
-  if (screenshot_data->callback)
Florian Müllner 2653871
-    screenshot_data->callback (screenshot_data->screenshot,
Florian Müllner 2653871
-                               g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)),
Florian Müllner 2653871
-                               &screenshot_data->screenshot_area,
Florian Müllner 2653871
-                               screenshot_data->filename_used);
Florian Müllner 2653871
-
Florian Müllner 2653871
-  cairo_surface_destroy (screenshot_data->image);
Florian Müllner 2653871
-  g_object_unref (screenshot_data->screenshot);
Florian Müllner 2653871
-  g_free (screenshot_data->filename);
Florian Müllner 2653871
-  g_free (screenshot_data->filename_used);
Florian Müllner 2653871
-  g_free (screenshot_data);
Florian Müllner 2653871
+  ShellScreenshot *screenshot = SHELL_SCREENSHOT (source);
Florian Müllner 2653871
+  ShellScreenshotPrivate *priv = screenshot->priv;
Florian Müllner 2653871
+
Florian Müllner 2653871
+  if (priv->callback)
Florian Müllner 2653871
+    priv->callback (screenshot,
Florian Müllner 2653871
+                    g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)),
Florian Müllner 2653871
+                    &priv->screenshot_area,
Florian Müllner 2653871
+                    priv->filename_used);
Florian Müllner 2653871
+
Florian Müllner 2653871
+  g_clear_pointer (&priv->image, cairo_surface_destroy);
Florian Müllner 2653871
+  g_clear_pointer (&priv->filename, g_free);
Florian Müllner 2653871
+  g_clear_pointer (&priv->filename_used, g_free);
Florian Müllner 2653871
 }
Florian Müllner 2653871
 
Florian Müllner 2653871
 /* called in an I/O thread */
Florian Müllner 2653871
@@ -173,12 +174,15 @@ write_screenshot_thread (GSimpleAsyncResult *result,
Florian Müllner 2653871
 {
Florian Müllner 2653871
   cairo_status_t status;
Florian Müllner 2653871
   GOutputStream *stream;
Florian Müllner 2653871
-  _screenshot_data *screenshot_data = g_async_result_get_user_data (G_ASYNC_RESULT (result));
Florian Müllner 2653871
+  ShellScreenshot *screenshot = SHELL_SCREENSHOT (object);
Florian Müllner 2653871
+  ShellScreenshotPrivate *priv;
Florian Müllner 2653871
 
Florian Müllner 2653871
-  g_assert (screenshot_data != NULL);
Florian Müllner 2653871
+  g_assert (screenshot != NULL);
Florian Müllner 2653871
 
Florian Müllner 2653871
-  stream = prepare_write_stream (screenshot_data->filename,
Florian Müllner 2653871
-                                 &screenshot_data->filename_used);
Florian Müllner 2653871
+  priv = screenshot->priv;
Florian Müllner 2653871
+
Florian Müllner 2653871
+  stream = prepare_write_stream (priv->filename,
Florian Müllner 2653871
+                                 &priv->filename_used);
Florian Müllner 2653871
 
Florian Müllner 2653871
   if (stream == NULL)
Florian Müllner 2653871
     status = CAIRO_STATUS_FILE_NOT_FOUND;
Florian Müllner 2653871
@@ -186,10 +190,10 @@ write_screenshot_thread (GSimpleAsyncResult *result,
Florian Müllner 2653871
     {
Florian Müllner 2653871
       GdkPixbuf *pixbuf;
Florian Müllner 2653871
 
Florian Müllner 2653871
-      pixbuf = gdk_pixbuf_get_from_surface (screenshot_data->image,
Florian Müllner 2653871
+      pixbuf = gdk_pixbuf_get_from_surface (priv->image,
Florian Müllner 2653871
                                             0, 0,
Florian Müllner 2653871
-                                            cairo_image_surface_get_width (screenshot_data->image),
Florian Müllner 2653871
-                                            cairo_image_surface_get_height (screenshot_data->image));
Florian Müllner 2653871
+                                            cairo_image_surface_get_width (priv->image),
Florian Müllner 2653871
+                                            cairo_image_surface_get_height (priv->image));
Florian Müllner 2653871
 
Florian Müllner 2653871
       if (gdk_pixbuf_save_to_stream (pixbuf, stream, "png", NULL, NULL,
Florian Müllner 2653871
                                     "tEXt::Software", "gnome-screenshot", NULL))
Florian Müllner 2653871
@@ -207,7 +211,7 @@ write_screenshot_thread (GSimpleAsyncResult *result,
Florian Müllner 2653871
 }
Florian Müllner 2653871
 
Florian Müllner 2653871
 static void
Florian Müllner 2653871
-do_grab_screenshot (_screenshot_data *screenshot_data,
Florian Müllner 2653871
+do_grab_screenshot (ShellScreenshot *screenshot,
Florian Müllner 2653871
                     int               x,
Florian Müllner 2653871
                     int               y,
Florian Müllner 2653871
                     int               width,
Florian Müllner 2653871
@@ -218,16 +222,17 @@ do_grab_screenshot (_screenshot_data *screenshot_data,
Florian Müllner 2653871
   CoglContext *context;
Florian Müllner 2653871
   int stride;
Florian Müllner 2653871
   guchar *data;
Florian Müllner 2653871
+  ShellScreenshotPrivate *priv = screenshot->priv;
Florian Müllner 2653871
 
Florian Müllner 2653871
   backend = clutter_get_default_backend ();
Florian Müllner 2653871
   context = clutter_backend_get_cogl_context (backend);
Florian Müllner 2653871
 
Florian Müllner 2653871
-  screenshot_data->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
Florian Müllner 2653871
-                                                       width, height);
Florian Müllner 2653871
+  priv->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
Florian Müllner 2653871
+                                            width, height);
Florian Müllner 2653871
 
Florian Müllner 2653871
 
Florian Müllner 2653871
-  data = cairo_image_surface_get_data (screenshot_data->image);
Florian Müllner 2653871
-  stride = cairo_image_surface_get_stride (screenshot_data->image);
Florian Müllner 2653871
+  data = cairo_image_surface_get_data (priv->image);
Florian Müllner 2653871
+  stride = cairo_image_surface_get_stride (priv->image);
Florian Müllner 2653871
 
Florian Müllner 2653871
   bitmap = cogl_bitmap_new_for_data (context,
Florian Müllner 2653871
                                      width,
Florian Müllner 2653871
@@ -240,7 +245,7 @@ do_grab_screenshot (_screenshot_data *screenshot_data,
Florian Müllner 2653871
                                             COGL_READ_PIXELS_COLOR_BUFFER,
Florian Müllner 2653871
                                             bitmap);
Florian Müllner 2653871
 
Florian Müllner 2653871
-  cairo_surface_mark_dirty (screenshot_data->image);
Florian Müllner 2653871
+  cairo_surface_mark_dirty (priv->image);
Florian Müllner 2653871
   cogl_object_unref (bitmap);
Florian Müllner 2653871
 }
Florian Müllner 2653871
 
Florian Müllner 2653871
@@ -313,17 +318,19 @@ _draw_cursor_image (MetaCursorTracker     *tracker,
Florian Müllner 2653871
 
Florian Müllner 2653871
 static void
Florian Müllner 2653871
 grab_screenshot (ClutterActor *stage,
Florian Müllner 2653871
-                 _screenshot_data *screenshot_data)
Florian Müllner 2653871
+                 ShellScreenshot *screenshot)
Florian Müllner 2653871
 {
Florian Müllner 2653871
-  MetaScreen *screen = shell_global_get_screen (screenshot_data->screenshot->global);
Florian Müllner 2653871
+  MetaScreen *screen;
Florian Müllner 2653871
   MetaCursorTracker *tracker;
Florian Müllner 2653871
   int width, height;
Florian Müllner 2653871
   GSimpleAsyncResult *result;
Florian Müllner 2653871
   GSettings *settings;
Florian Müllner 2653871
+  ShellScreenshotPrivate *priv = screenshot->priv;
Florian Müllner 2653871
 
Florian Müllner 2653871
+  screen = shell_global_get_screen (priv->global);
Florian Müllner 2653871
   meta_screen_get_size (screen, &width, &height);
Florian Müllner 2653871
 
Florian Müllner 2653871
-  do_grab_screenshot (screenshot_data, 0, 0, width, height);
Florian Müllner 2653871
+  do_grab_screenshot (screenshot, 0, 0, width, height);
Florian Müllner 2653871
 
Florian Müllner 2653871
   if (meta_screen_get_n_monitors (screen) > 1)
Florian Müllner 2653871
     {
Florian Müllner 2653871
@@ -349,7 +356,7 @@ grab_screenshot (ClutterActor *stage,
Florian Müllner 2653871
       cairo_region_xor (stage_region, screen_region);
Florian Müllner 2653871
       cairo_region_destroy (screen_region);
Florian Müllner 2653871
 
Florian Müllner 2653871
-      cr = cairo_create (screenshot_data->image);
Florian Müllner 2653871
+      cr = cairo_create (priv->image);
Florian Müllner 2653871
 
Florian Müllner 2653871
       for (i = 0; i < cairo_region_num_rectangles (stage_region); i++)
Florian Müllner 2653871
         {
Florian Müllner 2653871
@@ -363,41 +370,42 @@ grab_screenshot (ClutterActor *stage,
Florian Müllner 2653871
       cairo_region_destroy (stage_region);
Florian Müllner 2653871
     }
Florian Müllner 2653871
 
Florian Müllner 2653871
-  screenshot_data->screenshot_area.x = 0;
Florian Müllner 2653871
-  screenshot_data->screenshot_area.y = 0;
Florian Müllner 2653871
-  screenshot_data->screenshot_area.width = width;
Florian Müllner 2653871
-  screenshot_data->screenshot_area.height = height;
Florian Müllner 2653871
+  priv->screenshot_area.x = 0;
Florian Müllner 2653871
+  priv->screenshot_area.y = 0;
Florian Müllner 2653871
+  priv->screenshot_area.width = width;
Florian Müllner 2653871
+  priv->screenshot_area.height = height;
Florian Müllner 2653871
 
Florian Müllner 2653871
   settings = g_settings_new (A11Y_APPS_SCHEMA);
Florian Müllner 2653871
-  if (screenshot_data->include_cursor &&
Florian Müllner 2653871
+  if (priv->include_cursor &&
Florian Müllner 2653871
       !g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
Florian Müllner 2653871
     {
Florian Müllner 2653871
       tracker = meta_cursor_tracker_get_for_screen (screen);
Florian Müllner 2653871
-      _draw_cursor_image (tracker, screenshot_data->image, screenshot_data->screenshot_area);
Florian Müllner 2653871
+      _draw_cursor_image (tracker, priv->image, priv->screenshot_area);
Florian Müllner 2653871
     }
Florian Müllner 2653871
   g_object_unref (settings);
Florian Müllner 2653871
 
Florian Müllner 2653871
-  g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot_data);
Florian Müllner 2653871
+  g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot);
Florian Müllner 2653871
 
Florian Müllner 2653871
-  result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, grab_screenshot);
Florian Müllner 2653871
+  result = g_simple_async_result_new (G_OBJECT (screenshot), on_screenshot_written, NULL, grab_screenshot);
Florian Müllner 2653871
   g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
Florian Müllner 2653871
   g_object_unref (result);
Florian Müllner 2653871
 }
Florian Müllner 2653871
 
Florian Müllner 2653871
 static void
Florian Müllner 2653871
 grab_area_screenshot (ClutterActor *stage,
Florian Müllner 2653871
-                      _screenshot_data *screenshot_data)
Florian Müllner 2653871
+                      ShellScreenshot *screenshot)
Florian Müllner 2653871
 {
Florian Müllner 2653871
   GSimpleAsyncResult *result;
Florian Müllner 2653871
+  ShellScreenshotPrivate *priv = screenshot->priv;
Florian Müllner 2653871
 
Florian Müllner 2653871
-  do_grab_screenshot (screenshot_data,
Florian Müllner 2653871
-                      screenshot_data->screenshot_area.x,
Florian Müllner 2653871
-                      screenshot_data->screenshot_area.y,
Florian Müllner 2653871
-                      screenshot_data->screenshot_area.width,
Florian Müllner 2653871
-                      screenshot_data->screenshot_area.height);
Florian Müllner 2653871
+  do_grab_screenshot (screenshot,
Florian Müllner 2653871
+                      priv->screenshot_area.x,
Florian Müllner 2653871
+                      priv->screenshot_area.y,
Florian Müllner 2653871
+                      priv->screenshot_area.width,
Florian Müllner 2653871
+                      priv->screenshot_area.height);
Florian Müllner 2653871
 
Florian Müllner 2653871
-  g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot_data);
Florian Müllner 2653871
-  result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, grab_area_screenshot);
Florian Müllner 2653871
+  g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot);
Florian Müllner 2653871
+  result = g_simple_async_result_new (G_OBJECT (screenshot), on_screenshot_written, NULL, grab_area_screenshot);
Florian Müllner 2653871
   g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
Florian Müllner 2653871
   g_object_unref (result);
Florian Müllner 2653871
 }
Florian Müllner 2653871
@@ -421,16 +429,21 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot,
Florian Müllner 2653871
                              ShellScreenshotCallback callback)
Florian Müllner 2653871
 {
Florian Müllner 2653871
   ClutterActor *stage;
Florian Müllner 2653871
-  _screenshot_data *data = g_new0 (_screenshot_data, 1);
Florian Müllner 2653871
+  ShellScreenshotPrivate *priv = screenshot->priv;
Florian Müllner 2653871
+
Florian Müllner 2653871
+  if (priv->filename != NULL) {
Florian Müllner 2653871
+    if (callback)
Florian Müllner 2653871
+      callback (screenshot, FALSE, NULL, "");
Florian Müllner 2653871
+    return;
Florian Müllner 2653871
+  }
Florian Müllner 2653871
 
Florian Müllner 2653871
-  data->screenshot = g_object_ref (screenshot);
Florian Müllner 2653871
-  data->filename = g_strdup (filename);
Florian Müllner 2653871
-  data->callback = callback;
Florian Müllner 2653871
-  data->include_cursor = include_cursor;
Florian Müllner 2653871
+  priv->filename = g_strdup (filename);
Florian Müllner 2653871
+  priv->callback = callback;
Florian Müllner 2653871
+  priv->include_cursor = include_cursor;
Florian Müllner 2653871
 
Florian Müllner 2653871
-  stage = CLUTTER_ACTOR (shell_global_get_stage (screenshot->global));
Florian Müllner 2653871
+  stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
Florian Müllner 2653871
 
Florian Müllner 2653871
-  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), (gpointer)data);
Florian Müllner 2653871
+  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), (gpointer)screenshot);
Florian Müllner 2653871
 
Florian Müllner 2653871
   clutter_actor_queue_redraw (stage);
Florian Müllner 2653871
 }
Florian Müllner 2653871
@@ -460,19 +473,24 @@ shell_screenshot_screenshot_area (ShellScreenshot *screenshot,
Florian Müllner 2653871
                                   ShellScreenshotCallback callback)
Florian Müllner 2653871
 {
Florian Müllner 2653871
   ClutterActor *stage;
Florian Müllner 2653871
-  _screenshot_data *data = g_new0 (_screenshot_data, 1);
Florian Müllner 2653871
+  ShellScreenshotPrivate *priv = screenshot->priv;
Florian Müllner 2653871
+
Florian Müllner 2653871
+  if (priv->filename != NULL) {
Florian Müllner 2653871
+    if (callback)
Florian Müllner 2653871
+      callback (screenshot, FALSE, NULL, "");
Florian Müllner 2653871
+    return;
Florian Müllner 2653871
+  }
Florian Müllner 2653871
 
Florian Müllner 2653871
-  data->screenshot = g_object_ref (screenshot);
Florian Müllner 2653871
-  data->filename = g_strdup (filename);
Florian Müllner 2653871
-  data->screenshot_area.x = x;
Florian Müllner 2653871
-  data->screenshot_area.y = y;
Florian Müllner 2653871
-  data->screenshot_area.width = width;
Florian Müllner 2653871
-  data->screenshot_area.height = height;
Florian Müllner 2653871
-  data->callback = callback;
Florian Müllner 2653871
+  priv->filename = g_strdup (filename);
Florian Müllner 2653871
+  priv->screenshot_area.x = x;
Florian Müllner 2653871
+  priv->screenshot_area.y = y;
Florian Müllner 2653871
+  priv->screenshot_area.width = width;
Florian Müllner 2653871
+  priv->screenshot_area.height = height;
Florian Müllner 2653871
+  priv->callback = callback;
Florian Müllner 2653871
 
Florian Müllner 2653871
-  stage = CLUTTER_ACTOR (shell_global_get_stage (screenshot->global));
Florian Müllner 2653871
+  stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
Florian Müllner 2653871
 
Florian Müllner 2653871
-  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), (gpointer)data);
Florian Müllner 2653871
+  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), (gpointer)screenshot);
Florian Müllner 2653871
 
Florian Müllner 2653871
   clutter_actor_queue_redraw (stage);
Florian Müllner 2653871
 }
Florian Müllner 2653871
@@ -499,10 +517,9 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
Florian Müllner 2653871
 {
Florian Müllner 2653871
   GSimpleAsyncResult *result;
Florian Müllner 2653871
   GSettings *settings;
Florian Müllner 2653871
+  ShellScreenshotPrivate *priv = screenshot->priv;
Florian Müllner 2653871
 
Florian Müllner 2653871
-  _screenshot_data *screenshot_data = g_new0 (_screenshot_data, 1);
Florian Müllner 2653871
-
Florian Müllner 2653871
-  MetaScreen *screen = shell_global_get_screen (screenshot->global);
Florian Müllner 2653871
+  MetaScreen *screen = shell_global_get_screen (priv->global);
Florian Müllner 2653871
   MetaCursorTracker *tracker;
Florian Müllner 2653871
   MetaDisplay *display = meta_screen_get_display (screen);
Florian Müllner 2653871
   MetaWindow *window = meta_display_get_focus_window (display);
Florian Müllner 2653871
@@ -512,20 +529,14 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
Florian Müllner 2653871
   MetaRectangle rect;
Florian Müllner 2653871
   cairo_rectangle_int_t clip;
Florian Müllner 2653871
 
Florian Müllner 2653871
-  screenshot_data->screenshot = g_object_ref (screenshot);
Florian Müllner 2653871
-  screenshot_data->filename = g_strdup (filename);
Florian Müllner 2653871
-  screenshot_data->callback = callback;
Florian Müllner 2653871
-
Florian Müllner 2653871
-  if (!window)
Florian Müllner 2653871
-    {
Florian Müllner 2653871
-      screenshot_data->filename_used = g_strdup ("");
Florian Müllner 2653871
-      result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window);
Florian Müllner 2653871
-      g_simple_async_result_set_op_res_gboolean (result, FALSE);
Florian Müllner 2653871
-      g_simple_async_result_complete (result);
Florian Müllner 2653871
-      g_object_unref (result);
Florian Müllner 2653871
+  if (priv->filename != NULL || !window) {
Florian Müllner 2653871
+    if (callback)
Florian Müllner 2653871
+      callback (screenshot, FALSE, NULL, "");
Florian Müllner 2653871
+    return;
Florian Müllner 2653871
+  }
Florian Müllner 2653871
 
Florian Müllner 2653871
-      return;
Florian Müllner 2653871
-    }
Florian Müllner 2653871
+  priv->filename = g_strdup (filename);
Florian Müllner 2653871
+  priv->callback = callback;
Florian Müllner 2653871
 
Florian Müllner 2653871
   window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
Florian Müllner 2653871
   clutter_actor_get_position (window_actor, &actor_x, &actor_y);
Florian Müllner 2653871
@@ -534,8 +545,8 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
Florian Müllner 2653871
     {
Florian Müllner 2653871
       meta_window_get_outer_rect (window, &rect);
Florian Müllner 2653871
 
Florian Müllner 2653871
-      screenshot_data->screenshot_area.x = rect.x;
Florian Müllner 2653871
-      screenshot_data->screenshot_area.y = rect.y;
Florian Müllner 2653871
+      priv->screenshot_area.x = rect.x;
Florian Müllner 2653871
+      priv->screenshot_area.y = rect.y;
Florian Müllner 2653871
 
Florian Müllner 2653871
       clip.x = rect.x - (gint) actor_x;
Florian Müllner 2653871
       clip.y = rect.y - (gint) actor_y;
Florian Müllner 2653871
@@ -544,28 +555,27 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
Florian Müllner 2653871
     {
Florian Müllner 2653871
       rect = *meta_window_get_rect (window);
Florian Müllner 2653871
 
Florian Müllner 2653871
-      screenshot_data->screenshot_area.x = (gint) actor_x + rect.x;
Florian Müllner 2653871
-      screenshot_data->screenshot_area.y = (gint) actor_y + rect.y;
Florian Müllner 2653871
-
Florian Müllner 2653871
+      priv->screenshot_area.x = (gint) actor_x + rect.x;
Florian Müllner 2653871
+      priv->screenshot_area.y = (gint) actor_y + rect.y;
Florian Müllner 2653871
       clip.x = rect.x;
Florian Müllner 2653871
       clip.y = rect.y;
Florian Müllner 2653871
     }
Florian Müllner 2653871
 
Florian Müllner 2653871
-  clip.width = screenshot_data->screenshot_area.width = rect.width;
Florian Müllner 2653871
-  clip.height = screenshot_data->screenshot_area.height = rect.height;
Florian Müllner 2653871
+  clip.width = priv->screenshot_area.width = rect.width;
Florian Müllner 2653871
+  clip.height = priv->screenshot_area.height = rect.height;
Florian Müllner 2653871
 
Florian Müllner 2653871
   stex = META_SHAPED_TEXTURE (meta_window_actor_get_texture (META_WINDOW_ACTOR (window_actor)));
Florian Müllner 2653871
-  screenshot_data->image = meta_shaped_texture_get_image (stex, &clip);
Florian Müllner 2653871
+  priv->image = meta_shaped_texture_get_image (stex, &clip);
Florian Müllner 2653871
 
Florian Müllner 2653871
   settings = g_settings_new (A11Y_APPS_SCHEMA);
Florian Müllner 2653871
   if (include_cursor && !g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
Florian Müllner 2653871
     {
Florian Müllner 2653871
       tracker = meta_cursor_tracker_get_for_screen (screen);
Florian Müllner 2653871
-      _draw_cursor_image (tracker, screenshot_data->image, screenshot_data->screenshot_area);
Florian Müllner 2653871
+      _draw_cursor_image (tracker, priv->image, priv->screenshot_area);
Florian Müllner 2653871
     }
Florian Müllner 2653871
   g_object_unref (settings);
Florian Müllner 2653871
 
Florian Müllner 2653871
-  result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window);
Florian Müllner 2653871
+  result = g_simple_async_result_new (G_OBJECT (screenshot), on_screenshot_written, NULL, shell_screenshot_screenshot_window);
Florian Müllner 2653871
   g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
Florian Müllner 2653871
   g_object_unref (result);
Florian Müllner 2653871
 }
Florian Müllner 2653871
diff --git a/src/shell-screenshot.h b/src/shell-screenshot.h
Florian Müllner 2653871
index 76925f3..0b8ab1c 100644
Florian Müllner 2653871
--- a/src/shell-screenshot.h
Florian Müllner 2653871
+++ b/src/shell-screenshot.h
Florian Müllner 2653871
@@ -11,8 +11,9 @@
Florian Müllner 2653871
  *
Florian Müllner 2653871
  */
Florian Müllner 2653871
 
Florian Müllner 2653871
-typedef struct _ShellScreenshot      ShellScreenshot;
Florian Müllner 2653871
-typedef struct _ShellScreenshotClass ShellScreenshotClass;
Florian Müllner 2653871
+typedef struct _ShellScreenshot         ShellScreenshot;
Florian Müllner 2653871
+typedef struct _ShellScreenshotPrivate  ShellScreenshotPrivate;
Florian Müllner 2653871
+typedef struct _ShellScreenshotClass    ShellScreenshotClass;
Florian Müllner 2653871
 
Florian Müllner 2653871
 #define SHELL_TYPE_SCREENSHOT              (shell_screenshot_get_type ())
Florian Müllner 2653871
 #define SHELL_SCREENSHOT(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_SCREENSHOT, ShellScreenshot))
Florian Müllner 2653871
-- 
Florian Müllner 2653871
2.1.0
Florian Müllner 2653871