dialog.c 37.9 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * GIMP Help Browser
5
 * Copyright (C) 1999-2008 Sven Neumann <sven@gimp.org>
6
 *                         Michael Natterer <mitch@gimp.org>
7
 *                         Róman Joost <romanofski@gimp.org>
8 9 10
 *
 * dialog.c
 *
11
 * This program is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 3 of the License, or
14 15 16 17 18 19 20 21
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 24 25 26
 */

#include "config.h"

27
#include <stdlib.h>
28
#include <string.h>
29

30
#include <gtk/gtk.h>
31

32 33
#include <gdk/gdkkeysyms.h>

34
#include <webkit/webkit.h>
35 36 37 38

#include "libgimp/gimp.h"
#include "libgimp/gimpui.h"

39 40
#include "plug-ins/help/gimphelp.h"

41 42 43
#include "gimpthrobber.h"
#include "gimpthrobberaction.h"

44 45 46 47 48 49
#include "dialog.h"
#include "uri.h"

#include "libgimp/stdplugins-intl.h"


50 51 52 53
#define GIMP_HELP_BROWSER_DIALOG_DATA      "gimp-help-browser-dialog"

#define GIMP_HELP_BROWSER_INDEX_MAX_DEPTH  4

54 55 56

typedef struct
{
57 58 59 60 61
  gint      width;
  gint      height;
  gint      paned_position;
  gboolean  show_index;
  gdouble   zoom;
62 63
} DialogData;

64
enum
65
{
66
  HISTORY_TITLE,
67
  HISTORY_URI
68
};
69 70 71

/*  local function prototypes  */

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
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);
88 89
static void       find_again_callback     (GtkAction         *action,
                                           gpointer           data);
90 91
static void       copy_location_callback  (GtkAction         *action,
                                           gpointer           data);
92 93
static void       copy_selection_callback (GtkAction         *action,
                                           gpointer           data);
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
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);
119 120
static gboolean   view_key_press          (GtkWidget         *widget,
                                           GdkEventKey       *event);
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

static void       title_changed           (GtkWidget         *view,
                                           WebKitWebFrame    *frame,
                                           const gchar       *title,
                                           GtkWidget         *window);
static void       load_started            (GtkWidget         *view,
                                           WebKitWebFrame    *frame);
static void       load_finished           (GtkWidget         *view,
                                           WebKitWebFrame    *frame);

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,
Sven Neumann's avatar
Sven Neumann committed
137
                                           GtkWidget         *entry);
138
static void       search_next_clicked     (GtkWidget         *button,
Sven Neumann's avatar
Sven Neumann committed
139
                                           GtkWidget         *entry);
140 141 142
static void       search_close_clicked    (GtkWidget         *button);
static void       search                  (const gchar       *text,
                                           gboolean           forward);
143

144 145 146

/*  private variables  */

147
static GHashTable   *uri_hash_table = NULL;
148

149
static GtkWidget    *view           = NULL;
150
static GtkWidget    *sidebar        = NULL;
151
static GtkWidget    *searchbar      = NULL;
152 153 154 155 156
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;
157 158 159 160 161


/*  public functions  */

void
162
browser_dialog_open (const gchar *plug_in_binary)
163
{
164
  GtkWidget   *window;
165
  GtkWidget   *main_vbox;
166 167 168 169 170 171
  GtkWidget   *vbox;
  GtkWidget   *toolbar;
  GtkWidget   *paned;
  GtkWidget   *scrolled;
  GtkToolItem *item;
  GtkAction   *action;
172
  DialogData   data = { 720, 560, 240, TRUE, 1.0 };
173

174
  gimp_ui_init (plug_in_binary, TRUE);
175

176 177
  gimp_get_data (GIMP_HELP_BROWSER_DIALOG_DATA, &data);

178 179
  /*  the dialog window  */
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
180
  gtk_window_set_title (GTK_WINDOW (window), _("GIMP Help Browser"));
181
  gtk_window_set_role (GTK_WINDOW (window), plug_in_binary);
182
  gtk_window_set_icon_name (GTK_WINDOW (window), GIMP_STOCK_USER_MANUAL);
183

184
  gtk_window_set_default_size (GTK_WINDOW (window), data.width, data.height);
185

186
  g_signal_connect (window, "destroy",
187
                    G_CALLBACK (gtk_main_quit),
188 189
                    NULL);

Michael Natterer's avatar
Michael Natterer committed
190
  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
191 192 193
  gtk_container_add (GTK_CONTAINER (window), vbox);
  gtk_widget_show (vbox);

194
  ui_manager = ui_manager_new (window);
195

196
  toolbar = gtk_ui_manager_get_widget (ui_manager, "/help-browser-toolbar");
197
  gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
198 199
  gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
  gtk_widget_show (toolbar);
200

201 202 203 204 205 206
  item = g_object_new (GTK_TYPE_MENU_TOOL_BUTTON, NULL);
  gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0);
  gtk_widget_show (GTK_WIDGET (item));

  action = gtk_ui_manager_get_action (ui_manager,
                                      "/ui/help-browser-popup/forward");
207
  gtk_activatable_set_related_action (GTK_ACTIVATABLE (item), action);
208
  g_object_notify (G_OBJECT (action), "tooltip");
209 210 211 212 213 214 215 216
  button_next = GTK_WIDGET (item);

  item = g_object_new (GTK_TYPE_MENU_TOOL_BUTTON, NULL);
  gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0);
  gtk_widget_show (GTK_WIDGET (item));

  action = gtk_ui_manager_get_action (ui_manager,
                                      "/ui/help-browser-popup/back");
217
  gtk_activatable_set_related_action (GTK_ACTIVATABLE (item), action);
218
  g_object_notify (G_OBJECT (action), "tooltip");
219 220
  button_prev = GTK_WIDGET (item);

221 222 223 224 225 226
  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);

227
  /*  the horizontal paned  */
228
  paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
229 230 231
  gtk_box_pack_start (GTK_BOX (vbox), paned, TRUE, TRUE, 0);
  gtk_widget_show (paned);

232 233
  scrolled = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
234
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
235
  gtk_paned_add1 (GTK_PANED (paned), scrolled);
236
  gtk_paned_set_position (GTK_PANED (paned), data.paned_position);
237 238 239 240 241

  sidebar = scrolled;

  if (data.show_index)
    gtk_widget_show (sidebar);
242 243 244

  tree_view = gtk_tree_view_new ();
  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
245
  gtk_container_add (GTK_CONTAINER (scrolled), tree_view);
246 247 248 249 250 251 252 253 254 255 256 257
  gtk_widget_show (tree_view);

  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view), -1,
                                               NULL,
                                               gtk_cell_renderer_text_new (),
                                               "text", 1,
                                               NULL);

  g_signal_connect (tree_view, "row-activated",
                    G_CALLBACK (row_activated),
                    NULL);

258
  /*  HTML view  */
Michael Natterer's avatar
Michael Natterer committed
259
  main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
260 261 262
  gtk_widget_show (main_vbox);
  gtk_paned_pack2 (GTK_PANED (paned), main_vbox, TRUE, TRUE);

263 264
  scrolled = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
265 266
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

267
  gtk_widget_set_size_request (scrolled, 300, 200);
268
  gtk_box_pack_start (GTK_BOX (main_vbox), scrolled, TRUE, TRUE, 0);
269
  gtk_widget_show (scrolled);
270

271 272 273 274 275 276 277
  view = webkit_web_view_new ();
  webkit_web_view_set_maintains_back_forward_list (WEBKIT_WEB_VIEW (view),
                                                   TRUE);
  gtk_container_add (GTK_CONTAINER (scrolled), view);
  gtk_widget_show (view);

  g_signal_connect (view, "realize",
278 279
                    G_CALLBACK (view_realize),
                    NULL);
280
  g_signal_connect (view, "unrealize",
281 282 283
                    G_CALLBACK (view_unrealize),
                    NULL);

284
  g_signal_connect (view, "popup-menu",
285 286
                    G_CALLBACK (view_popup_menu),
                    NULL);
287
  g_signal_connect (view, "button-press-event",
288 289
                    G_CALLBACK (view_button_press),
                    NULL);
290 291 292
  g_signal_connect (view, "key-press-event",
                    G_CALLBACK (view_key_press),
                    NULL);
293

294
  webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (view), data.zoom);
295

296
  g_signal_connect (view, "title-changed",
297
                    G_CALLBACK (title_changed),
298 299
                    window);

300 301
  g_signal_connect (view, "load-started",
                    G_CALLBACK (load_started),
302
                    NULL);
303 304
  g_signal_connect (view, "load-finished",
                    G_CALLBACK (load_finished),
305 306
                    NULL);

307
  gtk_widget_grab_focus (view);
308

309 310 311
  g_signal_connect (window, "unmap",
                    G_CALLBACK (dialog_unmap),
                    paned);
312 313

  update_actions ();
314 315 316 317

  /* Searchbar */
  searchbar = build_searchbar ();
  gtk_box_pack_start (GTK_BOX (main_vbox), searchbar, FALSE, FALSE, 0);
318 319 320
}

void
321
browser_dialog_load (const gchar *uri)
322
{
323
  g_return_if_fail (uri != NULL);
324

325
  webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), uri);
326

327
  select_index (uri);
328

329
  gtk_window_present (GTK_WINDOW (gtk_widget_get_toplevel (view)));
330 331
}

332 333 334 335 336
static void
browser_dialog_make_index_foreach (const gchar    *help_id,
                                   GimpHelpItem   *item,
                                   GimpHelpLocale *locale)
{
337
  gchar *sort_key = item->title;
338

339
#if DEBUG_SORT_HELP_ITEMS
340
  g_printerr ("%s: processing %s (parent %s)\n",
341 342 343
              G_STRFUNC,
              item->title  ? item->title  : "NULL",
              item->parent ? item->parent : "NULL");
344 345
#endif

346
  if (item->sort &&
347
      g_regex_match_simple ("^[0-9]+([.][0-9]+)*$", item->sort, 0, 0))
348
    {
349
      sort_key = item->sort;
350

351
#if DEBUG_SORT_HELP_ITEMS
352
      g_printerr ("%s: sort key = %s\n", G_STRFUNC, sort_key);
353 354
#endif
    }
355

356 357 358 359 360 361
  item->index = 0;

  if (sort_key)
    {
      const gint max_tokens = GIMP_HELP_BROWSER_INDEX_MAX_DEPTH;
      gchar* *indices = g_strsplit (sort_key, ".", max_tokens + 1);
362
      gint    i;
363

364
      for (i = 0; i < max_tokens; i++)
365
        {
366 367
          gunichar c;

368
          if (! indices[i])
369 370 371 372 373
            {
              /* make sure that all item->index's are comparable */
              item->index <<= (8 * (max_tokens - i));
              break;
            }
374

375
          item->index <<= 8;  /* NOP if i = 0 */
376 377 378
          c = g_utf8_get_char (indices[i]);
          if (g_unichar_isdigit (c))
            {
379
              item->index += atoi (indices[i]);
380 381 382
            }
          else if (g_utf8_strlen (indices[i], -1) == 1)
            {
383
              item->index += (c & 0xFF);
384
            }
385 386 387
        }

      g_strfreev (indices);
388

389
#if DEBUG_SORT_HELP_ITEMS
390
      g_printerr ("%s: index = %lu\n", G_STRFUNC, item->index);
391
#endif
392
    }
393 394 395 396 397

  if (item->parent && strlen (item->parent))
    {
      GimpHelpItem *parent;

398
      parent = g_hash_table_lookup (locale->help_id_mapping, item->parent);
399 400

      if (parent)
401 402 403
        {
          parent->children = g_list_prepend (parent->children, item);
        }
404 405 406 407 408 409 410 411 412 413 414
    }
  else
    {
      locale->toplevel_items = g_list_prepend (locale->toplevel_items, item);
    }
}

static gint
help_item_compare (gconstpointer a,
                   gconstpointer b)
{
415 416
  const GimpHelpItem *item_a = a;
  const GimpHelpItem *item_b = b;
417 418 419 420 421 422 423 424 425 426

  if (item_a->index > item_b->index)
    return 1;
  else if (item_a->index < item_b->index)
    return -1;

  return 0;
}

static void
427 428 429 430
add_child (GtkTreeStore   *store,
           GimpHelpDomain *domain,
           GimpHelpLocale *locale,
           GtkTreeIter    *parent,
431 432
           GimpHelpItem   *item,
           gint            depth)
433 434 435
{
  GtkTreeIter  iter;
  GList       *list;
436
  gchar       *uri;
437 438 439 440 441 442 443 444

  gtk_tree_store_append (store, &iter, parent);

  gtk_tree_store_set (store, &iter,
                      0, item,
                      1, item->title,
                      -1);

445 446 447 448 449 450 451 452 453
  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));

454 455 456
  if (depth + 1 == GIMP_HELP_BROWSER_INDEX_MAX_DEPTH)
    return;

457 458 459 460 461 462
  item->children = g_list_sort (item->children, help_item_compare);

  for (list = item->children; list; list = g_list_next (list))
    {
      GimpHelpItem *item = list->data;

463
      add_child (store, domain, locale, &iter, item, depth + 1);
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
    }
}

void
browser_dialog_make_index (GimpHelpDomain *domain,
                           GimpHelpLocale *locale)
{
  GtkTreeStore *store;
  GList        *list;

  if (! locale->toplevel_items)
    {
      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);
    }

  store = gtk_tree_store_new (2,
                              G_TYPE_POINTER,
                              G_TYPE_STRING);

  g_object_set_data (G_OBJECT (store), "domain", domain);
  g_object_set_data (G_OBJECT (store), "locale", locale);

491 492 493
  if (uri_hash_table)
    g_hash_table_unref (uri_hash_table);

494 495 496 497 498
  uri_hash_table = g_hash_table_new_full (g_str_hash,
                                          g_str_equal,
                                          (GDestroyNotify) g_free,
                                          (GDestroyNotify) gtk_tree_iter_free);

499 500 501 502
  for (list = locale->toplevel_items; list; list = g_list_next (list))
    {
      GimpHelpItem *item = list->data;

503
      add_child (store, domain, locale, NULL, item, 0);
504 505
    }

506
  gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (store));
507 508 509
  g_object_unref (store);
}

510 511
static void
select_index (const gchar *uri)
512
{
513
  GtkTreeSelection *selection;
514
  GtkTreeIter      *iter = NULL;
515 516 517

  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));

518 519
  if (uri)
    iter = g_hash_table_lookup (uri_hash_table, uri);
520 521 522

  if (iter)
    {
523 524 525
      GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
      GtkTreePath  *path;
      GtkTreePath  *scroll_path;
526 527

      path = gtk_tree_model_get_path (model, iter);
528
      scroll_path = gtk_tree_path_copy (path);
529

530
      gtk_tree_path_up (path);
531
      gtk_tree_view_expand_to_path (GTK_TREE_VIEW (tree_view), path);
532
      gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view), scroll_path,
533 534 535
                                    NULL, FALSE, 0.0, 0.0);

      gtk_tree_path_free (path);
536
      gtk_tree_path_free (scroll_path);
537 538 539

      gtk_tree_selection_select_iter (selection, iter);
    }
540 541 542 543
  else
    {
      gtk_tree_selection_unselect_all (selection);
    }
544 545
}

546 547 548

/*  private functions  */

549 550 551
static GtkUIManager *
ui_manager_new (GtkWidget *window)
{
Sven Neumann's avatar
Sven Neumann committed
552
  static const GtkActionEntry actions[] =
553
  {
554
    {
555
      "back", "go-previous",
556
      NULL, "<alt>Left", N_("Go back one page"),
Sven Neumann's avatar
Sven Neumann committed
557 558
      G_CALLBACK (back_callback)
    },
559
    {
560
      "forward", "go-next",
561
      NULL, "<alt>Right", N_("Go forward one page"),
Sven Neumann's avatar
Sven Neumann committed
562 563
      G_CALLBACK (forward_callback)
    },
564
    {
565
      "reload", "view-refresh",
566
       N_("_Reload"), "<control>R", N_("Reload current page"),
567 568 569
      G_CALLBACK (reload_callback)
    },
    {
570
      "stop", "process-stop",
571
       N_("_Stop"), "Escape", N_("Stop loading this page"),
572 573
      G_CALLBACK (stop_callback)
    },
574
    {
575
      "home", "go-home",
576
      NULL, "<alt>Home", N_("Go to the index page"),
577
      G_CALLBACK (home_callback)
578 579
    },
    {
580
      "copy-location", "edit-copy",
581
      N_("C_opy location"), "",
582
      N_("Copy the location of this page to the clipboard"),
583 584
      G_CALLBACK (copy_location_callback)
    },
585
    {
586
      "copy-selection", "edit-copy",
587 588 589
      NULL, "<control>C", NULL,
      G_CALLBACK (copy_selection_callback)
    },
590
    {
591
      "zoom-in", "zoom-in",
592
      NULL, "<control>plus", NULL,
Sven Neumann's avatar
Sven Neumann committed
593 594
      G_CALLBACK (zoom_in_callback)
    },
595
    {
596
      "zoom-out", "zoom-out",
597
      NULL, "<control>minus", NULL,
Sven Neumann's avatar
Sven Neumann committed
598 599
      G_CALLBACK (zoom_out_callback)
    },
600
    {
601
      "find", "edit-find",
602 603 604 605 606 607 608 609
      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)
    },
610
    {
611
      "close", "window-close",
612
      NULL, "<control>W", NULL,
Sven Neumann's avatar
Sven Neumann committed
613 614
      G_CALLBACK (close_callback)
    },
615
    {
616
      "quit", "application-exit",
617
      NULL, "<control>Q", NULL,
Sven Neumann's avatar
Sven Neumann committed
618 619
      G_CALLBACK (close_callback)
    }
620 621
  };

622 623 624 625 626 627 628 629 630 631
  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
    }
  };

632 633
  GtkUIManager   *ui_manager = gtk_ui_manager_new ();
  GtkActionGroup *group      = gtk_action_group_new ("Actions");
634
  GtkAction      *action;
635
  GError         *error      = NULL;
636 637

  gtk_action_group_set_translation_domain (group, NULL);
638 639 640 641 642 643 644
  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);
645

646
  action = gimp_throbber_action_new ("website",
Sven Neumann's avatar
Sven Neumann committed
647
                                     "docs.gimp.org",
648
                                     _("Visit the GIMP documentation website"),
649
                                     GIMP_STOCK_USER_MANUAL);
650
  g_signal_connect_closure (action, "activate",
651
                            g_cclosure_new (G_CALLBACK (website_callback),
652 653 654 655 656
                                            NULL, NULL),
                            FALSE);
  gtk_action_group_add_action (group, action);
  g_object_unref (action);

657 658 659 660 661 662 663 664 665 666
  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\">"
667 668
                                     "    <toolitem action=\"reload\" />"
                                     "    <toolitem action=\"stop\" />"
669
                                     "    <toolitem action=\"home\" />"
670
                                     "    <separator name=\"space\" />"
671
                                     "    <toolitem action=\"website\" />"
672
                                     "  </toolbar>"
673 674
                                     "  <accelerator action=\"close\" />"
                                     "  <accelerator action=\"quit\" />"
675
                                     "</ui>",
676 677 678
                                     -1, &error);

  if (error)
679 680 681 682
    {
      g_warning ("error parsing ui: %s", error->message);
      g_clear_error (&error);
    }
683

684 685 686 687 688
  gtk_ui_manager_add_ui_from_string (ui_manager,
                                     "<ui>"
                                     "  <popup name=\"help-browser-popup\">"
                                     "    <menuitem action=\"back\" />"
                                     "    <menuitem action=\"forward\" />"
689 690
                                     "    <menuitem action=\"reload\" />"
                                     "    <menuitem action=\"stop\" />"
691
                                     "    <separator />"
692
                                     "    <menuitem action=\"home\" />"
693
                                     "    <menuitem action=\"copy-location\" />"
694
                                     "    <menuitem action=\"show-index\" />"
695 696 697
                                     "    <separator />"
                                     "    <menuitem action=\"find\" />"
                                     "    <menuitem action=\"find-again\" />"
Sven Neumann's avatar
Sven Neumann committed
698 699 700
                                     "    <separator />"
                                     "    <menuitem action=\"zoom-in\" />"
                                     "    <menuitem action=\"zoom-out\" />"
701 702
                                     "    <separator />"
                                     "    <menuitem action=\"close\" />"
703 704
                                     "  </popup>"
                                     "</ui>",
705 706 707 708 709 710 711
                                     -1, &error);

  if (error)
    {
      g_warning ("error parsing ui: %s", error->message);
      g_clear_error (&error);
    }
712

713 714 715 716 717 718 719 720 721 722 723 724 725 726
  gtk_ui_manager_add_ui_from_string (ui_manager,
                                     "<ui>"
                                     "  <popup name=\"help-browser-copy-popup\">"
                                     "    <menuitem action=\"copy-selection\" />"
                                     "  </popup>"
                                     "</ui>",
                                     -1, &error);

  if (error)
    {
      g_warning ("error parsing ui: %s", error->message);
      g_clear_error (&error);
    }

727 728 729
  return ui_manager;
}

730
static void
731 732
back_callback (GtkAction *action,
               gpointer   data)
733
{
734
  webkit_web_view_go_back (WEBKIT_WEB_VIEW (view));
735 736 737 738 739 740
}

static void
forward_callback (GtkAction *action,
                  gpointer   data)
{
741 742
  webkit_web_view_go_forward (WEBKIT_WEB_VIEW (view));
}
743

744 745 746 747 748 749
static void
reload_callback (GtkAction *action,
                 gpointer   data)
{
  webkit_web_view_reload (WEBKIT_WEB_VIEW (view));
}
750

751 752 753 754 755
static void
stop_callback (GtkAction *action,
               gpointer   data)
{
  webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (view));
756 757
}

758
static void
759 760
home_callback (GtkAction *action,
               gpointer   data)
761
{
762 763 764 765 766 767 768 769 770 771 772 773 774 775
  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");

  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);
    }
776 777
}

778 779 780 781
static void
find_callback (GtkAction *action,
               gpointer   data)
{
782 783
  GtkWidget *entry = g_object_get_data (G_OBJECT (searchbar), "entry");

784
  gtk_widget_show (searchbar);
785
  gtk_widget_grab_focus (entry);
786 787
}

788 789 790 791 792 793 794 795 796 797 798
static void
find_again_callback (GtkAction *action,
                     gpointer   data)
{
  GtkWidget *entry = g_object_get_data (G_OBJECT (searchbar), "entry");

  gtk_widget_show (searchbar);
  gtk_widget_grab_focus (entry);

  search (gtk_entry_get_text (GTK_ENTRY (entry)), TRUE);
}
799

800 801 802 803
static void
copy_location_callback (GtkAction *action,
                        gpointer   data)
{
804
  WebKitWebFrame *frame;
805 806
  const gchar    *uri;

807
  frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (view));
808 809 810 811 812 813 814 815 816 817 818 819
  uri = webkit_web_frame_get_uri (frame);

  if (uri)
    {
      GtkClipboard *clipboard;

      clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (view),
                                                 GDK_SELECTION_CLIPBOARD);
      gtk_clipboard_set_text (clipboard, uri, -1);
    }
}

820 821 822 823 824 825 826 827 828 829
static void
copy_selection_callback (GtkAction *action,
                         gpointer   data)
{
  if (webkit_web_view_can_copy_clipboard (WEBKIT_WEB_VIEW (view)))
    {
      webkit_web_view_copy_clipboard (WEBKIT_WEB_VIEW (view));
    }
}

830 831 832 833
static void
show_index_callback (GtkAction *action,
                     gpointer   data)
{
834 835
  gtk_widget_set_visible (sidebar,
                          gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
836 837
}

Sven Neumann's avatar
Sven Neumann committed
838
static void
839 840
zoom_in_callback (GtkAction *action,
                  gpointer   data)
Sven Neumann's avatar
Sven Neumann committed
841
{
842
  webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (view));
Sven Neumann's avatar
Sven Neumann committed
843 844 845 846 847 848
}

static void
zoom_out_callback (GtkAction *action,
                   gpointer   data)
{
849
  webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (view));
Sven Neumann's avatar
Sven Neumann committed
850 851
}

852
static void
853 854
website_callback (GtkAction *action,
                  gpointer   data)
855
{
856
  browser_dialog_load ("http://docs.gimp.org/");
857 858
}

859 860 861 862
static void
close_callback (GtkAction *action,
                gpointer   data)
{
863 864 865 866
  gtk_widget_destroy (gtk_widget_get_toplevel (view));
}

static void
Sven Neumann's avatar
Sven Neumann committed
867 868
menu_callback (GtkWidget *menu,
               gpointer   data)
869
{
Sven Neumann's avatar
Sven Neumann committed
870 871 872
  gint steps = GPOINTER_TO_INT (data);

  webkit_web_view_go_back_or_forward (WEBKIT_WEB_VIEW (view), steps);
873 874
}

875
static GtkWidget *
Sven Neumann's avatar
Sven Neumann committed
876 877
build_menu (const GList *items,
            gboolean     back)
878
{
Sven Neumann's avatar
Sven Neumann committed
879 880 881
  GtkWidget   *menu;
  const GList *iter;
  gint         steps;
882

Sven Neumann's avatar
Sven Neumann committed
883
  if (! items)
884 885
    return NULL;

Sven Neumann's avatar
Sven Neumann committed
886
  menu = gtk_menu_new ();
887

Sven Neumann's avatar
Sven Neumann committed
888
  for (iter = items, steps = 1; iter; iter = g_list_next (iter), steps++)