/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * The PIKA Help Browser * Copyright (C) 1999-2008 Sven Neumann * Michael Natterer * Henrik Brix Andersen * * Some code & ideas taken from the GNOME help browser. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include /* strlen, strcmp */ #include #include #include "plug-ins/help/pikahelp.h" #include "dialog.h" #include "libpika/stdplugins-intl.h" #define PIKA_HELP_BROWSER_EXT_PROC "extension-pika-help-browser" #define PIKA_HELP_BROWSER_TEMP_EXT_PROC "extension-pika-help-browser-temp" #define PLUG_IN_BINARY "help-browser" #define PLUG_IN_ROLE "pika-help-browser" #define PIKA_TYPE_HELP_BROWSER (pika_help_browser_get_type ()) G_DECLARE_FINAL_TYPE (PikaHelpBrowser, pika_help_browser, PIKA, HELP_BROWSER, PikaPlugIn) static PikaValueArray * help_browser_run (PikaProcedure *procedure, PikaProcedureConfig *config, gpointer run_data); static void temp_proc_install (PikaPlugIn *plug_in); static PikaValueArray * temp_proc_run (PikaProcedure *procedure, PikaProcedureConfig *config, gpointer run_data); static PikaHelpProgress * help_browser_progress_new (void); struct _PikaHelpBrowser { PikaPlugIn parent_instance; PikaProcedureConfig *config; GtkApplication *app; PikaHelpBrowserDialog *window; }; G_DEFINE_TYPE (PikaHelpBrowser, pika_help_browser, PIKA_TYPE_PLUG_IN) PIKA_MAIN (PIKA_TYPE_HELP_BROWSER) DEFINE_STD_SET_I18N static GList * help_browser_query_procedures (PikaPlugIn *plug_in) { return g_list_append (NULL, g_strdup (PIKA_HELP_BROWSER_EXT_PROC)); } static PikaProcedure * help_browser_create_procedure (PikaPlugIn *plug_in, const gchar *name) { PikaProcedure *procedure = NULL; if (! strcmp (name, PIKA_HELP_BROWSER_EXT_PROC)) { procedure = pika_procedure_new (plug_in, name, PIKA_PDB_PROC_TYPE_EXTENSION, help_browser_run, plug_in, NULL); pika_procedure_set_documentation (procedure, "Browse the PIKA user manual", "A small and simple HTML browser " "optimized for browsing the PIKA " "user manual.", PIKA_HELP_BROWSER_EXT_PROC); pika_procedure_set_attribution (procedure, "Sven Neumann , " "Michael Natterer " "Henrik Brix Andersen ", "Sven Neumann, Michael Natterer & " "Henrik Brix Andersen", "1999-2008"); PIKA_PROC_ARG_ENUM (procedure, "run-mode", "Run mode", "The run mode", PIKA_TYPE_RUN_MODE, PIKA_RUN_INTERACTIVE, G_PARAM_READWRITE); PIKA_PROC_ARG_STRV (procedure, "domain-names", "Domain names", "Domain names", G_PARAM_READWRITE); PIKA_PROC_ARG_STRV (procedure, "domain-uris", "Domain URIs", "Domain URIs", G_PARAM_READWRITE); PIKA_PROC_AUX_ARG_BYTES (procedure, "dialog-data", "Dialog data", "Remembering dialog's basic features; this is never meant to be a public argument", PIKA_PARAM_READWRITE); } return procedure; } static void on_app_activate (GApplication *gapp, gpointer user_data) { PikaHelpBrowser *browser = PIKA_HELP_BROWSER (user_data); GtkApplication *app = GTK_APPLICATION (gapp); browser->window = pika_help_browser_dialog_new (PLUG_IN_BINARY, gapp, browser->config); gtk_application_set_accels_for_action (app, "win.back", (const char*[]) { "Left", NULL }); gtk_application_set_accels_for_action (app, "win.forward", (const char*[]) { "Right", NULL }); gtk_application_set_accels_for_action (app, "win.reload", (const char*[]) { "R", NULL }); gtk_application_set_accels_for_action (app, "win.stop", (const char*[]) { "Escape", NULL }); gtk_application_set_accels_for_action (app, "win.home", (const char*[]) { "Home", NULL }); gtk_application_set_accels_for_action (app, "win.copy-selection", (const char*[]) { "C", NULL }); gtk_application_set_accels_for_action (app, "win.zoom-in", (const char*[]) { "plus", NULL }); gtk_application_set_accels_for_action (app, "win.zoom-out", (const char*[]) { "minus", NULL }); gtk_application_set_accels_for_action (app, "win.find", (const char*[]) { "F", NULL }); gtk_application_set_accels_for_action (app, "win.find-again", (const char*[]) { "G", NULL }); gtk_application_set_accels_for_action (app, "win.close", (const char*[]) { "W", "Q", NULL }); gtk_application_set_accels_for_action (app, "win.show-index", (const char*[]) { "I", NULL }); } static PikaValueArray * help_browser_run (PikaProcedure *procedure, PikaProcedureConfig *config, gpointer user_data) { PikaHelpBrowser *browser = PIKA_HELP_BROWSER (user_data); gchar **domain_names = NULL; gchar **domain_uris = NULL; browser->config = config; g_object_get (config, "domain-names", &domain_names, "domain-uris", &domain_uris, NULL); if (! pika_help_init ((const gchar **) domain_names, (const gchar **) domain_uris)) { g_strfreev (domain_names); g_strfreev (domain_uris); return pika_procedure_new_return_values (procedure, PIKA_PDB_CALLING_ERROR, NULL); } g_strfreev (domain_names); g_strfreev (domain_uris); temp_proc_install (pika_procedure_get_plug_in (procedure)); pika_procedure_extension_ready (procedure); pika_plug_in_extension_enable (pika_procedure_get_plug_in (procedure)); #if GLIB_CHECK_VERSION(2,74,0) browser->app = gtk_application_new (NULL, G_APPLICATION_DEFAULT_FLAGS); #else browser->app = gtk_application_new (NULL, G_APPLICATION_FLAGS_NONE); #endif g_signal_connect (browser->app, "activate", G_CALLBACK (on_app_activate), browser); g_application_run (G_APPLICATION (browser->app), 0, NULL); g_clear_object (&browser->app); return pika_procedure_new_return_values (procedure, PIKA_PDB_SUCCESS, NULL); } static void temp_proc_install (PikaPlugIn *plug_in) { PikaProcedure *procedure; procedure = pika_procedure_new (plug_in, PIKA_HELP_BROWSER_TEMP_EXT_PROC, PIKA_PDB_PROC_TYPE_TEMPORARY, temp_proc_run, plug_in, NULL); pika_procedure_set_documentation (procedure, "DON'T USE THIS ONE", "(Temporary procedure)", NULL); pika_procedure_set_attribution (procedure, "Sven Neumann , " "Michael Natterer " "Henrik Brix Andersen ", "Sven Neumann, Michael Natterer & " "Henrik Brix Andersen", "1999-2008"); PIKA_PROC_ARG_STRING (procedure, "help-domain", "Help domain", "Help domain to use", NULL, G_PARAM_READWRITE); PIKA_PROC_ARG_STRING (procedure, "help-locales", "Help locales", "Language to use", NULL, G_PARAM_READWRITE); PIKA_PROC_ARG_STRING (procedure, "help-id", "Help ID", "Help ID to open", NULL, G_PARAM_READWRITE); pika_plug_in_add_temp_procedure (plug_in, procedure); g_object_unref (procedure); } typedef struct _IdleClosure { PikaHelpBrowser *browser; char *help_domain; char *help_locales; char *help_id; } IdleClosure; static void idle_closure_free (gpointer data) { IdleClosure *closure = data; g_free (closure->help_domain); g_free (closure->help_locales); g_free (closure->help_id); g_free (closure); } static gboolean show_help_on_idle (gpointer user_data) { IdleClosure *closure = user_data; PikaHelpDomain *domain; PikaHelpProgress *progress = NULL; PikaHelpLocale *locale; GList *locales; char *uri; gboolean fatal_error; /* First get the URI to load */ domain = pika_help_lookup_domain (closure->help_domain); if (!domain) return G_SOURCE_REMOVE; locales = pika_help_parse_locales (closure->help_locales); if (! g_str_has_prefix (domain->help_uri, "file:")) progress = help_browser_progress_new (); uri = pika_help_domain_map (domain, locales, closure->help_id, progress, &locale, &fatal_error); if (progress) pika_help_progress_free (progress); g_list_free_full (locales, (GDestroyNotify) g_free); /* Now actually load it */ if (uri) { pika_help_browser_dialog_make_index (closure->browser->window, domain, locale); pika_help_browser_dialog_load (closure->browser->window, uri); g_free (uri); } return G_SOURCE_REMOVE; } static PikaValueArray * temp_proc_run (PikaProcedure *procedure, PikaProcedureConfig *config, gpointer user_data) { PikaHelpBrowser *browser = PIKA_HELP_BROWSER (user_data); IdleClosure *closure; gchar *str; closure = g_new0 (IdleClosure, 1); closure->browser = browser; g_object_get (config, "help-domain", &str, NULL); closure->help_domain = g_strdup ((str && *str)? str : PIKA_HELP_DEFAULT_DOMAIN); g_free (str); g_object_get (config, "help-locales", &str, NULL); if (str && *str) closure->help_locales = g_strdup (str); g_free (str); g_object_get (config, "help-id", &str, NULL); closure->help_id = g_strdup ((str && *str)? str : PIKA_HELP_DEFAULT_ID); g_free (str); /* Do this on idle, to make sure everything is initialized already */ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, show_help_on_idle, closure, idle_closure_free); return pika_procedure_new_return_values (procedure, PIKA_PDB_SUCCESS, NULL); } static void help_browser_progress_start (const gchar *message, gboolean cancelable, gpointer user_data) { pika_progress_init (message); } static void help_browser_progress_update (gdouble value, gpointer user_data) { pika_progress_update (value); } static void help_browser_progress_end (gpointer user_data) { pika_progress_end (); } static PikaHelpProgress * help_browser_progress_new (void) { static const PikaHelpProgressVTable vtable = { help_browser_progress_start, help_browser_progress_end, help_browser_progress_update }; return pika_help_progress_new (&vtable, NULL); } static void pika_help_browser_class_init (PikaHelpBrowserClass *klass) { PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass); plug_in_class->query_procedures = help_browser_query_procedures; plug_in_class->create_procedure = help_browser_create_procedure; plug_in_class->set_i18n = STD_SET_I18N; } static void pika_help_browser_init (PikaHelpBrowser *help_browser) { }