diff --git a/app/gui/dbus-service.xml b/app/gui/dbus-service.xml index 9324ad6c45..5badd9b33f 100644 --- a/app/gui/dbus-service.xml +++ b/app/gui/dbus-service.xml @@ -14,6 +14,12 @@ + + + + + + diff --git a/app/gui/gimpdbusservice.c b/app/gui/gimpdbusservice.c index c9598c0f6f..4bcdd5c045 100644 --- a/app/gui/gimpdbusservice.c +++ b/app/gui/gimpdbusservice.c @@ -34,6 +34,12 @@ #include "display/gimpdisplay.h" #include "display/gimpdisplayshell.h" +/* Dirty hack since we are not supposed to include batch.h + * from an app/ subdir. DBus is a special case. */ +#define GIMP_APP_GLUE_COMPILATION +#include "batch.h" +#undef GIMP_APP_GLUE_COMPILATION + #include "gimpdbusservice.h" @@ -41,8 +47,10 @@ typedef struct { GFile *file; gboolean as_new; -} OpenData; + gchar *interpreter; + gchar *command; +} IdleData; static void gimp_dbus_service_ui_iface_init (GimpDBusServiceUIIface *iface); @@ -59,6 +67,11 @@ static gboolean gimp_dbus_service_open_as_new (GimpDBusServiceUI *servi GDBusMethodInvocation *invocation, const gchar *uri); +static gboolean gimp_dbus_service_batch_run (GimpDBusServiceUI *service, + GDBusMethodInvocation *invocation, + const gchar *batch_interpreter, + const gchar *batch_command); + static void gimp_dbus_service_gimp_opened (Gimp *gimp, GFile *file, GimpDBusService *service); @@ -66,12 +79,18 @@ static void gimp_dbus_service_gimp_opened (Gimp *gimp, static gboolean gimp_dbus_service_queue_open (GimpDBusService *service, const gchar *uri, gboolean as_new); +static gboolean gimp_dbus_service_queue_batch (GimpDBusService *service, + const gchar *interpreter, + const gchar *command); -static gboolean gimp_dbus_service_open_idle (GimpDBusService *service); -static OpenData * gimp_dbus_service_open_data_new (GimpDBusService *service, +static gboolean gimp_dbus_service_process_idle (GimpDBusService *service); +static IdleData * gimp_dbus_service_open_data_new (GimpDBusService *service, const gchar *uri, gboolean as_new); -static void gimp_dbus_service_open_data_free (OpenData *data); +static IdleData * gimp_dbus_service_batch_data_new (GimpDBusService *service, + const gchar *interpreter, + const gchar *command); +static void gimp_dbus_service_idle_data_free (IdleData *data); G_DEFINE_TYPE_WITH_CODE (GimpDBusService, gimp_dbus_service, @@ -103,6 +122,7 @@ gimp_dbus_service_ui_iface_init (GimpDBusServiceUIIface *iface) iface->handle_activate = gimp_dbus_service_activate; iface->handle_open = gimp_dbus_service_open; iface->handle_open_as_new = gimp_dbus_service_open_as_new; + iface->handle_batch_run = gimp_dbus_service_batch_run; } GObject * @@ -136,7 +156,7 @@ gimp_dbus_service_dispose (GObject *object) while (! g_queue_is_empty (service->queue)) { - gimp_dbus_service_open_data_free (g_queue_pop_head (service->queue)); + gimp_dbus_service_idle_data_free (g_queue_pop_head (service->queue)); } G_OBJECT_CLASS (parent_class)->dispose (object); @@ -210,6 +230,23 @@ gimp_dbus_service_open_as_new (GimpDBusServiceUI *service, return TRUE; } +gboolean +gimp_dbus_service_batch_run (GimpDBusServiceUI *service, + GDBusMethodInvocation *invocation, + const gchar *batch_interpreter, + const gchar *batch_command) +{ + gboolean success; + + success = gimp_dbus_service_queue_batch (GIMP_DBUS_SERVICE (service), + batch_interpreter, + batch_command); + + gimp_dbus_service_ui_complete_batch_run (service, invocation, success); + + return TRUE; +} + static void gimp_dbus_service_gimp_opened (Gimp *gimp, GFile *file, @@ -240,7 +277,41 @@ gimp_dbus_service_queue_open (GimpDBusService *service, g_source_set_priority (service->source, G_PRIORITY_LOW); g_source_set_callback (service->source, - (GSourceFunc) gimp_dbus_service_open_idle, service, + (GSourceFunc) gimp_dbus_service_process_idle, + service, + NULL); + g_source_attach (service->source, NULL); + g_source_unref (service->source); + } + + /* The call always succeeds as it is handled in one way or another. + * Even presenting an error message is considered success ;-) + */ + return TRUE; +} + +/* + * Adds a request to run a batch command to the end of the queue and + * starts an idle source if it is not already running. + */ +static gboolean +gimp_dbus_service_queue_batch (GimpDBusService *service, + const gchar *interpreter, + const gchar *command) +{ + g_queue_push_tail (service->queue, + gimp_dbus_service_batch_data_new (service, + interpreter, + command)); + + if (! service->source) + { + service->source = g_idle_source_new (); + + g_source_set_priority (service->source, G_PRIORITY_LOW); + g_source_set_callback (service->source, + (GSourceFunc) gimp_dbus_service_process_idle, + service, NULL); g_source_attach (service->source, NULL); g_source_unref (service->source); @@ -258,9 +329,9 @@ gimp_dbus_service_queue_open (GimpDBusService *service, * removed. */ static gboolean -gimp_dbus_service_open_idle (GimpDBusService *service) +gimp_dbus_service_process_idle (GimpDBusService *service) { - OpenData *data; + IdleData *data; if (! service->gimp->restored) return TRUE; @@ -269,11 +340,20 @@ gimp_dbus_service_open_idle (GimpDBusService *service) if (data) { - file_open_from_command_line (service->gimp, data->file, data->as_new, - NULL, /* FIXME monitor */ - 0 /* FIXME monitor */); - gimp_dbus_service_open_data_free (data); + if (data->file) + file_open_from_command_line (service->gimp, data->file, data->as_new, + NULL, /* FIXME monitor */ + 0 /* FIXME monitor */); + if (data->command) + { + const gchar *commands[2] = {data->command, 0}; + + batch_run (service->gimp, data->interpreter, + commands); + } + + gimp_dbus_service_idle_data_free (data); return TRUE; } @@ -283,22 +363,51 @@ gimp_dbus_service_open_idle (GimpDBusService *service) return FALSE; } -static OpenData * +static IdleData * gimp_dbus_service_open_data_new (GimpDBusService *service, const gchar *uri, gboolean as_new) { - OpenData *data = g_slice_new (OpenData); + IdleData *data = g_slice_new (IdleData); - data->file = g_file_new_for_uri (uri); - data->as_new = as_new; + data->file = g_file_new_for_uri (uri); + data->as_new = as_new; + data->interpreter = NULL; + data->command = NULL; + + return data; +} + +static IdleData * +gimp_dbus_service_batch_data_new (GimpDBusService *service, + const gchar *interpreter, + const gchar *command) +{ + IdleData *data = g_slice_new (IdleData); + + data->file = NULL; + data->as_new = FALSE; + + data->command = g_strdup (command); + + if (g_strcmp0 (interpreter, "") == 0) + data->interpreter = NULL; + else + data->interpreter = g_strdup (interpreter); return data; } static void -gimp_dbus_service_open_data_free (OpenData *data) +gimp_dbus_service_idle_data_free (IdleData *data) { - g_object_unref (data->file); - g_slice_free (OpenData, data); + if (data->file) + g_object_unref (data->file); + + if (data->command) + g_free (data->command); + if (data->interpreter) + g_free (data->interpreter); + + g_slice_free (IdleData, data); } diff --git a/app/main.c b/app/main.c index 4c61ef0686..2b348cc732 100644 --- a/app/main.c +++ b/app/main.c @@ -483,6 +483,9 @@ main (int argc, g_print ("%s\n", _("Another GIMP instance is already running.")); + if (batch_commands) + gimp_unique_batch_run (batch_interpreter, batch_commands); + gdk_notify_startup_complete (); return EXIT_SUCCESS; diff --git a/app/unique.c b/app/unique.c index 55e63e1b67..cea778dcff 100644 --- a/app/unique.c +++ b/app/unique.c @@ -25,6 +25,11 @@ #include "core/core-types.h" +#ifndef GIMP_CONSOLE_COMPILATION +/* for the DBus service names */ +#include "gui/gimpdbusservice.h" +#endif + #include "unique.h" @@ -34,6 +39,8 @@ static gboolean gimp_unique_dbus_open (const gchar **filenames, static gboolean gimp_unique_win32_open (const gchar **filenames, gboolean as_new); #endif +static gboolean gimp_unique_dbus_batch_run (const gchar *batch_interpreter, + const gchar **batch_commands); gboolean gimp_unique_open (const gchar **filenames, @@ -46,15 +53,25 @@ gimp_unique_open (const gchar **filenames, #endif } +gboolean +gimp_unique_batch_run (const gchar *batch_interpreter, + const gchar **batch_commands) +{ +#ifdef G_OS_WIN32 + g_printerr ("Batch commands cannot be run in existing instance in Win32.\n"); + return FALSE; +#else + return gimp_unique_dbus_batch_run (batch_interpreter, + batch_commands); +#endif +} + static gboolean gimp_unique_dbus_open (const gchar **filenames, gboolean as_new) { #ifndef GIMP_CONSOLE_COMPILATION -/* for the DBus service names */ -#include "gui/gimpdbusservice.h" - GDBusConnection *connection; GError *error = NULL; @@ -211,3 +228,62 @@ gimp_unique_win32_open (const gchar **filenames, } #endif /* G_OS_WIN32 */ + +static gboolean +gimp_unique_dbus_batch_run (const gchar *batch_interpreter, + const gchar **batch_commands) +{ +#ifndef GIMP_CONSOLE_COMPILATION + + GDBusConnection *connection; + GError *error = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + + if (connection) + { + const gchar *method = "BatchRun"; + gboolean success = TRUE; + gint i; + + for (i = 0; batch_commands[i] && success; i++) + { + GVariant *result; + const gchar *interpreter; + + /* NULL is not a valid string GVariant. */ + interpreter = batch_interpreter ? batch_interpreter : ""; + + result = g_dbus_connection_call_sync (connection, + GIMP_DBUS_SERVICE_NAME, + GIMP_DBUS_SERVICE_PATH, + GIMP_DBUS_INTERFACE_NAME, + method, + g_variant_new ("(ss)", + interpreter, + batch_commands[i]), + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, + NULL, NULL); + + + if (result) + g_variant_unref (result); + else + success = FALSE; + } + + g_object_unref (connection); + + return success; + } + else + { + g_printerr ("%s\n", error->message); + g_clear_error (&error); + } +#endif + + return FALSE; +} diff --git a/app/unique.h b/app/unique.h index 68f05cadb8..d775fe61a6 100644 --- a/app/unique.h +++ b/app/unique.h @@ -22,5 +22,8 @@ gboolean gimp_unique_open (const gchar **filenames, gboolean as_new); +gboolean gimp_unique_batch_run (const gchar *batch_interpreter, + const gchar **batch_commands); + #endif /* __UNIQUE_H__ */