diff --git a/app/Makefile.am b/app/Makefile.am index 58746081119a36773dccf69c1150aecb1b304cf9..8fea0e4569f29370559e656845287e0e5f09fe48 100644 --- a/app/Makefile.am +++ b/app/Makefile.am @@ -57,6 +57,10 @@ libapp_sources = \ app.h \ errors.c \ errors.h \ + gimpcoreapp.c \ + gimpcoreapp.h \ + gimpconsoleapp.c \ + gimpconsoleapp.h \ language.c \ language.h \ sanity.c \ diff --git a/app/app.c b/app/app.c index 8e171fe786a9c7f1b380feb7916f091eb207bba6..7a9088e83051d31490d167389e07c8a96f8c13b5 100644 --- a/app/app.c +++ b/app/app.c @@ -67,6 +67,10 @@ #include "app.h" #include "errors.h" +#ifndef GIMP_CONSOLE_COMPILATION +#include "gui/gimpapp.h" +#endif +#include "gimpconsoleapp.h" #include "sanity.h" #include "gimp-debug.h" @@ -83,7 +87,7 @@ static void app_restore_after_callback (Gimp *gimp, GimpInitStatusFunc status_callback); static gboolean app_exit_after_callback (Gimp *gimp, gboolean kill_it, - GMainLoop **loop); + GApplication **app); #if 0 /* left here as documentation how to do compat enums */ @@ -161,6 +165,148 @@ app_exit (gint status) exit (status); } +static void +app_activate_callback (GimpCoreApp *app, + gpointer user_data) +{ + Gimp *gimp = NULL; + GimpInitStatusFunc update_status_func = NULL; + const gchar **filenames; + + g_return_if_fail (GIMP_IS_CORE_APP (app)); + + gimp = gimp_core_app_get_gimp (app); + +#ifndef GIMP_CONSOLE_COMPILATION + if (! gimp->no_interface) + update_status_func = gui_init (gimp, gimp_app_get_no_splash (GIMP_APP (app)), GIMP_APP (app), NULL); +#endif + + if (! update_status_func) + update_status_func = app_init_update_noop; + + /* Create all members of the global Gimp instance which need an already + * parsed gimprc, e.g. the data factories + */ + gimp_initialize (gimp, update_status_func); + + /* Load all data files */ + gimp_restore (gimp, update_status_func, NULL); + + /* enable autosave late so we don't autosave when the + * monitor resolution is set in gui_init() + */ + gimp_rc_set_autosave (GIMP_RC (gimp->edit_config), TRUE); + + /* check for updates *after* enabling config autosave, so that the timestamp + * is saved + */ + gimp_update_auto_check (gimp->edit_config, gimp); + + /* Set this after gimp_update_auto_check(). This will be used for the + * next run. + */ + g_object_set (gimp->edit_config, + "config-version", GIMP_VERSION, + NULL); + +#ifndef GIMP_CONSOLE_COMPILATION + if (! gimp->no_interface) + { + /* Before opening images from command line, check for salvaged images + * and query interactively to know if we should recover or discard + * them. + */ + GList *recovered_files; + GList *iter; + + recovered_files = errors_recovered (); + if (recovered_files && + gui_recover (g_list_length (recovered_files))) + { + for (iter = recovered_files; iter; iter = iter->next) + { + GFile *file; + GimpImage *image; + GError *error = NULL; + GimpPDBStatusType status; + + file = g_file_new_for_path (iter->data); + image = file_open_with_display (gimp, + gimp_get_user_context (gimp), + NULL, + file, + gimp_core_app_get_as_new (app), + initial_monitor, + &status, &error); + if (image) + { + /* Break ties with the backup directory. */ + gimp_image_set_file (image, NULL); + /* One of the rare exceptions where we should call + * gimp_image_dirty() directly instead of creating + * an undo. We want the image to be dirty from + * scratch, without anything to undo. + */ + gimp_image_dirty (image, GIMP_DIRTY_IMAGE); + } + else + { + g_error_free (error); + } + + g_object_unref (file); + } + } + /* Delete backup XCF images. */ + for (iter = recovered_files; iter; iter = iter->next) + { + g_unlink (iter->data); + } + g_list_free_full (recovered_files, g_free); + } +#endif + + /* Load the images given on the command-line. */ + filenames = gimp_core_app_get_filenames (app); + if (filenames != NULL) + { + gint i; + + for (i = 0; filenames[i] != NULL; i++) + { + if (app) + { + GFile *file = g_file_new_for_commandline_arg (filenames[i]); + + file_open_from_command_line (gimp, file, + gimp_core_app_get_as_new (app), + initial_monitor); + + g_object_unref (file); + } + } + } + + /* The software is now fully loaded and ready to be used and get + * external input. + */ + gimp->initialized = TRUE; + + if (app) + { + const char *batch_interpreter; + const char **batch_commands; + + batch_interpreter = gimp_core_app_get_batch_interpreter (app); + batch_commands = gimp_core_app_get_batch_commands (app); + + gimp_batch_run (gimp, + batch_interpreter, + batch_commands); + } +} + gint app_run (const gchar *full_prog_name, const gchar **filenames, @@ -186,15 +332,12 @@ app_run (const gchar *full_prog_name, GimpPDBCompatMode pdb_compat_mode, const gchar *backtrace_file) { - GimpInitStatusFunc update_status_func = NULL; - Gimp *gimp; - GMainLoop *loop; - GMainLoop *run_loop; + Gimp *gimp = NULL; + GApplication *app = NULL; GFile *default_folder = NULL; - GFile *gimpdir; - const gchar *abort_message; - GError *font_error = NULL; - gint retval = EXIT_SUCCESS; + GFile *gimpdir = NULL; + const gchar *abort_message = NULL; + gint retval = EXIT_SUCCESS; if (filenames && filenames[0] && ! filenames[1] && g_file_test (filenames[0], G_FILE_TEST_IS_DIR)) @@ -234,13 +377,17 @@ app_run (const gchar *full_prog_name, stack_trace_mode, pdb_compat_mode); - if (default_folder) - g_object_unref (default_folder); + g_clear_object (&default_folder); + +#ifndef GIMP_CONSOLE_COMPILATION + app = gimp_app_new (gimp, no_splash, as_new, filenames, batch_interpreter, batch_commands); +#else + app = gimp_console_app_new (gimp, as_new, filenames, batch_interpreter, batch_commands); +#endif gimp_cpu_accel_set_use (use_cpu_accel); - /* Check if the user's gimp_directory exists - */ + /* Check if the user's gimp_directory exists */ gimpdir = gimp_directory_file (NULL); if (g_file_query_file_type (gimpdir, G_FILE_QUERY_INFO_NONE, NULL) != @@ -296,155 +443,20 @@ app_run (const gchar *full_prog_name, G_CALLBACK (app_restore_after_callback), NULL); -#ifndef GIMP_CONSOLE_COMPILATION - if (! no_interface) - update_status_func = gui_init (gimp, no_splash, NULL); -#endif - - if (! update_status_func) - update_status_func = app_init_update_noop; - - /* Create all members of the global Gimp instance which need an already - * parsed gimprc, e.g. the data factories - */ - gimp_initialize (gimp, update_status_func); - - /* Load all data files - */ - gimp_restore (gimp, update_status_func, &font_error); - - /* enable autosave late so we don't autosave when the - * monitor resolution is set in gui_init() - */ - gimp_rc_set_autosave (GIMP_RC (gimp->edit_config), TRUE); - - /* check for updates *after* enabling config autosave, so that the timestamp - * is saved - */ - gimp_update_auto_check (gimp->edit_config, gimp); - - /* Set this after gimp_update_auto_check(). This will be used for the - * next run. - */ - g_object_set (gimp->edit_config, - "config-version", GIMP_VERSION, - NULL); - - loop = run_loop = g_main_loop_new (NULL, FALSE); - g_signal_connect_after (gimp, "exit", G_CALLBACK (app_exit_after_callback), - &run_loop); - -#ifndef GIMP_CONSOLE_COMPILATION - if (run_loop && ! no_interface) - { - /* Before opening images from command line, check for salvaged images - * and query interactively to know if we should recover or discard - * them. - */ - GList *recovered_files; - GList *iter; - - recovered_files = errors_recovered (); - if (recovered_files && - gui_recover (g_list_length (recovered_files))) - { - for (iter = recovered_files; iter; iter = iter->next) - { - GFile *file; - GimpImage *image; - GError *error = NULL; - GimpPDBStatusType status; - - file = g_file_new_for_path (iter->data); - image = file_open_with_display (gimp, - gimp_get_user_context (gimp), - NULL, - file, as_new, - initial_monitor, - &status, &error); - if (image) - { - /* Break ties with the backup directory. */ - gimp_image_set_file (image, NULL); - /* One of the rare exceptions where we should call - * gimp_image_dirty() directly instead of creating - * an undo. We want the image to be dirty from - * scratch, without anything to undo. - */ - gimp_image_dirty (image, GIMP_DIRTY_IMAGE); - } - else - { - g_error_free (error); - } + &app); - g_object_unref (file); - } - } - /* Delete backup XCF images. */ - for (iter = recovered_files; iter; iter = iter->next) - { - g_unlink (iter->data); - } - g_list_free_full (recovered_files, g_free); - } -#endif + g_signal_connect (app, "activate", + G_CALLBACK (app_activate_callback), + NULL); - /* Load the images given on the command-line. */ - if (filenames) - { - gint i; - - for (i = 0; filenames[i] != NULL; i++) - { - if (run_loop) - { - GFile *file = g_file_new_for_commandline_arg (filenames[i]); - - file_open_from_command_line (gimp, file, as_new, - initial_monitor); - - g_object_unref (file); - } - } - } - - /* The software is now fully loaded and ready to be used and get - * external input. - */ - gimp->initialized = TRUE; - - if (font_error) - { - gimp_message_literal (gimp, NULL, - GIMP_MESSAGE_INFO, - font_error->message); - g_error_free (font_error); - } - - if (run_loop) - retval = gimp_batch_run (gimp, batch_interpreter, batch_commands); - - if (quit) - /* Emit the "exit" signal, but also properly free all images still - * opened. - */ - gimp_exit (gimp, TRUE); - else - /* Only take into account the batch commands' success when we - * return immediately. - */ - retval = EXIT_SUCCESS; - - if (run_loop) - g_main_loop_run (loop); + g_application_run (app, 0, NULL); if (gimp->be_verbose) g_print ("EXIT: %s\n", G_STRFUNC); - g_main_loop_unref (loop); + g_clear_object (&app); gimp_gegl_exit (gimp); @@ -488,9 +500,9 @@ app_restore_after_callback (Gimp *gimp, } static gboolean -app_exit_after_callback (Gimp *gimp, - gboolean kill_it, - GMainLoop **loop) +app_exit_after_callback (Gimp *gimp, + gboolean kill_it, + GApplication **app) { if (gimp->be_verbose) g_print ("EXIT: %s\n", G_STRFUNC); @@ -506,10 +518,8 @@ app_exit_after_callback (Gimp *gimp, #ifdef GIMP_UNSTABLE - if (g_main_loop_is_running (*loop)) - g_main_loop_quit (*loop); - - *loop = NULL; + g_application_quit (G_APPLICATION (*app)); + *app = NULL; #else diff --git a/app/display/gimpimagewindow.c b/app/display/gimpimagewindow.c index 1499c27eed803ac2ddbc442a2710c808c322e6fa..d407cbf471e0feb5b8637e45adb0284555f3381f 100644 --- a/app/display/gimpimagewindow.c +++ b/app/display/gimpimagewindow.c @@ -1114,6 +1114,7 @@ gimp_image_window_new (Gimp *gimp, "gimp", gimp, "dialog-factory", dialog_factory, "initial-monitor", monitor, + "application", g_application_get_default (), /* The window position will be overridden by the * dialog factory, it is only really used on first * startup. diff --git a/app/gimpconsoleapp.c b/app/gimpconsoleapp.c new file mode 100644 index 0000000000000000000000000000000000000000..29114517787ddbbd6df3ace023629b5e493a929b --- /dev/null +++ b/app/gimpconsoleapp.c @@ -0,0 +1,197 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpapp.c + * Copyright (C) 2021 Niels De Graef + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include + +#include "gimpconsoleapp.h" + +#include "libgimpbase/gimpbase.h" + + +enum +{ + PROP_0, + PROP_GIMP, + N_PROPS +}; + +struct _GimpConsoleApp +{ + GApplication parent_instance; + + Gimp *gimp; + + gboolean as_new; + const gchar **filenames; + const gchar *batch_interpreter; + const gchar **batch_commands; +}; + + +static void gimp_console_app_finalize (GObject *object); +static void gimp_console_app_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_console_app_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static void gimp_core_app_interface_init (GimpCoreAppInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GimpConsoleApp, gimp_console_app, G_TYPE_APPLICATION, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CORE_APP, + gimp_core_app_interface_init)) + + +static void +gimp_console_app_class_init (GimpConsoleAppClass *klass) +{ + GObjectClass *gobj_class = G_OBJECT_CLASS (klass); + + gobj_class->get_property = gimp_console_app_get_property; + gobj_class->set_property = gimp_console_app_set_property; + gobj_class->finalize = gimp_console_app_finalize; + + g_object_class_override_property (gobj_class, PROP_GIMP, "gimp"); +} + +static void +gimp_core_app_interface_init (GimpCoreAppInterface *iface) +{ + iface->get_gimp = gimp_console_app_get_gimp; + iface->get_as_new = gimp_console_app_get_as_new; + iface->get_filenames = gimp_console_app_get_filenames; + iface->get_batch_interpreter = gimp_console_app_get_batch_interpreter; + iface->get_batch_commands = gimp_console_app_get_batch_commands; +} + +static void +gimp_console_app_init (GimpConsoleApp *self) +{ +} + +static void +gimp_console_app_finalize (GObject *object) +{ + GimpConsoleApp *self = GIMP_CONSOLE_APP (object); + + g_clear_object (&self->gimp); + + G_OBJECT_CLASS (gimp_console_app_parent_class)->finalize (object); +} + +static void +gimp_console_app_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpConsoleApp *self = GIMP_CONSOLE_APP (object); + + switch (property_id) + { + case PROP_GIMP: + g_value_set_object (value, self->gimp); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_console_app_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpConsoleApp *self = GIMP_CONSOLE_APP (object); + + switch (property_id) + { + case PROP_GIMP: + self->gimp = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +/* public functions */ + +GApplication * +gimp_console_app_new (Gimp *gimp, + gboolean as_new, + const char **filenames, + const char *batch_interpreter, + const char **batch_commands) +{ + GimpConsoleApp *app; + + app = g_object_new (GIMP_TYPE_CONSOLE_APP, + "gimp", gimp, + NULL); + + /* We shouldn't have to pass these externally, so I didn't bother making + * GObject properties for them. In the end, they should just be parsed by + * the GApplication code */ + app->as_new = as_new; + app->filenames = filenames; + app->batch_interpreter = batch_interpreter; + app->batch_commands = batch_commands; + + return G_APPLICATION (app); +} + +Gimp * +gimp_console_app_get_gimp (GimpCoreApp *self) +{ + g_return_val_if_fail (GIMP_IS_CONSOLE_APP (self), NULL); + return GIMP_CONSOLE_APP (self)->gimp; +} + +gboolean +gimp_console_app_get_as_new (GimpCoreApp *self) +{ + g_return_val_if_fail (GIMP_IS_CONSOLE_APP (self), FALSE); + return GIMP_CONSOLE_APP (self)->as_new; +} + +const char ** +gimp_console_app_get_filenames (GimpCoreApp *self) +{ + g_return_val_if_fail (GIMP_IS_CONSOLE_APP (self), NULL); + return GIMP_CONSOLE_APP (self)->filenames; +} + +const char * +gimp_console_app_get_batch_interpreter (GimpCoreApp *self) +{ + g_return_val_if_fail (GIMP_IS_CONSOLE_APP (self), NULL); + return GIMP_CONSOLE_APP (self)->batch_interpreter; +} + +const char ** +gimp_console_app_get_batch_commands (GimpCoreApp *self) +{ + g_return_val_if_fail (GIMP_IS_CONSOLE_APP (self), NULL); + return GIMP_CONSOLE_APP (self)->batch_commands; +} diff --git a/app/gimpconsoleapp.h b/app/gimpconsoleapp.h new file mode 100644 index 0000000000000000000000000000000000000000..d1d8ca0589d18e8009838b48f014b4d3e48e9c91 --- /dev/null +++ b/app/gimpconsoleapp.h @@ -0,0 +1,39 @@ + +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpapp.h + * Copyright (C) 2021 Niels De Graef + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#pragma once + +#include "gimpcoreapp.h" + +#define GIMP_TYPE_CONSOLE_APP (gimp_console_app_get_type ()) +G_DECLARE_FINAL_TYPE (GimpConsoleApp, gimp_console_app, GIMP, CONSOLE_APP, GApplication) + +GApplication * gimp_console_app_new (Gimp *gimp, + gboolean as_new, + const char **filenames, + const char *batch_interpreter, + const char **batch_commands); + +Gimp * gimp_console_app_get_gimp (GimpCoreApp *self); + +gboolean gimp_console_app_get_as_new (GimpCoreApp *self); + +const char ** gimp_console_app_get_filenames (GimpCoreApp *self); + +const char * gimp_console_app_get_batch_interpreter (GimpCoreApp *self); + +const char ** gimp_console_app_get_batch_commands (GimpCoreApp *self); diff --git a/app/gimpcoreapp.c b/app/gimpcoreapp.c new file mode 100644 index 0000000000000000000000000000000000000000..eb140d3149bf744a9d74574d38613d8d4fb6263d --- /dev/null +++ b/app/gimpcoreapp.c @@ -0,0 +1,95 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpapp.c + * Copyright (C) 2022 Lukas Oberhuber + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include + +#include "gimpcoreapp.h" + +#include "libgimpbase/gimpbase.h" + +G_DEFINE_INTERFACE (GimpCoreApp, gimp_core_app, G_TYPE_OBJECT) + +static void +gimp_core_app_default_init (GimpCoreAppInterface *iface) +{ + /* add properties and signals to the interface here */ + g_object_interface_install_property (iface, + g_param_spec_object ("gimp", + "GIMP", + "GIMP root object", + GIMP_TYPE_GIMP, + GIMP_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +Gimp * +gimp_core_app_get_gimp (GimpCoreApp *self) +{ + GimpCoreAppInterface *iface; + + g_return_val_if_fail (GIMP_IS_CORE_APP (self), NULL); + + iface = GIMP_CORE_APP_GET_IFACE (self); + g_return_val_if_fail (iface->get_gimp != NULL, NULL); + return iface->get_gimp (self); +} + +gboolean +gimp_core_app_get_as_new (GimpCoreApp *self) +{ + GimpCoreAppInterface *iface; + + g_return_val_if_fail (GIMP_IS_CORE_APP (self), FALSE); + + iface = GIMP_CORE_APP_GET_IFACE (self); + g_return_val_if_fail (iface->get_as_new != NULL, FALSE); + return iface->get_as_new (self); +} + +const char ** +gimp_core_app_get_filenames (GimpCoreApp *self) +{ + GimpCoreAppInterface *iface; + + g_return_val_if_fail (GIMP_IS_CORE_APP (self), NULL); + + iface = GIMP_CORE_APP_GET_IFACE (self); + g_return_val_if_fail (iface->get_filenames != NULL, NULL); + return iface->get_filenames (self); +} + +const char * +gimp_core_app_get_batch_interpreter (GimpCoreApp *self) +{ + GimpCoreAppInterface *iface; + + g_return_val_if_fail (GIMP_IS_CORE_APP (self), NULL); + + iface = GIMP_CORE_APP_GET_IFACE (self); + g_return_val_if_fail (iface->get_batch_interpreter != NULL, NULL); + return iface->get_batch_interpreter (self); +} + +const char ** +gimp_core_app_get_batch_commands (GimpCoreApp *self) +{ + GimpCoreAppInterface *iface; + + g_return_val_if_fail (GIMP_IS_CORE_APP (self), NULL); + + iface = GIMP_CORE_APP_GET_IFACE (self); + g_return_val_if_fail (iface->get_batch_commands != NULL, NULL); + return iface->get_batch_commands (self); +} diff --git a/app/gimpcoreapp.h b/app/gimpcoreapp.h new file mode 100644 index 0000000000000000000000000000000000000000..4f2e0ede486f4e74e8f5ec67aafc809a6bef9f34 --- /dev/null +++ b/app/gimpcoreapp.h @@ -0,0 +1,55 @@ + +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpcoreapp.h + * Copyright (C) 2022 Lukas Oberhuber + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#pragma once + +#include + +#include "core/core-types.h" +#include "core/gimp.h" + +G_BEGIN_DECLS + +#define GIMP_TYPE_CORE_APP gimp_core_app_get_type() +G_DECLARE_INTERFACE (GimpCoreApp, gimp_core_app, GIMP, CORE_APP, GObject) + +struct _GimpCoreAppInterface +{ + GTypeInterface parent_iface; + + Gimp * (*get_gimp) (GimpCoreApp *self); + gboolean (*get_as_new) (GimpCoreApp *self); + const char ** (*get_filenames) (GimpCoreApp *self); + const char * (*get_batch_interpreter) (GimpCoreApp *self); + const char ** (*get_batch_commands) (GimpCoreApp *self); + + /* Padding to allow adding up to 12 new virtual functions without + * breaking ABI. */ + gpointer padding[12]; +}; + +Gimp * gimp_core_app_get_gimp (GimpCoreApp *self); + +gboolean gimp_core_app_get_as_new (GimpCoreApp *self); + +const char ** gimp_core_app_get_filenames (GimpCoreApp *self); + +const char * gimp_core_app_get_batch_interpreter (GimpCoreApp *self); + +const char ** gimp_core_app_get_batch_commands (GimpCoreApp *self); + +G_END_DECLS diff --git a/app/gui/Makefile.am b/app/gui/Makefile.am index 579cd63bc0b58434dadf51596f0412dbf3d6887d..990607713f39c1757fcfa05f6026cb9f4eca61a0 100644 --- a/app/gui/Makefile.am +++ b/app/gui/Makefile.am @@ -31,6 +31,8 @@ AM_LDFLAGS = \ noinst_LIBRARIES = libappgui.a libappgui_a_sources = \ + gimpapp.c \ + gimpapp.h \ gimpdbusservice.c \ gimpdbusservice.h \ gimpuiconfigurer.c \ diff --git a/app/gui/gimpapp.c b/app/gui/gimpapp.c new file mode 100644 index 0000000000000000000000000000000000000000..e25de13c2750c790ef684a8217f0a8e822f71646 --- /dev/null +++ b/app/gui/gimpapp.c @@ -0,0 +1,207 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpapp.c + * Copyright (C) 2021 Niels De Graef + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include + +#include "gimpapp.h" + +#include "libgimpbase/gimpbase.h" + + +enum +{ + PROP_0, + PROP_GIMP, + N_PROPS +}; + +struct _GimpApp +{ + GtkApplication parent_instance; + + Gimp *gimp; + + gboolean no_splash; + gboolean as_new; + const gchar **filenames; + const gchar *batch_interpreter; + const gchar **batch_commands; +}; + +static void gimp_app_finalize (GObject *object); +static void gimp_app_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_app_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static void gimp_core_app_interface_init (GimpCoreAppInterface *iface); + + +G_DEFINE_TYPE_WITH_CODE (GimpApp, gimp_app, GTK_TYPE_APPLICATION, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CORE_APP, + gimp_core_app_interface_init)) + + +static void +gimp_app_class_init (GimpAppClass *klass) +{ + GObjectClass *gobj_class = G_OBJECT_CLASS (klass); + + gobj_class->get_property = gimp_app_get_property; + gobj_class->set_property = gimp_app_set_property; + gobj_class->finalize = gimp_app_finalize; + + g_object_class_override_property (gobj_class, PROP_GIMP, "gimp"); +} + +static void +gimp_core_app_interface_init (GimpCoreAppInterface *iface) +{ + iface->get_gimp = gimp_app_get_gimp; + iface->get_as_new = gimp_app_get_as_new; + iface->get_filenames = gimp_app_get_filenames; + iface->get_batch_interpreter = gimp_app_get_batch_interpreter; + iface->get_batch_commands = gimp_app_get_batch_commands; +} + +static void +gimp_app_init (GimpApp *self) +{ +} + +static void +gimp_app_finalize (GObject *object) +{ + GimpApp *self = GIMP_APP (object); + + g_clear_object (&self->gimp); + + G_OBJECT_CLASS (gimp_app_parent_class)->finalize (object); +} + +static void +gimp_app_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpApp *self = GIMP_APP (object); + + switch (property_id) + { + case PROP_GIMP: + g_value_set_object (value, self->gimp); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_app_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpApp *self = GIMP_APP (object); + + switch (property_id) + { + case PROP_GIMP: + self->gimp = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +/* public functions */ + +GApplication * +gimp_app_new (Gimp *gimp, + gboolean no_splash, + gboolean as_new, + const char **filenames, + const char *batch_interpreter, + const char **batch_commands) +{ + GimpApp *app; + + app = g_object_new (GIMP_TYPE_APP, + "gimp", gimp, + NULL); + + /* We shouldn't have to pass these externally, so I didn't bother making + * GObject properties for them. In the end, they should just be parsed by + * the GApplication code */ + app->no_splash = no_splash; + app->as_new = as_new; + app->filenames = filenames; + app->batch_interpreter = batch_interpreter; + app->batch_commands = batch_commands; + + return G_APPLICATION (app); +} + +Gimp * +gimp_app_get_gimp (GimpCoreApp *self) +{ + g_return_val_if_fail (GIMP_IS_APP (self), NULL); + return GIMP_APP (self)->gimp; +} + +gboolean +gimp_app_get_no_splash (GimpApp *self) +{ + g_return_val_if_fail (GIMP_IS_APP (self), FALSE); + return GIMP_APP (self)->no_splash; +} + +gboolean +gimp_app_get_as_new (GimpCoreApp *self) +{ + g_return_val_if_fail (GIMP_IS_APP (self), FALSE); + return GIMP_APP (self)->as_new; +} + +const char ** +gimp_app_get_filenames (GimpCoreApp *self) +{ + g_return_val_if_fail (GIMP_IS_APP (self), NULL); + return GIMP_APP (self)->filenames; +} + +const char * +gimp_app_get_batch_interpreter (GimpCoreApp *self) +{ + g_return_val_if_fail (GIMP_IS_APP (self), NULL); + return GIMP_APP (self)->batch_interpreter; +} + +const char ** +gimp_app_get_batch_commands (GimpCoreApp *self) +{ + g_return_val_if_fail (GIMP_IS_APP (self), NULL); + return GIMP_APP (self)->batch_commands; +} diff --git a/app/gui/gimpapp.h b/app/gui/gimpapp.h new file mode 100644 index 0000000000000000000000000000000000000000..28fb5f0e558b98da03766d93a266c59e35236296 --- /dev/null +++ b/app/gui/gimpapp.h @@ -0,0 +1,47 @@ + +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpapp.h + * Copyright (C) 2021 Niels De Graef + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#ifndef __GIMP_APP_H__ +#define __GIMP_APP_H__ + +#include + +#include "gimpcoreapp.h" + +#define GIMP_TYPE_APP (gimp_app_get_type ()) +G_DECLARE_FINAL_TYPE (GimpApp, gimp_app, GIMP, APP, GtkApplication) + +GApplication * gimp_app_new (Gimp *gimp, + gboolean no_splash, + gboolean as_new, + const char **filenames, + const char *batch_interpreter, + const char **batch_commands); + +Gimp * gimp_app_get_gimp (GimpCoreApp *self); + +gboolean gimp_app_get_no_splash (GimpApp *self); + +gboolean gimp_app_get_as_new (GimpCoreApp *self); + +const char ** gimp_app_get_filenames (GimpCoreApp *self); + +const char * gimp_app_get_batch_interpreter (GimpCoreApp *self); + +const char ** gimp_app_get_batch_commands (GimpCoreApp *self); + +#endif /* __GIMP_APP_H__ */ diff --git a/app/gui/gui.c b/app/gui/gui.c index c2f69af9eae1f71706a297ab4a71b04343947d71..9909cc1c3efc72af1be21eba2db5b76a66c83e7d 100644 --- a/app/gui/gui.c +++ b/app/gui/gui.c @@ -222,15 +222,17 @@ gui_abort (const gchar *abort_message) * unit testing calls. */ GimpInitStatusFunc -gui_init (Gimp *gimp, - gboolean no_splash, - const gchar *test_base_dir) +gui_init (Gimp *gimp, + gboolean no_splash, + GimpApp *app, + const gchar *test_base_dir) { GimpInitStatusFunc status_callback = NULL; gchar *abort_message; g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); g_return_val_if_fail (the_gui_gimp == NULL, NULL); + g_return_val_if_fail (GIMP_IS_APP (app) || app == NULL, NULL); abort_message = gui_sanity_check (); if (abort_message) @@ -283,7 +285,7 @@ gui_init (Gimp *gimp, if (! no_splash) { - splash_create (gimp, gimp->be_verbose, initial_monitor); + splash_create (gimp, gimp->be_verbose, initial_monitor, app); status_callback = splash_update; } @@ -698,8 +700,6 @@ gui_restore_after_callback (Gimp *gimp, g_signal_connect (osx_app, "NSApplicationBlockTermination", G_CALLBACK (gui_quartz_quit_callback), image_ui_manager); - - gtkosx_application_ready (osx_app); } #endif /* GDK_WINDOWING_QUARTZ */ diff --git a/app/gui/gui.h b/app/gui/gui.h index a5cf0fecc4bec674ef64d0d3a1488c605e49c84a..e64f5fa1d9a3d89c75365f61f00a2408415e63b4 100644 --- a/app/gui/gui.h +++ b/app/gui/gui.h @@ -18,12 +18,14 @@ #ifndef __GUI_H__ #define __GUI_H__ +#include "gimpapp.h" void gui_libs_init (GOptionContext *context); void gui_abort (const gchar *abort_message); GimpInitStatusFunc gui_init (Gimp *gimp, gboolean no_splash, + GimpApp *app, const gchar *test_base_dir); gboolean gui_recover (gint n_recoveries); diff --git a/app/gui/meson.build b/app/gui/meson.build index d128d3101fb9b14f7e6eca264997292f418e6ef8..31b208550e74b5a7522627c71939e59b3f87a6b6 100644 --- a/app/gui/meson.build +++ b/app/gui/meson.build @@ -7,6 +7,7 @@ gimpdbusservice_gen = gnome.gdbus_codegen( ) libappgui_sources = [ + 'gimpapp.c', 'gimpdbusservice.c', 'gimpuiconfigurer.c', 'gui-message.c', diff --git a/app/gui/splash.c b/app/gui/splash.c index 8df1d8039a4849916eab0e99fdd69223fe5a68e0..390dfdc88edd7df9aabca8ecc0d42e252785ee20 100644 --- a/app/gui/splash.c +++ b/app/gui/splash.c @@ -109,9 +109,10 @@ static void splash_timer_elapsed (void); /* public functions */ void -splash_create (Gimp *gimp, - gboolean be_verbose, - GdkMonitor *monitor) +splash_create (Gimp *gimp, + gboolean be_verbose, + GdkMonitor *monitor, + GimpApp *app) { GtkWidget *frame; GtkWidget *vbox; @@ -123,6 +124,7 @@ splash_create (Gimp *gimp, g_return_if_fail (splash == NULL); g_return_if_fail (GDK_IS_MONITOR (monitor)); + g_return_if_fail (GIMP_IS_APP (app) || app == NULL); gdk_monitor_get_workarea (monitor, &workarea); @@ -162,13 +164,14 @@ splash_create (Gimp *gimp, splash = g_slice_new0 (GimpSplash); splash->window = - g_object_new (GTK_TYPE_WINDOW, + g_object_new (GTK_TYPE_APPLICATION_WINDOW, "type", GTK_WINDOW_TOPLEVEL, "type-hint", GDK_WINDOW_TYPE_HINT_SPLASHSCREEN, "title", _("GIMP Startup"), "role", "gimp-startup", "window-position", GTK_WIN_POS_CENTER, "resizable", FALSE, + "application", GTK_APPLICATION (app), NULL); /* Don't remove this call, it's necessary to remove decorations on Windows diff --git a/app/gui/splash.h b/app/gui/splash.h index e3d86da9fba39f92631335e1f85e5c5461d9982d..51e8af63de2552b563a4552b4bab106d034136ef 100644 --- a/app/gui/splash.h +++ b/app/gui/splash.h @@ -18,10 +18,12 @@ #ifndef __SPLASH_H__ #define __SPLASH_H__ +#include "gimpapp.h" -void splash_create (Gimp *gimp, - gboolean be_verbose, - GdkMonitor *mointor); +void splash_create (Gimp *gimp, + gboolean be_verbose, + GdkMonitor *monitor, + GimpApp *app); void splash_destroy (void); void splash_update (const gchar *label1, diff --git a/app/meson.build b/app/meson.build index 4bc7ea2cca3cd995697feb58acf2f2bb364f1a1f..7b76bab4d5c3d57a063937cfdd01ffc3d4f83015 100644 --- a/app/meson.build +++ b/app/meson.build @@ -50,6 +50,8 @@ app_debug_files = files( libapp_sources = [ 'app.c', 'errors.c', + 'gimpcoreapp.c', + 'gimpconsoleapp.c', 'gimp-debug.c', 'gimp-log.c', 'gimp-update.c', diff --git a/app/tests.c b/app/tests.c index c1b26c4ff9803aa073c3210b05a6f9c4a991c8f7..3777057631d6c7236d8cf7519d3493f5d7f55143 100644 --- a/app/tests.c +++ b/app/tests.c @@ -138,7 +138,7 @@ gimp_init_for_gui_testing_internal (gboolean show_gui, gimp_set_show_gui (gimp, show_gui); gimp_load_config (gimp, gimprc, NULL); gimp_gegl_init (gimp); - gui_init (gimp, TRUE, g_getenv ("GIMP_TESTING_ABS_TOP_SRCDIR")); + gui_init (gimp, TRUE, NULL, g_getenv ("GIMP_TESTING_ABS_TOP_SRCDIR")); gimp_init_icon_theme_for_testing (); gimp_initialize (gimp, gimp_status_func_dummy); gimp_restore (gimp, gimp_status_func_dummy, NULL); diff --git a/app/widgets/gimpwindow.c b/app/widgets/gimpwindow.c index d9bc728c9eb6e821834cddcddf3cacda9392ad84..866bb1f92a40220055f8f80681836e9ba3e424cd 100644 --- a/app/widgets/gimpwindow.c +++ b/app/widgets/gimpwindow.c @@ -59,7 +59,7 @@ static gboolean gimp_window_key_press_event (GtkWidget *widget, GdkEventKey *kevent); -G_DEFINE_TYPE_WITH_PRIVATE (GimpWindow, gimp_window, GTK_TYPE_WINDOW) +G_DEFINE_TYPE_WITH_PRIVATE (GimpWindow, gimp_window, GTK_TYPE_APPLICATION_WINDOW) #define parent_class gimp_window_parent_class diff --git a/app/widgets/gimpwindow.h b/app/widgets/gimpwindow.h index 9ee3af2cb16f1de43ff0131ba340ca8538dc8061..be372a138d01d278cddf7e75f05a0dc468f0088c 100644 --- a/app/widgets/gimpwindow.h +++ b/app/widgets/gimpwindow.h @@ -34,14 +34,14 @@ typedef struct _GimpWindowPrivate GimpWindowPrivate; struct _GimpWindow { - GtkWindow parent_instance; + GtkApplicationWindow parent_instance; - GimpWindowPrivate *private; + GimpWindowPrivate *private; }; struct _GimpWindowClass { - GtkWindowClass parent_class; + GtkApplicationWindowClass parent_class; void (* monitor_changed) (GimpWindow *window, GdkMonitor *monitor);