From 5987115b7918e6bd090f178d4ee23d1991eae6b0 Mon Sep 17 00:00:00 2001 From: mbkma Date: Sun, 12 Apr 2026 09:00:36 +0200 Subject: rewrite screenshot find save location logic --- mate-screenshot/src/mate-screenshot.c | 232 ++++++++++++++++++---------------- 1 file changed, 120 insertions(+), 112 deletions(-) diff --git a/mate-screenshot/src/mate-screenshot.c b/mate-screenshot/src/mate-screenshot.c index df203a88..7c162ea1 100644 --- a/mate-screenshot/src/mate-screenshot.c +++ b/mate-screenshot/src/mate-screenshot.c @@ -75,19 +75,9 @@ typedef enum { SCREENSHOT_EFFECT_BORDER } ScreenshotEffectType; -typedef enum -{ - TEST_LAST_DIR = 0, - TEST_DESKTOP = 1, - TEST_TMP = 2, -} TestType; - typedef struct { char *base_uris[3]; - char *retval; - int iteration; - TestType type; GdkWindow *window; GdkRectangle *rectangle; } AsyncExistenceJob; @@ -889,143 +879,163 @@ async_existence_job_free (AsyncExistenceJob *job) g_slice_free (AsyncExistenceJob, job); } -static gboolean -check_file_done (gpointer user_data) +static void +on_check_file_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { - AsyncExistenceJob *job = user_data; + AsyncExistenceJob *job = g_task_get_task_data (G_TASK (result)); + GError *error = NULL; + char *uri; - finish_prepare_screenshot (job->retval, job->window, job->rectangle); + (void) source; + (void) user_data; - async_existence_job_free (job); + uri = g_task_propagate_pointer (G_TASK (result), &error); - return FALSE; + if (error != NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Unable to determine screenshot save URI: %s", error->message); + + g_error_free (error); + screenshot_release_lock (); + return; + } + + finish_prepare_screenshot (uri, job->window, job->rectangle); } static char * -build_uri (AsyncExistenceJob *job) +build_screenshot_filename (int iteration) { - char *retval, *file_name; - char *timestamp; GDateTime *d; + char *timestamp, *file_name; d = g_date_time_new_now_local (); timestamp = g_date_time_format (d, "%Y-%m-%d %H-%M-%S"); g_date_time_unref (d); - if (job->iteration == 0) - { - /* translators: this is the name of the file that gets made up - * with the screenshot if the entire screen is taken */ - file_name = g_strdup_printf (_("Screenshot at %s.png"), timestamp); - } + if (iteration == 0) + /* translators: this is the name of the file that gets made up + * with the screenshot if the entire screen is taken */ + file_name = g_strdup_printf (_("Screenshot at %s.png"), timestamp); else - { - /* translators: this is the name of the file that gets - * made up with the screenshot if the entire screen is - * taken */ - file_name = g_strdup_printf (_("Screenshot at %s - %d.png"), timestamp, job->iteration); - } + /* translators: this is the name of the file that gets + * made up with the screenshot if the entire screen is + * taken */ + file_name = g_strdup_printf (_("Screenshot at %s - %d.png"), timestamp, iteration); - retval = g_build_filename (job->base_uris[job->type], file_name, NULL); - g_free (file_name); g_free (timestamp); - - return retval; + return file_name; } -static gboolean -try_check_file (GIOSchedulerJob *io_job, - GCancellable *cancellable, - gpointer data) +static void +try_check_file (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) { - AsyncExistenceJob *job = data; - GFile *file; - GFileInfo *info; - GError *error; - char *uri; + AsyncExistenceJob *job = task_data; + guint n_types = G_N_ELEMENTS (job->base_uris); -retry: - error = NULL; - uri = build_uri (job); - file = g_file_new_for_uri (uri); + (void) source_object; - info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, - G_FILE_QUERY_INFO_NONE, cancellable, &error); - if (info != NULL) + for (guint t = 0; t < n_types; t++) { - /* file already exists, iterate again */ - g_object_unref (info); - g_object_unref (file); - g_free (uri); + GFile *dir; + GFileInfo *dir_info; + GError *error = NULL; + gboolean writable; - (job->iteration)++; + if (job->base_uris[t] == NULL) + continue; - goto retry; - } - else - { - /* see the error to check whether the location is not accessible - * or the file does not exist. - */ - if (error->code == G_IO_ERROR_NOT_FOUND) + if (cancellable != NULL && g_cancellable_is_cancelled (cancellable)) { - GFile *parent; + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_CANCELLED, + "Screenshot save URI lookup cancelled"); + return; + } - /* if the parent directory doesn't exist as well, forget the saved - * directory and treat this as a generic error. - */ + dir = g_file_new_for_uri (job->base_uris[t]); - parent = g_file_get_parent (file); + /* Query the directory itself to verify writability before probing names. */ + dir_info = g_file_query_info (dir, + G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, + G_FILE_QUERY_INFO_NONE, + cancellable, + &error); + if (dir_info == NULL) + { + g_clear_error (&error); + g_object_unref (dir); + continue; + } - if (!g_file_query_exists (parent, NULL)) - { - (job->type)++; - job->iteration = 0; + writable = !g_file_info_has_attribute (dir_info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE) || + g_file_info_get_attribute_boolean (dir_info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE); + g_object_unref (dir_info); - g_object_unref (file); - g_object_unref (parent); - goto retry; - } - else - { - job->retval = uri; - - g_object_unref (parent); - goto out; - } + if (!writable) + { + g_object_unref (dir); + continue; } - else + + for (int iteration = 0; ; iteration++) { - /* another kind of error, assume this location is not - * accessible. - */ - g_free (uri); - if (job->type == TEST_TMP) + char *file_name; + GFile *file; + GFileInfo *file_info; + + if (cancellable != NULL && g_cancellable_is_cancelled (cancellable)) { - job->retval = NULL; - goto out; + g_object_unref (dir); + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_CANCELLED, + "Screenshot save URI lookup cancelled"); + return; } - else + + file_name = build_screenshot_filename (iteration); + file = g_file_get_child (dir, file_name); + g_free (file_name); + + file_info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_TYPE, + G_FILE_QUERY_INFO_NONE, + cancellable, + &error); + if (file_info != NULL) { - (job->type)++; - job->iteration = 0; + g_object_unref (file_info); + g_object_unref (file); + continue; + } - g_error_free (error); + if (error != NULL && error->code == G_IO_ERROR_NOT_FOUND) + { + char *uri = g_file_get_uri (file); + g_clear_error (&error); g_object_unref (file); - goto retry; + g_object_unref (dir); + g_task_return_pointer (task, uri, g_free); + return; } + + g_clear_error (&error); + g_object_unref (file); + break; } - } -out: - g_error_free (error); - g_object_unref (file); + g_object_unref (dir); + } - g_io_scheduler_job_send_to_mainloop_async (io_job, - check_file_done, - job, - NULL); - return FALSE; + g_task_return_pointer (task, NULL, NULL); } static GdkWindow * @@ -1063,8 +1073,6 @@ push_check_file_job (GdkRectangle *rectangle) /* we'll have to free these two */ job->base_uris[1] = get_desktop_dir (); job->base_uris[2] = g_strconcat ("file://", g_get_tmp_dir (), NULL); - job->iteration = 0; - job->type = TEST_LAST_DIR; job->window = find_current_window (); if (rectangle != NULL) @@ -1085,11 +1093,11 @@ push_check_file_job (GdkRectangle *rectangle) return; } - g_io_scheduler_push_job (try_check_file, - job, - NULL, - 0, NULL); + GTask *task = g_task_new (NULL, NULL, on_check_file_done, NULL); + g_task_set_task_data (task, job, (GDestroyNotify) async_existence_job_free); + g_task_run_in_thread (task, try_check_file); + g_object_unref (task); } static void -- cgit v1.2.1