/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * The GIMP Help Browser * Copyright (C) 1999 Sven Neumann * Michael Natterer * * Some code & ideas stolen from the GNOME help browser. * * 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 #include #include #include #include "queue.h" #include "libgimp/stdplugins-intl.h" #include "forward.xpm" #include "back.xpm" /* defines */ #ifdef __EMX__ #define chdir _chdir2 #endif #define GIMP_HELP_EXT_NAME "extension_gimp_help_browser" #define GIMP_HELP_TEMP_EXT_NAME "extension_gimp_help_browser_temp" #define GIMP_HELP_PREFIX "help" enum { CONTENTS, INDEX, HELP }; enum { URL_UNKNOWN, URL_NAMED, /* ??? */ URL_JUMP, URL_FILE_LOCAL, /* aliases */ URL_LAST = URL_FILE_LOCAL }; /* structures */ typedef struct { gint index; gchar *label; Queue *queue; gchar *current_ref; GtkWidget *html; gchar *home; } HelpPage; typedef struct { gchar *title; gchar *ref; gint count; } HistoryItem; /* constant strings */ static gchar *doc_not_found_format_string = N_("Document not found" "" "
" "

" "%s" "

Couldn't find document

" "%s" "
" "

" "This either means that the help for this topic has not been written " "yet or that something is wrong with your installation. " "Please check carefully before you report this as a bug." "" ""); static gchar *dir_not_found_format_string = N_("Directory not found" "" "

" "

" "%s" "

Couldn't change to directory

" "%s" "

while trying to access

" "%s" "
" "

" "This either means that the help for this topic has not been written " "yet or that something is wrong with your installation. " "Please check carefully before you report this as a bug." "" ""); static gchar *eek_png_tag = "

Eeek!

"; /* the three help notebook pages */ static HelpPage pages[] = { { CONTENTS, N_("Contents"), NULL, NULL, NULL, "contents.html" }, { INDEX, N_("Index"), NULL, NULL, NULL, "index.html" }, { HELP, NULL, NULL, NULL, NULL, "introduction.html" } }; static gchar *gimp_help_root = NULL; static HelpPage *current_page = &pages[HELP]; static GList *history = NULL; static GtkWidget *back_button; static GtkWidget *forward_button; static GtkWidget *notebook; static GtkWidget *combo; static GtkTargetEntry help_dnd_target_table[] = { { "_NETSCAPE_URL", 0, 0 }, }; static guint n_help_dnd_targets = (sizeof (help_dnd_target_table) / sizeof (help_dnd_target_table[0])); /* GIMP plugin stuff */ static void query (void); static void run (gchar *name, gint nparams, GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; static gboolean temp_proc_installed = FALSE; /* forward declaration */ static gint load_page (HelpPage *source_page, HelpPage *dest_page, gchar *ref, gint pos, gboolean add_to_queue, gboolean add_to_history); /* functions */ static void close_callback (GtkWidget *widget, gpointer user_data) { gtk_main_quit (); } static void update_toolbar (HelpPage *page) { if (back_button) gtk_widget_set_sensitive (back_button, queue_isprev (page->queue)); if (forward_button) gtk_widget_set_sensitive (forward_button, queue_isnext (page->queue)); } static void jump_to_anchor (HelpPage *page, gchar *anchor) { gint pos; g_return_if_fail (page != NULL && anchor != NULL); if (*anchor != '#') { gchar *a = g_strconcat ("#", anchor, NULL); XmHTMLAnchorScrollToName (page->html, a); g_free (a); } else XmHTMLAnchorScrollToName (page->html, anchor); pos = gtk_xmhtml_get_topline (GTK_XMHTML (page->html)); queue_add (page->queue, page->current_ref, pos); update_toolbar (page); } static void forward_callback (GtkWidget *widget, gpointer data) { gchar *ref; gint pos; if (!(ref = queue_next (current_page->queue, &pos))) return; load_page (current_page, current_page, ref, pos, FALSE, FALSE); queue_move_next (current_page->queue); update_toolbar (current_page); } static void back_callback (GtkWidget *widget, gpointer data) { gchar *ref; gint pos; if (!(ref = queue_prev (current_page->queue, &pos))) return; load_page (current_page, current_page, ref, pos, FALSE, FALSE); queue_move_prev (current_page->queue); update_toolbar (current_page); } static void entry_changed_callback (GtkWidget *widget, gpointer data) { GList *list; HistoryItem *item; gchar *entry_text; gchar *compare_text; gboolean found = FALSE; entry_text = gtk_entry_get_text (GTK_ENTRY (widget)); for (list = history; list && !found; list = list->next) { item = (HistoryItem *) list->data; if (item->count) compare_text = g_strdup_printf ("%s <%i>", item->title, item->count + 1); else compare_text = item->title; if (strcmp (compare_text, entry_text) == 0) { load_page (&pages[HELP], &pages[HELP], item->ref, 0, TRUE, FALSE); found = TRUE; } if (item->count) g_free (compare_text); } } static gint entry_button_press_callback (GtkWidget *widget, GdkEventButton *bevent, gpointer data) { if (current_page != &pages[HELP]) gtk_notebook_set_page (GTK_NOTEBOOK (notebook), HELP); return FALSE; } static void history_add (gchar *ref, gchar *title) { GList *list; GList *found = NULL; HistoryItem *item; GList *combo_list = NULL; gint title_found_count = 0; for (list = history; list && !found; list = list->next) { item = (HistoryItem *) list->data; if (strcmp (item->title, title) == 0) { if (strcmp (item->ref, ref) != 0) { title_found_count++; continue; } found = list; } } if (found) { item = (HistoryItem *) found->data; history = g_list_remove_link (history, found); } else { item = g_new (HistoryItem, 1); item->ref = g_strdup (ref); item->title = g_strdup (title); item->count = title_found_count; } history = g_list_prepend (history, item); for (list = history; list; list = list->next) { gchar* combo_title; item = (HistoryItem *) list->data; if (item->count) combo_title = g_strdup_printf ("%s <%i>", item->title, item->count + 1); else combo_title = g_strdup (item->title); combo_list = g_list_prepend (combo_list, combo_title); } combo_list = g_list_reverse (combo_list); gtk_signal_handler_block_by_data (GTK_OBJECT (GTK_COMBO (combo)->entry), combo); gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); /* gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), item->title); */ gtk_signal_handler_unblock_by_data (GTK_OBJECT (GTK_COMBO (combo)->entry), combo); for (list = combo_list; list; list = list->next) g_free (list->data); g_list_free (combo_list); } static void html_source (HelpPage *page, gchar *ref, gint pos, gchar *source, gboolean add_to_queue, gboolean add_to_history) { gchar *title = NULL; g_return_if_fail (page != NULL && ref != NULL && source != NULL); /* Load it up */ gtk_xmhtml_source (GTK_XMHTML (page->html), source); gtk_xmhtml_set_topline (GTK_XMHTML(page->html), pos); if (add_to_queue) queue_add (page->queue, ref, pos); if (page->index == HELP) { title = XmHTMLGetTitle (page->html); if (!title) title = (_("")); if (add_to_history) history_add (ref, title); gtk_signal_handler_block_by_data (GTK_OBJECT (GTK_COMBO (combo)->entry), combo); gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), title); gtk_signal_handler_unblock_by_data (GTK_OBJECT (GTK_COMBO (combo)->entry), combo); } update_toolbar (page); } static gint load_page (HelpPage *source_page, HelpPage *dest_page, gchar *ref, gint pos, gboolean add_to_queue, gboolean add_to_history) { GString *file_contents; FILE *afile = NULL; char aline[1024]; gchar *old_dir; gchar *new_dir, *new_base; gchar *new_ref; gboolean page_valid = FALSE; gboolean filters_dir = FALSE; g_return_val_if_fail (ref != NULL && source_page != NULL && dest_page != NULL, FALSE); old_dir = g_dirname (source_page->current_ref); new_dir = g_dirname (ref); new_base = g_basename (ref); /* return value is intentionally ignored */ chdir (old_dir); file_contents = g_string_new (NULL); if (chdir (new_dir) == -1) { if (g_path_is_absolute (ref)) new_ref = g_strdup (ref); else new_ref = g_strconcat (old_dir, G_DIR_SEPARATOR_S, ref, NULL); g_string_sprintf (file_contents, gettext (dir_not_found_format_string), eek_png_tag, new_dir, new_ref); html_source (dest_page, new_ref, 0, file_contents->str, add_to_queue, FALSE); goto FINISH; } if (strcmp (g_basename (new_dir), "filters") == 0) filters_dir = TRUE; g_free (new_dir); new_dir = g_get_current_dir (); new_ref = g_strconcat (new_dir, G_DIR_SEPARATOR_S, new_base, NULL); if (strcmp (dest_page->current_ref, new_ref) == 0) { gtk_xmhtml_set_topline (GTK_XMHTML (dest_page->html), pos); if (add_to_queue) queue_add (dest_page->queue, new_ref, pos); goto FINISH; } /* * handle basename like: filename.html#11111 -> filename.html */ g_strdelimit (new_base,"#",'\0'); afile = fopen (new_base, "rt"); if (afile != NULL) { while (fgets (aline, sizeof (aline), afile)) file_contents = g_string_append (file_contents, aline); fclose (afile); } else if (filters_dir) { gchar *undocumented_filter; undocumented_filter = g_strconcat (new_dir, G_DIR_SEPARATOR_S, "undocumented_filter.html", NULL); afile = fopen (undocumented_filter, "rt"); if (afile != NULL) { while (fgets (aline, sizeof (aline), afile)) file_contents = g_string_append (file_contents, aline); fclose (afile); } g_free (undocumented_filter); } if (strlen (file_contents->str) <= 0) { chdir (old_dir); g_string_sprintf (file_contents, gettext (doc_not_found_format_string), eek_png_tag, ref); } else page_valid = TRUE; html_source (dest_page, new_ref, 0, file_contents->str, add_to_queue, add_to_history && page_valid); FINISH: g_free (dest_page->current_ref); dest_page->current_ref = new_ref; g_string_free (file_contents, TRUE); g_free (old_dir); g_free (new_dir); gtk_notebook_set_page (GTK_NOTEBOOK (notebook), dest_page->index); return (page_valid); } static void xmhtml_activate (GtkWidget *html, gpointer data) { XmHTMLAnchorCallbackStruct *cbs = (XmHTMLAnchorCallbackStruct *) data; GimpParam *return_vals; gint nreturn_vals; switch (cbs->url_type) { case URL_JUMP: jump_to_anchor (current_page, cbs->href); break; case URL_FILE_LOCAL: load_page (current_page, &pages[HELP], cbs->href, 0, TRUE, TRUE); break; default: /* try to call netscape through the web_browser interface */ return_vals = gimp_run_procedure ("extension_web_browser", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_STRING, cbs->href, GIMP_PDB_INT32, FALSE, GIMP_PDB_END); gimp_destroy_params (return_vals, nreturn_vals); break; } } static void notebook_switch_callback (GtkNotebook *notebook, GtkNotebookPage *page, gint page_num, gpointer user_data) { GtkXmHTML *html; gint i; GList *children; g_return_if_fail (page_num >= 0 && page_num < 3); html = GTK_XMHTML (current_page->html); /* The html widget fails to do the following by itself */ GTK_WIDGET_UNSET_FLAGS (html->html.work_area, GTK_MAPPED); GTK_WIDGET_UNSET_FLAGS (html->html.vsb, GTK_MAPPED); GTK_WIDGET_UNSET_FLAGS (html->html.hsb, GTK_MAPPED); /* Frames */ for (i = 0; i < html->html.nframes; i++) GTK_WIDGET_UNSET_FLAGS (html->html.frames[i]->frame, GTK_MAPPED); /* Form widgets */ for (children = html->children; children; children = children->next) GTK_WIDGET_UNSET_FLAGS (children->data, GTK_MAPPED); /* Set the new page */ current_page = &pages[page_num]; } static void notebook_switch_after_callback (GtkNotebook *notebook, GtkNotebookPage *page, gint page_num, gpointer user_data) { GtkAccelGroup *accel_group = gtk_accel_group_get_default (); gtk_widget_add_accelerator (GTK_XMHTML (current_page->html)->html.vsb, "page_up", accel_group, 'b', 0, 0); gtk_widget_add_accelerator (GTK_XMHTML (current_page->html)->html.vsb, "page_down", accel_group, ' ', 0, 0); gtk_widget_add_accelerator (GTK_XMHTML (current_page->html)->html.vsb, "page_up", accel_group, GDK_Page_Up, 0, 0); gtk_widget_add_accelerator (GTK_XMHTML (current_page->html)->html.vsb, "page_down", accel_group, GDK_Page_Down, 0, 0); update_toolbar (current_page); } static gint notebook_label_button_press_callback (GtkWidget *widget, GdkEvent *event, gpointer data) { guint i = GPOINTER_TO_UINT (data); if (current_page != &pages[i]) gtk_notebook_set_page (GTK_NOTEBOOK (notebook), i); return TRUE; } static void combo_drag_begin (GtkWidget *widget, gpointer data) { } static void combo_drag_handle (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer data) { HelpPage *page = (HelpPage*)data; if (page->current_ref != NULL) { gtk_selection_data_set (selection_data, selection_data->target, 8, page->current_ref, strlen (page->current_ref)); } } static void page_up_callback (GtkWidget *widget, GtkWidget *html) { GtkAdjustment *adj; adj = GTK_ADJUSTMENT (GTK_XMHTML (html)->vsba); gtk_adjustment_set_value (adj, adj->value - (adj->page_size)); } static void page_down_callback (GtkWidget *widget, GtkWidget *html) { GtkAdjustment *adj; adj = GTK_ADJUSTMENT (GTK_XMHTML (html)->vsba); gtk_adjustment_set_value (adj, adj->value + (adj->page_size)); } static gint wheel_callback (GtkWidget *widget, GdkEventButton *bevent, GtkWidget *html) { GtkAdjustment *adj; gfloat new_value; if (! GTK_XMHTML (html)->html.needs_vsb) return FALSE; adj = GTK_ADJUSTMENT (GTK_XMHTML (html)->vsba); switch (bevent->button) { case 4: new_value = adj->value - adj->page_increment / 2; break; case 5: new_value = adj->value + adj->page_increment / 2; break; default: return FALSE; } new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size); gtk_adjustment_set_value (adj, new_value); return TRUE; } static gint set_initial_history (gpointer data) { gint add_to_history = GPOINTER_TO_INT (data); gchar *title; title = XmHTMLGetTitle (pages[HELP].html); if (add_to_history) history_add (pages[HELP].current_ref, title); gtk_signal_handler_block_by_data (GTK_OBJECT (GTK_COMBO (combo)->entry), combo); gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), title); gtk_signal_handler_unblock_by_data (GTK_OBJECT (GTK_COMBO (combo)->entry), combo); return FALSE; } gboolean open_browser_dialog (gchar *help_path, gchar *locale, gchar *help_file) { GtkWidget *window; GtkWidget *vbox, *hbox, *bbox, *html_box; GtkWidget *button; GtkWidget *title; GtkWidget *drag_source; GtkWidget *label; gchar *initial_dir; gchar *initial_ref; gchar *root_dir; gchar *eek_png_path; gint success; guint i; gimp_ui_init ("helpbrowser", TRUE); root_dir = g_strdup (gimp_help_root); if (chdir (root_dir) == -1) { g_message (_("GIMP Help Browser Error.\n\n" "Couldn't find my root html directory.\n" "(%s)"), root_dir); return FALSE; } eek_png_path = g_strconcat (root_dir, G_DIR_SEPARATOR_S, "images", G_DIR_SEPARATOR_S, "eek.png", NULL); if (access (eek_png_path, R_OK) == 0) eek_png_tag = g_strdup_printf ("", eek_png_path); g_free (eek_png_path); if (chdir (help_path) == -1) { g_message (_("GIMP Help Browser Error.\n\n" "Couldn't find my root html directory.\n" "(%s)"), help_path); return FALSE; } initial_dir = g_get_current_dir (); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (close_callback), NULL); gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (close_callback), NULL); gtk_window_set_wmclass (GTK_WINDOW (window), "helpbrowser", "Gimp"); gtk_window_set_title (GTK_WINDOW (window), _("GIMP Help Browser")); gimp_help_connect_help_accel (window, gimp_standard_help_func, "dialogs/help.html"); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); bbox = gtk_hbutton_box_new (); gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 0); gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, FALSE, 0); back_button = gimp_pixmap_button_new (back_xpm, _("Back")); gtk_button_set_relief (GTK_BUTTON (back_button), GTK_RELIEF_NONE); gtk_container_add (GTK_CONTAINER (bbox), back_button); gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE); gtk_signal_connect (GTK_OBJECT (back_button), "clicked", GTK_SIGNAL_FUNC (back_callback), NULL); gtk_widget_show (back_button); forward_button = gimp_pixmap_button_new (forward_xpm, _("Forward")); gtk_button_set_relief (GTK_BUTTON (forward_button), GTK_RELIEF_NONE); gtk_container_add (GTK_CONTAINER (bbox), forward_button); gtk_widget_set_sensitive (GTK_WIDGET (forward_button), FALSE); gtk_signal_connect (GTK_OBJECT (forward_button), "clicked", GTK_SIGNAL_FUNC (forward_callback), NULL); gtk_widget_show (forward_button); gtk_widget_show (bbox); bbox = gtk_hbutton_box_new (); gtk_box_pack_end (GTK_BOX (hbox), bbox, FALSE, FALSE, 0); button = gtk_button_new_with_label (_("Close")); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_container_add (GTK_CONTAINER (bbox), button); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (close_callback), NULL); gtk_widget_show (button); gtk_widget_show (bbox); gtk_widget_show (hbox); notebook = gtk_notebook_new (); gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); gtk_notebook_set_tab_vborder (GTK_NOTEBOOK (notebook), 0); gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0); for (i = 0; i < 3; i++) { static guint page_up_signal = 0; static guint page_down_signal = 0; pages[i].index = i; pages[i].html = gtk_xmhtml_new (); pages[i].queue = queue_new (); gtk_xmhtml_set_anchor_underline_type (GTK_XMHTML (pages[i].html), GTK_ANCHOR_SINGLE_LINE); gtk_xmhtml_set_anchor_buttons (GTK_XMHTML (pages[i].html), FALSE); gtk_widget_set_usize (GTK_WIDGET (pages[i].html), -1, 300); switch (i) { case CONTENTS: case INDEX: pages[i].current_ref = g_strconcat (root_dir, G_DIR_SEPARATOR_S, locale, G_DIR_SEPARATOR_S, ".", NULL); title = drag_source = gtk_event_box_new (); label = gtk_label_new (gettext (pages[i].label)); gtk_container_add (GTK_CONTAINER (title), label); gtk_widget_show (label); break; case HELP: pages[i].current_ref = g_strconcat (initial_dir, G_DIR_SEPARATOR_S, locale, G_DIR_SEPARATOR_S, ".", NULL); title = combo = gtk_combo_new (); drag_source = GTK_COMBO (combo)->entry; gtk_widget_set_usize (GTK_WIDGET (combo), 300, -1); gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); gtk_combo_set_use_arrows (GTK_COMBO (combo), TRUE); gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", GTK_SIGNAL_FUNC (entry_changed_callback), combo); gtk_signal_connect (GTK_OBJECT (GTK_WIDGET (GTK_COMBO (combo)->entry)), "button-press-event", GTK_SIGNAL_FUNC (entry_button_press_callback), NULL); gtk_widget_show (combo); break; default: title = drag_source = NULL; /* to please the compiler */ break; } /* connect to the button_press signal to make notebook switching work */ gtk_signal_connect (GTK_OBJECT (title), "button_press_event", GTK_SIGNAL_FUNC (notebook_label_button_press_callback), GUINT_TO_POINTER (i)); /* dnd source */ gtk_drag_source_set (GTK_WIDGET (drag_source), GDK_BUTTON1_MASK, help_dnd_target_table, n_help_dnd_targets, GDK_ACTION_MOVE | GDK_ACTION_COPY); gtk_signal_connect (GTK_OBJECT (drag_source), "drag_begin", GTK_SIGNAL_FUNC (combo_drag_begin), &pages[i]); gtk_signal_connect (GTK_OBJECT (drag_source), "drag_data_get", GTK_SIGNAL_FUNC (combo_drag_handle), &pages[i]); html_box = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (html_box), pages[i].html); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), html_box, title); gtk_widget_show (title); if (i == HELP && help_file) { initial_ref = g_strconcat (initial_dir, G_DIR_SEPARATOR_S, locale, G_DIR_SEPARATOR_S, help_file, NULL); } else { initial_ref = g_strconcat (root_dir, G_DIR_SEPARATOR_S, locale, G_DIR_SEPARATOR_S, pages[i].home, NULL); } success = load_page (&pages[i], &pages[i], initial_ref, 0, TRUE, FALSE); g_free (initial_ref); gtk_widget_show (pages[i].html); gtk_widget_show (html_box); gtk_signal_connect (GTK_OBJECT (pages[i].html), "activate", (GtkSignalFunc) xmhtml_activate, &pages[i]); if (! page_up_signal) { page_up_signal = gtk_object_class_user_signal_new (GTK_OBJECT (GTK_XMHTML (pages[i].html)->html.vsb)->klass, "page_up", GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); page_down_signal = gtk_object_class_user_signal_new (GTK_OBJECT (GTK_XMHTML (pages[i].html)->html.vsb)->klass, "page_down", GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); } gtk_signal_connect (GTK_OBJECT (GTK_XMHTML (pages[i].html)->html.vsb), "page_up", GTK_SIGNAL_FUNC (page_up_callback), pages[i].html); gtk_signal_connect (GTK_OBJECT (GTK_XMHTML (pages[i].html)->html.vsb), "page_down", GTK_SIGNAL_FUNC (page_down_callback), pages[i].html); gtk_signal_connect (GTK_OBJECT (GTK_XMHTML (pages[i].html)->html.work_area), "button_press_event", GTK_SIGNAL_FUNC (wheel_callback), pages[i].html); } g_free (root_dir); gtk_signal_connect (GTK_OBJECT (notebook), "switch-page", GTK_SIGNAL_FUNC (notebook_switch_callback), NULL); gtk_signal_connect_after (GTK_OBJECT (notebook), "switch-page", GTK_SIGNAL_FUNC (notebook_switch_after_callback), NULL); gtk_notebook_set_page (GTK_NOTEBOOK (notebook), HELP); gtk_widget_show (notebook); gtk_widget_show (vbox); gtk_widget_show (window); gtk_idle_add ((GtkFunction) set_initial_history, GINT_TO_POINTER (success)); g_free (initial_dir); return TRUE; } static gint idle_load_page (gpointer data) { gchar *path = data; load_page (&pages[HELP], &pages[HELP], path, 0, TRUE, TRUE); g_free (path); return FALSE; } static void run_temp_proc (gchar *name, gint nparams, GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; GimpPDBStatusType status = GIMP_PDB_SUCCESS; gchar *help_path; gchar *locale; gchar *help_file; gchar *path; /* set default values */ help_path = g_strdup (gimp_help_root); locale = g_strdup ("C"); help_file = g_strdup ("introduction.html"); /* Make sure all the arguments are there! */ if (nparams == 3) { if (param[0].data.d_string && strlen (param[0].data.d_string)) { g_free (help_path); help_path = g_strdup (param[0].data.d_string); g_strdelimit (help_path, "/", G_DIR_SEPARATOR); } if (param[1].data.d_string && strlen (param[1].data.d_string)) { g_free (locale); locale = g_strdup (param[1].data.d_string); } if (param[2].data.d_string && strlen (param[2].data.d_string)) { g_free (help_file); help_file = g_strdup (param[2].data.d_string); g_strdelimit (help_file, "/", G_DIR_SEPARATOR); } } path = g_strconcat (help_path, G_DIR_SEPARATOR_S, locale, G_DIR_SEPARATOR_S, help_file, NULL); g_free (help_path); g_free (locale); g_free (help_file); gtk_idle_add (idle_load_page, path); *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; } /* from libgimp/gimp.c */ void gimp_run_temp (void); static gboolean input_callback (GIOChannel *channel, GIOCondition condition, gpointer data) { /* We have some data in the wire - read it */ /* The below will only ever run a single proc */ gimp_run_temp (); return TRUE; } static void install_temp_proc (void) { static GimpParamDef args[] = { { GIMP_PDB_STRING, "help_path", "" }, { GIMP_PDB_STRING, "locale", "Langusge to use" }, { GIMP_PDB_STRING, "help_file", "Path of a local document to open. " "Can be relative to GIMP_HELP_PATH." } }; static gint nargs = sizeof (args) / sizeof (args[0]); gimp_install_temp_proc (GIMP_HELP_TEMP_EXT_NAME, "DON'T USE THIS ONE", "(Temporary procedure)", "Sven Neumann , " "Michael Natterer ", "Sven Neumann & Michael Natterer", "1999", NULL, "", GIMP_TEMPORARY, nargs, 0, args, NULL, run_temp_proc); /* Tie into the gdk input function */ g_io_add_watch (_readchannel, G_IO_IN | G_IO_PRI, input_callback, NULL); temp_proc_installed = TRUE; } static gboolean open_url (gchar *help_path, gchar *locale, gchar *help_file) { if (! open_browser_dialog (help_path, locale, help_file)) return FALSE; install_temp_proc (); gtk_main (); return TRUE; } MAIN () static void query (void) { static GimpParamDef args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive" }, { GIMP_PDB_STRING, "help_path", "" }, { GIMP_PDB_STRING, "locale", "Language to use" }, { GIMP_PDB_STRING, "help_file", "Path of a local document to open. " "Can be relative to GIMP_HELP_PATH." } }; static gint nargs = sizeof (args) / sizeof (args[0]); gimp_install_procedure (GIMP_HELP_EXT_NAME, "Browse the GIMP help pages", "A small and simple HTML browser optimzed for " "browsing the GIMP help pages.", "Sven Neumann , " "Michael Natterer ", "Sven Neumann & Michael Natterer", "1999", NULL, "", GIMP_EXTENSION, nargs, 0, args, NULL); } static void run (gchar *name, gint nparams, GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; GimpRunModeType run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; gchar *env_root_dir = NULL; gchar *help_path = NULL; gchar *locale = NULL; gchar *help_file = NULL; run_mode = param[0].data.d_int32; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; *nreturn_vals = 1; *return_vals = values; INIT_I18N_UI (); if (strcmp (name, GIMP_HELP_EXT_NAME) == 0) { switch (run_mode) { case GIMP_RUN_INTERACTIVE: case GIMP_RUN_NONINTERACTIVE: case GIMP_RUN_WITH_LAST_VALS: /* set default values */ env_root_dir = g_getenv ("GIMP_HELP_ROOT"); if (env_root_dir) { if (chdir (env_root_dir) == -1) { g_message (_("GIMP Help Browser Error.\n\n" "Couldn't find GIMP_HELP_ROOT html directory.\n" "(%s)"), env_root_dir); status = GIMP_PDB_EXECUTION_ERROR; break; } gimp_help_root = g_strdup (env_root_dir); } else { gimp_help_root = g_strconcat (gimp_data_directory(), G_DIR_SEPARATOR_S, GIMP_HELP_PREFIX, NULL); } help_path = g_strdup (gimp_help_root); locale = g_strdup ("C"); help_file = g_strdup ("introduction.html"); /* Make sure all the arguments are there! */ if (nparams == 4) { if (param[1].data.d_string && strlen (param[1].data.d_string)) { g_free (help_path); help_path = g_strdup (param[1].data.d_string); g_strdelimit (help_path, "/", G_DIR_SEPARATOR); } if (param[2].data.d_string && strlen (param[2].data.d_string)) { g_free (locale); locale = g_strdup (param[2].data.d_string); } if (param[3].data.d_string && strlen (param[3].data.d_string)) { g_free (help_file); help_file = g_strdup (param[3].data.d_string); g_strdelimit (help_file, "/", G_DIR_SEPARATOR); } } break; default: status = GIMP_PDB_CALLING_ERROR; break; } if (status == GIMP_PDB_SUCCESS) { if (!open_url (help_path, locale, help_file)) values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; else values[0].data.d_status = GIMP_PDB_SUCCESS; g_free (help_path); g_free (locale); g_free (help_file); } else values[0].data.d_status = status; } else values[0].data.d_status = GIMP_PDB_CALLING_ERROR; }