[gimp/nielsdg/help-browser-dialog-gtk-actions: 18/18] help-browser: Rewrite without GtkAction
- From: Niels De Graef <nielsdg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/nielsdg/help-browser-dialog-gtk-actions: 18/18] help-browser: Rewrite without GtkAction
- Date: Tue, 7 Dec 2021 08:49:04 +0000 (UTC)
commit 73bab7009fe68ddbf4ebe71d901c074181bc18b8
Author: Niels De Graef <nielsdegraef gmail com>
Date: Sat Nov 27 08:57:30 2021 +0100
help-browser: Rewrite without GtkAction
The initial attempt of this commit was to remove the `GtkAction` usage,
but grew a bit wider than that. The following happened:
* The dialog became a proper GObject, rather than being a big chunk of
static variables that were hopefully initialized before you used them.
* The dialog now uses `GAction`s to implement actions, and converted
some signal handlers to actions as well.
* The plug-in run procedure now uses `GtkApplication`. This is one hand
necessary to be able to set accelerators for actions, but on the other
hand is more future-proof, as GTK4 removes `gtk_main()`
libgimp/gimpplugin.h | 1 +
plug-ins/help-browser/Makefile.am | 4 -
plug-ins/help-browser/dialog.c | 1888 ++++++++++++++--------------
plug-ins/help-browser/dialog.h | 17 +-
plug-ins/help-browser/gimpthrobber.c | 331 -----
plug-ins/help-browser/gimpthrobber.h | 68 -
plug-ins/help-browser/gimpthrobberaction.c | 133 --
plug-ins/help-browser/gimpthrobberaction.h | 48 -
plug-ins/help-browser/help-browser.c | 235 ++--
plug-ins/help-browser/meson.build | 2 -
10 files changed, 1082 insertions(+), 1645 deletions(-)
---
diff --git a/libgimp/gimpplugin.h b/libgimp/gimpplugin.h
index 9cc9c521a0..0d1e40a2ca 100644
--- a/libgimp/gimpplugin.h
+++ b/libgimp/gimpplugin.h
@@ -176,6 +176,7 @@ void gimp_plug_in_set_pdb_error_handler (GimpPlugIn *plug_in,
GimpPDBErrorHandler
gimp_plug_in_get_pdb_error_handler (GimpPlugIn *plug_in);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GimpPlugIn, g_object_unref);
G_END_DECLS
diff --git a/plug-ins/help-browser/Makefile.am b/plug-ins/help-browser/Makefile.am
index e4f7a3b5f5..256c04e3fc 100644
--- a/plug-ins/help-browser/Makefile.am
+++ b/plug-ins/help-browser/Makefile.am
@@ -48,10 +48,6 @@ LDADD = \
$(help_browser_RC)
help_browser_SOURCES = \
- gimpthrobber.c \
- gimpthrobber.h \
- gimpthrobberaction.c \
- gimpthrobberaction.h \
help-browser.c \
dialog.c \
dialog.h \
diff --git a/plug-ins/help-browser/dialog.c b/plug-ins/help-browser/dialog.c
index 8288c1a4a0..5500590134 100644
--- a/plug-ins/help-browser/dialog.c
+++ b/plug-ins/help-browser/dialog.c
@@ -5,6 +5,7 @@
* Copyright (C) 1999-2008 Sven Neumann <sven gimp org>
* Michael Natterer <mitch gimp org>
* Róman Joost <romanofski gimp org>
+ * Niels De Graef <nielsdg redhat com>
*
* dialog.c
*
@@ -38,9 +39,6 @@
#include "plug-ins/help/gimphelp.h"
-#include "gimpthrobber.h"
-#include "gimpthrobberaction.h"
-
#include "dialog.h"
#include "uri.h"
@@ -48,465 +46,534 @@
#define GIMP_HELP_BROWSER_DIALOG_DATA "gimp-help-browser-dialog"
-
#define GIMP_HELP_BROWSER_INDEX_MAX_DEPTH 4
typedef struct
{
- gint width;
- gint height;
- gint paned_position;
- gboolean show_index;
- gdouble zoom;
+ int width;
+ int height;
+ int paned_position;
+ gboolean show_index;
+ double zoom;
} DialogData;
-enum
-{
- HISTORY_TITLE,
- HISTORY_URI
+struct _GimpHelpBrowserDialog {
+ GtkApplicationWindow parent_instance;
+
+ GHashTable *uri_hash_table; /* (char*) → (GtkTreeIter) */
+
+ GtkWidget *webview;
+ GtkWidget *paned;
+ GtkWidget *sidebar;
+ GtkWidget *searchbar;
+ GtkWidget *search_entry;
+ GtkWidget *tree_view;
+ GtkWidget *button_prev;
+ GtkWidget *button_next;
+ GdkCursor *busy_cursor;
+
+ GMenuModel *popup_menu_model;
+ GMenuModel *copy_popup_menu_model;
};
-/* local function prototypes */
-
-static GtkUIManager * ui_manager_new (GtkWidget *window);
-
-static GtkWidget * build_searchbar (void);
-
-static void back_callback (GtkAction *action,
- gpointer data);
-static void forward_callback (GtkAction *action,
- gpointer data);
-static void reload_callback (GtkAction *action,
- gpointer data);
-static void stop_callback (GtkAction *action,
- gpointer data);
-static void home_callback (GtkAction *action,
- gpointer data);
-static void find_callback (GtkAction *action,
- gpointer data);
-static void find_again_callback (GtkAction *action,
- gpointer data);
-static void copy_location_callback (GtkAction *action,
- gpointer data);
-static void copy_selection_callback (GtkAction *action,
- gpointer data);
-static void show_index_callback (GtkAction *action,
- gpointer data);
-static void zoom_in_callback (GtkAction *action,
- gpointer data);
-static void zoom_out_callback (GtkAction *action,
- gpointer data);
-static void close_callback (GtkAction *action,
- gpointer data);
-static void website_callback (GtkAction *action,
- gpointer data);
-
-static void update_actions (void);
-
-static void row_activated (GtkTreeView *tree_view,
- GtkTreePath *path,
- GtkTreeViewColumn *column);
-static void dialog_unmap (GtkWidget *window,
- GtkWidget *paned);
-
-static void view_realize (GtkWidget *widget);
-static void view_unrealize (GtkWidget *widget);
-static gboolean view_popup_menu (GtkWidget *widget,
- GdkEventButton *event);
-static gboolean view_button_press (GtkWidget *widget,
- GdkEventButton *event);
-static gboolean view_key_press (GtkWidget *widget,
- GdkEventKey *event);
-
-static void title_changed (WebKitWebView *view,
- GParamSpec *pspec,
- GtkWidget *window);
-
-static void load_changed (WebKitWebView *view,
- WebKitLoadEvent event);
-
-static void select_index (const gchar *uri);
-
-static void search_entry_changed (GtkWidget *entry);
-static gboolean search_entry_key_press (GtkWidget *entry,
- GdkEventKey *event);
-static void search_prev_clicked (GtkWidget *button,
- GtkWidget *entry);
-static void search_next_clicked (GtkWidget *button,
- GtkWidget *entry);
-static void search_close_clicked (GtkWidget *button);
-static void search (const gchar *text);
-
-
-/* private variables */
-
-static GHashTable *uri_hash_table = NULL;
-
-static GtkWidget *view = NULL;
-static GtkWidget *sidebar = NULL;
-static GtkWidget *searchbar = NULL;
-static GtkWidget *tree_view = NULL;
-static GtkUIManager *ui_manager = NULL;
-static GtkWidget *button_prev = NULL;
-static GtkWidget *button_next = NULL;
-static GdkCursor *busy_cursor = NULL;
-
-
-/* public functions */
+G_DEFINE_TYPE (GimpHelpBrowserDialog, gimp_help_browser_dialog, GTK_TYPE_APPLICATION_WINDOW)
-void
-browser_dialog_open (const gchar *plug_in_binary)
+static void
+search (GimpHelpBrowserDialog *self,
+ const char *text)
{
- GtkWidget *window;
- GtkWidget *main_vbox;
- GtkWidget *vbox;
- GtkWidget *toolbar;
- GtkWidget *paned;
- GtkWidget *scrolled;
- GtkToolItem *item;
- GtkAction *action;
- DialogData data = { 720, 560, 240, TRUE, 1.0 };
+ WebKitFindController *find_controller;
- gimp_ui_init (plug_in_binary);
+ find_controller = webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (self->webview));
+ if (text)
+ {
+ const char *prev_text =
+ webkit_find_controller_get_search_text (find_controller);
- gimp_get_data (GIMP_HELP_BROWSER_DIALOG_DATA, &data);
+ /* The previous search, if any, may need to be canceled. */
+ if (prev_text && strcmp (text, prev_text) != 0)
+ webkit_find_controller_search_finish (find_controller);
- /* the dialog window */
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title (GTK_WINDOW (window), _("GIMP Help Browser"));
- gtk_window_set_role (GTK_WINDOW (window), plug_in_binary);
- gtk_window_set_icon_name (GTK_WINDOW (window), GIMP_ICON_HELP_USER_MANUAL);
+ webkit_find_controller_search (find_controller,
+ text,
+ WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE |
+ WEBKIT_FIND_OPTIONS_WRAP_AROUND,
+ G_MAXUINT);
+ }
+ else
+ webkit_find_controller_search_finish (find_controller);
+}
- gtk_window_set_default_size (GTK_WINDOW (window), data.width, data.height);
+static void
+back_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- g_signal_connect (window, "destroy",
- G_CALLBACK (gtk_main_quit),
- NULL);
+ webkit_web_view_go_back (WEBKIT_WEB_VIEW (self->webview));
+}
- vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
- gtk_container_add (GTK_CONTAINER (window), vbox);
- gtk_widget_show (vbox);
+static void
+step_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ gint steps;
+ WebKitBackForwardList *back_fw_list;
+ WebKitBackForwardListItem *back_fw_list_item;
- ui_manager = ui_manager_new (window);
+ g_return_if_fail (parameter);
- toolbar = gtk_ui_manager_get_widget (ui_manager, "/help-browser-toolbar");
- gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
- gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
- gtk_widget_show (toolbar);
+ steps = g_variant_get_int32 (parameter);
- item = g_object_new (GTK_TYPE_MENU_TOOL_BUTTON, NULL);
- gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0);
- gtk_widget_show (GTK_WIDGET (item));
+ back_fw_list =
+ webkit_web_view_get_back_forward_list (WEBKIT_WEB_VIEW (self->webview));
+ back_fw_list_item = webkit_back_forward_list_get_nth_item (back_fw_list, steps);
+ if (back_fw_list_item)
+ webkit_web_view_go_to_back_forward_list_item (WEBKIT_WEB_VIEW (self->webview),
+ back_fw_list_item);
+}
- action = gtk_ui_manager_get_action (ui_manager,
- "/ui/help-browser-popup/forward");
- gtk_activatable_set_related_action (GTK_ACTIVATABLE (item), action);
- g_object_notify (G_OBJECT (action), "tooltip");
- button_next = GTK_WIDGET (item);
+static void
+forward_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- item = g_object_new (GTK_TYPE_MENU_TOOL_BUTTON, NULL);
- gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0);
- gtk_widget_show (GTK_WIDGET (item));
+ webkit_web_view_go_forward (WEBKIT_WEB_VIEW (self->webview));
+}
- action = gtk_ui_manager_get_action (ui_manager,
- "/ui/help-browser-popup/back");
- gtk_activatable_set_related_action (GTK_ACTIVATABLE (item), action);
- g_object_notify (G_OBJECT (action), "tooltip");
- button_prev = GTK_WIDGET (item);
+static void
+reload_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- item =
- GTK_TOOL_ITEM (gtk_ui_manager_get_widget (ui_manager,
- "/help-browser-toolbar/space"));
- gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (item), FALSE);
- gtk_tool_item_set_expand (item, TRUE);
+ webkit_web_view_reload (WEBKIT_WEB_VIEW (self->webview));
+}
- /* the horizontal paned */
- paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
- gtk_box_pack_start (GTK_BOX (vbox), paned, TRUE, TRUE, 0);
- gtk_widget_show (paned);
+static void
+stop_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- scrolled = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_paned_add1 (GTK_PANED (paned), scrolled);
- gtk_paned_set_position (GTK_PANED (paned), data.paned_position);
+ webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (self->webview));
+}
- sidebar = scrolled;
+static void
+home_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ GtkTreeModel *model;
+ GimpHelpDomain *domain;
+ GimpHelpLocale *locale;
- if (data.show_index)
- gtk_widget_show (sidebar);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->tree_view));
+ domain = g_object_get_data (G_OBJECT (model), "domain");
+ locale = g_object_get_data (G_OBJECT (model), "locale");
+ if (domain && locale)
+ {
+ gchar *uri = g_strconcat (domain->help_uri, "/",
+ locale->locale_id, "/",
+ gimp_help_locale_map (locale,
+ GIMP_HELP_DEFAULT_ID),
+ NULL);
+ gimp_help_browser_dialog_load (self, uri);
+ g_free (uri);
+ }
+}
+
+static void
+find_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- tree_view = gtk_tree_view_new ();
- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
- gtk_container_add (GTK_CONTAINER (scrolled), tree_view);
- gtk_widget_show (tree_view);
+ gtk_widget_show (self->searchbar);
+ gtk_widget_grab_focus (self->search_entry);
+}
- gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view), -1,
- NULL,
- gtk_cell_renderer_text_new (),
- "text", 1,
- NULL);
+static void
+find_again_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- g_signal_connect (tree_view, "row-activated",
- G_CALLBACK (row_activated),
- NULL);
+ gtk_widget_show (self->searchbar);
+ gtk_widget_grab_focus (self->search_entry);
- /* HTML view */
- main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
- gtk_widget_show (main_vbox);
- gtk_paned_pack2 (GTK_PANED (paned), main_vbox, TRUE, TRUE);
+ search (self, gtk_entry_get_text (GTK_ENTRY (self->search_entry)));
+}
- view = webkit_web_view_new ();
- gtk_widget_set_size_request (view, 300, 200);
- gtk_widget_show (view);
+static void
+search_next_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ WebKitFindController *find_controller;
- gtk_box_pack_start (GTK_BOX (main_vbox), view, TRUE, TRUE, 0);
+ find_controller =
+ webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (self->webview));
+ webkit_find_controller_search_next (find_controller);
+}
- g_signal_connect (view, "realize",
- G_CALLBACK (view_realize),
- NULL);
- g_signal_connect (view, "unrealize",
- G_CALLBACK (view_unrealize),
- NULL);
+static void
+search_previous_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ WebKitFindController *find_controller;
- g_signal_connect (view, "popup-menu",
- G_CALLBACK (view_popup_menu),
- NULL);
- g_signal_connect (view, "button-press-event",
- G_CALLBACK (view_button_press),
- NULL);
- g_signal_connect (view, "key-press-event",
- G_CALLBACK (view_key_press),
- NULL);
+ find_controller =
+ webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (self->webview));
+ webkit_find_controller_search_previous (find_controller);
+}
- webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (view), data.zoom);
+static void
+copy_location_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ const char *uri;
- g_signal_connect (view, "notify::title",
- G_CALLBACK (title_changed),
- window);
+ uri = webkit_web_view_get_uri (WEBKIT_WEB_VIEW (self->webview));
+ if (uri)
+ {
+ GtkClipboard *clipboard;
- g_signal_connect (view, "load-changed",
- G_CALLBACK (load_changed),
- NULL);
+ clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (self->webview),
+ GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_set_text (clipboard, uri, -1);
+ }
+}
- gtk_widget_grab_focus (view);
+static void
+copy_selection_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ WebKitEditorState *editor_state;
- g_signal_connect (window, "unmap",
- G_CALLBACK (dialog_unmap),
- paned);
+ editor_state = webkit_web_view_get_editor_state (WEBKIT_WEB_VIEW (self->webview));
+ if (webkit_editor_state_is_copy_available (editor_state))
+ {
+ webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (self->webview),
+ WEBKIT_EDITING_COMMAND_COPY);
+ }
+}
- update_actions ();
+static void
+show_index_change_state (GSimpleAction *action,
+ GVariant *new_state,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ gboolean show_index;
- /* Searchbar */
- searchbar = build_searchbar ();
- gtk_box_pack_start (GTK_BOX (main_vbox), searchbar, FALSE, FALSE, 0);
+ show_index = g_variant_get_boolean (new_state);
+ g_warning ("NEW STATE %s", show_index? "true" : "false");
+ gtk_widget_set_visible (self->sidebar, show_index);
+ g_simple_action_set_state (action, new_state);
}
-void
-browser_dialog_load (const gchar *uri)
+static void
+zoom_in_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ double zoom_level;
+
+ zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (self->webview));
+ if (zoom_level < 10.0)
+ webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (self->webview), zoom_level + 0.1);
+}
+
+static void
+zoom_out_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
{
- g_return_if_fail (uri != NULL);
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ double zoom_level;
- webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), uri);
+ zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (self->webview));
+ if (zoom_level > 0.1)
+ webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (self->webview), zoom_level - 0.1);
+}
- select_index (uri);
+static void
+load_uri_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ const char *uri;
- gtk_window_present (GTK_WINDOW (gtk_widget_get_toplevel (view)));
+ uri = g_variant_get_string (parameter, NULL);
+ gimp_help_browser_dialog_load (self, uri);
}
static void
-browser_dialog_make_index_foreach (const gchar *help_id,
- GimpHelpItem *item,
- GimpHelpLocale *locale)
+close_action (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
{
- gchar *sort_key = item->title;
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
-#if DEBUG_SORT_HELP_ITEMS
- g_printerr ("%s: processing %s (parent %s)\n",
- G_STRFUNC,
- item->title ? item->title : "NULL",
- item->parent ? item->parent : "NULL");
-#endif
+ gtk_widget_destroy (GTK_WIDGET (self));
+}
- if (item->sort &&
- g_regex_match_simple ("^[0-9]+([.][0-9]+)*$", item->sort, 0, 0))
- {
- sort_key = item->sort;
+static const GActionEntry ACTIONS[] =
+{
+ { "back", back_action },
+ { "forward", forward_action },
+ { "step", step_action, "i" },
+ { "reload", reload_action },
+ { "stop", stop_action },
+ { "home", home_action },
+ { "load-uri", load_uri_action, "s" },
+ { "copy-location", copy_location_action },
+ { "copy-selection", copy_selection_action },
+ { "zoom-in", zoom_in_action },
+ { "zoom-out", zoom_out_action },
+ { "find", find_action },
+ { "find-again", find_again_action },
+ { "search-next", search_next_action },
+ { "search-previous", search_previous_action },
+ { "close", close_action },
+ { "show-index", NULL, NULL, "true", show_index_change_state },
+};
-#if DEBUG_SORT_HELP_ITEMS
- g_printerr ("%s: sort key = %s\n", G_STRFUNC, sort_key);
-#endif
- }
+static GtkWidget *
+build_menu (const GList *items,
+ gboolean back)
+{
+ GMenu *menu;
+ const GList *iter;
+ int steps;
- item->index = 0;
+ if (!items)
+ return NULL;
- if (sort_key)
+ menu = g_menu_new ();
+
+ /* Go over every item in the back_fw list and add it to the menu */
+ for (iter = items, steps = 1; iter; iter = g_list_next (iter), steps++)
{
- const gint max_tokens = GIMP_HELP_BROWSER_INDEX_MAX_DEPTH;
- gchar* *indices = g_strsplit (sort_key, ".", max_tokens + 1);
- gint i;
+ WebKitBackForwardListItem *item = iter->data;
+ const char *title;
+ char *action;
- for (i = 0; i < max_tokens; i++)
- {
- gunichar c;
+ title = webkit_back_forward_list_item_get_title (item);
+ if (title == NULL)
+ continue;
- if (! indices[i])
- {
- /* make sure that all item->index's are comparable */
- item->index <<= (8 * (max_tokens - i));
- break;
- }
+ action = g_strdup_printf ("steps(%d)", steps);
+ g_menu_insert (menu, steps - 1, title, action);
+ g_free (action);
+ }
- item->index <<= 8; /* NOP if i = 0 */
- c = g_utf8_get_char (indices[i]);
- if (g_unichar_isdigit (c))
- {
- item->index += atoi (indices[i]);
- }
- else if (g_utf8_strlen (indices[i], -1) == 1)
- {
- item->index += (c & 0xFF);
- }
- }
+ return gtk_menu_new_from_model (G_MENU_MODEL (menu));
+}
- g_strfreev (indices);
+static void
+update_actions (GimpHelpBrowserDialog *self)
+{
+ GActionMap *action_map = G_ACTION_MAP (self);
+ GAction *action;
+ WebKitBackForwardList *back_forward_list;
-#if DEBUG_SORT_HELP_ITEMS
- g_printerr ("%s: index = %lu\n", G_STRFUNC, item->index);
-#endif
- }
+ back_forward_list =
+ webkit_web_view_get_back_forward_list (WEBKIT_WEB_VIEW (self->webview));
- if (item->parent && strlen (item->parent))
+ /* update the back button and its menu */
+ action = g_action_map_lookup_action (action_map, "back");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ webkit_web_view_can_go_back (WEBKIT_WEB_VIEW (self->webview)));
+
+ if (back_forward_list)
{
- GimpHelpItem *parent;
+ const GList *list;
- parent = g_hash_table_lookup (locale->help_id_mapping, item->parent);
+ list = webkit_back_forward_list_get_back_list_with_limit (back_forward_list,
+ 12);
+ gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (self->button_prev),
+ build_menu (list, TRUE));
+ }
+ else
+ {
+ gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (self->button_prev), NULL);
+ }
- if (parent)
- {
- parent->children = g_list_prepend (parent->children, item);
- }
+ /* update the forward button and its menu */
+ action = g_action_map_lookup_action (action_map, "forward");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW (self->webview)));
+
+ if (back_forward_list)
+ {
+ const GList *list;
+
+ list = webkit_back_forward_list_get_forward_list_with_limit (back_forward_list,
+ 12);
+ gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (self->button_next),
+ build_menu (list, FALSE));
}
else
{
- locale->toplevel_items = g_list_prepend (locale->toplevel_items, item);
+ gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (self->button_next), NULL);
}
+
+ /* update the copy-location action */
+ action = g_action_map_lookup_action (action_map, "copy-location");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ webkit_web_view_get_uri (WEBKIT_WEB_VIEW (self->webview)) != NULL);
+
+ /* update the show-index action */
+ action = g_action_map_lookup_action (action_map, "show-index");
+ g_simple_action_set_state (G_SIMPLE_ACTION (action),
+ g_variant_new_boolean (gtk_widget_get_visible (self->sidebar)));
}
-static gint
-help_item_compare (gconstpointer a,
- gconstpointer b)
+static void
+webview_realize (GtkWidget *webview,
+ gpointer user_data)
{
- const GimpHelpItem *item_a = a;
- const GimpHelpItem *item_b = b;
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- if (item_a->index > item_b->index)
- return 1;
- else if (item_a->index < item_b->index)
- return -1;
+ g_return_if_fail (self->busy_cursor == NULL);
- return 0;
+ self->busy_cursor = gdk_cursor_new_for_display (gtk_widget_get_display (webview),
+ GDK_WATCH);
}
static void
-add_child (GtkTreeStore *store,
- GimpHelpDomain *domain,
- GimpHelpLocale *locale,
- GtkTreeIter *parent,
- GimpHelpItem *item,
- gint depth)
+webview_unrealize (GtkWidget *widget,
+ gpointer user_data)
{
- GtkTreeIter iter;
- GList *list;
- gchar *uri;
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- gtk_tree_store_append (store, &iter, parent);
+ g_clear_object (&self->busy_cursor);
+}
- gtk_tree_store_set (store, &iter,
- 0, item,
- 1, item->title,
- -1);
+static void
+do_popup_menu (GimpHelpBrowserDialog *self,
+ GtkWidget *webview,
+ GdkEvent *event)
+{
+ WebKitEditorState *editor_state;
+ GMenuModel *menu_model;
+ GtkWidget *menu;
- uri = g_strconcat (domain->help_uri, "/",
- locale->locale_id, "/",
- item->ref,
- NULL);
-
- g_hash_table_insert (uri_hash_table,
- uri,
- gtk_tree_iter_copy (&iter));
+ editor_state = webkit_web_view_get_editor_state (WEBKIT_WEB_VIEW (webview));
+ if (webkit_editor_state_is_copy_available (editor_state))
+ menu_model = self->copy_popup_menu_model;
+ else
+ menu_model = self->popup_menu_model;
- if (depth + 1 == GIMP_HELP_BROWSER_INDEX_MAX_DEPTH)
- return;
+ menu = gtk_menu_new_from_model (menu_model);
+ g_signal_connect (menu, "deactivate",
+ G_CALLBACK (gtk_widget_destroy), NULL);
- item->children = g_list_sort (item->children, help_item_compare);
+ gtk_menu_attach_to_widget (GTK_MENU (menu), webview, NULL);
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), event);
+}
- for (list = item->children; list; list = g_list_next (list))
- {
- GimpHelpItem *item = list->data;
+static gboolean
+webview_popup_menu (GtkWidget *webview,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- add_child (store, domain, locale, &iter, item, depth + 1);
- }
+ do_popup_menu (self, webview, NULL);
+ return TRUE;
}
-void
-browser_dialog_make_index (GimpHelpDomain *domain,
- GimpHelpLocale *locale)
+static gboolean
+webview_button_press (GtkWidget *webview,
+ GdkEventButton *event,
+ gpointer user_data)
{
- GtkTreeStore *store;
- GList *list;
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- if (! locale->toplevel_items)
+ if (gdk_event_triggers_context_menu ((GdkEvent *) event))
{
- g_hash_table_foreach (locale->help_id_mapping,
- (GHFunc) browser_dialog_make_index_foreach,
- locale);
-
- locale->toplevel_items = g_list_sort (locale->toplevel_items,
- help_item_compare);
+ do_popup_menu (self, webview, (GdkEvent *) event);
+ return TRUE;
}
- store = gtk_tree_store_new (2,
- G_TYPE_POINTER,
- G_TYPE_STRING);
+ return FALSE;
+}
- g_object_set_data (G_OBJECT (store), "domain", domain);
- g_object_set_data (G_OBJECT (store), "locale", locale);
+static gboolean
+webview_key_press (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- if (uri_hash_table)
- g_hash_table_unref (uri_hash_table);
+ if (event->keyval == GDK_KEY_slash)
+ {
+ g_action_group_activate_action (G_ACTION_GROUP (self),
+ "find",
+ NULL);
+ return TRUE;
+ }
- uri_hash_table = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) gtk_tree_iter_free);
+ return FALSE;
+}
- for (list = locale->toplevel_items; list; list = g_list_next (list))
- {
- GimpHelpItem *item = list->data;
+static void
+webview_title_changed (WebKitWebView *webview,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ const char *title;
+ char *full_title;
- add_child (store, domain, locale, NULL, item, 0);
- }
+ title = webkit_web_view_get_title (webview);
+ full_title = g_strdup_printf ("%s - %s",
+ title ? title : _("Untitled"),
+ _("GIMP Help Browser"));
- gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (store));
- g_object_unref (store);
+ gtk_window_set_title (GTK_WINDOW (self), full_title);
+ g_free (full_title);
+
+ update_actions (self);
}
static void
-select_index (const gchar *uri)
+select_index (GimpHelpBrowserDialog *self,
+ const char *uri)
{
GtkTreeSelection *selection;
GtkTreeIter *iter = NULL;
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->tree_view));
if (uri)
- iter = g_hash_table_lookup (uri_hash_table, uri);
+ iter = g_hash_table_lookup (self->uri_hash_table, uri);
if (iter)
{
- GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->tree_view));
GtkTreePath *path;
GtkTreePath *scroll_path;
@@ -514,8 +581,8 @@ select_index (const gchar *uri)
scroll_path = gtk_tree_path_copy (path);
gtk_tree_path_up (path);
- gtk_tree_view_expand_to_path (GTK_TREE_VIEW (tree_view), path);
- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view), scroll_path,
+ gtk_tree_view_expand_to_path (GTK_TREE_VIEW (self->tree_view), path);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (self->tree_view), scroll_path,
NULL, FALSE, 0.0, 0.0);
gtk_tree_path_free (path);
@@ -529,752 +596,675 @@ select_index (const gchar *uri)
}
}
-
-/* private functions */
-
-static GtkUIManager *
-ui_manager_new (GtkWidget *window)
+static gboolean
+webview_decide_policy (WebKitWebView *webview,
+ WebKitPolicyDecision *decision,
+ WebKitPolicyDecisionType decision_type,
+ gpointer user_data)
{
- static const GtkActionEntry actions[] =
- {
- {
- "back", GIMP_ICON_GO_PREVIOUS,
- NULL, "<alt>Left", N_("Go back one page"),
- G_CALLBACK (back_callback)
- },
- {
- "forward", GIMP_ICON_GO_NEXT,
- NULL, "<alt>Right", N_("Go forward one page"),
- G_CALLBACK (forward_callback)
- },
- {
- "reload", GIMP_ICON_VIEW_REFRESH,
- N_("_Reload"), "<control>R", N_("Reload current page"),
- G_CALLBACK (reload_callback)
- },
- {
- "stop", GIMP_ICON_PROCESS_STOP,
- N_("_Stop"), "Escape", N_("Stop loading this page"),
- G_CALLBACK (stop_callback)
- },
- {
- "home", GIMP_ICON_GO_HOME,
- NULL, "<alt>Home", N_("Go to the index page"),
- G_CALLBACK (home_callback)
- },
- {
- "copy-location", GIMP_ICON_EDIT_COPY,
- N_("C_opy location"), "",
- N_("Copy the location of this page to the clipboard"),
- G_CALLBACK (copy_location_callback)
- },
- {
- "copy-selection", GIMP_ICON_EDIT_COPY,
- NULL, "<control>C", NULL,
- G_CALLBACK (copy_selection_callback)
- },
- {
- "zoom-in", GIMP_ICON_ZOOM_IN,
- NULL, "<control>plus", NULL,
- G_CALLBACK (zoom_in_callback)
- },
- {
- "zoom-out", GIMP_ICON_ZOOM_OUT,
- NULL, "<control>minus", NULL,
- G_CALLBACK (zoom_out_callback)
- },
- {
- "find", GIMP_ICON_EDIT_FIND,
- NULL, "<control>F", N_("Find text in current page"),
- G_CALLBACK (find_callback)
- },
- {
- "find-again", NULL,
- N_("Find _Again"), "<control>G", NULL,
- G_CALLBACK (find_again_callback)
- },
- {
- "close", GIMP_ICON_WINDOW_CLOSE,
- NULL, "<control>W", NULL,
- G_CALLBACK (close_callback)
- },
- {
- "quit", GIMP_ICON_APPLICATION_EXIT,
- NULL, "<control>Q", NULL,
- G_CALLBACK (close_callback)
- }
- };
-
- static const GtkToggleActionEntry toggle_actions[] =
- {
- {
- "show-index", NULL,
- N_("S_how Index"), "<control>I",
- N_("Toggle the visibility of the sidebar"),
- G_CALLBACK (show_index_callback), FALSE
- }
- };
+ /* Some files return mime types like application/x-extension-html,
+ * which is not supported by default */
+ webkit_policy_decision_use (decision);
+ return FALSE;
+}
- GtkUIManager *ui_manager = gtk_ui_manager_new ();
- GtkActionGroup *group = gtk_action_group_new ("Actions");
- GtkAction *action;
- GError *error = NULL;
+static gboolean
+webview_load_failed (WebKitWebView *webview,
+ WebKitLoadEvent load_event,
+ char *failing_uri,
+ GError *error,
+ gpointer user_data)
+{
+ g_warning ("Failed to load page: %s", error->message);
+ return TRUE;
+}
- gtk_action_group_set_translation_domain (group, NULL);
- gtk_action_group_add_actions (group,
- actions, G_N_ELEMENTS (actions),
- NULL);
- gtk_action_group_add_toggle_actions (group,
- toggle_actions,
- G_N_ELEMENTS (toggle_actions),
- NULL);
-
- action = gimp_throbber_action_new ("website",
- "docs.gimp.org",
- _("Visit the GIMP documentation website"),
- GIMP_ICON_HELP_USER_MANUAL);
- g_signal_connect_closure (action, "activate",
- g_cclosure_new (G_CALLBACK (website_callback),
- NULL, NULL),
- FALSE);
- gtk_action_group_add_action (group, action);
- g_object_unref (action);
-
- gtk_window_add_accel_group (GTK_WINDOW (window),
- gtk_ui_manager_get_accel_group (ui_manager));
- gtk_accel_group_lock (gtk_ui_manager_get_accel_group (ui_manager));
-
- gtk_ui_manager_insert_action_group (ui_manager, group, -1);
- g_object_unref (group);
-
- gtk_ui_manager_add_ui_from_string (ui_manager,
- "<ui>"
- " <toolbar name=\"help-browser-toolbar\">"
- " <toolitem action=\"reload\" />"
- " <toolitem action=\"stop\" />"
- " <toolitem action=\"home\" />"
- " <separator name=\"space\" />"
- " <toolitem action=\"website\" />"
- " </toolbar>"
- " <accelerator action=\"close\" />"
- " <accelerator action=\"quit\" />"
- "</ui>",
- -1, &error);
-
- if (error)
- {
- g_warning ("error parsing ui: %s", error->message);
- g_clear_error (&error);
- }
+static void
+webview_load_changed (WebKitWebView *webview,
+ WebKitLoadEvent event,
+ gpointer user_data)
+{
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ GAction *action;
- gtk_ui_manager_add_ui_from_string (ui_manager,
- "<ui>"
- " <popup name=\"help-browser-popup\">"
- " <menuitem action=\"back\" />"
- " <menuitem action=\"forward\" />"
- " <menuitem action=\"reload\" />"
- " <menuitem action=\"stop\" />"
- " <separator />"
- " <menuitem action=\"home\" />"
- " <menuitem action=\"copy-location\" />"
- " <menuitem action=\"show-index\" />"
- " <separator />"
- " <menuitem action=\"find\" />"
- " <menuitem action=\"find-again\" />"
- " <separator />"
- " <menuitem action=\"zoom-in\" />"
- " <menuitem action=\"zoom-out\" />"
- " <separator />"
- " <menuitem action=\"close\" />"
- " </popup>"
- "</ui>",
- -1, &error);
-
- if (error)
+ action = g_action_map_lookup_action (G_ACTION_MAP (self), "back");
+ switch (event)
{
- g_warning ("error parsing ui: %s", error->message);
- g_clear_error (&error);
- }
+ case WEBKIT_LOAD_STARTED:
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
+ break;
- gtk_ui_manager_add_ui_from_string (ui_manager,
- "<ui>"
- " <popup name=\"help-browser-copy-popup\">"
- " <menuitem action=\"copy-selection\" />"
- " </popup>"
- "</ui>",
- -1, &error);
+ case WEBKIT_LOAD_FINISHED:
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+ update_actions (self);
+ select_index (self, webkit_web_view_get_uri (webview));
+ break;
- if (error)
- {
- g_warning ("error parsing ui: %s", error->message);
- g_clear_error (&error);
+ case WEBKIT_LOAD_REDIRECTED:
+ case WEBKIT_LOAD_COMMITTED:
+ break;
}
-
- return ui_manager;
}
static void
-back_callback (GtkAction *action,
- gpointer data)
+row_activated (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer user_data)
{
- webkit_web_view_go_back (WEBKIT_WEB_VIEW (view));
-}
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GimpHelpDomain *domain;
+ GimpHelpLocale *locale;
+ GimpHelpItem *item;
+ char *uri;
+
+ model = gtk_tree_view_get_model (tree_view);
+ gtk_tree_model_get_iter (model, &iter, path);
-static void
-forward_callback (GtkAction *action,
- gpointer data)
-{
- webkit_web_view_go_forward (WEBKIT_WEB_VIEW (view));
-}
+ gtk_tree_model_get (model, &iter,
+ 0, &item,
+ -1);
-static void
-reload_callback (GtkAction *action,
- gpointer data)
-{
- webkit_web_view_reload (WEBKIT_WEB_VIEW (view));
-}
+ domain = g_object_get_data (G_OBJECT (model), "domain");
+ locale = g_object_get_data (G_OBJECT (model), "locale");
-static void
-stop_callback (GtkAction *action,
- gpointer data)
-{
- webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (view));
-}
+ uri = g_strconcat (domain->help_uri, "/",
+ locale->locale_id, "/",
+ item->ref,
+ NULL);
-static void
-home_callback (GtkAction *action,
- gpointer data)
-{
- GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
- GimpHelpDomain *domain = g_object_get_data (G_OBJECT (model), "domain");
- GimpHelpLocale *locale = g_object_get_data (G_OBJECT (model), "locale");
+ gimp_help_browser_dialog_load (self, uri);
- if (domain && locale)
- {
- gchar *uri = g_strconcat (domain->help_uri, "/",
- locale->locale_id, "/",
- gimp_help_locale_map (locale,
- GIMP_HELP_DEFAULT_ID),
- NULL);
- browser_dialog_load (uri);
- g_free (uri);
- }
+ g_free (uri);
}
static void
-find_callback (GtkAction *action,
- gpointer data)
+search_close_clicked (GtkWidget *button,
+ gpointer user_data)
{
- GtkWidget *entry = g_object_get_data (G_OBJECT (searchbar), "entry");
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ WebKitFindController *find_controller =
+ webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (self->webview));
+
+ gtk_widget_hide (self->searchbar);
- gtk_widget_show (searchbar);
- gtk_widget_grab_focus (entry);
+ webkit_find_controller_search_finish (find_controller);
}
static void
-find_again_callback (GtkAction *action,
- gpointer data)
+search_entry_changed (GtkWidget *search_entry,
+ gpointer user_data)
{
- GtkWidget *entry = g_object_get_data (G_OBJECT (searchbar), "entry");
-
- gtk_widget_show (searchbar);
- gtk_widget_grab_focus (entry);
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
- search (gtk_entry_get_text (GTK_ENTRY (entry)));
+ search (self, gtk_entry_get_text (GTK_ENTRY (search_entry)));
}
-static void
-copy_location_callback (GtkAction *action,
- gpointer data)
+static gboolean
+search_entry_key_press (GtkWidget *search_entry,
+ GdkEventKey *event,
+ gpointer user_data)
{
- const gchar *uri;
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ WebKitFindController *find_controller;
- uri = webkit_web_view_get_uri (WEBKIT_WEB_VIEW (view));
-
- if (uri)
+ find_controller = webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (self->webview));
+ switch (event->keyval)
{
- GtkClipboard *clipboard;
+ case GDK_KEY_Escape:
+ gtk_widget_hide (self->searchbar);
+ webkit_find_controller_search_finish (find_controller);
+ return TRUE;
- clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (view),
- GDK_SELECTION_CLIPBOARD);
- gtk_clipboard_set_text (clipboard, uri, -1);
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ case GDK_KEY_ISO_Enter:
+ search (self, gtk_entry_get_text (GTK_ENTRY (search_entry)));
+ return TRUE;
}
-}
-static void
-copy_selection_callback (GtkAction *action,
- gpointer data)
-{
- WebKitEditorState *editor_state =
- webkit_web_view_get_editor_state (WEBKIT_WEB_VIEW (view));
-
- if (webkit_editor_state_is_copy_available (editor_state))
- {
- webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (view),
- WEBKIT_EDITING_COMMAND_COPY);
- }
+ return FALSE;
}
static void
-show_index_callback (GtkAction *action,
- gpointer data)
+dialog_unmap (GtkWidget *window,
+ gpointer user_data)
{
- gtk_widget_set_visible (sidebar,
- gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
-}
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
+ DialogData data;
-static void
-zoom_in_callback (GtkAction *action,
- gpointer data)
-{
- gdouble zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (view));
- if (zoom_level < 10.0)
- webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (view), zoom_level + 0.1);
-}
+ gtk_window_get_size (GTK_WINDOW (window), &data.width, &data.height);
-static void
-zoom_out_callback (GtkAction *action,
- gpointer data)
-{
- gdouble zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (view));
- if (zoom_level > 0.1)
- webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (view), zoom_level - 0.1);
-}
+ data.paned_position = gtk_paned_get_position (GTK_PANED (self->paned));
+ data.show_index = gtk_widget_get_visible (self->sidebar);
-static void
-website_callback (GtkAction *action,
- gpointer data)
-{
- browser_dialog_load ("https://docs.gimp.org/");
-}
+ data.zoom = (self->webview ?
+ webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (self->webview)) : 1.0);
-static void
-close_callback (GtkAction *action,
- gpointer data)
-{
- gtk_widget_destroy (gtk_widget_get_toplevel (view));
+ gimp_set_data (GIMP_HELP_BROWSER_DIALOG_DATA, &data, sizeof (data));
}
static void
-menu_callback (GtkWidget *menu,
- gpointer data)
+add_tool_button (GtkWidget *toolbar,
+ const char *action,
+ const char *icon,
+ const char *label,
+ const char *tooltip)
{
- gint steps = GPOINTER_TO_INT (data);
+ GtkWidget *tool_icon;
+ GtkToolItem *tool_button;
- WebKitBackForwardList *back_fw_list =
- webkit_web_view_get_back_forward_list (WEBKIT_WEB_VIEW (view));
- WebKitBackForwardListItem *back_fw_list_item =
- webkit_back_forward_list_get_nth_item (back_fw_list, steps);
+ tool_icon = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_BUTTON);
+ gtk_widget_show (GTK_WIDGET (tool_icon));
+ tool_button = gtk_tool_button_new (tool_icon, label);
+ gtk_widget_show (GTK_WIDGET (tool_button));
+ gtk_tool_item_set_tooltip_text (tool_button, tooltip);
+ gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (tool_button), action);
- if (back_fw_list_item)
- webkit_web_view_go_to_back_forward_list_item (WEBKIT_WEB_VIEW (view),
- back_fw_list_item);
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_button, -1);
}
static GtkWidget *
-build_menu (const GList *items,
- gboolean back)
+build_searchbar (GimpHelpBrowserDialog *self)
{
- GtkWidget *menu;
- const GList *iter;
- gint steps;
+ GtkWidget *button;
+ GtkWidget *hbox;
+ GtkWidget *label;
- if (! items)
- return NULL;
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
- menu = gtk_menu_new ();
+ label = gtk_label_new (_("Find:"));
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- for (iter = items, steps = 1; iter; iter = g_list_next (iter), steps++)
- {
- WebKitBackForwardListItem *item = iter->data;
- const gchar *title;
+ self->search_entry = gtk_entry_new ();
+ gtk_widget_show (self->search_entry);
+ gtk_box_pack_start (GTK_BOX (hbox), self->search_entry, TRUE, TRUE, 0);
- title = webkit_back_forward_list_item_get_title (item);
+ g_signal_connect (self->search_entry, "changed",
+ G_CALLBACK (search_entry_changed),
+ self);
- if (title)
- {
- GtkWidget *menu_item = gtk_menu_item_new_with_label (title);
+ g_signal_connect (self->search_entry, "key-press-event",
+ G_CALLBACK (search_entry_key_press),
+ self);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
- gtk_widget_show (menu_item);
+ button = gtk_button_new_with_mnemonic (C_("search", "_Previous"));
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_button_set_image (GTK_BUTTON (button),
+ gtk_image_new_from_icon_name (GIMP_ICON_GO_PREVIOUS,
+ GTK_ICON_SIZE_BUTTON));
+ gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "win.search-previous");
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
- g_signal_connect (menu_item, "activate",
- G_CALLBACK (menu_callback),
- GINT_TO_POINTER (back ? - steps : steps));
- }
- }
+ button = gtk_button_new_with_mnemonic (C_("search", "_Next"));
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_button_set_image (GTK_BUTTON (button),
+ gtk_image_new_from_icon_name (GIMP_ICON_GO_NEXT,
+ GTK_ICON_SIZE_BUTTON));
+ gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "win.search-next");
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_mnemonic (C_("search", "_Close"));
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (search_close_clicked),
+ self);
- return menu;
+ return hbox;
}
static void
-update_actions (void)
+gimp_help_browser_dialog_init (GimpHelpBrowserDialog *self)
{
- GtkAction *action;
- WebKitBackForwardList *back_forward_list;
+ GtkWindow *window = GTK_WINDOW (self);
+ GtkWidget *vbox;
+ GtkWidget *toolbar;
+ GtkBuilder *builder;
+ GtkToolItem *item;
+ GtkWidget *main_vbox;
+ WebKitSettings *settings;
- back_forward_list =
- webkit_web_view_get_back_forward_list (WEBKIT_WEB_VIEW (view));
+ /* the dialog window */
+ gtk_window_set_title (GTK_WINDOW (window), _("GIMP Help Browser"));
+ gtk_window_set_icon_name (GTK_WINDOW (window), GIMP_ICON_HELP_USER_MANUAL);
- /* update the back button and its menu */
+ g_action_map_add_action_entries (G_ACTION_MAP (self),
+ ACTIONS, G_N_ELEMENTS (ACTIONS),
+ self);
- action = gtk_ui_manager_get_action (ui_manager,
- "/ui/help-browser-popup/back");
- gtk_action_set_sensitive (action,
- webkit_web_view_can_go_back (WEBKIT_WEB_VIEW (view)));
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+ gtk_widget_show (vbox);
- if (back_forward_list)
- {
- const GList *list;
+ /* Toolbar */
+ toolbar = gtk_toolbar_new ();
- list = webkit_back_forward_list_get_back_list_with_limit (back_forward_list,
- 12);
- gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (button_prev),
- build_menu (list, TRUE));
- }
- else
- {
- gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (button_prev), NULL);
- }
+ add_tool_button (toolbar, "win.reload", GIMP_ICON_VIEW_REFRESH, _("_Reload"), _("Reload current page"));
+ add_tool_button (toolbar, "win.stop", GIMP_ICON_PROCESS_STOP, _("_Stop"), _("Stop loading this page"));
+ add_tool_button (toolbar, "win.home", GIMP_ICON_GO_HOME, NULL, _("Go to the index page"));
+ item = gtk_separator_tool_item_new ();
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
+ gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (item), FALSE);
+ gtk_tool_item_set_expand (item, TRUE);
+ gtk_widget_show (GTK_WIDGET (item));
+ add_tool_button (toolbar, "win.load-uri('https://docs.gimp.org')", GIMP_ICON_HELP_USER_MANUAL,
"docs.gimp.org", _("Visit the GIMP documentation website"));
- /* update the forward button and its menu */
+ item = gtk_menu_tool_button_new (gtk_image_new_from_icon_name (GIMP_ICON_GO_NEXT, GTK_ICON_SIZE_BUTTON),
NULL);
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0);
+ gtk_widget_show (GTK_WIDGET (item));
+ gtk_actionable_set_action_name (GTK_ACTIONABLE (item), "win.forward");
+ self->button_next = GTK_WIDGET (item);
- action = gtk_ui_manager_get_action (ui_manager,
- "/ui/help-browser-popup/forward");
- gtk_action_set_sensitive (action,
- webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW (view)));
+ item = gtk_menu_tool_button_new (gtk_image_new_from_icon_name (GIMP_ICON_GO_PREVIOUS,
GTK_ICON_SIZE_BUTTON), NULL);
+ gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0);
+ gtk_widget_show (GTK_WIDGET (item));
+ gtk_actionable_set_action_name (GTK_ACTIONABLE (item), "win.back");
+ self->button_prev = GTK_WIDGET (item);
- if (back_forward_list)
- {
- const GList *list;
-
- list = webkit_back_forward_list_get_forward_list_with_limit (back_forward_list,
- 12);
- gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (button_next),
- build_menu (list, FALSE));
- }
- else
- {
- gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (button_next), NULL);
- }
+ gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
+ gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
+ gtk_widget_show (toolbar);
- /* update the copy-location action */
- action = gtk_ui_manager_get_action (ui_manager,
- "/ui/help-browser-popup/copy-location");
+ /* Context menu */
+ builder = gtk_builder_new_from_string (
+ "<interface>"
+ "<menu id=\"help_browser_popup_menu\">"
+ "<section>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">_Back</attribute>"
+ "<attribute name=\"action\">win.back</attribute>"
+ "</item>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">_Previous</attribute>"
+ "<attribute name=\"action\">win.forward</attribute>"
+ "</item>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">_Reload</attribute>"
+ "<attribute name=\"action\">win.reload</attribute>"
+ "</item>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">_Stop</attribute>"
+ "<attribute name=\"action\">win.stop</attribute>"
+ "</item>"
+ "</section>"
+ "<section>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">_Home</attribute>"
+ "<attribute name=\"action\">win.home</attribute>"
+ "</item>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">C_opy location</attribute>"
+ "<attribute name=\"action\">win.copy-location</attribute>"
+ "</item>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">S_how index</attribute>"
+ "<attribute name=\"action\">win.show-index</attribute>"
+ "</item>"
+ "</section>"
+ "<section>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">Find</attribute>"
+ "<attribute name=\"action\">win.find</attribute>"
+ "</item>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">Find _Again</attribute>"
+ "<attribute name=\"action\">win.find-again</attribute>"
+ "</item>"
+ "</section>"
+ "<section>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">Zoom in</attribute>"
+ "<attribute name=\"action\">win.zoom-in</attribute>"
+ "</item>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">Zoom out</attribute>"
+ "<attribute name=\"action\">win.zoom-out</attribute>"
+ "</item>"
+ "</section>"
+ "<section>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">Close</attribute>"
+ "<attribute name=\"action\">win.close</attribute>"
+ "</item>"
+ "</section>"
+ "</menu>"
+ "<menu id=\"help_browser_copy_popup_menu\">"
+ "<section>"
+ "<item>"
+ "<attribute name=\"label\" translatable=\"yes\">Copy selection</attribute>"
+ "<attribute name=\"action\">win.copy-selection</attribute>"
+ "</item>"
+ "</section>"
+ "</menu>"
+ "</interface>",
+ -1);
+ self->popup_menu_model = G_MENU_MODEL (gtk_builder_get_object (builder, "help_browser_popup_menu"));
+ g_object_ref (self->popup_menu_model);
+ self->copy_popup_menu_model = G_MENU_MODEL (gtk_builder_get_object (builder,
"help_browser_copy_popup_menu"));
+ g_object_ref (self->copy_popup_menu_model);
+ g_object_unref (builder);
- gtk_action_set_sensitive (action, webkit_web_view_get_uri (WEBKIT_WEB_VIEW (view)) != NULL);
+ /* the horizontal paned */
+ self->paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_box_pack_start (GTK_BOX (vbox), self->paned, TRUE, TRUE, 0);
+ gtk_widget_show (self->paned);
- /* update the show-index action */
- action = gtk_ui_manager_get_action (ui_manager,
- "/ui/help-browser-popup/show-index");
- gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
- gtk_widget_get_visible (sidebar));
-}
+ self->sidebar = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->sidebar),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_paned_add1 (GTK_PANED (self->paned), self->sidebar);
-static void
-row_activated (GtkTreeView *tree_view,
- GtkTreePath *path,
- GtkTreeViewColumn *column)
-{
- GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
- GtkTreeIter iter;
- GimpHelpDomain *domain;
- GimpHelpLocale *locale;
- GimpHelpItem *item;
- gchar *uri;
+ self->tree_view = gtk_tree_view_new ();
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self->tree_view), FALSE);
+ gtk_container_add (GTK_CONTAINER (self->sidebar), self->tree_view);
+ gtk_widget_show (self->tree_view);
- gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->tree_view), -1,
+ NULL,
+ gtk_cell_renderer_text_new (),
+ "text", 1,
+ NULL);
- gtk_tree_model_get (model, &iter,
- 0, &item,
- -1);
+ g_signal_connect (self->tree_view, "row-activated",
+ G_CALLBACK (row_activated),
+ self);
- domain = g_object_get_data (G_OBJECT (model), "domain");
- locale = g_object_get_data (G_OBJECT (model), "locale");
+ /* HTML webview */
+ main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_widget_show (main_vbox);
+ gtk_paned_pack2 (GTK_PANED (self->paned), main_vbox, TRUE, TRUE);
+
+ settings = webkit_settings_new_with_settings ("default-charset", "utf-8",
+ NULL);
+ self->webview = webkit_web_view_new_with_settings (settings);
+ g_object_unref (settings);
+
+ gtk_widget_set_size_request (self->webview, 300, 200);
+ gtk_widget_show (self->webview);
+
+ gtk_box_pack_start (GTK_BOX (main_vbox), self->webview, TRUE, TRUE, 0);
+
+ g_signal_connect (self->webview, "realize",
+ G_CALLBACK (webview_realize),
+ self);
+ g_signal_connect (self->webview, "unrealize",
+ G_CALLBACK (webview_unrealize),
+ self);
+ g_signal_connect (self->webview, "popup-menu",
+ G_CALLBACK (webview_popup_menu),
+ self);
+ g_signal_connect (self->webview, "button-press-event",
+ G_CALLBACK (webview_button_press),
+ self);
+ g_signal_connect (self->webview, "key-press-event",
+ G_CALLBACK (webview_key_press),
+ self);
+ g_signal_connect (self->webview, "notify::title",
+ G_CALLBACK (webview_title_changed),
+ self);
+ g_signal_connect (self->webview, "load-changed",
+ G_CALLBACK (webview_load_changed),
+ self);
+ g_signal_connect (self->webview, "load-failed",
+ G_CALLBACK (webview_load_failed),
+ self);
+ g_signal_connect (self->webview, "decide-policy",
+ G_CALLBACK (webview_decide_policy),
+ self);
+
+ gtk_widget_grab_focus (self->webview);
- uri = g_strconcat (domain->help_uri, "/",
- locale->locale_id, "/",
- item->ref,
- NULL);
+ g_signal_connect (window, "unmap",
+ G_CALLBACK (dialog_unmap),
+ self);
- browser_dialog_load (uri);
+ update_actions (self);
- g_free (uri);
+ /* Searchbar */
+ self->searchbar = build_searchbar (self);
+ gtk_box_pack_start (GTK_BOX (main_vbox), self->searchbar, FALSE, FALSE, 0);
}
static void
-dialog_unmap (GtkWidget *window,
- GtkWidget *paned)
+gimp_help_browser_dialog_finalize (GObject *object)
{
- DialogData data;
-
- gtk_window_get_size (GTK_WINDOW (window), &data.width, &data.height);
-
- data.paned_position = gtk_paned_get_position (GTK_PANED (paned));
- data.show_index = gtk_widget_get_visible (sidebar);
+ GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (object);
- data.zoom = (view ?
- webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (view)) : 1.0);
+ g_clear_pointer (&self->uri_hash_table, g_hash_table_unref);
+ g_clear_object (&self->popup_menu_model);
+ g_clear_object (&self->copy_popup_menu_model);
- gimp_set_data (GIMP_HELP_BROWSER_DIALOG_DATA, &data, sizeof (data));
-
- gtk_main_quit ();
+ G_OBJECT_CLASS (gimp_help_browser_dialog_parent_class)->finalize (object);
}
static void
-view_realize (GtkWidget *widget)
+gimp_help_browser_dialog_class_init (GimpHelpBrowserDialogClass *klass)
{
- g_return_if_fail (busy_cursor == NULL);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
- busy_cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
- GDK_WATCH);
-}
-
-static void
-view_unrealize (GtkWidget *widget)
-{
- if (busy_cursor)
- {
- g_object_unref (busy_cursor);
- busy_cursor = NULL;
- }
+ object_class->finalize = gimp_help_browser_dialog_finalize;
}
-static gboolean
-view_popup_menu (GtkWidget *widget,
- GdkEventButton *event)
+GimpHelpBrowserDialog *
+gimp_help_browser_dialog_new (const gchar *plug_in_binary, GApplication *app)
{
- GtkWidget *menu;
- const gchar *path;
-
- WebKitEditorState *editor_state =
- webkit_web_view_get_editor_state (WEBKIT_WEB_VIEW (view));
+ GimpHelpBrowserDialog *window;
+ DialogData data = { 720, 560, 240, TRUE, 1.0 };
- if (webkit_editor_state_is_copy_available (editor_state))
- path = "/help-browser-copy-popup";
- else
- path = "/help-browser-popup";
+ gimp_ui_init (plug_in_binary);
- menu = gtk_ui_manager_get_widget (ui_manager, path);
+ gimp_get_data (GIMP_HELP_BROWSER_DIALOG_DATA, &data);
- gtk_menu_set_screen (GTK_MENU (menu), gtk_widget_get_screen (widget));
- gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *) event);
+ window = g_object_new (GIMP_TYPE_HELP_BROWSER_DIALOG,
+ "application", app,
+ "role", plug_in_binary,
+ "default-width", data.width,
+ "default-height", data.height,
+ NULL);
+ gtk_paned_set_position (GTK_PANED (window->paned), data.paned_position);
+ if (data.show_index)
+ gtk_widget_show (window->sidebar);
+ webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (window->webview), data.zoom);
- return TRUE;
+ return GTK_WINDOW (window);
}
-static gboolean
-view_button_press (GtkWidget *widget,
- GdkEventButton *event)
+void
+gimp_help_browser_dialog_load (GimpHelpBrowserDialog *self,
+ const char *uri)
{
- if (gdk_event_triggers_context_menu ((GdkEvent *) event))
- return view_popup_menu (widget, event);
+ g_return_if_fail (uri && *uri);
- return FALSE;
+ webkit_web_view_load_uri (WEBKIT_WEB_VIEW (self->webview), uri);
+
+ select_index (self, uri);
+
+ gtk_window_present (GTK_WINDOW (gtk_widget_get_toplevel (self->webview)));
}
-static gboolean
-view_key_press (GtkWidget *widget,
- GdkEventKey *event)
+static void
+browser_dialog_make_index_foreach (const gchar *help_id,
+ GimpHelpItem *item,
+ GimpHelpLocale *locale)
{
- if (event->keyval == GDK_KEY_slash)
- {
- GtkAction *action;
+ gchar *sort_key = item->title;
+
+#if DEBUG_SORT_HELP_ITEMS
+ g_printerr ("%s: processing %s (parent %s)\n",
+ G_STRFUNC,
+ item->title ? item->title : "NULL",
+ item->parent ? item->parent : "NULL");
+#endif
- action = gtk_ui_manager_get_action (ui_manager,
- "/ui/help-browser-popup/find");
- gtk_action_activate (action);
+ if (item->sort &&
+ g_regex_match_simple ("^[0-9]+([.][0-9]+)*$", item->sort, 0, 0))
+ {
+ sort_key = item->sort;
- return TRUE;
+#if DEBUG_SORT_HELP_ITEMS
+ g_printerr ("%s: sort key = %s\n", G_STRFUNC, sort_key);
+#endif
}
- return FALSE;
-}
+ item->index = 0;
-static void
-title_changed (WebKitWebView *view,
- GParamSpec *pspec,
- GtkWidget *window)
-{
- gchar *full_title;
+ if (sort_key)
+ {
+ int max_tokens = GIMP_HELP_BROWSER_INDEX_MAX_DEPTH;
+ char **indices = g_strsplit (sort_key, ".", max_tokens + 1);
+ int i;
- const char *title = webkit_web_view_get_title (view);
- full_title = g_strdup_printf ("%s - %s",
- title ? title : _("Untitled"),
- _("GIMP Help Browser"));
+ for (i = 0; i < max_tokens; i++)
+ {
+ gunichar c;
- gtk_window_set_title (GTK_WINDOW (window), full_title);
- g_free (full_title);
+ if (! indices[i])
+ {
+ /* make sure that all item->index's are comparable */
+ item->index <<= (8 * (max_tokens - i));
+ break;
+ }
- update_actions ();
-}
+ item->index <<= 8; /* NOP if i = 0 */
+ c = g_utf8_get_char (indices[i]);
+ if (g_unichar_isdigit (c))
+ {
+ item->index += atoi (indices[i]);
+ }
+ else if (g_utf8_strlen (indices[i], -1) == 1)
+ {
+ item->index += (c & 0xFF);
+ }
+ }
-static void
-load_changed (WebKitWebView *view,
- WebKitLoadEvent event)
-{
- GtkAction *action = gtk_ui_manager_get_action (ui_manager,
- "/ui/help-browser-popup/stop");
- switch (event)
+ g_strfreev (indices);
+
+#if DEBUG_SORT_HELP_ITEMS
+ g_printerr ("%s: index = %lu\n", G_STRFUNC, item->index);
+#endif
+ }
+
+ if (item->parent && strlen (item->parent))
{
- case WEBKIT_LOAD_STARTED:
- gtk_action_set_sensitive (action, TRUE);
- break;
+ GimpHelpItem *parent;
- case WEBKIT_LOAD_FINISHED:
- gtk_action_set_sensitive (action, FALSE);
- update_actions ();
- select_index (webkit_web_view_get_uri (view));
- break;
+ parent = g_hash_table_lookup (locale->help_id_mapping, item->parent);
- case WEBKIT_LOAD_REDIRECTED:
- case WEBKIT_LOAD_COMMITTED:
- break;
+ if (parent)
+ {
+ parent->children = g_list_prepend (parent->children, item);
+ }
+ }
+ else
+ {
+ locale->toplevel_items = g_list_prepend (locale->toplevel_items, item);
}
}
-static GtkWidget *
-build_searchbar (void)
+static gint
+help_item_compare (gconstpointer a,
+ gconstpointer b)
{
- GtkWidget *button;
- GtkWidget *entry;
- GtkWidget *hbox;
- GtkWidget *label;
-
- hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
-
- label = gtk_label_new (_("Find:"));
- gtk_widget_show (label);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ const GimpHelpItem *item_a = a;
+ const GimpHelpItem *item_b = b;
- entry = gtk_entry_new ();
- gtk_widget_show (entry);
- gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
- g_object_set_data (G_OBJECT (hbox), "entry", entry);
+ if (item_a->index > item_b->index)
+ return 1;
+ else if (item_a->index < item_b->index)
+ return -1;
- g_signal_connect (entry, "changed",
- G_CALLBACK (search_entry_changed),
- NULL);
+ return 0;
+}
- g_signal_connect (entry, "key-press-event",
- G_CALLBACK (search_entry_key_press),
- NULL);
+static void
+add_child (GimpHelpBrowserDialog *self,
+ GtkTreeStore *store,
+ GimpHelpDomain *domain,
+ GimpHelpLocale *locale,
+ GtkTreeIter *parent,
+ GimpHelpItem *item,
+ int depth)
+{
+ GtkTreeIter iter;
+ char *uri;
- button = gtk_button_new_with_mnemonic (C_("search", "_Previous"));
- gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
- gtk_button_set_image (GTK_BUTTON (button),
- gtk_image_new_from_icon_name (GIMP_ICON_GO_PREVIOUS,
- GTK_ICON_SIZE_BUTTON));
- gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- gtk_widget_show (button);
+ gtk_tree_store_append (store, &iter, parent);
- g_signal_connect (button, "clicked",
- G_CALLBACK (search_prev_clicked),
- entry);
+ gtk_tree_store_set (store, &iter,
+ 0, item,
+ 1, item->title,
+ -1);
- button = gtk_button_new_with_mnemonic (C_("search", "_Next"));
- gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
- gtk_button_set_image (GTK_BUTTON (button),
- gtk_image_new_from_icon_name (GIMP_ICON_GO_NEXT,
- GTK_ICON_SIZE_BUTTON));
- gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- gtk_widget_show (button);
+ uri = g_strconcat (domain->help_uri, "/",
+ locale->locale_id, "/",
+ item->ref,
+ NULL);
- g_signal_connect (button, "clicked",
- G_CALLBACK (search_next_clicked),
- entry);
+ g_hash_table_insert (self->uri_hash_table,
+ uri,
+ gtk_tree_iter_copy (&iter));
- button = gtk_button_new_with_mnemonic (C_("search", "_Close"));
- gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
- gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- gtk_widget_show (button);
+ if (depth + 1 == GIMP_HELP_BROWSER_INDEX_MAX_DEPTH)
+ return;
- g_signal_connect (button, "clicked",
- G_CALLBACK (search_close_clicked),
- NULL);
+ item->children = g_list_sort (item->children, help_item_compare);
- return hbox;
-}
+ for (GList *list = item->children; list; list = g_list_next (list))
+ {
+ GimpHelpItem *item = list->data;
-static void
-search_entry_changed (GtkWidget *entry)
-{
- search (gtk_entry_get_text (GTK_ENTRY (entry)));
+ add_child (self, store, domain, locale, &iter, item, depth + 1);
+ }
}
-static gboolean
-search_entry_key_press (GtkWidget *entry,
- GdkEventKey *event)
+void
+gimp_help_browser_dialog_make_index (GimpHelpBrowserDialog *self,
+ GimpHelpDomain *domain,
+ GimpHelpLocale *locale)
{
- WebKitFindController *find_controller =
- webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (view));
+ GtkTreeStore *store;
+ GList *list;
- switch (event->keyval)
+ if (! locale->toplevel_items)
{
- case GDK_KEY_Escape:
- gtk_widget_hide (searchbar);
- webkit_find_controller_search_finish (find_controller);
- return TRUE;
+ g_hash_table_foreach (locale->help_id_mapping,
+ (GHFunc) browser_dialog_make_index_foreach,
+ locale);
- case GDK_KEY_Return:
- case GDK_KEY_KP_Enter:
- case GDK_KEY_ISO_Enter:
- search (gtk_entry_get_text (GTK_ENTRY (entry)));
- return TRUE;
+ locale->toplevel_items = g_list_sort (locale->toplevel_items,
+ help_item_compare);
}
- return FALSE;
-}
+ store = gtk_tree_store_new (2,
+ G_TYPE_POINTER,
+ G_TYPE_STRING);
-static void
-search_prev_clicked (GtkWidget *button,
- GtkWidget *entry)
-{
- WebKitFindController *find_controller =
- webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (view));
- webkit_find_controller_search_previous (find_controller);
-}
+ g_object_set_data (G_OBJECT (store), "domain", domain);
+ g_object_set_data (G_OBJECT (store), "locale", locale);
-static void
-search_next_clicked (GtkWidget *button,
- GtkWidget *entry)
-{
- WebKitFindController *find_controller =
- webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (view));
- webkit_find_controller_search_next (find_controller);
-}
+ if (self->uri_hash_table)
+ g_hash_table_unref (self->uri_hash_table);
-static void
-search (const gchar *text)
-{
- WebKitFindController *find_controller =
- webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (view));
- if (text)
- {
- const char *prev_text =
- webkit_find_controller_get_search_text (find_controller);
+ self->uri_hash_table = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) gtk_tree_iter_free);
- /* The previous search, if any, may need to be canceled. */
- if (prev_text && strcmp (text, prev_text) != 0)
- webkit_find_controller_search_finish (find_controller);
+ for (list = locale->toplevel_items; list; list = g_list_next (list))
+ {
+ GimpHelpItem *item = list->data;
- webkit_find_controller_search (find_controller,
- text,
- WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE |
- WEBKIT_FIND_OPTIONS_WRAP_AROUND,
- G_MAXUINT);
+ add_child (self, store, domain, locale, NULL, item, 0);
}
- else
- webkit_find_controller_search_finish (find_controller);
-}
-static void
-search_close_clicked (GtkWidget *button)
-{
- WebKitFindController *find_controller =
- webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (view));
-
- gtk_widget_hide (searchbar);
-
- webkit_find_controller_search_finish (find_controller);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (self->tree_view), GTK_TREE_MODEL (store));
+ g_object_unref (store);
}
diff --git a/plug-ins/help-browser/dialog.h b/plug-ins/help-browser/dialog.h
index a895af9493..1f3adc43bf 100644
--- a/plug-ins/help-browser/dialog.h
+++ b/plug-ins/help-browser/dialog.h
@@ -24,12 +24,21 @@
#ifndef __DIALOG_H__
#define __DIALOG_H__
+#include <gtk/gtk.h>
-void browser_dialog_open (const gchar *plug_in_binary);
-void browser_dialog_load (const gchar *uri);
+#define GIMP_TYPE_HELP_BROWSER_DIALOG (gimp_help_browser_dialog_get_type ())
+G_DECLARE_FINAL_TYPE (GimpHelpBrowserDialog, gimp_help_browser_dialog,
+ GIMP, HELP_BROWSER_DIALOG,
+ GtkApplicationWindow)
-void browser_dialog_make_index (GimpHelpDomain *domain,
- GimpHelpLocale *locale);
+GimpHelpBrowserDialog * gimp_help_browser_dialog_new (const char *plug_in_binary,
+ GApplication *app);
+void gimp_help_browser_dialog_load (GimpHelpBrowserDialog *self,
+ const char *uri);
+
+void gimp_help_browser_dialog_make_index (GimpHelpBrowserDialog *self,
+ GimpHelpDomain *domain,
+ GimpHelpLocale *locale);
#endif /* ! __DIALOG_H__ */
diff --git a/plug-ins/help-browser/help-browser.c b/plug-ins/help-browser/help-browser.c
index be00b00c98..66a6f3b7c9 100644
--- a/plug-ins/help-browser/help-browser.c
+++ b/plug-ins/help-browser/help-browser.c
@@ -42,28 +42,10 @@
#define PLUG_IN_ROLE "gimp-help-browser"
-typedef struct _HelpBrowser HelpBrowser;
-typedef struct _HelpBrowserClass HelpBrowserClass;
-
-struct _HelpBrowser
-{
- GimpPlugIn parent_instance;
-};
-
-struct _HelpBrowserClass
-{
- GimpPlugInClass parent_class;
-};
-
-
-#define HELP_BROWSER_TYPE (help_browser_get_type ())
-#define HELP_BROWSER (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), HELP_BROWSER_TYPE, HelpBrowser))
-
-GType help_browser_get_type (void) G_GNUC_CONST;
-
-static GList * help_browser_query_procedures (GimpPlugIn *plug_in);
-static GimpProcedure * help_browser_create_procedure (GimpPlugIn *plug_in,
- const gchar *name);
+#define GIMP_TYPE_HELP_BROWSER (gimp_help_browser_get_type ())
+G_DECLARE_FINAL_TYPE (GimpHelpBrowser, gimp_help_browser,
+ GIMP, HELP_BROWSER,
+ GimpPlugIn)
static GimpValueArray * help_browser_run (GimpProcedure *procedure,
const GimpValueArray *args,
@@ -74,32 +56,19 @@ static GimpValueArray * temp_proc_run (GimpProcedure *pro
const GimpValueArray *args,
gpointer run_data);
-static gboolean help_browser_show_help (const gchar *help_domain,
- const gchar *help_locales,
- const gchar *help_id);
-
static GimpHelpProgress * help_browser_progress_new (void);
-
-
-G_DEFINE_TYPE (HelpBrowser, help_browser, GIMP_TYPE_PLUG_IN)
-
-GIMP_MAIN (HELP_BROWSER_TYPE)
-
-
-static void
-help_browser_class_init (HelpBrowserClass *klass)
+struct _GimpHelpBrowser
{
- GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
+ GimpPlugIn parent_instance;
- plug_in_class->query_procedures = help_browser_query_procedures;
- plug_in_class->create_procedure = help_browser_create_procedure;
-}
+ GtkApplication *app;
+ GimpHelpBrowserDialog *window;
+};
-static void
-help_browser_init (HelpBrowser *help_browser)
-{
-}
+G_DEFINE_TYPE (GimpHelpBrowser, gimp_help_browser, GIMP_TYPE_PLUG_IN)
+
+GIMP_MAIN (GIMP_TYPE_HELP_BROWSER)
static GList *
help_browser_query_procedures (GimpPlugIn *plug_in)
@@ -117,7 +86,7 @@ help_browser_create_procedure (GimpPlugIn *plug_in,
{
procedure = gimp_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_EXTENSION,
- help_browser_run, NULL, NULL);
+ help_browser_run, plug_in, NULL);
gimp_procedure_set_documentation (procedure,
"Browse the GIMP user manual",
@@ -166,11 +135,35 @@ help_browser_create_procedure (GimpPlugIn *plug_in,
return procedure;
}
+static void
+on_app_activate (GApplication *gapp, gpointer user_data)
+{
+ GimpHelpBrowser *browser = GIMP_HELP_BROWSER (user_data);
+ GtkApplication *app = GTK_APPLICATION (gapp);
+
+ browser->window = gimp_help_browser_dialog_new (PLUG_IN_BINARY, gapp);
+
+ 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 GimpValueArray *
help_browser_run (GimpProcedure *procedure,
const GimpValueArray *args,
- gpointer run_data)
+ gpointer user_data)
{
+ GimpHelpBrowser *browser = GIMP_HELP_BROWSER (user_data);
+
INIT_I18N ();
if (! gimp_help_init (GIMP_VALUES_GET_INT (args, 1),
@@ -183,14 +176,17 @@ help_browser_run (GimpProcedure *procedure,
NULL);
}
- browser_dialog_open (PLUG_IN_BINARY);
-
temp_proc_install (gimp_procedure_get_plug_in (procedure));
gimp_procedure_extension_ready (procedure);
gimp_plug_in_extension_enable (gimp_procedure_get_plug_in (procedure));
- gtk_main ();
+ browser->app = gtk_application_new (NULL, G_APPLICATION_FLAGS_NONE);
+ 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 gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL);
}
@@ -202,7 +198,7 @@ temp_proc_install (GimpPlugIn *plug_in)
procedure = gimp_procedure_new (plug_in, GIMP_HELP_BROWSER_TEMP_EXT_PROC,
GIMP_PDB_PROC_TYPE_TEMPORARY,
- temp_proc_run, NULL, NULL);
+ temp_proc_run, plug_in, NULL);
gimp_procedure_set_documentation (procedure,
"DON'T USE THIS ONE",
@@ -238,81 +234,94 @@ temp_proc_install (GimpPlugIn *plug_in)
g_object_unref (procedure);
}
-static GimpValueArray *
-temp_proc_run (GimpProcedure *procedure,
- const GimpValueArray *args,
- gpointer run_data)
+typedef struct _IdleClosure
{
- const gchar *help_domain = GIMP_HELP_DEFAULT_DOMAIN;
- const gchar *help_locales = NULL;
- const gchar *help_id = GIMP_HELP_DEFAULT_ID;
- const gchar *string;
-
- string = GIMP_VALUES_GET_STRING (args, 0);
- if (string && strlen (string))
- help_domain = string;
-
- string = GIMP_VALUES_GET_STRING (args, 1);
- if (string && strlen (string))
- help_locales = string;
+ GimpHelpBrowser *browser;
+ char *help_domain;
+ char *help_locales;
+ char *help_id;
+} IdleClosure;
- string = GIMP_VALUES_GET_STRING (args, 2);
- if (string && strlen (string))
- help_id = string;
-
- if (! help_browser_show_help (help_domain, help_locales, help_id))
- {
- gtk_main_quit ();
- }
+static void
+idle_closure_free (gpointer data)
+{
+ IdleClosure *closure = data;
- return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL);
+ g_free (closure->help_domain);
+ g_free (closure->help_locales);
+ g_free (closure->help_id);
+ g_free (closure);
}
static gboolean
-help_browser_show_help (const gchar *help_domain,
- const gchar *help_locales,
- const gchar *help_id)
+show_help_on_idle (gpointer user_data)
{
- GimpHelpDomain *domain;
- gboolean success = TRUE;
+ IdleClosure *closure = user_data;
+ GimpHelpDomain *domain;
+ GimpHelpProgress *progress = NULL;
+ GimpHelpLocale *locale;
+ GList *locales;
+ char *uri;
+ gboolean fatal_error;
- domain = gimp_help_lookup_domain (help_domain);
+ /* First get the URI to load */
+ domain = gimp_help_lookup_domain (closure->help_domain);
+ if (!domain)
+ return G_SOURCE_REMOVE;
- if (domain)
+ locales = gimp_help_parse_locales (closure->help_locales);
+
+ if (! g_str_has_prefix (domain->help_uri, "file:"))
+ progress = help_browser_progress_new ();
+
+ uri = gimp_help_domain_map (domain, locales, closure->help_id,
+ progress, &locale, &fatal_error);
+
+ if (progress)
+ gimp_help_progress_free (progress);
+
+ g_list_free_full (locales, (GDestroyNotify) g_free);
+
+ /* Now actually load it */
+ if (uri)
{
- GimpHelpProgress *progress = NULL;
- GimpHelpLocale *locale;
- GList *locales;
- gchar *uri;
- gboolean fatal_error;
+ gimp_help_browser_dialog_make_index (closure->browser->window, domain, locale);
+ gimp_help_browser_dialog_load (closure->browser->window, uri);
- locales = gimp_help_parse_locales (help_locales);
+ g_free (uri);
+ }
- if (! g_str_has_prefix (domain->help_uri, "file:"))
- progress = help_browser_progress_new ();
+ return G_SOURCE_REMOVE;
+}
- uri = gimp_help_domain_map (domain, locales, help_id,
- progress, &locale, &fatal_error);
+static GimpValueArray *
+temp_proc_run (GimpProcedure *procedure,
+ const GimpValueArray *args,
+ gpointer user_data)
+{
+ GimpHelpBrowser *browser = GIMP_HELP_BROWSER (user_data);
+ IdleClosure *closure;
+ const char *str;
- if (progress)
- gimp_help_progress_free (progress);
+ closure = g_new0 (IdleClosure, 1);
+ closure->browser = browser;
- g_list_free_full (locales, (GDestroyNotify) g_free);
+ str = GIMP_VALUES_GET_STRING (args, 0);
+ closure->help_domain = g_strdup ((str && *str)? str : GIMP_HELP_DEFAULT_DOMAIN);
- if (uri)
- {
- browser_dialog_make_index (domain, locale);
- browser_dialog_load (uri);
+ str = GIMP_VALUES_GET_STRING (args, 1);
+ if (str && *str)
+ closure->help_locales = g_strdup (str);
- g_free (uri);
- }
- else if (fatal_error)
- {
- success = FALSE;
- }
- }
+ str = GIMP_VALUES_GET_STRING (args, 2);
+ closure->help_id = g_strdup ((str && *str)? str : GIMP_HELP_DEFAULT_ID);
- return success;
+ /* 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 gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL);
}
@@ -349,3 +358,17 @@ help_browser_progress_new (void)
return gimp_help_progress_new (&vtable, NULL);
}
+
+static void
+gimp_help_browser_class_init (GimpHelpBrowserClass *klass)
+{
+ GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
+
+ plug_in_class->query_procedures = help_browser_query_procedures;
+ plug_in_class->create_procedure = help_browser_create_procedure;
+}
+
+static void
+gimp_help_browser_init (GimpHelpBrowser *help_browser)
+{
+}
diff --git a/plug-ins/help-browser/meson.build b/plug-ins/help-browser/meson.build
index a801f400ce..d4378c5f75 100644
--- a/plug-ins/help-browser/meson.build
+++ b/plug-ins/help-browser/meson.build
@@ -4,8 +4,6 @@ plugin_name = 'help-browser'
plugin_sources = [
'dialog.c',
- 'gimpthrobber.c',
- 'gimpthrobberaction.c',
'help-browser.c',
'uri.c',
]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]