[gnome-shell/wip/fmuellner/color-picker: 2/5] screenshot: Adopt GIO's async pattern



commit da537cda4345374a68570846a91d8d5f2c836d7e
Author: Florian Müllner <fmuellner gnome org>
Date:   Thu Jul 19 15:54:33 2018 +0200

    screenshot: Adopt GIO's async pattern
    
    A custom callback type is more convenient, but only as long as no
    other callback type is required. We are about to add functionality
    that does not return the filename to a screenshot saved on disk, so
    prepare for that by moving to GIO's generic async callback pattern.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/issues/286

 js/ui/screenshot.js    |  38 ++++++--
 src/shell-screenshot.c | 242 ++++++++++++++++++++++++++++++++++++++-----------
 src/shell-screenshot.h |  55 ++++++-----
 3 files changed, 253 insertions(+), 82 deletions(-)
---
diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js
index 6e99568a3..5f9ab1933 100644
--- a/js/ui/screenshot.js
+++ b/js/ui/screenshot.js
@@ -110,7 +110,7 @@ var ScreenshotService = new Lang.Class({
                y + height <= global.screen_height;
     },
 
-    _onScreenshotComplete(obj, result, area, filenameUsed, flash, invocation) {
+    _onScreenshotComplete(result, area, filenameUsed, flash, invocation) {
         if (result) {
             if (flash) {
                 let flashspot = new Flashspot(area);
@@ -157,9 +157,15 @@ var ScreenshotService = new Lang.Class({
         if (!screenshot)
             return;
         screenshot.screenshot_area (x, y, width, height, filename,
-            (obj, result, area, filenameUsed) => {
-                this._onScreenshotComplete(obj, result, area, filenameUsed,
-                                           flash, invocation);
+            (o, res) => {
+                try {
+                    let [result, area, filenameUsed] =
+                        screenshot.screenshot_area_finish(res);
+                    this._onScreenshotComplete(result, area, filenameUsed,
+                                               flash, invocation);
+                } catch (e) {
+                    invocation.return_gerror (e);
+                }
             });
     },
 
@@ -169,9 +175,15 @@ var ScreenshotService = new Lang.Class({
         if (!screenshot)
             return;
         screenshot.screenshot_window (include_frame, include_cursor, filename,
-            (obj, result, area, filenameUsed) => {
-                this._onScreenshotComplete(obj, result, area, filenameUsed,
-                                           flash, invocation);
+            (o, res) => {
+                try {
+                    let [result, area, filenameUsed] =
+                        screenshot.screenshot_window_finish(res);
+                    this._onScreenshotComplete(result, area, filenameUsed,
+                                               flash, invocation);
+                } catch (e) {
+                    invocation.return_gerror (e);
+                }
             });
     },
 
@@ -181,9 +193,15 @@ var ScreenshotService = new Lang.Class({
         if (!screenshot)
             return;
         screenshot.screenshot(include_cursor, filename,
-            (obj, result, area, filenameUsed) => {
-                this._onScreenshotComplete(obj, result, area, filenameUsed,
-                                           flash, invocation);
+            (o, res) => {
+                try {
+                    let [result, area, filenameUsed] =
+                        screenshot.screenshot_finish(res);
+                    this._onScreenshotComplete(result, area, filenameUsed,
+                                               flash, invocation);
+                } catch (e) {
+                    invocation.return_gerror (e);
+                }
             });
     },
 
diff --git a/src/shell-screenshot.c b/src/shell-screenshot.c
index e0b765d53..f26ff64b5 100644
--- a/src/shell-screenshot.c
+++ b/src/shell-screenshot.c
@@ -38,8 +38,6 @@ struct _ShellScreenshotPrivate
 
   gboolean include_cursor;
   gboolean include_frame;
-
-  ShellScreenshotCallback callback;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (ShellScreenshot, shell_screenshot, G_TYPE_OBJECT);
@@ -59,17 +57,15 @@ shell_screenshot_init (ShellScreenshot *screenshot)
 
 static void
 on_screenshot_written (GObject      *source,
-                       GAsyncResult *result,
+                       GAsyncResult *task,
                        gpointer      user_data)
 {
   ShellScreenshot *screenshot = SHELL_SCREENSHOT (source);
   ShellScreenshotPrivate *priv = screenshot->priv;
+  GTask *result = user_data;
 
-  if (priv->callback)
-    priv->callback (screenshot,
-                    g_task_propagate_boolean (G_TASK (result), NULL),
-                    &priv->screenshot_area,
-                    priv->filename_used);
+  g_task_return_boolean (result, g_task_propagate_boolean (G_TASK (task), NULL));
+  g_object_unref (result);
 
   g_clear_pointer (&priv->image, cairo_surface_destroy);
   g_clear_pointer (&priv->filename, g_free);
@@ -313,14 +309,15 @@ _draw_cursor_image (MetaCursorTracker     *tracker,
 
 static void
 grab_screenshot (ClutterActor *stage,
-                 ShellScreenshot *screenshot)
+                 GTask        *result)
 {
   MetaDisplay *display;
   MetaCursorTracker *tracker;
   int width, height;
-  GTask *result;
   GSettings *settings;
+  ShellScreenshot *screenshot = g_task_get_source_object (result);
   ShellScreenshotPrivate *priv = screenshot->priv;
+  GTask *task;
 
   display = shell_global_get_display (priv->global);
   meta_display_get_size (display, &width, &height);
@@ -380,19 +377,20 @@ grab_screenshot (ClutterActor *stage,
     }
   g_object_unref (settings);
 
-  g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot);
+  g_signal_handlers_disconnect_by_func (stage, grab_screenshot, result);
 
-  result = g_task_new (screenshot, NULL, on_screenshot_written, NULL);
-  g_task_run_in_thread (result, write_screenshot_thread);
-  g_object_unref (result);
+  task = g_task_new (screenshot, NULL, on_screenshot_written, result);
+  g_task_run_in_thread (task, write_screenshot_thread);
+  g_object_unref (task);
 }
 
 static void
 grab_area_screenshot (ClutterActor *stage,
-                      ShellScreenshot *screenshot)
+                      GTask        *result)
 {
-  GTask *result;
+  ShellScreenshot *screenshot = g_task_get_source_object (result);
   ShellScreenshotPrivate *priv = screenshot->priv;
+  GTask *task;
 
   do_grab_screenshot (screenshot,
                       CLUTTER_STAGE (stage),
@@ -401,18 +399,19 @@ grab_area_screenshot (ClutterActor *stage,
                       priv->screenshot_area.width,
                       priv->screenshot_area.height);
 
-  g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot);
-  result = g_task_new (screenshot, NULL, on_screenshot_written, NULL);
-  g_task_run_in_thread (result, write_screenshot_thread);
-  g_object_unref (result);
+  g_signal_handlers_disconnect_by_func (stage, grab_area_screenshot, result);
+  task = g_task_new (screenshot, NULL, on_screenshot_written, result);
+  g_task_run_in_thread (task, write_screenshot_thread);
+  g_object_unref (task);
 }
 
 static void
 grab_window_screenshot (ClutterActor *stage,
-                        ShellScreenshot *screenshot)
+                        GTask        *result)
 {
+  ShellScreenshot *screenshot = g_task_get_source_object (result);
   ShellScreenshotPrivate *priv = screenshot->priv;
-  GTask *result;
+  GTask *task;
   GSettings *settings;
   MetaDisplay *display = shell_global_get_display (priv->global);
   MetaCursorTracker *tracker;
@@ -451,10 +450,31 @@ grab_window_screenshot (ClutterActor *stage,
     }
   g_object_unref (settings);
 
-  g_signal_handlers_disconnect_by_func (stage, (void *)grab_window_screenshot, (gpointer)screenshot);
-  result = g_task_new (screenshot, NULL, on_screenshot_written, NULL);
-  g_task_run_in_thread (result, write_screenshot_thread);
-  g_object_unref (result);
+  g_signal_handlers_disconnect_by_func (stage, grab_window_screenshot, result);
+  task = g_task_new (screenshot, NULL, on_screenshot_written, result);
+  g_task_run_in_thread (task, write_screenshot_thread);
+  g_object_unref (task);
+}
+
+static gboolean
+finish_screenshot (ShellScreenshot        *screenshot,
+                   GAsyncResult           *result,
+                   cairo_rectangle_int_t **area,
+                   const char            **filename_used,
+                   GError                **error)
+{
+  ShellScreenshotPrivate *priv = screenshot->priv;
+
+  if (!g_task_propagate_boolean (G_TASK (result), error))
+    return FALSE;
+
+  if (area)
+    *area = &priv->screenshot_area;
+
+  if (filename_used)
+    *filename_used = priv->filename_used;
+
+  return TRUE;
 }
 
 /**
@@ -464,39 +484,79 @@ grab_window_screenshot (ClutterActor *stage,
  * @filename: The filename for the screenshot
  * @callback: (scope async): function to call returning success or failure
  * of the async grabbing
+ * @user_data: the data to pass to callback function
  *
  * Takes a screenshot of the whole screen
  * in @filename as png image.
  *
  */
 void
-shell_screenshot_screenshot (ShellScreenshot *screenshot,
-                             gboolean include_cursor,
-                             const char *filename,
-                             ShellScreenshotCallback callback)
+shell_screenshot_screenshot (ShellScreenshot     *screenshot,
+                             gboolean             include_cursor,
+                             const char          *filename,
+                             GAsyncReadyCallback  callback,
+                             gpointer             user_data)
 {
   ClutterActor *stage;
   ShellScreenshotPrivate *priv = screenshot->priv;
+  GTask *result;
 
   if (priv->filename != NULL) {
     if (callback)
-      callback (screenshot, FALSE, NULL, "");
+      g_task_report_new_error (screenshot,
+                               callback,
+                               user_data,
+                               shell_screenshot_screenshot,
+                               G_IO_ERROR,
+                               G_IO_ERROR_PENDING,
+                               "Only one screenshot operation at a time "
+                               "is permitted");
     return;
   }
 
+  result = g_task_new (screenshot, NULL, callback, user_data);
+  g_task_set_source_tag (result, shell_screenshot_screenshot);
+
   priv->filename = g_strdup (filename);
-  priv->callback = callback;
   priv->include_cursor = include_cursor;
 
   stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
 
   meta_disable_unredirect_for_display (shell_global_get_display (priv->global));
 
-  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), (gpointer)screenshot);
+  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), result);
 
   clutter_actor_queue_redraw (stage);
 }
 
+/**
+ * shell_screenshot_screenshot_finish:
+ * @screenshot: the #ShellScreenshot
+ * @result: the #GAsyncResult that was provided to the callback
+ * @area: (out) (transfer none): the area that was grabbed in screen coordinates
+ * @filename_used: (out) (transfer none): the name of the file the screenshot
+ * was written to
+ * @error: #GError for error reporting
+ *
+ * Finish the asynchronous operation started by shell_screenshot_screenshot()
+ * and obtain its result.
+ *
+ * Returns: whether the operation was successful
+ *
+ */
+gboolean
+shell_screenshot_screenshot_finish (ShellScreenshot        *screenshot,
+                                    GAsyncResult           *result,
+                                    cairo_rectangle_int_t **area,
+                                    const char            **filename_used,
+                                    GError                **error)
+{
+  g_return_val_if_fail (g_async_result_is_tagged (result,
+                                                  shell_screenshot_screenshot),
+                        FALSE);
+  return finish_screenshot (screenshot, result, area, filename_used, error);
+}
+
 /**
  * shell_screenshot_screenshot_area:
  * @screenshot: the #ShellScreenshot
@@ -507,45 +567,85 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot,
  * @filename: The filename for the screenshot
  * @callback: (scope async): function to call returning success or failure
  * of the async grabbing
+ * @user_data: the data to pass to callback function
  *
  * Takes a screenshot of the passed in area and saves it
  * in @filename as png image.
  *
  */
 void
-shell_screenshot_screenshot_area (ShellScreenshot *screenshot,
-                                  int x,
-                                  int y,
-                                  int width,
-                                  int height,
-                                  const char *filename,
-                                  ShellScreenshotCallback callback)
+shell_screenshot_screenshot_area (ShellScreenshot     *screenshot,
+                                  int                  x,
+                                  int                  y,
+                                  int                  width,
+                                  int                  height,
+                                  const char          *filename,
+                                  GAsyncReadyCallback  callback,
+                                  gpointer             user_data)
 {
   ClutterActor *stage;
   ShellScreenshotPrivate *priv = screenshot->priv;
+  GTask *result;
 
   if (priv->filename != NULL) {
     if (callback)
-      callback (screenshot, FALSE, NULL, "");
+      g_task_report_new_error (screenshot,
+                               callback,
+                               NULL,
+                               shell_screenshot_screenshot_area,
+                               G_IO_ERROR,
+                               G_IO_ERROR_PENDING,
+                               "Only one screenshot operation at a time "
+                               "is permitted");
     return;
   }
 
+  result = g_task_new (screenshot, NULL, callback, user_data);
+  g_task_set_source_tag (result, shell_screenshot_screenshot_area);
+
   priv->filename = g_strdup (filename);
   priv->screenshot_area.x = x;
   priv->screenshot_area.y = y;
   priv->screenshot_area.width = width;
   priv->screenshot_area.height = height;
-  priv->callback = callback;
 
   stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
 
   meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ()));
 
-  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), (gpointer)screenshot);
+  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), result);
 
   clutter_actor_queue_redraw (stage);
 }
 
+/**
+ * shell_screenshot_screenshot_area_finish:
+ * @screenshot: the #ShellScreenshot
+ * @result: the #GAsyncResult that was provided to the callback
+ * @area: (out) (transfer none): the area that was grabbed in screen coordinates
+ * @filename_used: (out) (transfer none): the name of the file the screenshot
+ * was written to
+ * @error: #GError for error reporting
+ *
+ * Finish the asynchronous operation started by shell_screenshot_screenshot_area()
+ * and obtain its result.
+ *
+ * Returns: whether the operation was successful
+ *
+ */
+gboolean
+shell_screenshot_screenshot_area_finish (ShellScreenshot        *screenshot,
+                                         GAsyncResult           *result,
+                                         cairo_rectangle_int_t **area,
+                                         const char            **filename_used,
+                                         GError                **error)
+{
+  g_return_val_if_fail (g_async_result_is_tagged (result,
+                                                  shell_screenshot_screenshot_area),
+                        FALSE);
+  return finish_screenshot (screenshot, result, area, filename_used, error);
+}
+
 /**
  * shell_screenshot_screenshot_window:
  * @screenshot: the #ShellScreenshot
@@ -554,31 +654,43 @@ shell_screenshot_screenshot_area (ShellScreenshot *screenshot,
  * @filename: The filename for the screenshot
  * @callback: (scope async): function to call returning success or failure
  * of the async grabbing
+ * @user_data: the data to pass to callback function
  *
  * 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)
+shell_screenshot_screenshot_window (ShellScreenshot     *screenshot,
+                                    gboolean             include_frame,
+                                    gboolean             include_cursor,
+                                    const char          *filename,
+                                    GAsyncReadyCallback  callback,
+                                    gpointer             user_data)
 {
   ShellScreenshotPrivate *priv = screenshot->priv;
   MetaDisplay *display = shell_global_get_display (priv->global);
   ClutterActor *stage;
   MetaWindow *window = meta_display_get_focus_window (display);
+  GTask *result;
 
   if (priv->filename != NULL || !window) {
     if (callback)
-      callback (screenshot, FALSE, NULL, "");
+      g_task_report_new_error (screenshot,
+                               callback,
+                               NULL,
+                               shell_screenshot_screenshot_window,
+                               G_IO_ERROR,
+                               G_IO_ERROR_PENDING,
+                               "Only one screenshot operation at a time "
+                               "is permitted");
     return;
   }
 
+  result = g_task_new (screenshot, NULL, callback, user_data);
+  g_task_set_source_tag (result, shell_screenshot_screenshot_window);
+
   priv->filename = g_strdup (filename);
-  priv->callback = callback;
   priv->include_frame = include_frame;
   priv->include_cursor = include_cursor;
 
@@ -586,11 +698,39 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
 
   meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ()));
 
-  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_window_screenshot), (gpointer)screenshot);
+  g_signal_connect_after (stage, "paint", G_CALLBACK (grab_window_screenshot), result);
 
   clutter_actor_queue_redraw (stage);
 }
 
+/**
+ * shell_screenshot_screenshot_window_finish:
+ * @screenshot: the #ShellScreenshot
+ * @result: the #GAsyncResult that was provided to the callback
+ * @area: (out) (transfer none): the area that was grabbed in screen coordinates
+ * @filename_used: (out) (transfer none): the name of the file the screenshot
+ * was written to
+ * @error: #GError for error reporting
+ *
+ * Finish the asynchronous operation started by shell_screenshot_screenshot_window()
+ * and obtain its result.
+ *
+ * Returns: whether the operation was successful
+ *
+ */
+gboolean
+shell_screenshot_screenshot_window_finish (ShellScreenshot        *screenshot,
+                                           GAsyncResult           *result,
+                                           cairo_rectangle_int_t **area,
+                                           const char            **filename_used,
+                                           GError                **error)
+{
+  g_return_val_if_fail (g_async_result_is_tagged (result,
+                                                  shell_screenshot_screenshot_window),
+                        FALSE);
+  return finish_screenshot (screenshot, result, area, filename_used, error);
+}
+
 ShellScreenshot *
 shell_screenshot_new (void)
 {
diff --git a/src/shell-screenshot.h b/src/shell-screenshot.h
index df00568f7..61178e2ec 100644
--- a/src/shell-screenshot.h
+++ b/src/shell-screenshot.h
@@ -16,28 +16,41 @@ G_DECLARE_FINAL_TYPE (ShellScreenshot, shell_screenshot,
 
 ShellScreenshot *shell_screenshot_new (void);
 
-typedef void (*ShellScreenshotCallback)  (ShellScreenshot *screenshot,
-                                          gboolean success,
-                                          cairo_rectangle_int_t *screenshot_area,
-                                          const gchar *filename_used);
+void    shell_screenshot_screenshot_area      (ShellScreenshot      *screenshot,
+                                               int                   x,
+                                               int                   y,
+                                               int                   width,
+                                               int                   height,
+                                               const char           *filename,
+                                               GAsyncReadyCallback   callback,
+                                               gpointer              user_data);
+gboolean shell_screenshot_screenshot_area_finish (ShellScreenshot       *screenshot,
+                                                  GAsyncResult          *result,
+                                                  cairo_rectangle_int_t **area,
+                                                  const char            **filename_used,
+                                                  GError                **error);
 
-void    shell_screenshot_screenshot_area      (ShellScreenshot *screenshot,
-                                                int x,
-                                                int y,
-                                                int width,
-                                                int height,
-                                                const char *filename,
-                                                ShellScreenshotCallback callback);
+void    shell_screenshot_screenshot_window    (ShellScreenshot     *screenshot,
+                                               gboolean             include_frame,
+                                               gboolean             include_cursor,
+                                               const char          *filename,
+                                               GAsyncReadyCallback  callback,
+                                               gpointer             user_data);
+gboolean shell_screenshot_screenshot_window_finish (ShellScreenshot        *screenshot,
+                                                    GAsyncResult           *result,
+                                                    cairo_rectangle_int_t **area,
+                                                    const char            **filename_used,
+                                                    GError                **error);
 
-void    shell_screenshot_screenshot_window    (ShellScreenshot *screenshot,
-                                                gboolean include_frame,
-                                                gboolean include_cursor,
-                                                const char *filename,
-                                                ShellScreenshotCallback callback);
-
-void    shell_screenshot_screenshot           (ShellScreenshot *screenshot,
-                                                gboolean include_cursor,
-                                                const char *filename,
-                                                ShellScreenshotCallback callback);
+void    shell_screenshot_screenshot           (ShellScreenshot     *screenshot,
+                                               gboolean             include_cursor,
+                                               const char          *filename,
+                                               GAsyncReadyCallback  callback,
+                                               gpointer             user_data);
+gboolean shell_screenshot_screenshot_finish   (ShellScreenshot        *screenshot,
+                                               GAsyncResult           *result,
+                                               cairo_rectangle_int_t **area,
+                                               const char            **filename_used,
+                                               GError                **error);
 
 #endif /* ___SHELL_SCREENSHOT_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]