mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 23:32:04 +02:00
clapper-app: Create pipeline preview file async
This commit is contained in:
@@ -41,6 +41,7 @@ struct _ClapperAppApplication
|
|||||||
GtkApplication parent;
|
GtkApplication parent;
|
||||||
|
|
||||||
GSettings *settings;
|
GSettings *settings;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
|
||||||
gboolean need_init_state;
|
gboolean need_init_state;
|
||||||
};
|
};
|
||||||
@@ -61,6 +62,12 @@ struct ClapperPluginData
|
|||||||
struct ClapperPluginFeatureData features[10];
|
struct ClapperPluginFeatureData features[10];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ClapperAppApplication *app;
|
||||||
|
guint id;
|
||||||
|
} ClapperAppWindowData;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
const gchar *action;
|
const gchar *action;
|
||||||
@@ -396,7 +403,7 @@ show_info (GSimpleAction *action, GVariant *param, gpointer user_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_show_pipeline_cb (GtkFileLauncher *launcher,
|
_launch_pipeline_cb (GtkFileLauncher *launcher,
|
||||||
GAsyncResult *res, gpointer user_data G_GNUC_UNUSED)
|
GAsyncResult *res, gpointer user_data G_GNUC_UNUSED)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
@@ -411,14 +418,52 @@ _show_pipeline_cb (GtkFileLauncher *launcher,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
GtkWindow *window;
|
||||||
GtkFileLauncher *launcher;
|
|
||||||
GFile *svg_file;
|
GFile *svg_file;
|
||||||
GError *error = NULL;
|
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);
|
window = gtk_application_get_active_window (gtk_app);
|
||||||
|
|
||||||
while (window && !CLAPPER_APP_IS_WINDOW (window))
|
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))
|
if (G_UNLIKELY (window == NULL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(svg_file = clapper_app_utils_create_pipeline_svg_file (
|
if (self->cancellable) {
|
||||||
clapper_app_window_get_player (CLAPPER_APP_WINDOW (window)), &error))) {
|
g_cancellable_cancel (self->cancellable);
|
||||||
GST_ERROR ("Could not create pipeline graph file, reason: %s",
|
g_object_unref (self->cancellable);
|
||||||
GST_STR_NULL (error->message));
|
|
||||||
g_error_free (error);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
self->cancellable = g_cancellable_new ();
|
||||||
|
|
||||||
launcher = gtk_file_launcher_new (svg_file);
|
win_data = g_new (ClapperAppWindowData, 1);
|
||||||
g_object_unref (svg_file);
|
win_data->app = self;
|
||||||
|
win_data->id = gtk_application_window_get_id (GTK_APPLICATION_WINDOW (window));
|
||||||
|
|
||||||
#if GTK_CHECK_VERSION(4,12,0)
|
clapper_app_utils_create_pipeline_svg_file_async (
|
||||||
gtk_file_launcher_set_always_ask (launcher, TRUE);
|
clapper_app_window_get_player (CLAPPER_APP_WINDOW (window)),
|
||||||
#endif
|
self->cancellable, (GAsyncReadyCallback) _show_pipeline_cb, win_data);
|
||||||
|
|
||||||
gtk_file_launcher_launch (launcher, window, NULL,
|
|
||||||
(GAsyncReadyCallback) _show_pipeline_cb, NULL);
|
|
||||||
g_object_unref (launcher);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -809,6 +848,19 @@ clapper_app_application_constructed (GObject *object)
|
|||||||
G_OBJECT_CLASS (parent_class)->constructed (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
|
static void
|
||||||
clapper_app_application_finalize (GObject *object)
|
clapper_app_application_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
@@ -832,6 +884,7 @@ clapper_app_application_class_init (ClapperAppApplicationClass *klass)
|
|||||||
"Clapper App Application");
|
"Clapper App Application");
|
||||||
|
|
||||||
gobject_class->constructed = clapper_app_application_constructed;
|
gobject_class->constructed = clapper_app_application_constructed;
|
||||||
|
gobject_class->dispose = clapper_app_application_dispose;
|
||||||
gobject_class->finalize = clapper_app_application_finalize;
|
gobject_class->finalize = clapper_app_application_finalize;
|
||||||
|
|
||||||
gtk_application_class->window_removed = clapper_app_application_window_removed;
|
gtk_application_class->window_removed = clapper_app_application_window_removed;
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@@ -548,42 +548,42 @@ _get_tmp_dir (const gchar *subdir)
|
|||||||
|
|
||||||
#ifdef HAVE_GRAPHVIZ
|
#ifdef HAVE_GRAPHVIZ
|
||||||
static GFile *
|
static GFile *
|
||||||
_create_tmp_subdir (const gchar *subdir)
|
_create_tmp_subdir (const gchar *subdir, GCancellable *cancellable, GError **error)
|
||||||
{
|
{
|
||||||
GFile *tmp_dir;
|
GFile *tmp_dir;
|
||||||
GError *error = NULL;
|
GError *my_error = NULL;
|
||||||
|
|
||||||
tmp_dir = _get_tmp_dir (subdir);
|
tmp_dir = _get_tmp_dir (subdir);
|
||||||
|
|
||||||
if (!g_file_make_directory_with_parents (tmp_dir, NULL, &error)) {
|
if (!g_file_make_directory_with_parents (tmp_dir, cancellable, &my_error)) {
|
||||||
if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_EXISTS) {
|
if (my_error->domain != G_IO_ERROR || my_error->code != G_IO_ERROR_EXISTS) {
|
||||||
GST_ERROR ("Could not create temp dir, reason: %s",
|
*error = g_error_copy (my_error);
|
||||||
GST_STR_NULL (error->message));
|
|
||||||
g_clear_object (&tmp_dir); // return NULL
|
g_clear_object (&tmp_dir); // return NULL
|
||||||
}
|
}
|
||||||
g_error_free (error);
|
g_error_free (my_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmp_dir;
|
return tmp_dir;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GFile *
|
static void
|
||||||
clapper_app_utils_create_pipeline_svg_file (ClapperPlayer *player, GError **error)
|
_create_pipeline_svg_file_in_thread (GTask *task, GObject *source G_GNUC_UNUSED,
|
||||||
|
ClapperPlayer *player, GCancellable *cancellable)
|
||||||
{
|
{
|
||||||
GFile *tmp_file = NULL;
|
GFile *tmp_file = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
#ifdef HAVE_GRAPHVIZ
|
#ifdef HAVE_GRAPHVIZ
|
||||||
GFile *tmp_subdir;
|
GFile *tmp_subdir;
|
||||||
Agraph_t *graph;
|
Agraph_t *graph;
|
||||||
GVC_t *gvc;
|
GVC_t *gvc;
|
||||||
gchar *path, *template, *dot_data, *img_data = NULL;
|
gchar *path, *template = NULL, *dot_data = NULL, *img_data = NULL;
|
||||||
gint fd;
|
gint fd;
|
||||||
guint size = 0;
|
guint size = 0;
|
||||||
|
|
||||||
tmp_subdir = _create_tmp_subdir ("pipelines");
|
if (!(tmp_subdir = _create_tmp_subdir ("pipelines", cancellable, &error)))
|
||||||
if (G_UNLIKELY (tmp_subdir == NULL))
|
goto finish;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
path = g_file_get_path (tmp_subdir);
|
path = g_file_get_path (tmp_subdir);
|
||||||
g_object_unref (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
|
fd = g_mkstemp (template); // Modifies template to actual filename
|
||||||
|
|
||||||
if (G_UNLIKELY (fd == -1)) {
|
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");
|
"Could not open temp file for writing");
|
||||||
g_free (template);
|
goto finish;
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dot_data = clapper_player_make_pipeline_graph (player, GST_DEBUG_GRAPH_SHOW_ALL);
|
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);
|
graph = agmemread (dot_data);
|
||||||
|
|
||||||
gvc = gvContext ();
|
gvc = gvContext ();
|
||||||
@@ -610,27 +612,48 @@ clapper_app_utils_create_pipeline_svg_file (ClapperPlayer *player, GError **erro
|
|||||||
|
|
||||||
agclose (graph);
|
agclose (graph);
|
||||||
gvFreeContext (gvc);
|
gvFreeContext (gvc);
|
||||||
g_free (dot_data);
|
|
||||||
|
if (g_cancellable_is_cancelled (cancellable))
|
||||||
|
goto close_and_finish;
|
||||||
|
|
||||||
if (write (fd, img_data, size) != -1) {
|
if (write (fd, img_data, size) != -1) {
|
||||||
tmp_file = g_file_new_for_path (template);
|
tmp_file = g_file_new_for_path (template);
|
||||||
} else {
|
} 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");
|
"Could not write data to temp file");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close_and_finish:
|
||||||
/* Always close the file IO */
|
/* Always close the file IO */
|
||||||
if (G_UNLIKELY (close (fd) == -1))
|
if (G_UNLIKELY (close (fd) == -1))
|
||||||
GST_ERROR ("Could not close temp file!");
|
GST_ERROR ("Could not close temp file!");
|
||||||
|
|
||||||
g_free (img_data);
|
finish:
|
||||||
g_free (template);
|
g_free (template);
|
||||||
|
g_free (dot_data);
|
||||||
|
g_free (img_data);
|
||||||
#else
|
#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");
|
"Cannot create graph file when compiled without Graphviz");
|
||||||
#endif
|
#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
|
static gboolean
|
||||||
|
@@ -85,7 +85,7 @@ G_GNUC_INTERNAL
|
|||||||
GstElement * clapper_app_utils_make_element (const gchar *string);
|
GstElement * clapper_app_utils_make_element (const gchar *string);
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
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
|
G_GNUC_INTERNAL
|
||||||
void clapper_app_utils_delete_tmp_dir (void);
|
void clapper_app_utils_delete_tmp_dir (void);
|
||||||
|
Reference in New Issue
Block a user