/* * Dillo * * Some code copied from: * The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include "history.h" #include "nav.h" #include "commands.h" #include "dw_gtk_scrolled_window.h" #include "dw_page.h" /* for a_Dw_page_add_anchor */ #include "bookmark.h" #include "interface.h" #include "menu.h" #include "selection.h" #include "gtk_ext_menu.h" #include "gtk_ext_menu_item.h" #include "gtk_menu_title.h" /* * Forward declarations */ static void Menu_pagemarks_goto_pagemark(GtkWidget *widget, gpointer client_data); /* * Make a new menu, insert it into the menu bar, and return it. */ static GtkWidget* Menu_new(GtkWidget *menubar, const char *name, gboolean right_justify, BrowserWindow *bw) { GtkWidget *menu; GtkWidget *menuitem; guint tmp_key; menu = gtk_menu_new(); menuitem = gtk_menu_item_new_with_label((char *) name); tmp_key = gtk_label_parse_uline(GTK_LABEL(GTK_BIN(menuitem)->child), name); gtk_widget_add_accelerator(menuitem, "activate_item", bw->accel_group, tmp_key, GDK_MOD1_MASK, 0); if ( right_justify ) gtk_menu_item_right_justify(GTK_MENU_ITEM(menuitem)); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu); gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuitem); gtk_widget_show(menuitem); gtk_menu_set_accel_group(GTK_MENU(menu), bw->accel_group); return menu; } /* * Pick the right URL for this popup. */ static void Menu_pick_url (GtkWidget *widget, gpointer client_data) { BrowserWindow *bw = (BrowserWindow *)client_data; if (gtk_object_get_data(GTK_OBJECT (GTK_MENU (widget->parent)), "url2")) { a_Menu_popup_set_url(bw, bw->menu_popup.url2); } /* clean the url2 tag (currently "over_image" is the only one using it) */ gtk_object_remove_data(GTK_OBJECT (bw->menu_popup.over_image), "url2"); } /* * Add an item to a menu, including the name, an accelerator (not yet * implemented), and a callback function for activation. */ static GtkWidget * Menu_add (GtkWidget *menu, const char *name, const char *accel, BrowserWindow *bw, void (*callback) (GtkWidget *widget, void *data), void *data) { GtkWidget *menuitem; GtkAccelGroup *menu_accels; GdkModifierType accel_mods; guint accel_key; guint tmp_key; menuitem = gtk_menu_item_new_with_label((char *) name); gtk_menu_append(GTK_MENU(menu), menuitem); menu_accels = gtk_menu_ensure_uline_accel_group(GTK_MENU(menu)); tmp_key = gtk_label_parse_uline(GTK_LABEL(GTK_BIN(menuitem)->child), name); gtk_widget_add_accelerator(menuitem, "activate_item", menu_accels, tmp_key, 0, 0); gtk_widget_show(menuitem); if (accel != NULL) { gtk_accelerator_parse(accel, &accel_key, &accel_mods); gtk_widget_add_accelerator(menuitem, "activate", bw->accel_group, accel_key, (guint)accel_mods, GTK_ACCEL_VISIBLE); } if (callback != NULL) { gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc) Menu_pick_url, bw); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc) callback, data); } return menuitem; } /* * Add a menu title. */ static GtkWidget *Menu_add_title (GtkWidget *menu, const char *name) { GtkWidget *menuitem; menuitem = a_Gtk_menu_title_new(name); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_widget_show(menuitem); return menuitem; } /* * Add a separator into the menu. */ static void Menu_sep(GtkWidget *menu) { GtkWidget *widget; widget = gtk_menu_item_new(); gtk_menu_append(GTK_MENU(menu), widget); gtk_widget_set_sensitive(widget, FALSE); gtk_widget_show(widget); } /* * Make up a new menubar for a main browser window. The accelerator table * is stored in bw->accel_group. * Currently does not deal with dynamic menu items (bookmarks and history). * CP: It *seems* to handle dynamic menu items... */ GtkWidget *a_Menu_mainbar_new(BrowserWindow *bw, gint tiny) { GtkWidget *menubar; GtkWidget *file_menu; /* GtkWidget *help_menu; */ bw->menubar = menubar = gtk_menu_bar_new(); /* FILE MENU */ file_menu = Menu_new(menubar, tiny ? "_F" : "_File", FALSE, bw); Menu_add(file_menu, "_New Browser", "N", bw, a_Commands_new_callback, bw); Menu_add(file_menu, "_Open File...", "O", bw, a_Commands_openfile_callback, bw); Menu_add(file_menu, "Open _URL...", "L", bw, a_Commands_openurl_callback, bw); /* Menu_add(file_menu, "_Preferences", "E", bw, a_Commands_prefs_callback, bw); */ Menu_add(file_menu, "Close Window", "Q", bw, a_Commands_close_callback, bw); Menu_sep(file_menu); Menu_add(file_menu, "Exit Dillo", "Q", bw, a_Commands_exit_callback, bw); /* HELP MENU help_menu = Menu_new(menubar, "_Help", TRUE, bw); Menu_add(help_menu, "Dillo _Home", NULL, bw, a_Commands_helphome_callback, bw); */ return menubar; } /* * Make a new popup menu and return it. */ GtkWidget *a_Menu_popup_op_new(BrowserWindow *bw) { GtkWidget *menu; menu = gtk_menu_new(); Menu_sep(menu); Menu_add_title(menu, "PAGE OPTIONS"); Menu_sep(menu); Menu_add(menu, "View page Source", NULL, bw, a_Commands_viewsource_callback, bw); bw->viewbugs_menuitem = Menu_add(menu, "View page Bugs", NULL,bw, NULL,bw); Menu_add(menu, "Bookmark this page", NULL, bw, a_Commands_addbm_callback, bw); Menu_sep(menu); Menu_add(menu, "_Find Text", "F", bw, a_Commands_findtext_callback, bw); bw->pagemarks_menuitem = Menu_add(menu, "Jump to...", NULL, bw, NULL, bw); Menu_sep(menu); Menu_add(menu, "Save page As...", NULL, bw, a_Commands_save_callback, bw); return menu; } /* * Set the popup's primary DilloUrl */ void a_Menu_popup_set_url(BrowserWindow *bw, const DilloUrl *url) { if (bw->menu_popup.url) a_Url_free(bw->menu_popup.url); bw->menu_popup.url = a_Url_dup(url); } /* * Set the popup's secondary DilloUrl * Note: this URL is used by the image submenu of the link popup. * (If the need arises, this can be extended using an URL array in the popup * structure, and by setting the to-be-picked-URL-index in the popup) */ void a_Menu_popup_set_url2(BrowserWindow *bw, const DilloUrl *url) { if (bw->menu_popup.url2) a_Url_free(bw->menu_popup.url2); bw->menu_popup.url2 = a_Url_dup(url); } /* * Remove the popup's secondary DilloUrl. * (This is done at popup time, so and old "url2" can't linger) */ void a_Menu_popup_clear_url2(GtkWidget *menu_popup) { /* clear the url2 tag (currently "over_image" is the only one using it) */ gtk_object_remove_data(GTK_OBJECT (menu_popup), "url2"); } /* * Get the popup's DilloUrl */ DilloUrl *a_Menu_popup_get_url(BrowserWindow *bw) { return bw->menu_popup.url; } /* * Put the url in the status bar when moving cursor over menuitem. */ static void Menu_popup_history_select_callback(GtkWidget *widget, gpointer data) { gint idx; BrowserWindow *bw = data; idx = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT (widget), "nav_idx")); if (idx >= 0 && idx < a_Nav_stack_size(bw)) { a_Interface_msg(bw, "%s", URL_STR_(a_History_get_url(NAV_IDX(bw,idx)))); bw->status_is_link = 1; } } /* * Remove the url in the status bar when removing cursor from menuitem. */ static void Menu_popup_history_deselect_callback(GtkWidget *widget, gpointer data) { BrowserWindow *bw = data; a_Interface_msg(bw, ""); } /* * Make a new popup menu for history browsing * direction: {backward = -1, forward = 1} */ GtkWidget *a_Menu_popup_history_new(BrowserWindow *bw, gint direction) { int i; GtkWidget *menu, *menu_item; GString *text = g_string_sized_new(128); menu = a_Gtk_ext_menu_new(); Menu_sep(menu); if (direction>0) { Menu_add_title(menu, "FOLLOWING PAGES"); i = a_Nav_stack_ptr(bw) + 1; } else { Menu_add_title(menu, "PREVIOUS PAGES"); i = a_Nav_stack_ptr(bw) - 1; } Menu_sep(menu); for ( ; i >= 0 && i < a_Nav_stack_size(bw); i+=direction ) { if (a_History_get_title(NAV_IDX(bw,i))) { g_string_assign(text, a_History_get_title(NAV_IDX(bw,i))); } else { g_string_assign(text, URL_STR(a_History_get_url(NAV_IDX(bw,i)))); } if ( text->len > 64 ) { g_string_truncate(text, 64); g_string_append(text, "..."); } menu_item = a_Gtk_ext_menu_item_new_with_label(text->str); gtk_menu_append(GTK_MENU(menu), menu_item); gtk_widget_show(menu_item); /* attach the nav_stack index to the menu item */ gtk_object_set_data(GTK_OBJECT (menu_item), "nav_idx", GINT_TO_POINTER(i)); gtk_signal_connect ( GTK_OBJECT (menu_item), "select", GTK_SIGNAL_FUNC (a_Interface_scroll_popup), NULL); gtk_signal_connect ( GTK_OBJECT (menu_item), "select", GTK_SIGNAL_FUNC (Menu_popup_history_select_callback), bw); gtk_signal_connect ( GTK_OBJECT (menu_item), "deselect", GTK_SIGNAL_FUNC (Menu_popup_history_deselect_callback), bw); gtk_signal_connect ( GTK_OBJECT (menu_item), "activate", GTK_SIGNAL_FUNC (a_Commands_history_callback_same_bw), bw); gtk_signal_connect ( GTK_OBJECT (menu_item), "activate1", GTK_SIGNAL_FUNC (a_Commands_history_callback_same_bw), bw); gtk_signal_connect ( GTK_OBJECT (menu_item), "activate2", GTK_SIGNAL_FUNC (a_Commands_history_callback_new_bw), bw); gtk_signal_connect ( GTK_OBJECT (menu_item), "activate3", GTK_SIGNAL_FUNC (a_Commands_history_callback_same_bw), bw); } g_string_free(text, TRUE); return menu; } /* * Make a new popup menu for when the mouse is over a link. */ GtkWidget *a_Menu_popup_ol_new(BrowserWindow *bw) { GtkWidget *menu; GtkWidget *copy; GtkWidget *menuitem; menu = gtk_menu_new(); Menu_sep(menu); Menu_add_title(menu, "LINK OPTIONS"); Menu_sep(menu); Menu_add(menu, "Open Link in New Window", NULL, bw, a_Commands_open_link_nw_callback, bw); Menu_add(menu, "Bookmark this Link", NULL, bw, a_Commands_addbm_callback, bw); copy = Menu_add(menu, "Copy Link location", NULL, bw, a_Commands_select_popup_url_callback, bw); a_Selection_init_selection(copy); Menu_sep(menu); Menu_add(menu, "Save Link As...", NULL, bw, a_Commands_save_link_callback, bw); Menu_sep(menu); menuitem = Menu_add(menu, "Image Menu...", NULL, bw, NULL, bw); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), bw->menu_popup.over_image); bw->menu_popup.ol_oi_submenu = menuitem; return menu; } /* * Make a new popup menu for when the mouse is over an image */ GtkWidget *a_Menu_popup_oi_new (BrowserWindow *bw) { GtkWidget *menu; GtkWidget *copy; menu = gtk_menu_new(); Menu_sep(menu); Menu_add_title(menu, "IMAGE OPTIONS"); Menu_sep(menu); Menu_add(menu, "Isolate Image", NULL, bw, a_Commands_open_link_callback, bw); Menu_add(menu, "Open Image in New Window", NULL, bw, a_Commands_open_link_nw_callback, bw); Menu_add(menu, "Bookmark this Image", NULL, bw, a_Commands_addbm_callback, bw); copy = Menu_add(menu, "Copy Image location", NULL, bw, a_Commands_select_popup_url_callback, bw); a_Selection_init_selection(copy); Menu_sep(menu); Menu_add(menu, "Save Image As...", NULL, bw, a_Commands_save_link_callback, bw); return menu; } /* * Make a new popup menu for right click over the bug meter. */ GtkWidget *a_Menu_popup_ob_new (BrowserWindow *bw) { GtkWidget *menu; menu = gtk_menu_new(); Menu_sep(menu); Menu_add_title(menu, "BUG METER OPTIONS"); Menu_sep(menu); Menu_add(menu, "Validate URL with W3C", NULL, bw, a_Commands_ob_w3c_callback, bw); Menu_add(menu, "Validate URL with WDG", NULL, bw, a_Commands_ob_wdg_callback, bw); Menu_sep(menu); Menu_add(menu, "About Bug Meter...", NULL, bw, a_Commands_ob_info_callback, bw); return menu; } /* * Show or Hide the image submenu. */ void a_Menu_popup_ol_show_oi(BrowserWindow *bw, gboolean show) { if (show) gtk_widget_show(bw->menu_popup.ol_oi_submenu); else gtk_widget_hide(bw->menu_popup.ol_oi_submenu); } /* * Functions to manipulate Pagemarks menu. * Should this be in a separate "pagemark.c" ? */ /* * make the page scroll to the pagemark */ static void Menu_pagemarks_goto_pagemark(GtkWidget *widget, gpointer client_data) { BrowserWindow *bw = (BrowserWindow *) client_data; char anchor[32]; g_snprintf (anchor, 32, "#%ld", (long int)widget); a_Dw_gtk_scrolled_window_set_anchor(GTK_DW_SCROLLED_WINDOW(bw->docwin), anchor); } /* * Deallocate the memory used by a pagemarks menu and create a new one */ void a_Menu_pagemarks_new(BrowserWindow *bw) { gtk_widget_set_sensitive(bw->pagemarks_menuitem, FALSE); if (bw->pagemarks_menu) gtk_widget_destroy(bw->pagemarks_menu); bw->pagemarks_menu = gtk_menu_new(); bw->pagemarks_last = NULL; gtk_menu_item_set_submenu(GTK_MENU_ITEM(bw->pagemarks_menuitem), bw->pagemarks_menu); } /* * Add a new pagemark (opening H tag). * The text can be set only at the closing H tag. * level is the level of the heading (1-6). */ void a_Menu_pagemarks_add(BrowserWindow *bw, void *page, void *style, gint level) { char anchor[32], spaces[32], name[32]; gtk_widget_set_sensitive(bw->pagemarks_menuitem, TRUE); g_snprintf(spaces, 32, "%*s", 3 * (level - 1), ""); bw->pagemarks_last = Menu_add(bw->pagemarks_menu, spaces, NULL, bw, Menu_pagemarks_goto_pagemark, bw); g_snprintf(anchor, 32, "#%ld", (glong)(bw->pagemarks_last)); a_Dw_page_add_anchor(page, anchor, style); gtk_signal_connect (GTK_OBJECT (bw->pagemarks_last), "select", GTK_SIGNAL_FUNC (a_Interface_scroll_popup), NULL); g_snprintf(name, 32, "dilloHeading%d", level); gtk_widget_set_name(bw->pagemarks_last, name); } /* * Set the text for the last created pagemark. */ void a_Menu_pagemarks_set_text(BrowserWindow *bw, const char *str) { GString *text; GtkWidget *child; /* Avoid problems with lonely closing tags and nested headings */ if ( bw->pagemarks_last && (child = GTK_BIN (bw->pagemarks_last)->child) && GTK_IS_LABEL (child) ) { text = g_string_new(GTK_LABEL(child)->label); g_string_append(text, str); if ( text->len > 64 ) { g_string_truncate(text, 64); g_string_append(text, "..."); } gtk_label_set_text(GTK_LABEL (child), text->str); g_string_free(text, 1); bw->pagemarks_last = NULL; } }