/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2001-2005 Imendio AB * * 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 #include #include #include #include #include #include "dh-book-tree.h" #include "dh-html.h" #include "dh-preferences.h" #include "dh-search.h" #include "dh-window.h" #include "eggfindbar.h" struct _DhWindowPriv { DhBase *base; GConfClient *gconf_client; GtkWidget *main_box; GtkWidget *menu_box; GtkWidget *hpaned; GtkWidget *control_notebook; GtkWidget *book_tree; GtkWidget *search; GtkWidget *html_notebook; GtkWidget *vbox; GtkWidget *findbar; GtkUIManager *manager; GtkActionGroup *action_group; }; static guint tab_accel_keys[] = { GDK_1, GDK_2, GDK_3, GDK_4, GDK_5, GDK_6, GDK_7, GDK_8, GDK_9, GDK_0 }; /* People have reported problems with the default values in GConf so I'm * adding this to make sure that the window isn't started 1x1 pixels or the * paned having size 0 */ #define DEFAULT_WIDTH 700 #define DEFAULT_HEIGHT 500 #define DEFAULT_PANED_LOC 250 static void window_class_init (DhWindowClass *klass); static void window_init (DhWindow *window); static void window_finalize (GObject *object); static void window_populate (DhWindow *window); static void window_activate_new_window (GtkAction *action, DhWindow *window); static void window_activate_new_tab (GtkAction *action, DhWindow *window); static void window_activate_close (GtkAction *action, DhWindow *window); static void window_activate_quit (GtkAction *action, DhWindow *window); static void window_activate_copy (GtkAction *action, DhWindow *window); static void window_activate_find (GtkAction *action, DhWindow *window); static void window_activate_preferences (GtkAction *action, DhWindow *window); static void window_activate_back (GtkAction *action, DhWindow *window); static void window_activate_forward (GtkAction *action, DhWindow *window); static void window_activate_show_contents (GtkAction *action, DhWindow *window); static void window_activate_show_search (GtkAction *action, DhWindow *window); static void window_activate_about (GtkAction *action, DhWindow *window); static void window_save_state (DhWindow *window); static void window_restore_state (DhWindow *window); static gboolean window_delete_cb (GtkWidget *widget, GdkEventAny *event, gpointer user_data); static void window_tree_link_selected_cb (GObject *ignored, DhLink *link, DhWindow *window); static void window_search_link_selected_cb (GObject *ignored, DhLink *link, DhWindow *window); static void window_manager_add_widget (GtkUIManager *manager, GtkWidget *widget, DhWindow *window); static void window_check_history (DhWindow *window, DhHtml *html); static void window_html_location_changed_cb (DhHtml *html, const gchar *location, DhWindow *window); static void window_html_title_changed_cb (DhHtml *html, const gchar *location, DhWindow *window); static gboolean window_html_open_uri_cb (DhHtml *html, const gchar *uri, DhWindow *window); static void window_html_open_new_tab_cb (DhHtml *html, const gchar *location, DhWindow *window); static void window_html_tab_accel_cb (GtkAccelGroup *accel_group, GObject *object, guint key, GdkModifierType mod, DhWindow *window); static void window_findbar_search_changed_cb(GObject *object, GParamSpec *arg1, DhWindow *window); static void window_findbar_case_sensitive_changed_cb (GObject *object, GParamSpec *arg1, DhWindow *window); static void window_find_previous_cb (GtkEntry *entry, DhWindow *window); static void window_find_next_cb (GtkEntry *entry, DhWindow *window); static void window_findbar_close_cb (GtkWidget *widget, DhWindow *window); static GtkWidget *window_new_tab_label (DhWindow *window, const gchar *label); static void window_open_new_tab (DhWindow *window, const gchar *location); static DhHtml * window_get_active_html (DhWindow *window); static void window_update_title (DhWindow *window, DhHtml *html); static void window_tab_set_title (DhWindow *window, DhHtml *html, const gchar *title); static GtkWindowClass *parent_class = NULL; static const GtkActionEntry actions[] = { { "FileMenu", NULL, N_("_File") }, { "EditMenu", NULL, N_("_Edit") }, { "GoMenu", NULL, N_("_Go") }, { "HelpMenu", NULL, N_("_Help") }, /* File menu */ { "NewWindow", GTK_STOCK_NEW, N_("_New Window"), "N", NULL, G_CALLBACK (window_activate_new_window) }, { "NewTab", GTK_STOCK_NEW, N_("New _Tab"), "T", NULL, G_CALLBACK (window_activate_new_tab) }, { "Close", GTK_STOCK_CLOSE, NULL, NULL, NULL, G_CALLBACK (window_activate_close) }, { "Quit", GTK_STOCK_QUIT, NULL, NULL, NULL, G_CALLBACK (window_activate_quit) }, /* Edit menu */ { "Copy", GTK_STOCK_COPY, NULL, "C", NULL, G_CALLBACK (window_activate_copy) }, { "Find", GTK_STOCK_FIND, NULL, "F", NULL, G_CALLBACK (window_activate_find) }, { "Find Next", GTK_STOCK_GO_FORWARD, N_("Find Next"), "G", NULL, G_CALLBACK (window_find_next_cb) }, { "Find Previous", GTK_STOCK_GO_BACK, N_("Find Previous"), "G", NULL, G_CALLBACK (window_find_previous_cb) }, { "Preferences", GTK_STOCK_PREFERENCES, NULL, NULL, NULL, G_CALLBACK (window_activate_preferences) }, /* Go menu */ { "Back", GTK_STOCK_GO_BACK, NULL, "Left", NULL, G_CALLBACK (window_activate_back) }, { "Forward", GTK_STOCK_GO_FORWARD, NULL, "Right", NULL, G_CALLBACK (window_activate_forward) }, { "ShowContentsTab", NULL, N_("_Contents Tab"), "B", NULL, G_CALLBACK (window_activate_show_contents) }, { "ShowSearchTab", NULL, N_("_Search Tab"), "S", NULL, G_CALLBACK (window_activate_show_search) }, /* About menu */ { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK (window_activate_about) }, }; GType dh_window_get_type (void) { static GType type = 0; if (!type) { static const GTypeInfo info = { sizeof (DhWindowClass), NULL, NULL, (GClassInitFunc) window_class_init, NULL, NULL, sizeof (DhWindow), 0, (GInstanceInitFunc) window_init }; type = g_type_register_static (GTK_TYPE_WINDOW, "DhWindow", &info, 0); } return type; } static void window_class_init (DhWindowClass *klass) { GObjectClass *object_class; parent_class = g_type_class_peek_parent (klass); object_class = G_OBJECT_CLASS (klass); object_class->finalize = window_finalize; } static void window_init (DhWindow *window) { DhWindowPriv *priv; GtkAction *action; GtkAccelGroup *accel_group; GClosure *closure; gint i; priv = g_new0 (DhWindowPriv, 1); window->priv = priv; priv->manager = gtk_ui_manager_new (); priv->gconf_client = gconf_client_get_default (); accel_group = gtk_ui_manager_get_accel_group (priv->manager); gtk_window_add_accel_group (GTK_WINDOW (window), accel_group); priv->main_box = gtk_vbox_new (FALSE, 0); gtk_widget_show (priv->main_box); priv->menu_box = gtk_vbox_new (FALSE, 0); gtk_widget_show (priv->menu_box); gtk_container_set_border_width (GTK_CONTAINER (priv->menu_box), 0); gtk_box_pack_start (GTK_BOX (priv->main_box), priv->menu_box, FALSE, TRUE, 0); gtk_container_add (GTK_CONTAINER (window), priv->main_box); g_signal_connect (priv->manager, "add-widget", G_CALLBACK (window_manager_add_widget), window); priv->action_group = gtk_action_group_new ("MainWindow"); gtk_action_group_set_translation_domain (priv->action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions (priv->action_group, actions, G_N_ELEMENTS (actions), window); gtk_ui_manager_insert_action_group (priv->manager, priv->action_group, 0); action = gtk_action_group_get_action (priv->action_group, "Back"); g_object_set (action, "sensitive", FALSE, NULL); action = gtk_action_group_get_action (priv->action_group, "Forward"); g_object_set (action, "sensitive", FALSE, NULL); accel_group = gtk_accel_group_new (); gtk_window_add_accel_group (GTK_WINDOW (window), accel_group); for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) { closure = g_cclosure_new (G_CALLBACK (window_html_tab_accel_cb), window, NULL); gtk_accel_group_connect (accel_group, tab_accel_keys[i], GDK_MOD1_MASK, 0, closure); } } static void window_finalize (GObject *object) { DhWindow *window = DH_WINDOW (object); DhBase *base = window->priv->base; G_OBJECT_CLASS (parent_class)->finalize (object); g_object_unref (base); } /* The ugliest hack. When switching tabs, the selection and cursor is changed * for the tree view so the html content is changed. Block the signal during * switch. */ static void window_control_switch_page_cb (GtkWidget *notebook, GtkNotebookPage *page, guint page_num, DhWindow *window) { DhWindowPriv *priv; priv = window->priv; g_signal_handlers_block_by_func (priv->book_tree, window_tree_link_selected_cb, window); } static void window_control_after_switch_page_cb (GtkWidget *notebook, GtkNotebookPage *page, guint page_num, DhWindow *window) { DhWindowPriv *priv; priv = window->priv; g_signal_handlers_unblock_by_func (priv->book_tree, window_tree_link_selected_cb, window); } static void window_html_switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page, guint new_page_num, DhWindow *window) { DhWindowPriv *priv; GtkWidget *new_page; priv = window->priv; new_page = gtk_notebook_get_nth_page (notebook, new_page_num); if (new_page) { DhHtml *new_html; gchar *title, *location; new_html = g_object_get_data (G_OBJECT (new_page), "html"); window_update_title (window, new_html); return; title = dh_html_get_title (new_html); gtk_window_set_title (GTK_WINDOW (window), title); g_free (title); /* Sync the book tree. */ location = dh_html_get_location (new_html); if (location) { dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree), location); g_free (location); } window_check_history (window, new_html); } else { gtk_window_set_title (GTK_WINDOW (window), "Devhelp"); window_check_history (window, NULL); } } static void window_populate (DhWindow *window) { DhWindowPriv *priv; GtkWidget *book_tree_sw; GNode *contents_tree; GList *keywords; gint hpaned_position; priv = window->priv; gtk_ui_manager_add_ui_from_file (priv->manager, DATADIR "/devhelp/ui/window.ui", NULL); gtk_ui_manager_ensure_update (priv->manager); priv->hpaned = gtk_hpaned_new (); gtk_box_pack_start (GTK_BOX (priv->main_box), priv->hpaned, TRUE, TRUE, 0); hpaned_position = gconf_client_get_int (priv->gconf_client, GCONF_PANED_LOCATION, NULL); /* This workaround for broken schema installs is not really working that * well, since it makes having a 0 location not possible. */ if (hpaned_position <= 0) { hpaned_position = DEFAULT_PANED_LOC; } gtk_paned_set_position (GTK_PANED (priv->hpaned), hpaned_position); /* Search and contents notebook. */ priv->control_notebook = gtk_notebook_new (); gtk_paned_add1 (GTK_PANED (priv->hpaned), priv->control_notebook); g_signal_connect (priv->control_notebook, "switch-page", G_CALLBACK (window_control_switch_page_cb), window); g_signal_connect_after (priv->control_notebook, "switch-page", G_CALLBACK (window_control_after_switch_page_cb), window); book_tree_sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (book_tree_sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (book_tree_sw), GTK_SHADOW_IN); gtk_container_set_border_width (GTK_CONTAINER (book_tree_sw), 2); contents_tree = dh_base_get_book_tree (priv->base); keywords = dh_base_get_keywords (priv->base); priv->book_tree = dh_book_tree_new (contents_tree); gtk_container_add (GTK_CONTAINER (book_tree_sw), priv->book_tree); gtk_notebook_append_page (GTK_NOTEBOOK (priv->control_notebook), book_tree_sw, gtk_label_new (_("Contents"))); g_signal_connect (priv->book_tree, "link-selected", G_CALLBACK (window_tree_link_selected_cb), window); priv->search = dh_search_new (keywords); gtk_notebook_append_page (GTK_NOTEBOOK (priv->control_notebook), priv->search, gtk_label_new (_("Search"))); g_signal_connect (priv->search, "link-selected", G_CALLBACK (window_search_link_selected_cb), window); priv->vbox = gtk_vbox_new (FALSE, 0); gtk_paned_add2 (GTK_PANED (priv->hpaned), priv->vbox); /* HTML tabs notebook. */ priv->html_notebook = gtk_notebook_new (); gtk_box_pack_start (GTK_BOX (priv->vbox), priv->html_notebook, TRUE, TRUE, 0); g_signal_connect (priv->html_notebook, "switch-page", G_CALLBACK (window_html_switch_page_cb), window); /* Create findbar. */ priv->findbar = egg_find_bar_new (); gtk_widget_set_no_show_all (priv->findbar, TRUE); gtk_box_pack_start (GTK_BOX (priv->vbox), priv->findbar, FALSE, FALSE, 0); g_signal_connect (priv->findbar, "notify::search-string", G_CALLBACK(window_findbar_search_changed_cb), window); g_signal_connect (priv->findbar, "notify::case-sensitive", G_CALLBACK (window_findbar_case_sensitive_changed_cb), window); g_signal_connect (priv->findbar, "previous", G_CALLBACK (window_find_previous_cb), window); g_signal_connect (priv->findbar, "next", G_CALLBACK (window_find_next_cb), window); g_signal_connect (priv->findbar, "close", G_CALLBACK (window_findbar_close_cb), window); dh_preferences_setup_fonts (); gtk_widget_show_all (priv->hpaned); window_open_new_tab (window, NULL); } static void window_activate_new_window (GtkAction *action, DhWindow *window) { DhWindowPriv *priv; GtkWidget *new_window; priv = window->priv; new_window = dh_base_new_window (priv->base); gtk_widget_show (new_window); } static void window_activate_new_tab (GtkAction *action, DhWindow *window) { DhWindowPriv *priv; priv = window->priv; window_open_new_tab (window, NULL); } static void window_activate_close (GtkAction *action, DhWindow *window) { DhWindowPriv *priv; gint page_num; priv = window->priv; page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->html_notebook)); gtk_notebook_remove_page (GTK_NOTEBOOK (priv->html_notebook), page_num); if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->html_notebook)) == 0) { window_save_state (window); gtk_widget_destroy (GTK_WIDGET (window)); } } static void window_activate_quit (GtkAction *action, DhWindow *window) { gtk_main_quit (); } static void window_activate_copy (GtkAction *action, DhWindow *window) { GtkWidget *widget; widget = gtk_window_get_focus (GTK_WINDOW (window)); if (GTK_IS_EDITABLE (widget)) { gtk_editable_copy_clipboard (GTK_EDITABLE (widget)); } else { DhHtml *html; html = window_get_active_html (window); dh_html_copy_selection (html); } } static void window_activate_find (GtkAction *action, DhWindow *window) { DhWindowPriv *priv; DhHtml *html; priv = window->priv; html = window_get_active_html (window); dh_html_search_find ( html, egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar))); dh_html_search_set_case_sensitive ( html, egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar))); gtk_widget_show (priv->findbar); gtk_widget_grab_focus (priv->findbar); } static void window_activate_preferences (GtkAction *action, DhWindow *window) { dh_preferences_show_dialog (GTK_WINDOW (window)); } static void window_activate_back (GtkAction *action, DhWindow *window) { DhWindowPriv *priv; DhHtml *html; GtkWidget *frame; priv = window->priv; frame = gtk_notebook_get_nth_page ( GTK_NOTEBOOK (priv->html_notebook), gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->html_notebook))); html = g_object_get_data (G_OBJECT (frame), "html"); dh_html_go_back (html); } static void window_activate_forward (GtkAction *action, DhWindow *window) { DhWindowPriv *priv; DhHtml *html; GtkWidget *frame; priv = window->priv; frame = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->html_notebook), gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->html_notebook)) ); html = g_object_get_data (G_OBJECT (frame), "html"); dh_html_go_forward (html); } static void window_activate_show_contents (GtkAction *action, DhWindow *window) { DhWindowPriv *priv; priv = window->priv; gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 0); gtk_widget_grab_focus (priv->book_tree); } static void window_activate_show_search (GtkAction *action, DhWindow *window) { DhWindowPriv *priv; priv = window->priv; gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1); dh_search_grab_focus (DH_SEARCH (priv->search)); } static void window_activate_about (GtkAction *action, DhWindow *window) { const gchar *authors[] = { "Mikael Hallendal ", "Richard Hult ", "Johan Dahlin ", "Ross Burton ", NULL }; const gchar **documenters = NULL; const gchar *translator_credits = _("translator_credits"); gtk_show_about_dialog (GTK_WINDOW (window), "name",_("Devhelp"), "version", VERSION, "comments", _("A developer's help browser for GNOME 2"), "authors", authors, "documenters", documenters, "translator-credits", strcmp (translator_credits, "translator_credits") != 0 ? translator_credits : NULL, "website", "http://developer.imendio.com/wiki/Devhelp", "logo-icon-name", "devhelp", NULL); } static void window_save_state (DhWindow *window) { DhWindowPriv *priv; GdkWindowState state; gboolean maximized; priv = window->priv; state = gdk_window_get_state (GTK_WIDGET (window)->window); if (state & GDK_WINDOW_STATE_MAXIMIZED) { maximized = TRUE; } else { maximized = FALSE; } gconf_client_set_bool (priv->gconf_client, GCONF_MAIN_WINDOW_MAXIMIZED, maximized, NULL); /* If maximized don't save the size and position */ if (!maximized) { gint width, height; gint x, y; gtk_window_get_size (GTK_WINDOW (window), &width, &height); gconf_client_set_int (priv->gconf_client, GCONF_MAIN_WINDOW_WIDTH, width, NULL); gconf_client_set_int (priv->gconf_client, GCONF_MAIN_WINDOW_HEIGHT, height, NULL); gtk_window_get_position (GTK_WINDOW (window), &x, &y); gconf_client_set_int (priv->gconf_client, GCONF_MAIN_WINDOW_POS_X, x, NULL); gconf_client_set_int (priv->gconf_client, GCONF_MAIN_WINDOW_POS_Y, y, NULL); } gconf_client_set_int (priv->gconf_client, GCONF_PANED_LOCATION, gtk_paned_get_position (GTK_PANED (priv->hpaned)), NULL); if (gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->control_notebook)) == 0) { gconf_client_set_string (priv->gconf_client, GCONF_SELECTED_TAB, "content", NULL); } else { gconf_client_set_string (priv->gconf_client, GCONF_SELECTED_TAB, "search", NULL); } } static void window_restore_state (DhWindow *window) { DhWindowPriv *priv; gboolean maximized; int width, height; int x, y; gchar *tab; priv = window->priv; width = gconf_client_get_int (priv->gconf_client, GCONF_MAIN_WINDOW_WIDTH, NULL); if (width <= 0) { width = DEFAULT_WIDTH; } height = gconf_client_get_int (priv->gconf_client, GCONF_MAIN_WINDOW_HEIGHT, NULL); if (height <= 0) { height = DEFAULT_HEIGHT; } gtk_window_set_default_size (GTK_WINDOW (window), width, height); x = gconf_client_get_int (priv->gconf_client, GCONF_MAIN_WINDOW_POS_X, NULL); y = gconf_client_get_int (priv->gconf_client, GCONF_MAIN_WINDOW_POS_Y, NULL); gtk_window_move (GTK_WINDOW (window), x, y); maximized = gconf_client_get_bool (priv->gconf_client, GCONF_MAIN_WINDOW_MAXIMIZED, NULL); if (maximized) { gtk_window_maximize (GTK_WINDOW (window)); } tab = gconf_client_get_string (priv->gconf_client, GCONF_SELECTED_TAB, NULL); if (!tab || strcmp (tab, "") == 0 || strcmp (tab, "content") == 0) { gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 0); gtk_widget_grab_focus (priv->book_tree); } else { gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1); dh_search_grab_focus (DH_SEARCH (priv->search)); } g_free (tab); } static gboolean window_delete_cb (GtkWidget *widget, GdkEventAny *event, gpointer user_data) { window_save_state (DH_WINDOW (widget)); return FALSE; } static void window_tree_link_selected_cb (GObject *ignored, DhLink *link, DhWindow *window) { DhWindowPriv *priv; DhHtml *html; priv = window->priv; html = window_get_active_html (window); /* Block so we don't try to sync the tree when we have already clicked * in it. */ g_signal_handlers_block_by_func (html, window_html_open_uri_cb, window); dh_html_open_uri (html, link->uri); g_signal_handlers_unblock_by_func (html, window_html_open_uri_cb, window); window_check_history (window, html); } static void window_search_link_selected_cb (GObject *ignored, DhLink *link, DhWindow *window) { DhWindowPriv *priv; DhHtml *html; priv = window->priv; html = window_get_active_html (window); dh_html_open_uri (html, link->uri); window_check_history (window, html); } static void window_manager_add_widget (GtkUIManager *manager, GtkWidget *widget, DhWindow *window) { DhWindowPriv *priv; priv = window->priv; gtk_box_pack_start (GTK_BOX (priv->menu_box), widget, FALSE, FALSE, 0); gtk_widget_show (widget); } static void window_check_history (DhWindow *window, DhHtml *html) { DhWindowPriv *priv; GtkAction *action; priv = window->priv; action = gtk_action_group_get_action (priv->action_group, "Forward"); g_object_set (action, "sensitive", html ? dh_html_can_go_forward (html) : FALSE, NULL); action = gtk_action_group_get_action (priv->action_group, "Back"); g_object_set (action, "sensitive", html ? dh_html_can_go_back (html) : FALSE, NULL); } static void window_html_location_changed_cb (DhHtml *html, const gchar *location, DhWindow *window) { DhWindowPriv *priv; priv = window->priv; if (html == window_get_active_html (window)) { window_check_history (window, html); } } static gboolean window_html_open_uri_cb (DhHtml *html, const gchar *uri, DhWindow *window) { DhWindowPriv *priv; priv = window->priv; if (html == window_get_active_html (window)) { dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree), uri); } return FALSE; } static void window_html_title_changed_cb (DhHtml *html, const gchar *title, DhWindow *window) { window_update_title (window, window_get_active_html (window)); } static void window_findbar_search_changed_cb (GObject *object, GParamSpec *pspec, DhWindow *window) { DhWindowPriv *priv; DhHtml *html; priv = window->priv; html = window_get_active_html (window); dh_html_search_find (html, egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar))); } static void window_findbar_case_sensitive_changed_cb (GObject *object, GParamSpec *pspec, DhWindow *window) { DhWindowPriv *priv; DhHtml *html; priv = window->priv; html = window_get_active_html (window); dh_html_search_set_case_sensitive ( html, egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar))); } static void window_find_next_cb (GtkEntry *entry, DhWindow *window) { DhHtml *html; DhWindowPriv *priv = window->priv; priv = window->priv; gtk_widget_show (priv->findbar); html = window_get_active_html (window); dh_html_search_find_again (html, FALSE); } static void window_find_previous_cb (GtkEntry *entry, DhWindow *window) { DhHtml *html; DhWindowPriv *priv = window->priv; priv = window->priv; gtk_widget_show (priv->findbar); html = window_get_active_html (window); dh_html_search_find_again (html, TRUE); } static void window_findbar_close_cb (GtkWidget *widget, DhWindow *window) { DhWindowPriv *priv; priv = window->priv; gtk_widget_hide (priv->findbar); } static void window_html_open_new_tab_cb (DhHtml *html, const gchar *location, DhWindow *window) { window_open_new_tab (window, location); } static void window_html_tab_accel_cb (GtkAccelGroup *accel_group, GObject *object, guint key, GdkModifierType mod, DhWindow *window) { DhWindowPriv *priv; gint i, num; priv = window->priv; num = -1; for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) { if (tab_accel_keys[i] == key) { num = i; break; } } if (num != -1) { gtk_notebook_set_current_page ( GTK_NOTEBOOK (priv->html_notebook), num); } } static void window_open_new_tab (DhWindow *window, const gchar *location) { DhWindowPriv *priv; DhHtml *html; GtkWidget *frame; GtkWidget *view; GtkWidget *label; gint num; priv = window->priv; html = dh_html_new (); view = dh_html_get_widget (html); gtk_widget_show (view); frame = gtk_frame_new (NULL); gtk_widget_show (frame); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); gtk_container_set_border_width (GTK_CONTAINER (frame), 2); gtk_container_add (GTK_CONTAINER (frame), view); g_object_set_data (G_OBJECT (frame), "html", html); label = window_new_tab_label (window, _("Empty Page")); gtk_widget_show (label); g_signal_connect (html, "title-changed", G_CALLBACK (window_html_title_changed_cb), window); g_signal_connect (html, "open-uri", G_CALLBACK (window_html_open_uri_cb), window); g_signal_connect (html, "location-changed", G_CALLBACK (window_html_location_changed_cb), window); g_signal_connect (html, "open-new-tab", G_CALLBACK (window_html_open_new_tab_cb), window); num = gtk_notebook_append_page (GTK_NOTEBOOK (priv->html_notebook), frame, NULL); gtk_notebook_set_tab_label (GTK_NOTEBOOK (priv->html_notebook), frame, label); gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (priv->html_notebook), frame, TRUE, TRUE, GTK_PACK_START); /* Hack to get GtkMozEmbed to work properly. */ gtk_widget_realize (view); if (location) { dh_html_open_uri (html, location); } else { dh_html_clear (html); } gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->html_notebook), num); } static GtkWidget* window_new_tab_label (DhWindow *window, const gchar *str) { GtkWidget *label; label = gtk_label_new (str); gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_misc_set_padding (GTK_MISC (label), 0, 0); return label; } static DhHtml * window_get_active_html (DhWindow *window) { DhWindowPriv *priv; gint page_num; GtkWidget *page; priv = window->priv; page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->html_notebook)); if (page_num == -1) { return NULL; } page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->html_notebook), page_num); return g_object_get_data (G_OBJECT (page), "html"); } static void window_update_title (DhWindow *window, DhHtml *html) { DhWindowPriv *priv; gchar *html_title; const gchar *book_title; gchar *full_title; priv = window->priv; html_title = dh_html_get_title (html); window_tab_set_title (window, html, html_title); if (html_title && *html_title == '\0') { g_free (html_title); html_title = NULL; } book_title = dh_book_tree_get_selected_book_title (DH_BOOK_TREE (priv->book_tree)); /* Don't use both titles if they are the same. */ if (book_title && html_title && strcmp (book_title, html_title) == 0) { g_free (html_title); html_title = NULL; } if (!book_title) { book_title = "Devhelp"; } if (html_title) { full_title = g_strdup_printf ("%s : %s", book_title, html_title); g_free (html_title); } else { full_title = g_strdup (book_title); } gtk_window_set_title (GTK_WINDOW (window), full_title); g_free (full_title); } static void window_tab_set_title (DhWindow *window, DhHtml *html, const gchar *title) { DhWindowPriv *priv; gint num_pages, i; GtkWidget *view; GtkWidget *page; GtkWidget *label; priv = window->priv; view = dh_html_get_widget (html); if (!title || title[0] == '\0') { title = _("Empty Page"); } num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->html_notebook)); for (i = 0; i < num_pages; i++) { page = gtk_notebook_get_nth_page ( GTK_NOTEBOOK (priv->html_notebook), i); /* The html widget is inside a frame. */ if (gtk_bin_get_child (GTK_BIN (page)) == view) { label = gtk_notebook_get_tab_label ( GTK_NOTEBOOK (priv->html_notebook), page); if (label) { gtk_label_set_text (GTK_LABEL (label), title); } break; } } } GtkWidget * dh_window_new (DhBase *base) { DhWindow *window; DhWindowPriv *priv; window = g_object_new (DH_TYPE_WINDOW, NULL); priv = window->priv; priv->base = g_object_ref (base); g_signal_connect (window, "delete-event", G_CALLBACK (window_delete_cb), NULL); window_populate (window); window_restore_state (window); gtk_window_set_icon_name (GTK_WINDOW (window), "devhelp"); return GTK_WIDGET (window); } void dh_window_search (DhWindow *window, const gchar *str) { DhWindowPriv *priv; g_return_if_fail (DH_IS_WINDOW (window)); priv = window->priv; gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1); dh_search_set_search_string (DH_SEARCH (priv->search), str); } void dh_window_focus_search (DhWindow *window) { DhWindowPriv *priv; g_return_if_fail (DH_IS_WINDOW (window)); priv = window->priv; gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1); dh_search_grab_focus (DH_SEARCH (priv->search)); }