From 224326857b15ad5f7fccf544f08cd3bdb0772dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Dzi=C4=99giel?= Date: Tue, 18 Feb 2025 21:32:35 +0100 Subject: [PATCH] clapper-app: Create pipeline preview file async --- src/bin/clapper-app/clapper-app-application.c | 93 +++++++++++++++---- src/bin/clapper-app/clapper-app-application.h | 1 + src/bin/clapper-app/clapper-app-utils.c | 67 ++++++++----- src/bin/clapper-app/clapper-app-utils.h | 2 +- 4 files changed, 120 insertions(+), 43 deletions(-) diff --git a/src/bin/clapper-app/clapper-app-application.c b/src/bin/clapper-app/clapper-app-application.c index eae3e248..288ae041 100644 --- a/src/bin/clapper-app/clapper-app-application.c +++ b/src/bin/clapper-app/clapper-app-application.c @@ -41,6 +41,7 @@ struct _ClapperAppApplication GtkApplication parent; GSettings *settings; + GCancellable *cancellable; gboolean need_init_state; }; @@ -61,6 +62,12 @@ struct ClapperPluginData struct ClapperPluginFeatureData features[10]; }; +typedef struct +{ + ClapperAppApplication *app; + guint id; +} ClapperAppWindowData; + typedef struct { const gchar *action; @@ -396,7 +403,7 @@ show_info (GSimpleAction *action, GVariant *param, gpointer user_data) } static void -_show_pipeline_cb (GtkFileLauncher *launcher, +_launch_pipeline_cb (GtkFileLauncher *launcher, GAsyncResult *res, gpointer user_data G_GNUC_UNUSED) { GError *error = NULL; @@ -411,14 +418,52 @@ _show_pipeline_cb (GtkFileLauncher *launcher, } static void -show_pipeline (GSimpleAction *action, GVariant *param, gpointer user_data) +_show_pipeline_cb (GObject *source G_GNUC_UNUSED, + GAsyncResult *res, ClapperAppWindowData *win_data) { - GtkApplication *gtk_app = GTK_APPLICATION (user_data); + GTask *task = G_TASK (res); GtkWindow *window; - GtkFileLauncher *launcher; GFile *svg_file; GError *error = NULL; + svg_file = (GFile *) g_task_propagate_pointer (task, &error); + + if (error) { + if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_CANCELLED) { + GST_ERROR ("Could not create pipeline graph file, reason: %s", + GST_STR_NULL (error->message)); + } + g_error_free (error); + g_free (win_data); + + return; + } + + if ((window = gtk_application_get_window_by_id ( + GTK_APPLICATION (win_data->app), win_data->id))) { + GtkFileLauncher *launcher = gtk_file_launcher_new (svg_file); + +#if GTK_CHECK_VERSION(4,12,0) + gtk_file_launcher_set_always_ask (launcher, TRUE); +#endif + + gtk_file_launcher_launch (launcher, window, NULL, + (GAsyncReadyCallback) _launch_pipeline_cb, NULL); + g_object_unref (launcher); + } + + g_object_unref (svg_file); + g_free (win_data); +} + +static void +show_pipeline (GSimpleAction *action, GVariant *param, gpointer user_data) +{ + ClapperAppApplication *self = CLAPPER_APP_APPLICATION_CAST (user_data); + GtkApplication *gtk_app = GTK_APPLICATION (self); + GtkWindow *window; + ClapperAppWindowData *win_data; + window = gtk_application_get_active_window (gtk_app); while (window && !CLAPPER_APP_IS_WINDOW (window)) @@ -427,25 +472,19 @@ show_pipeline (GSimpleAction *action, GVariant *param, gpointer user_data) if (G_UNLIKELY (window == NULL)) return; - if (!(svg_file = clapper_app_utils_create_pipeline_svg_file ( - clapper_app_window_get_player (CLAPPER_APP_WINDOW (window)), &error))) { - GST_ERROR ("Could not create pipeline graph file, reason: %s", - GST_STR_NULL (error->message)); - g_error_free (error); - - return; + if (self->cancellable) { + g_cancellable_cancel (self->cancellable); + g_object_unref (self->cancellable); } + self->cancellable = g_cancellable_new (); - launcher = gtk_file_launcher_new (svg_file); - g_object_unref (svg_file); + win_data = g_new (ClapperAppWindowData, 1); + win_data->app = self; + win_data->id = gtk_application_window_get_id (GTK_APPLICATION_WINDOW (window)); -#if GTK_CHECK_VERSION(4,12,0) - gtk_file_launcher_set_always_ask (launcher, TRUE); -#endif - - gtk_file_launcher_launch (launcher, window, NULL, - (GAsyncReadyCallback) _show_pipeline_cb, NULL); - g_object_unref (launcher); + clapper_app_utils_create_pipeline_svg_file_async ( + clapper_app_window_get_player (CLAPPER_APP_WINDOW (window)), + self->cancellable, (GAsyncReadyCallback) _show_pipeline_cb, win_data); } static void @@ -809,6 +848,19 @@ clapper_app_application_constructed (GObject *object) G_OBJECT_CLASS (parent_class)->constructed (object); } +static void +clapper_app_application_dispose (GObject *object) +{ + ClapperAppApplication *self = CLAPPER_APP_APPLICATION_CAST (object); + + if (self->cancellable) { + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + static void clapper_app_application_finalize (GObject *object) { @@ -832,6 +884,7 @@ clapper_app_application_class_init (ClapperAppApplicationClass *klass) "Clapper App Application"); gobject_class->constructed = clapper_app_application_constructed; + gobject_class->dispose = clapper_app_application_dispose; gobject_class->finalize = clapper_app_application_finalize; gtk_application_class->window_removed = clapper_app_application_window_removed; diff --git a/src/bin/clapper-app/clapper-app-application.h b/src/bin/clapper-app/clapper-app-application.h index 17a7e1c1..8edfc585 100644 --- a/src/bin/clapper-app/clapper-app-application.h +++ b/src/bin/clapper-app/clapper-app-application.h @@ -19,6 +19,7 @@ #include #include +#include #include G_BEGIN_DECLS diff --git a/src/bin/clapper-app/clapper-app-utils.c b/src/bin/clapper-app/clapper-app-utils.c index 135feffc..3da4a28d 100644 --- a/src/bin/clapper-app/clapper-app-utils.c +++ b/src/bin/clapper-app/clapper-app-utils.c @@ -548,42 +548,42 @@ _get_tmp_dir (const gchar *subdir) #ifdef HAVE_GRAPHVIZ static GFile * -_create_tmp_subdir (const gchar *subdir) +_create_tmp_subdir (const gchar *subdir, GCancellable *cancellable, GError **error) { GFile *tmp_dir; - GError *error = NULL; + GError *my_error = NULL; tmp_dir = _get_tmp_dir (subdir); - if (!g_file_make_directory_with_parents (tmp_dir, NULL, &error)) { - if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_EXISTS) { - GST_ERROR ("Could not create temp dir, reason: %s", - GST_STR_NULL (error->message)); + if (!g_file_make_directory_with_parents (tmp_dir, cancellable, &my_error)) { + if (my_error->domain != G_IO_ERROR || my_error->code != G_IO_ERROR_EXISTS) { + *error = g_error_copy (my_error); g_clear_object (&tmp_dir); // return NULL } - g_error_free (error); + g_error_free (my_error); } return tmp_dir; } #endif -GFile * -clapper_app_utils_create_pipeline_svg_file (ClapperPlayer *player, GError **error) +static void +_create_pipeline_svg_file_in_thread (GTask *task, GObject *source G_GNUC_UNUSED, + ClapperPlayer *player, GCancellable *cancellable) { GFile *tmp_file = NULL; + GError *error = NULL; #ifdef HAVE_GRAPHVIZ GFile *tmp_subdir; Agraph_t *graph; GVC_t *gvc; - gchar *path, *template, *dot_data, *img_data = NULL; + gchar *path, *template = NULL, *dot_data = NULL, *img_data = NULL; gint fd; guint size = 0; - tmp_subdir = _create_tmp_subdir ("pipelines"); - if (G_UNLIKELY (tmp_subdir == NULL)) - return NULL; + if (!(tmp_subdir = _create_tmp_subdir ("pipelines", cancellable, &error))) + goto finish; path = g_file_get_path (tmp_subdir); g_object_unref (tmp_subdir); @@ -594,14 +594,16 @@ clapper_app_utils_create_pipeline_svg_file (ClapperPlayer *player, GError **erro fd = g_mkstemp (template); // Modifies template to actual filename if (G_UNLIKELY (fd == -1)) { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Could not open temp file for writing"); - g_free (template); - - return NULL; + goto finish; } dot_data = clapper_player_make_pipeline_graph (player, GST_DEBUG_GRAPH_SHOW_ALL); + + if (g_cancellable_is_cancelled (cancellable)) + goto close_and_finish; + graph = agmemread (dot_data); gvc = gvContext (); @@ -610,27 +612,48 @@ clapper_app_utils_create_pipeline_svg_file (ClapperPlayer *player, GError **erro agclose (graph); gvFreeContext (gvc); - g_free (dot_data); + + if (g_cancellable_is_cancelled (cancellable)) + goto close_and_finish; if (write (fd, img_data, size) != -1) { tmp_file = g_file_new_for_path (template); } else { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Could not write data to temp file"); } +close_and_finish: /* Always close the file IO */ if (G_UNLIKELY (close (fd) == -1)) GST_ERROR ("Could not close temp file!"); - g_free (img_data); +finish: g_free (template); + g_free (dot_data); + g_free (img_data); #else - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Cannot create graph file when compiled without Graphviz"); #endif - return tmp_file; + if (tmp_file) + g_task_return_pointer (task, tmp_file, (GDestroyNotify) g_object_unref); + else + g_task_return_error (task, error); +} + +void +clapper_app_utils_create_pipeline_svg_file_async (ClapperPlayer *player, + GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) +{ + GTask *task; + + task = g_task_new (NULL, cancellable, callback, user_data); + g_task_set_task_data (task, gst_object_ref (player), (GDestroyNotify) gst_object_unref); + g_task_run_in_thread (task, (GTaskThreadFunc) _create_pipeline_svg_file_in_thread); + + g_object_unref (task); } static gboolean diff --git a/src/bin/clapper-app/clapper-app-utils.h b/src/bin/clapper-app/clapper-app-utils.h index 90771021..d02b6bc5 100644 --- a/src/bin/clapper-app/clapper-app-utils.h +++ b/src/bin/clapper-app/clapper-app-utils.h @@ -85,7 +85,7 @@ G_GNUC_INTERNAL GstElement * clapper_app_utils_make_element (const gchar *string); G_GNUC_INTERNAL -GFile * clapper_app_utils_create_pipeline_svg_file (ClapperPlayer *player, GError **error); +void clapper_app_utils_create_pipeline_svg_file_async (ClapperPlayer *player, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); G_GNUC_INTERNAL void clapper_app_utils_delete_tmp_dir (void);