/* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * GIMP Help Browser * Copyright (C) 1999-2008 Sven Neumann * Michael Natterer * RĂ³man Joost * * dialog.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #include #include "libgimpwidgets/gimpwidgets.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" #include "plug-ins/help/gimphelp.h" #include "gimpthrobber.h" #include "gimpthrobberaction.h" #include "dialog.h" #include "uri.h" #include "libgimp/stdplugins-intl.h" #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; } DialogData; enum { HISTORY_TITLE, HISTORY_URI }; /* 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 window_set_icons (GtkWidget *window); 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 (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, GtkWidget *entry); static void search_next_clicked (GtkWidget *button, GtkWidget *entry); static void search_close_clicked (GtkWidget *button); static void search (const gchar *text, gboolean forward); /* 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 */ void browser_dialog_open (const gchar *plug_in_binary) { GtkWidget *window; GtkWidget *main_vbox; GtkWidget *vbox; GtkWidget *toolbar; GtkWidget *paned; GtkWidget *scrolled; GtkWidget *button; GtkToolItem *item; GtkAction *action; DialogData data = { 720, 560, 240, TRUE, 1.0 }; gimp_ui_init (plug_in_binary, TRUE); gimp_get_data (GIMP_HELP_BROWSER_DIALOG_DATA, &data); /* 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_default_size (GTK_WINDOW (window), data.width, data.height); g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); window_set_icons (window); vbox = gtk_vbox_new (FALSE, 2); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show (vbox); ui_manager = ui_manager_new (window); 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); 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"); gtk_action_connect_proxy (action, GTK_WIDGET (item)); g_object_notify (G_OBJECT (action), "tooltip"); 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"); gtk_action_connect_proxy (action, GTK_WIDGET (item)); g_object_notify (G_OBJECT (action), "tooltip"); button_prev = GTK_WIDGET (item); 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); button = gtk_ui_manager_get_widget (ui_manager, "/help-browser-toolbar/website"); /* the horizontal paned */ paned = gtk_hpaned_new (); gtk_box_pack_start (GTK_BOX (vbox), paned, TRUE, TRUE, 0); gtk_widget_show (paned); 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); sidebar = scrolled; if (data.show_index) gtk_widget_show (sidebar); 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_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); /* HTML view */ main_vbox = gtk_vbox_new (FALSE, 0); gtk_widget_show (main_vbox); gtk_paned_pack2 (GTK_PANED (paned), main_vbox, TRUE, TRUE); scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_widget_set_size_request (scrolled, 300, 200); gtk_box_pack_start (GTK_BOX (main_vbox), scrolled, TRUE, TRUE, 0); gtk_widget_show (scrolled); 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", G_CALLBACK (view_realize), NULL); g_signal_connect (view, "unrealize", G_CALLBACK (view_unrealize), NULL); 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); #if HAVE_WEBKIT_ZOOM_API webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (view), data.zoom); #endif g_signal_connect (view, "title-changed", G_CALLBACK (title_changed), window); g_signal_connect (view, "load-started", G_CALLBACK (load_started), NULL); g_signal_connect (view, "load-finished", G_CALLBACK (load_finished), NULL); gtk_widget_grab_focus (view); g_signal_connect (window, "unmap", G_CALLBACK (dialog_unmap), paned); update_actions (); /* Searchbar */ searchbar = build_searchbar (); gtk_box_pack_start (GTK_BOX (main_vbox), searchbar, FALSE, FALSE, 0); } void browser_dialog_load (const gchar *uri) { g_return_if_fail (uri != NULL); webkit_web_view_open (WEBKIT_WEB_VIEW (view), uri); select_index (uri); gtk_window_present (GTK_WINDOW (gtk_widget_get_toplevel (view))); } static void window_set_icons (GtkWidget *window) { const GtkIconSize sizes[] = { GTK_ICON_SIZE_MENU, GTK_ICON_SIZE_BUTTON, GTK_ICON_SIZE_DND, GTK_ICON_SIZE_DIALOG }; GList *list = NULL; gint i; for (i = 0; i < G_N_ELEMENTS (sizes); i++) list = g_list_prepend (list, gtk_widget_render_icon (window, GIMP_STOCK_USER_MANUAL, sizes[i], NULL)); gtk_window_set_icon_list (GTK_WINDOW (window), list); g_list_foreach (list, (GFunc) g_object_unref, NULL); g_list_free (list); } static void browser_dialog_make_index_foreach (const gchar *help_id, GimpHelpItem *item, GimpHelpLocale *locale) { #if 0 g_printerr ("%s: processing %s (parent %s)\n", G_STRFUNC, item->title ? item->title : "NULL", item->parent ? item->parent : "NULL"); #endif if (item->title) { gchar **indices = g_strsplit (item->title, ".", -1); gint i; for (i = 0; i < 5; i++) { gunichar c; if (! indices[i]) break; c = g_utf8_get_char (indices[i]); if (g_unichar_isdigit (c)) { item->index += atoi (indices[i]) << (8 * (5 - i)); } else if (g_utf8_strlen (indices[i], -1) == 1) { item->index += (c & 0xFF) << (8 * (5 - i)); } } g_strfreev (indices); } if (item->parent && strlen (item->parent)) { GimpHelpItem *parent; parent = g_hash_table_lookup (locale->help_id_mapping, item->parent); if (parent) { parent->children = g_list_prepend (parent->children, item); } } else { locale->toplevel_items = g_list_prepend (locale->toplevel_items, item); } } static gint help_item_compare (gconstpointer a, gconstpointer b) { const GimpHelpItem *item_a = a; const GimpHelpItem *item_b = b; if (item_a->index > item_b->index) return 1; else if (item_a->index < item_b->index) return -1; return 0; } static void add_child (GtkTreeStore *store, GimpHelpDomain *domain, GimpHelpLocale *locale, GtkTreeIter *parent, GimpHelpItem *item, gint depth) { GtkTreeIter iter; GList *list; gchar *uri; gtk_tree_store_append (store, &iter, parent); gtk_tree_store_set (store, &iter, 0, item, 1, item->title, -1); 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)); if (depth + 1 == GIMP_HELP_BROWSER_INDEX_MAX_DEPTH) return; item->children = g_list_sort (item->children, help_item_compare); for (list = item->children; list; list = g_list_next (list)) { GimpHelpItem *item = list->data; add_child (store, domain, locale, &iter, item, depth + 1); } } 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); if (uri_hash_table) g_hash_table_unref (uri_hash_table); uri_hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) gtk_tree_iter_free); for (list = locale->toplevel_items; list; list = g_list_next (list)) { GimpHelpItem *item = list->data; add_child (store, domain, locale, NULL, item, 0); } gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (store)); g_object_unref (store); } static void select_index (const gchar *uri) { GtkTreeSelection *selection; GtkTreeIter *iter = NULL; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); if (uri) iter = g_hash_table_lookup (uri_hash_table, uri); if (iter) { GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); GtkTreePath *path; GtkTreePath *scroll_path; path = gtk_tree_model_get_path (model, iter); 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, NULL, FALSE, 0.0, 0.0); gtk_tree_path_free (path); gtk_tree_path_free (scroll_path); gtk_tree_selection_select_iter (selection, iter); } else { gtk_tree_selection_unselect_all (selection); } } /* private functions */ static GtkUIManager * ui_manager_new (GtkWidget *window) { static const GtkActionEntry actions[] = { { "back", GTK_STOCK_GO_BACK, NULL, "Left", N_("Go back one page"), G_CALLBACK (back_callback) }, { "forward", GTK_STOCK_GO_FORWARD, NULL, "Right", N_("Go forward one page"), G_CALLBACK (forward_callback) }, { "reload", GTK_STOCK_REFRESH, N_("_Reload"), "R", N_("Reload current page"), G_CALLBACK (reload_callback) }, { "stop", GTK_STOCK_CANCEL, N_("_Stop"), "Escape", N_("Stop loading this page"), G_CALLBACK (stop_callback) }, { "home", GTK_STOCK_HOME, NULL, "Home", N_("Go to the index page"), G_CALLBACK (home_callback) }, { "copy-location", GTK_STOCK_COPY, N_("C_opy location"), "", N_("Copy the location of this page to the clipboard"), G_CALLBACK (copy_location_callback) }, { "copy-selection", GTK_STOCK_COPY, NULL, "C", NULL, G_CALLBACK (copy_selection_callback) }, { "zoom-in", GTK_STOCK_ZOOM_IN, NULL, "plus", NULL, G_CALLBACK (zoom_in_callback) }, { "zoom-out", GTK_STOCK_ZOOM_OUT, NULL, "minus", NULL, G_CALLBACK (zoom_out_callback) }, { "find", GTK_STOCK_FIND, NULL, "F", N_("Find text in current page"), G_CALLBACK (find_callback) }, { "find-again", NULL, N_("Find _Again"), "G", NULL, G_CALLBACK (find_again_callback) }, { "close", GTK_STOCK_CLOSE, NULL, "W", NULL, G_CALLBACK (close_callback) }, { "quit", GTK_STOCK_QUIT, NULL, "Q", NULL, G_CALLBACK (close_callback) } }; static const GtkToggleActionEntry toggle_actions[] = { { "show-index", NULL, N_("S_how Index"), "I", N_("Toggle the visibility of the sidebar"), G_CALLBACK (show_index_callback), FALSE } }; GtkUIManager *ui_manager = gtk_ui_manager_new (); GtkActionGroup *group = gtk_action_group_new ("Actions"); GtkAction *action; GError *error = NULL; 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_STOCK_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, "" " " " " " " " " " " " " " " " " " " "", -1, &error); if (error) { g_warning ("error parsing ui: %s", error->message); g_clear_error (&error); } gtk_ui_manager_add_ui_from_string (ui_manager, "" " " " " " " " " " " " " " " " " " " " " " " " " #ifdef HAVE_WEBKIT_ZOOM_API " " " " " " #endif " " " " " " "", -1, &error); if (error) { g_warning ("error parsing ui: %s", error->message); g_clear_error (&error); } gtk_ui_manager_add_ui_from_string (ui_manager, "" " " " " " " "", -1, &error); if (error) { g_warning ("error parsing ui: %s", error->message); g_clear_error (&error); } return ui_manager; } static void back_callback (GtkAction *action, gpointer data) { webkit_web_view_go_back (WEBKIT_WEB_VIEW (view)); } static void forward_callback (GtkAction *action, gpointer data) { webkit_web_view_go_forward (WEBKIT_WEB_VIEW (view)); } static void reload_callback (GtkAction *action, gpointer data) { webkit_web_view_reload (WEBKIT_WEB_VIEW (view)); } static void stop_callback (GtkAction *action, gpointer data) { webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (view)); } 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"); 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); } } static void find_callback (GtkAction *action, gpointer data) { GtkWidget *entry = g_object_get_data (G_OBJECT (searchbar), "entry"); gtk_widget_show (searchbar); gtk_widget_grab_focus (entry); } 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); } static void copy_location_callback (GtkAction *action, gpointer data) { WebKitWebFrame *frame; const gchar *uri; frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (view)); 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); } } 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)); } } static void show_index_callback (GtkAction *action, gpointer data) { if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) { gtk_widget_show (sidebar); } else { gtk_widget_hide (sidebar); } } static void zoom_in_callback (GtkAction *action, gpointer data) { #ifdef HAVE_WEBKIT_ZOOM_API webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (view)); #endif } static void zoom_out_callback (GtkAction *action, gpointer data) { #ifdef HAVE_WEBKIT_ZOOM_API webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (view)); #endif } static void website_callback (GtkAction *action, gpointer data) { browser_dialog_load ("http://docs.gimp.org/"); } static void close_callback (GtkAction *action, gpointer data) { gtk_widget_destroy (gtk_widget_get_toplevel (view)); } static void menu_callback (GtkWidget *menu, WebKitWebHistoryItem *item) { browser_dialog_load (webkit_web_history_item_get_uri (item)); } /* this function unrefs the items and frees the list */ static GtkWidget * build_menu (GList *items) { GtkWidget *menu; GList *list; if (! items) return NULL; menu = gtk_menu_new (); for (list = items; list; list = g_list_next (list)) { WebKitWebHistoryItem *item = list->data; const gchar *title; title = webkit_web_history_item_get_title (item); if (title) { GtkWidget *menu_item = gtk_menu_item_new_with_label (title); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); gtk_widget_show (menu_item); g_signal_connect_object (menu_item, "activate", G_CALLBACK (menu_callback), item, 0); g_object_unref (item); } } g_list_free (items); return menu; } static void update_actions (void) { GtkAction *action; WebKitWebBackForwardList *back_forward_list; WebKitWebFrame *frame; back_forward_list = webkit_web_view_get_back_forward_list (WEBKIT_WEB_VIEW (view)); /* update the back button and its menu */ 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))); if (back_forward_list) { GList *list; list = webkit_web_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)); } else { gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (button_prev), NULL); } /* update the forward button and its menu */ 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))); if (back_forward_list) { GList *list; list = webkit_web_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)); } else { gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (button_next), NULL); } /* update the copy-location action */ action = gtk_ui_manager_get_action (ui_manager, "/ui/help-browser-popup/copy-location"); frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (view)); gtk_action_set_sensitive (action, webkit_web_frame_get_uri (frame) != NULL); /* 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_VISIBLE (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; gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, 0, &item, -1); domain = g_object_get_data (G_OBJECT (model), "domain"); locale = g_object_get_data (G_OBJECT (model), "locale"); uri = g_strconcat (domain->help_uri, "/", locale->locale_id, "/", item->ref, NULL); browser_dialog_load (uri); g_free (uri); } static void dialog_unmap (GtkWidget *window, GtkWidget *paned) { 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_VISIBLE (sidebar); #ifdef HAVE_WEBKIT_ZOOM_API data.zoom = (view ? webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (view)) : 1.0); #else data.zoom = 1.0; #endif gimp_set_data (GIMP_HELP_BROWSER_DIALOG_DATA, &data, sizeof (data)); gtk_main_quit (); } static void view_realize (GtkWidget *widget) { g_return_if_fail (busy_cursor == NULL); busy_cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_WATCH); } static void view_unrealize (GtkWidget *widget) { if (busy_cursor) { gdk_cursor_unref (busy_cursor); busy_cursor = NULL; } } static gboolean view_popup_menu (GtkWidget *widget, GdkEventButton *event) { GtkWidget *menu; const gchar *path; if (webkit_web_view_can_copy_clipboard (WEBKIT_WEB_VIEW (view))) path = "/help-browser-copy-popup"; else path = "/help-browser-popup"; menu = gtk_ui_manager_get_widget (ui_manager, path); gtk_menu_set_screen (GTK_MENU (menu), gtk_widget_get_screen (widget)); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event ? event->button : 0, event ? event->time : gtk_get_current_event_time ()); return TRUE; } static gboolean view_button_press (GtkWidget *widget, GdkEventButton *event) { if (event->button == 3 && event->type == GDK_BUTTON_PRESS) return view_popup_menu (widget, event); return FALSE; } static gboolean view_key_press (GtkWidget *widget, GdkEventKey *event) { if (event->keyval == GDK_slash) { GtkAction *action; action = gtk_ui_manager_get_action (ui_manager, "/ui/help-browser-popup/find"); gtk_action_activate (action); return TRUE; } return FALSE; } static void title_changed (GtkWidget *view, WebKitWebFrame *frame, const gchar *title, GtkWidget *window) { gchar *full_title; full_title = g_strdup_printf ("%s - %s", title ? title : _("Untitled"), _("GIMP Help Browser")); gtk_window_set_title (GTK_WINDOW (window), full_title); g_free (full_title); update_actions (); } static void load_started (GtkWidget *view, WebKitWebFrame *frame) { GtkAction *action = gtk_ui_manager_get_action (ui_manager, "/ui/help-browser-popup/stop"); gtk_action_set_sensitive (action, TRUE); } static void load_finished (GtkWidget *view, WebKitWebFrame *frame) { GtkAction *action = gtk_ui_manager_get_action (ui_manager, "/ui/help-browser-popup/stop"); gtk_action_set_sensitive (action, FALSE); update_actions (); select_index (webkit_web_frame_get_uri (frame)); } static GtkWidget * build_searchbar (void) { GtkWidget *button; GtkWidget *image; GtkWidget *entry; GtkWidget *hbox; GtkWidget *label; hbox = gtk_hbox_new (FALSE, 6); label = gtk_label_new (_("Find:")); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); 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); g_signal_connect (entry, "changed", G_CALLBACK (search_entry_changed), NULL); g_signal_connect (entry, "key-press-event", G_CALLBACK (search_entry_key_press), NULL); 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_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON)); gtk_widget_show (button); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); g_signal_connect (button, "clicked", G_CALLBACK (search_prev_clicked), entry); 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_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON)); gtk_widget_show (button); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); g_signal_connect (button, "clicked", G_CALLBACK (search_next_clicked), entry); button = gtk_button_new_from_stock (GTK_STOCK_CLOSE); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); g_object_get (button, "image", &image, NULL); g_object_set (image, "icon-size", GTK_ICON_SIZE_MENU, NULL); g_object_unref (image); gtk_widget_show (button); gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); g_signal_connect (button, "clicked", G_CALLBACK (search_close_clicked), NULL); return hbox; } static void search_entry_changed (GtkWidget *entry) { search (gtk_entry_get_text (GTK_ENTRY (entry)), TRUE); } static gboolean search_entry_key_press (GtkWidget *entry, GdkEventKey *event) { switch (event->keyval) { case GDK_Escape: gtk_widget_hide (searchbar); webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (view)); return TRUE; case GDK_Return: case GDK_KP_Enter: case GDK_ISO_Enter: search (gtk_entry_get_text (GTK_ENTRY (entry)), TRUE); return TRUE; } return FALSE; } static void search_prev_clicked (GtkWidget *button, GtkWidget *entry) { search (gtk_entry_get_text (GTK_ENTRY (entry)), FALSE); } static void search_next_clicked (GtkWidget *button, GtkWidget *entry) { search (gtk_entry_get_text (GTK_ENTRY (entry)), TRUE); } static void search (const gchar *text, gboolean forward) { if (text) webkit_web_view_search_text (WEBKIT_WEB_VIEW (view), text, FALSE, forward, TRUE); } static void search_close_clicked (GtkWidget *button) { gtk_widget_hide (searchbar); webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (view)); }