PIKApp/plug-ins/help-browser/help-browser.c

391 lines
13 KiB
C
Raw Normal View History

2023-09-26 00:35:21 +02:00
/* 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 <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
* Henrik Brix Andersen <brix@gimp.org>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h> /* strlen, strcmp */
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#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,
2023-10-30 23:55:30 +01:00
PikaProcedureConfig *config,
2023-09-26 00:35:21 +02:00
gpointer run_data);
static void temp_proc_install (PikaPlugIn *plug_in);
static PikaValueArray * temp_proc_run (PikaProcedure *procedure,
2023-10-30 23:55:30 +01:00
PikaProcedureConfig *config,
2023-09-26 00:35:21 +02:00
gpointer run_data);
static PikaHelpProgress * help_browser_progress_new (void);
struct _PikaHelpBrowser
{
PikaPlugIn parent_instance;
2023-10-30 23:55:30 +01:00
PikaProcedureConfig *config;
2023-09-26 00:35:21 +02:00
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 <sven@gimp.org>, "
"Michael Natterer <mitch@gimp.org>"
"Henrik Brix Andersen <brix@gimp.org>",
"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);
2023-10-30 23:55:30 +01:00
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);
2023-09-26 00:35:21 +02:00
}
return procedure;
}
static void
on_app_activate (GApplication *gapp,
gpointer user_data)
{
PikaHelpBrowser *browser = PIKA_HELP_BROWSER (user_data);
GtkApplication *app = GTK_APPLICATION (gapp);
2023-10-30 23:55:30 +01:00
browser->window = pika_help_browser_dialog_new (PLUG_IN_BINARY, gapp, browser->config);
2023-09-26 00:35:21 +02:00
gtk_application_set_accels_for_action (app, "win.back", (const char*[]) { "<alt>Left", NULL });
gtk_application_set_accels_for_action (app, "win.forward", (const char*[]) { "<alt>Right", NULL });
gtk_application_set_accels_for_action (app, "win.reload", (const char*[]) { "<control>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*[]) { "<alt>Home", NULL });
gtk_application_set_accels_for_action (app, "win.copy-selection", (const char*[]) { "<control>C", NULL });
gtk_application_set_accels_for_action (app, "win.zoom-in", (const char*[]) { "<control>plus", NULL });
gtk_application_set_accels_for_action (app, "win.zoom-out", (const char*[]) { "<control>minus", NULL });
gtk_application_set_accels_for_action (app, "win.find", (const char*[]) { "<control>F", NULL });
gtk_application_set_accels_for_action (app, "win.find-again", (const char*[]) { "<control>G", NULL });
gtk_application_set_accels_for_action (app, "win.close", (const char*[]) { "<control>W", "<control>Q", NULL });
gtk_application_set_accels_for_action (app, "win.show-index", (const char*[]) { "<control>I", NULL });
}
static PikaValueArray *
help_browser_run (PikaProcedure *procedure,
2023-10-30 23:55:30 +01:00
PikaProcedureConfig *config,
2023-09-26 00:35:21 +02:00
gpointer user_data)
{
2023-10-30 23:55:30 +01:00
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))
2023-09-26 00:35:21 +02:00
{
2023-10-30 23:55:30 +01:00
g_strfreev (domain_names);
g_strfreev (domain_uris);
2023-09-26 00:35:21 +02:00
return pika_procedure_new_return_values (procedure,
PIKA_PDB_CALLING_ERROR,
NULL);
}
2023-10-30 23:55:30 +01:00
g_strfreev (domain_names);
g_strfreev (domain_uris);
2023-09-26 00:35:21 +02:00
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 <sven@gimp.org>, "
"Michael Natterer <mitch@gimp.org>"
"Henrik Brix Andersen <brix@gimp.org>",
"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,
2023-10-30 23:55:30 +01:00
PikaProcedureConfig *config,
2023-09-26 00:35:21 +02:00
gpointer user_data)
{
PikaHelpBrowser *browser = PIKA_HELP_BROWSER (user_data);
IdleClosure *closure;
2023-10-30 23:55:30 +01:00
gchar *str;
2023-09-26 00:35:21 +02:00
closure = g_new0 (IdleClosure, 1);
closure->browser = browser;
2023-10-30 23:55:30 +01:00
g_object_get (config, "help-domain", &str, NULL);
2023-09-26 00:35:21 +02:00
closure->help_domain = g_strdup ((str && *str)? str : PIKA_HELP_DEFAULT_DOMAIN);
2023-10-30 23:55:30 +01:00
g_free (str);
2023-09-26 00:35:21 +02:00
2023-10-30 23:55:30 +01:00
g_object_get (config, "help-locales", &str, NULL);
2023-09-26 00:35:21 +02:00
if (str && *str)
closure->help_locales = g_strdup (str);
2023-10-30 23:55:30 +01:00
g_free (str);
2023-09-26 00:35:21 +02:00
2023-10-30 23:55:30 +01:00
g_object_get (config, "help-id", &str, NULL);
2023-09-26 00:35:21 +02:00
closure->help_id = g_strdup ((str && *str)? str : PIKA_HELP_DEFAULT_ID);
2023-10-30 23:55:30 +01:00
g_free (str);
2023-09-26 00:35:21 +02:00
/* 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)
{
}