summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColomban Wendling <[email protected]>2025-11-05 11:23:45 +0100
committerColomban Wendling <[email protected]>2025-11-05 12:25:46 +0100
commit24d047ed571b71161ebc089d34dcf30d71dc42e4 (patch)
treee8591c818077d4b8590dec938c0e087123b58f55
parentc74d86d0f25435b1d90f70015d210448126bb6ef (diff)
downloadmate-utils-24d047ed571b71161ebc089d34dcf30d71dc42e4.tar.bz2
mate-utils-24d047ed571b71161ebc089d34dcf30d71dc42e4.tar.xz
mate-screenshot: Replace sync save with async save
Restore asynchronous screenshot saving to improve reactivity, but use proper asynchronous APIs instead of the previous dangerous fork()-based solution, that mostly worked out of luck and stopped working with newer gdk-pixbuf versions.
-rw-r--r--mate-screenshot/src/screenshot-save.c121
1 files changed, 104 insertions, 17 deletions
diff --git a/mate-screenshot/src/screenshot-save.c b/mate-screenshot/src/screenshot-save.c
index dd9c032c..e3e04768 100644
--- a/mate-screenshot/src/screenshot-save.c
+++ b/mate-screenshot/src/screenshot-save.c
@@ -29,6 +29,15 @@
#include "screenshot-save.h"
+typedef struct
+{
+ GdkPixbuf *pixbuf;
+ GFileOutputStream *stream;
+ SaveFunction callback;
+ gpointer user_data;
+}
+SaveAsyncData;
+
static char *parent_dir = NULL;
static char *tmp_filename = NULL;
@@ -81,12 +90,97 @@ cleanup_handler (void)
clean_up_temporary_dir ();
}
+static void
+save_async_finish_and_free (SaveAsyncData *data, GError *err)
+{
+ if (err)
+ {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "Unable to save the screenshot to disk:\n\n%s",
+ err->message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ clean_up_temporary_dir ();
+ }
+
+ if (data->callback)
+ data->callback (data->user_data);
+
+ if (data->stream)
+ g_clear_object (&data->stream);
+
+ g_clear_object (&data->pixbuf);
+ g_free (data);
+}
+
+static void
+stream_close_async_ready (GObject* object, GAsyncResult* res, gpointer user_data)
+{
+ SaveAsyncData *data = user_data;
+ GError *err = NULL;
+
+ if (! g_output_stream_close_finish (G_OUTPUT_STREAM(object), res, &err))
+ {
+ save_async_finish_and_free (data, err);
+ g_error_free (err);
+ }
+ else
+ {
+ /* all done! */
+ save_async_finish_and_free (data, NULL);
+ }
+}
+
+static void
+save_to_stream_async_ready (GObject* object, GAsyncResult* res, gpointer user_data)
+{
+ SaveAsyncData *data = user_data;
+ GError *err = NULL;
+
+ if (! gdk_pixbuf_save_to_stream_finish (res, &err))
+ {
+ save_async_finish_and_free (data, err);
+ g_error_free (err);
+ }
+ else
+ {
+ g_output_stream_close_async (G_OUTPUT_STREAM (data->stream), G_PRIORITY_DEFAULT,
+ NULL, stream_close_async_ready, data);
+ }
+}
+
+static void
+replace_async_ready (GObject* object, GAsyncResult* res, gpointer user_data)
+{
+ SaveAsyncData *data = user_data;
+ GError *err = NULL;
+
+ data->stream = g_file_replace_finish (G_FILE(object), res, &err);
+ if (! data->stream)
+ {
+ save_async_finish_and_free (data, err);
+ g_error_free (err);
+ }
+ else
+ {
+ gdk_pixbuf_save_to_stream_async (data->pixbuf, G_OUTPUT_STREAM (data->stream),
+ "png", NULL, save_to_stream_async_ready, data,
+ "tEXt::Software", "mate-screenshot",
+ NULL);
+ }
+}
+
void
screenshot_save_start (GdkPixbuf *pixbuf,
SaveFunction callback,
gpointer user_data)
{
- GError *error = NULL;
+ SaveAsyncData *data;
+ GFile *file;
static gboolean cleanup_registered = FALSE;
if (!cleanup_registered)
@@ -109,23 +203,16 @@ screenshot_save_start (GdkPixbuf *pixbuf,
_("Screenshot.png"),
NULL);
- if (! gdk_pixbuf_save (pixbuf, tmp_filename,
- "png", &error,
- "tEXt::Software", "mate-screenshot",
- NULL))
- {
- if (error && error->message)
- g_warning ("Failed to save screenshot: %s", error->message);
- else
- g_warning ("Failed to save screenshot: Unknown error");
-
- g_error_free (error);
-
- clean_up_temporary_dir ();
- }
+ data = g_malloc (sizeof *data);
+ data->pixbuf = g_object_ref (pixbuf);
+ data->stream = NULL;
+ data->callback = callback;
+ data->user_data = user_data;
- if (callback)
- callback (user_data);
+ file = g_file_new_for_path (tmp_filename);
+ g_file_replace_async (file, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
+ G_PRIORITY_DEFAULT, NULL, replace_async_ready, data);
+ g_object_unref (file);
}
const char *