[gimp/nielsdg/help-browser-dialog-gtk-actions: 5/5] help-browser: Rewrite without GtkAction




commit 814c7fc4beec08b2f612123d7b259e7c655fa8b1
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]