/* * Copyright 2003 Phil Mellor * Copyright 2005 James Bursa * Copyright 2003 John M Bell * Copyright 2005 Richard Wilson * * This file is part of NetSurf, http://www.netsurf-browser.org/ * * NetSurf 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; version 2 of the License. * * NetSurf 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, see . */ /** \file * Menu creation and handling (implementation). */ #include #include #include #include "oslib/os.h" #include "oslib/osbyte.h" #include "oslib/osgbpb.h" #include "oslib/territory.h" #include "oslib/wimp.h" #include "content/urldb.h" #include "desktop/gui.h" #include "desktop/history_core.h" #include "desktop/netsurf.h" #include "desktop/selection.h" #include "desktop/textinput.h" #include "render/box.h" #include "riscos/dialog.h" #include "render/form.h" #include "riscos/configure.h" #include "riscos/cookies.h" #include "riscos/gui.h" #include "riscos/global_history.h" #include "riscos/help.h" #include "riscos/menus.h" #include "riscos/options.h" #include "riscos/save.h" #include "riscos/tinct.h" #include "riscos/theme.h" #include "riscos/treeview.h" #include "riscos/wimp.h" #include "riscos/wimp_event.h" #include "utils/log.h" #include "utils/messages.h" #include "utils/url.h" #include "utils/utils.h" #include "utils/utf8.h" struct ns_menu_entry { const char *text; /**< menu text (from messages) */ menu_action action; /**< associated action */ wimp_w *sub_window; /**< sub-window if any */ }; struct ns_menu { const char *title; struct ns_menu_entry entries[]; }; struct menu_definition_entry { menu_action action; /**< menu action */ wimp_menu_entry *menu_entry; /**< corresponding menu entry */ const char *entry_key; /**< Messages key for entry text */ struct menu_definition_entry *next; /**< next menu entry */ }; struct menu_definition { wimp_menu *menu; /**< corresponding menu */ const char *title_key; /**< Messages key for title text */ int current_encoding; /**< Identifier for current text encoding of menu text (as per OS_Byte,71,127) */ struct menu_definition_entry *entries; /**< menu entries */ struct menu_definition *next; /**< next menu */ }; static wimp_menu *ro_gui_menu_define_menu(const struct ns_menu *menu); static void ro_gui_menu_define_menu_add(struct menu_definition *definition, const struct ns_menu *menu, int depth, wimp_menu_entry *parent_entry, int first, int last, const char *prefix, int prefix_length); static struct menu_definition *ro_gui_menu_find_menu(wimp_menu *menu); static struct menu_definition_entry *ro_gui_menu_find_entry(wimp_menu *menu, menu_action action); static menu_action ro_gui_menu_find_action(wimp_menu *menu, wimp_menu_entry *menu_entry); static void ro_gui_menu_set_entry_shaded(wimp_menu *menu, menu_action action, bool shaded); static void ro_gui_menu_set_entry_ticked(wimp_menu *menu, menu_action action, bool ticked); static void ro_gui_menu_get_window_details(wimp_w w, struct gui_window **g, struct browser_window **bw, struct content **content, struct toolbar **toolbar, struct tree **tree); static int ro_gui_menu_get_checksum(void); static bool ro_gui_menu_prepare_url_suggest(void); static void ro_gui_menu_prepare_pageinfo(struct gui_window *g); static void ro_gui_menu_prepare_objectinfo(struct content *object, const char *href); static void ro_gui_menu_refresh_toolbar(struct toolbar *toolbar); static bool ro_gui_menu_translate(struct menu_definition *menu); /* default menu item flags */ #define DEFAULT_FLAGS (wimp_ICON_TEXT | wimp_ICON_FILLED | \ (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | \ (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT)) /** The currently defined menus to perform actions for */ static struct menu_definition *ro_gui_menu_definitions; /** The current menu being worked with (may not be open) */ wimp_menu *current_menu; /** Whether a menu is currently open */ bool current_menu_open = false; /** Object under menu, or 0 if no object. */ static struct content *current_menu_object = 0; /** URL of link under menu, or 0 if no link. */ static const char *current_menu_url = 0; /** Menu of options for form select controls. */ static wimp_menu *gui_form_select_menu = 0; /** Form control which gui_form_select_menu is for. */ static struct form_control *gui_form_select_control; /** Window that owns the current menu */ wimp_w current_menu_window; /** Icon that owns the current menu (only valid for popup menus) */ static wimp_i current_menu_icon; /** The height of the iconbar menu */ int iconbar_menu_height = 5 * 44; /** The available menus */ wimp_menu *iconbar_menu, *browser_menu, *hotlist_menu, *global_history_menu, *cookies_menu, *image_quality_menu, *browser_toolbar_menu, *tree_toolbar_menu, *proxy_type_menu, *languages_menu; /** URL suggestion menu */ static wimp_MENU(GLOBAL_HISTORY_RECENT_URLS) url_suggest; wimp_menu *url_suggest_menu = (wimp_menu *)&url_suggest; /* the values given in PRM 3-157 for how to check menus/windows are * incorrect so we use a hack of checking if the sub-menu has bit 0 * set which is undocumented but true of window handles on * all target OS versions */ #define IS_MENU(menu) !((int)(menu) & 1) /** * Create menu structures. */ void ro_gui_menu_init(void) { /* iconbar menu */ static const struct ns_menu iconbar_definition = { "NetSurf", { { "Info", NO_ACTION, &dialog_info }, { "AppHelp", HELP_OPEN_CONTENTS, 0 }, { "Open", BROWSER_NAVIGATE_URL, 0 }, { "Open.OpenURL", BROWSER_NAVIGATE_URL, &dialog_openurl }, { "Open.HotlistShow", HOTLIST_SHOW, 0 }, { "Open.HistGlobal", HISTORY_SHOW_GLOBAL, 0 }, { "Open.ShowCookies", COOKIES_SHOW, 0 }, { "Choices", CHOICES_SHOW, 0 }, { "Quit", APPLICATION_QUIT, 0 }, {NULL, 0, 0} } }; iconbar_menu = ro_gui_menu_define_menu(&iconbar_definition); /* browser menu */ static const struct ns_menu browser_definition = { "NetSurf", { { "Page", BROWSER_PAGE, 0 }, { "Page.PageInfo",BROWSER_PAGE_INFO, &dialog_pageinfo }, { "Page.Save", BROWSER_SAVE, &dialog_saveas }, { "Page.SaveComp", BROWSER_SAVE_COMPLETE, &dialog_saveas }, { "Page.Export", NO_ACTION, 0 }, #ifdef WITH_DRAW_EXPORT { "Page.Export.Draw", BROWSER_EXPORT_DRAW, &dialog_saveas }, #endif #ifdef WITH_PDF_EXPORT { "Page.Export.PDF", BROWSER_EXPORT_PDF, &dialog_saveas }, #endif { "Page.Export.Text", BROWSER_EXPORT_TEXT, &dialog_saveas }, { "Page.SaveURL", NO_ACTION, 0 }, { "Page.SaveURL.URI", BROWSER_SAVE_URL_URI, &dialog_saveas }, { "Page.SaveURL.URL", BROWSER_SAVE_URL_URL, &dialog_saveas }, { "Page.SaveURL.LinkText", BROWSER_SAVE_URL_TEXT, &dialog_saveas }, { "_Page.Print", BROWSER_PRINT, &dialog_print }, { "Page.NewWindow", BROWSER_NEW_WINDOW, 0 }, { "Page.FindText", BROWSER_FIND_TEXT, &dialog_search }, { "Page.ViewSrc", BROWSER_VIEW_SOURCE, 0 }, { "Object", BROWSER_OBJECT, 0 }, { "Object.Object", BROWSER_OBJECT_OBJECT, 0 }, { "Object.Object.ObjInfo", BROWSER_OBJECT_INFO, &dialog_objinfo }, { "Object.Object.ObjSave", BROWSER_OBJECT_SAVE, &dialog_saveas }, { "Object.Object.Export", BROWSER_OBJECT_EXPORT, 0 }, { "Object.Object.Export.Sprite", BROWSER_OBJECT_EXPORT_SPRITE, &dialog_saveas }, #ifdef WITH_DRAW_EXPORT { "Object.Object.Export.ObjDraw", BROWSER_OBJECT_EXPORT_DRAW, &dialog_saveas }, #endif { "Object.Object.SaveURL", NO_ACTION, 0 }, { "Object.Object.SaveURL.URI", BROWSER_OBJECT_SAVE_URL_URI, &dialog_saveas }, { "Object.Object.SaveURL.URL", BROWSER_OBJECT_SAVE_URL_URL, &dialog_saveas }, { "Object.Object.SaveURL.LinkText", BROWSER_OBJECT_SAVE_URL_TEXT, &dialog_saveas }, { "Object.Object.ObjPrint", BROWSER_OBJECT_PRINT, 0 }, { "Object.Object.ObjReload", BROWSER_OBJECT_RELOAD, 0 }, { "Object.Link", BROWSER_OBJECT_LINK, 0 }, { "Object.Link.LinkSave", BROWSER_LINK_SAVE, 0 }, { "Object.Link.LinkSave.URI", BROWSER_LINK_SAVE_URI, &dialog_saveas }, { "Object.Link.LinkSave.URL", BROWSER_LINK_SAVE_URL, &dialog_saveas }, { "Object.Link.LinkSave.LinkText", BROWSER_LINK_SAVE_TEXT, &dialog_saveas }, { "_Object.Link.LinkDload", BROWSER_LINK_DOWNLOAD, 0 }, { "Object.Link.LinkNew", BROWSER_LINK_NEW_WINDOW, 0 }, { "Selection", BROWSER_SELECTION, 0 }, { "_Selection.SelSave", BROWSER_SELECTION_SAVE, &dialog_saveas }, { "Selection.Copy", BROWSER_SELECTION_COPY, 0 }, { "Selection.Cut", BROWSER_SELECTION_CUT, 0 }, { "_Selection.Paste", BROWSER_SELECTION_PASTE, 0 }, { "Selection.Clear", BROWSER_SELECTION_CLEAR, 0 }, { "Selection.SelectAll", BROWSER_SELECTION_ALL, 0 }, { "Navigate", NO_ACTION, 0 }, { "Navigate.Home", BROWSER_NAVIGATE_HOME, 0 }, { "Navigate.Back", BROWSER_NAVIGATE_BACK, 0 }, { "Navigate.Forward", BROWSER_NAVIGATE_FORWARD, 0 }, { "_Navigate.UpLevel", BROWSER_NAVIGATE_UP, 0 }, { "Navigate.Reload", BROWSER_NAVIGATE_RELOAD_ALL, 0 }, { "Navigate.Stop", BROWSER_NAVIGATE_STOP, 0 }, { "View", NO_ACTION, 0 }, { "View.ScaleView", BROWSER_SCALE_VIEW, &dialog_zoom }, { "View.Images", NO_ACTION, 0 }, { "View.Images.ForeImg", BROWSER_IMAGES_FOREGROUND, 0 }, { "View.Images.BackImg", BROWSER_IMAGES_BACKGROUND, 0 }, { "View.Toolbars", NO_ACTION, 0 }, { "View.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, { "View.Toolbars.ToolAddress", TOOLBAR_ADDRESS_BAR, 0 }, { "_View.Toolbars.ToolThrob", TOOLBAR_THROBBER, 0 }, { "View.Toolbars.EditToolbar", TOOLBAR_EDIT, 0 }, { "_View.Render", NO_ACTION, 0 }, { "View.Render.RenderAnims", BROWSER_BUFFER_ANIMS, 0 }, { "View.Render.RenderAll", BROWSER_BUFFER_ALL, 0 }, { "_View.OptDefault", BROWSER_SAVE_VIEW, 0 }, { "View.Window", NO_ACTION, 0 }, { "View.Window.WindowSave", BROWSER_WINDOW_DEFAULT, 0 }, { "View.Window.WindowStagr", BROWSER_WINDOW_STAGGER, 0 }, { "_View.Window.WindowSize", BROWSER_WINDOW_COPY, 0 }, { "View.Window.WindowReset", BROWSER_WINDOW_RESET, 0 }, { "Utilities", NO_ACTION, 0 }, { "Utilities.Hotlist", HOTLIST_SHOW, 0 }, { "Utilities.Hotlist.HotlistAdd", HOTLIST_ADD_URL, 0 }, { "Utilities.Hotlist.HotlistShow", HOTLIST_SHOW, 0 }, { "Utilities.History", HISTORY_SHOW_GLOBAL, 0 }, { "Utilities.History.HistLocal", HISTORY_SHOW_LOCAL, 0 }, { "Utilities.History.HistGlobal", HISTORY_SHOW_GLOBAL, 0 }, { "Utilities.Cookies", COOKIES_SHOW, 0 }, { "Utilities.Cookies.ShowCookies", COOKIES_SHOW, 0 }, { "Utilities.Cookies.DeleteCookies", COOKIES_DELETE, 0 }, { "Help", HELP_OPEN_CONTENTS, 0 }, { "Help.HelpContent", HELP_OPEN_CONTENTS, 0 }, { "Help.HelpGuide", HELP_OPEN_GUIDE, 0 }, { "_Help.HelpInfo", HELP_OPEN_INFORMATION, 0 }, { "_Help.HelpAbout", HELP_OPEN_ABOUT, 0 }, { "Help.HelpInter", HELP_LAUNCH_INTERACTIVE, 0 }, {NULL, 0, 0} } }; browser_menu = ro_gui_menu_define_menu(&browser_definition); /* hotlist menu */ static wimp_w one = (wimp_w) 1; static const struct ns_menu hotlist_definition = { "Hotlist", { { "Hotlist", NO_ACTION, 0 }, { "Hotlist.New", NO_ACTION, 0 }, { "Hotlist.New.Folder", TREE_NEW_FOLDER, &dialog_folder }, { "Hotlist.New.Link", TREE_NEW_LINK, &dialog_entry }, { "_Hotlist.Export", HOTLIST_EXPORT, &dialog_saveas }, { "Hotlist.Expand", TREE_EXPAND_ALL, 0 }, { "Hotlist.Expand.All", TREE_EXPAND_ALL, 0 }, { "Hotlist.Expand.Folders", TREE_EXPAND_FOLDERS, 0 }, { "Hotlist.Expand.Links", TREE_EXPAND_LINKS, 0 }, { "Hotlist.Collapse", TREE_COLLAPSE_ALL, 0 }, { "Hotlist.Collapse.All", TREE_COLLAPSE_ALL, 0 }, { "Hotlist.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 }, { "Hotlist.Collapse.Links", TREE_COLLAPSE_LINKS, 0 }, { "Hotlist.Toolbars", NO_ACTION, 0 }, { "_Hotlist.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, { "Hotlist.Toolbars.EditToolbar", TOOLBAR_EDIT, 0 }, { "Selection", TREE_SELECTION, 0 }, /* We want a window, but it changes depending upon * context. Therefore, ensure that the structure is * created so that we can dynamically modify the * actual item presented. We do this by creating a * fake wimp_w with the value 1, which indicates a * window handle as opposed to a submenu. */ { "Selection.Edit", TREE_SELECTION_EDIT, &one }, { "Selection.Launch", TREE_SELECTION_LAUNCH, 0 }, { "Selection.Delete", TREE_SELECTION_DELETE, 0 }, { "SelectAll", TREE_SELECT_ALL, 0 }, { "Clear", TREE_CLEAR_SELECTION, 0 }, {NULL, 0, 0} } }; hotlist_menu = ro_gui_menu_define_menu(&hotlist_definition); /* history menu */ static const struct ns_menu global_history_definition = { "History", { { "History", NO_ACTION, 0 }, { "_History.Export", HISTORY_EXPORT, &dialog_saveas }, { "History.Expand", TREE_EXPAND_ALL, 0 }, { "History.Expand.All", TREE_EXPAND_ALL, 0 }, { "History.Expand.Folders", TREE_EXPAND_FOLDERS, 0 }, { "History.Expand.Links", TREE_EXPAND_LINKS, 0 }, { "History.Collapse", TREE_COLLAPSE_ALL, 0 }, { "History.Collapse.All", TREE_COLLAPSE_ALL, 0 }, { "History.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 }, { "History.Collapse.Links", TREE_COLLAPSE_LINKS, 0 }, { "History.Toolbars", NO_ACTION, 0 }, { "_History.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, { "History.Toolbars.EditToolbar",TOOLBAR_EDIT, 0 }, { "Selection", TREE_SELECTION, 0 }, { "Selection.Launch", TREE_SELECTION_LAUNCH, 0 }, { "Selection.Delete", TREE_SELECTION_DELETE, 0 }, { "SelectAll", TREE_SELECT_ALL, 0 }, { "Clear", TREE_CLEAR_SELECTION, 0 }, {NULL, 0, 0} } }; global_history_menu = ro_gui_menu_define_menu( &global_history_definition); /* history menu */ static const struct ns_menu cookies_definition = { "Cookies", { { "Cookies", NO_ACTION, 0 }, { "Cookies.Expand", TREE_EXPAND_ALL, 0 }, { "Cookies.Expand.All", TREE_EXPAND_ALL, 0 }, { "Cookies.Expand.Folders", TREE_EXPAND_FOLDERS, 0 }, { "Cookies.Expand.Links", TREE_EXPAND_LINKS, 0 }, { "Cookies.Collapse", TREE_COLLAPSE_ALL, 0 }, { "Cookies.Collapse.All", TREE_COLLAPSE_ALL, 0 }, { "Cookies.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 }, { "Cookies.Collapse.Links", TREE_COLLAPSE_LINKS, 0 }, { "Cookies.Toolbars", NO_ACTION, 0 }, { "_Cookies.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, { "Cookies.Toolbars.EditToolbar",TOOLBAR_EDIT, 0 }, { "Selection", TREE_SELECTION, 0 }, { "Selection.Delete", TREE_SELECTION_DELETE, 0 }, { "SelectAll", TREE_SELECT_ALL, 0 }, { "Clear", TREE_CLEAR_SELECTION, 0 }, {NULL, 0, 0} } }; cookies_menu = ro_gui_menu_define_menu(&cookies_definition); /* image quality menu */ static const struct ns_menu images_definition = { "Display", { { "ImgStyle0", NO_ACTION, 0 }, { "ImgStyle1", NO_ACTION, 0 }, { "ImgStyle2", NO_ACTION, 0 }, { "ImgStyle3", NO_ACTION, 0 }, {NULL, 0, 0} } }; image_quality_menu = ro_gui_menu_define_menu(&images_definition); /* browser toolbar menu */ static const struct ns_menu browser_toolbar_definition = { "Toolbar", { { "Toolbars", NO_ACTION, 0 }, { "Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, { "Toolbars.ToolAddress", TOOLBAR_ADDRESS_BAR, 0 }, { "Toolbars.ToolThrob", TOOLBAR_THROBBER, 0 }, { "EditToolbar", TOOLBAR_EDIT, 0 }, {NULL, 0, 0} } }; browser_toolbar_menu = ro_gui_menu_define_menu( &browser_toolbar_definition); /* tree toolbar menu */ static const struct ns_menu tree_toolbar_definition = { "Toolbar", { { "Toolbars", NO_ACTION, 0 }, { "Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, { "EditToolbar", TOOLBAR_EDIT, 0 }, {NULL, 0, 0} } }; tree_toolbar_menu = ro_gui_menu_define_menu(&tree_toolbar_definition); /* proxy menu */ static const struct ns_menu proxy_type_definition = { "ProxyType", { { "ProxyNone", NO_ACTION, 0 }, { "ProxyNoAuth", NO_ACTION, 0 }, { "ProxyBasic", NO_ACTION, 0 }, { "ProxyNTLM", NO_ACTION, 0 }, {NULL, 0, 0} } }; proxy_type_menu = ro_gui_menu_define_menu(&proxy_type_definition); /* special case menus */ url_suggest_menu->title_data.indirected_text.text = (char *) messages_get("URLSuggest"); ro_gui_menu_init_structure(url_suggest_menu, GLOBAL_HISTORY_RECENT_URLS); /* Note: This table *must* be kept in sync with the LangNames file */ static const struct ns_menu lang_definition = { "Languages", { { "lang_af", NO_ACTION, 0 }, { "lang_bm", NO_ACTION, 0 }, { "lang_ca", NO_ACTION, 0 }, { "lang_cs", NO_ACTION, 0 }, { "lang_cy", NO_ACTION, 0 }, { "lang_da", NO_ACTION, 0 }, { "lang_de", NO_ACTION, 0 }, { "lang_en", NO_ACTION, 0 }, { "lang_es", NO_ACTION, 0 }, { "lang_et", NO_ACTION, 0 }, { "lang_eu", NO_ACTION, 0 }, { "lang_ff", NO_ACTION, 0 }, { "lang_fi", NO_ACTION, 0 }, { "lang_fr", NO_ACTION, 0 }, { "lang_ga", NO_ACTION, 0 }, { "lang_gl", NO_ACTION, 0 }, { "lang_ha", NO_ACTION, 0 }, { "lang_hr", NO_ACTION, 0 }, { "lang_hu", NO_ACTION, 0 }, { "lang_id", NO_ACTION, 0 }, { "lang_is", NO_ACTION, 0 }, { "lang_it", NO_ACTION, 0 }, { "lang_lt", NO_ACTION, 0 }, { "lang_lv", NO_ACTION, 0 }, { "lang_ms", NO_ACTION, 0 }, { "lang_mt", NO_ACTION, 0 }, { "lang_nl", NO_ACTION, 0 }, { "lang_no", NO_ACTION, 0 }, { "lang_pl", NO_ACTION, 0 }, { "lang_pt", NO_ACTION, 0 }, { "lang_rn", NO_ACTION, 0 }, { "lang_ro", NO_ACTION, 0 }, { "lang_rw", NO_ACTION, 0 }, { "lang_sk", NO_ACTION, 0 }, { "lang_sl", NO_ACTION, 0 }, { "lang_so", NO_ACTION, 0 }, { "lang_sq", NO_ACTION, 0 }, { "lang_sr", NO_ACTION, 0 }, { "lang_sv", NO_ACTION, 0 }, { "lang_sw", NO_ACTION, 0 }, { "lang_tr", NO_ACTION, 0 }, { "lang_uz", NO_ACTION, 0 }, { "lang_vi", NO_ACTION, 0 }, { "lang_wo", NO_ACTION, 0 }, { "lang_xs", NO_ACTION, 0 }, { "lang_yo", NO_ACTION, 0 }, { "lang_zu", NO_ACTION, 0 }, { NULL, 0, 0 } } }; languages_menu = ro_gui_menu_define_menu(&lang_definition); } /** * Display a menu. */ void ro_gui_menu_create(wimp_menu *menu, int x, int y, wimp_w w) { struct gui_window *g; os_error *error; os_coord pos; int i; menu_action action; struct menu_definition *definition; /* translate menu, if necessary (this returns quickly * if there's nothing to be done) */ definition = ro_gui_menu_find_menu(menu); if (definition) { if (!ro_gui_menu_translate(definition)) { warn_user("NoMemory", 0); return; } } /* read the object under the pointer for a new gui_window menu */ if ((!current_menu) && (menu == browser_menu)) { g = ro_gui_window_lookup(w); if (!ro_gui_window_to_window_pos(g, x, y, &pos)) return; current_menu_object = NULL; current_menu_url = NULL; if (g->bw->current_content) { switch (g->bw->current_content->type) { case CONTENT_HTML: { struct box *box; box = box_object_at_point(g->bw->current_content, pos.x, pos.y); current_menu_object = box ? box->object : NULL; box = box_href_at_point(g->bw->current_content, pos.x, pos.y); current_menu_url = box ? box->href : NULL; } break; case CONTENT_TEXTPLAIN: /* no object, no url */ break; default: current_menu_object = g->bw->current_content; break; } } } /* store the menu characteristics */ current_menu = menu; current_menu_window = w; current_menu_icon = -1; /* prepare the menu state */ if (menu == url_suggest_menu) { if (!ro_gui_menu_prepare_url_suggest()) return; } else if (menu == recent_search_menu) { if (!ro_gui_search_prepare_menu()) return; } else { i = 0; do { action = ro_gui_menu_find_action(menu, &menu->entries[i]); if (action != NO_ACTION) ro_gui_menu_prepare_action(w, action, false); } while (!(menu->entries[i++].menu_flags & wimp_MENU_LAST)); } /* create the menu */ current_menu_open = true; error = xwimp_create_menu(menu, x - 64, y); if (error) { LOG(("xwimp_create_menu: 0x%x: %s", error->errnum, error->errmess)); warn_user("MenuError", error->errmess); ro_gui_menu_closed(true); } } /** * Display a pop-up menu next to the specified icon. * * \param menu menu to open * \param w window handle * \param i icon handle */ void ro_gui_popup_menu(wimp_menu *menu, wimp_w w, wimp_i i) { wimp_window_state state; wimp_icon_state icon_state; os_error *error; state.w = w; icon_state.w = w; icon_state.i = i; error = xwimp_get_window_state(&state); if (error) { LOG(("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("MenuError", error->errmess); return; } error = xwimp_get_icon_state(&icon_state); if (error) { LOG(("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("MenuError", error->errmess); return; } ro_gui_menu_create(menu, state.visible.x0 + icon_state.icon.extent.x1 + 64, state.visible.y1 + icon_state.icon.extent.y1 - state.yscroll, w); current_menu_icon = i; } /** * Clean up after a menu has been closed, or forcible close an open menu. * * \param cleanup Call any terminating functions (sub-window isn't going to be instantly re-opened) */ void ro_gui_menu_closed(bool cleanup) { struct gui_window *g; struct browser_window *bw; struct content *c; struct toolbar *t; struct tree *tree; os_error *error; if (current_menu) { error = xwimp_create_menu(wimp_CLOSE_MENU, 0, 0); if (error) { LOG(("xwimp_create_menu: 0x%x: %s", error->errnum, error->errmess)); warn_user("MenuError", error->errmess); } ro_gui_menu_get_window_details(current_menu_window, &g, &bw, &c, &t, &tree); current_menu = NULL; if (cleanup) { ro_gui_wimp_event_menus_closed(); if (tree) ro_gui_tree_menu_closed(tree); } } current_menu_window = NULL; current_menu_icon = 0; current_menu_open = false; gui_form_select_control = NULL; } /** * The content has changed, reset object references */ void ro_gui_menu_objects_moved(void) { gui_form_select_control = NULL; current_menu_object = NULL; current_menu_url = NULL; ro_gui_menu_prepare_action(0, BROWSER_OBJECT, false); if ((current_menu) && (current_menu == gui_form_select_menu)) ro_gui_menu_closed(true); } /** * Handle menu selection. */ void ro_gui_menu_selection(wimp_selection *selection) { int i, j; wimp_menu_entry *menu_entry; menu_action action; wimp_pointer pointer; struct gui_window *g = NULL; wimp_menu *menu; os_error *error; int previous_menu_icon = current_menu_icon; char *url; /* if we are using gui_multitask then menu selection events * may be delivered after the menu has been closed. As such, * we simply ignore these events. */ if (!current_menu) return assert(current_menu_window); /* get the menu entry and associated action */ menu_entry = ¤t_menu->entries[selection->items[0]]; for (i = 1; selection->items[i] != -1; i++) menu_entry = &menu_entry->sub_menu-> entries[selection->items[i]]; action = ro_gui_menu_find_action(current_menu, menu_entry); /* perform menu action */ if (action != NO_ACTION) ro_gui_menu_handle_action(current_menu_window, action, false); /* perform non-automated actions */ if (current_menu == url_suggest_menu) { g = ro_gui_toolbar_lookup(current_menu_window); if (g) { url = url_suggest_menu->entries[selection->items[0]]. data.indirected_text.text; gui_window_set_url(g, url); browser_window_go(g->bw, url, 0, true); global_history_add_recent(url); } } else if (current_menu == gui_form_select_menu) { g = ro_gui_window_lookup(current_menu_window); assert(g); if (selection->items[0] >= 0) { browser_window_form_select(g->bw, gui_form_select_control, selection->items[0]); } } /* allow automatic menus to have their data updated */ ro_gui_wimp_event_menu_selection(current_menu_window, current_menu_icon, current_menu, selection); /* re-open the menu for Adjust clicks */ error = xwimp_get_pointer_info(&pointer); if (error) { LOG(("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); ro_gui_menu_closed(true); return; } if (pointer.buttons != wimp_CLICK_ADJUST) { ro_gui_menu_closed(true); return; } /* re-prepare all the visible entries */ i = 0; menu = current_menu; do { j = 0; do { action = ro_gui_menu_find_action(current_menu, &menu->entries[j]); if (action != NO_ACTION) ro_gui_menu_prepare_action(current_menu_window, action, false); } while (!(menu->entries[j++].menu_flags & wimp_MENU_LAST)); j = selection->items[i++]; if (j != -1) { menu = menu->entries[j].sub_menu; if ((!menu) || (menu == wimp_NO_SUB_MENU)) break; } } while (j != -1); if (current_menu == gui_form_select_menu) { assert(g); /* Keep scan-build happy */ gui_create_form_select_menu(g->bw, gui_form_select_control); } else ro_gui_menu_create(current_menu, 0, 0, current_menu_window); current_menu_icon = previous_menu_icon; } /** * Handle Message_MenuWarning. */ void ro_gui_menu_warning(wimp_message_menu_warning *warning) { int i; menu_action action; wimp_menu_entry *menu_entry; wimp_menu *sub_menu; os_error *error; assert(current_menu); assert(current_menu_window); /* get the sub-menu of the warning */ if (warning->selection.items[0] == -1) return; menu_entry = ¤t_menu->entries[warning->selection.items[0]]; for (i = 1; warning->selection.items[i] != -1; i++) menu_entry = &menu_entry->sub_menu-> entries[warning->selection.items[i]]; if (IS_MENU(menu_entry->sub_menu)) { ro_gui_wimp_event_register_submenu((wimp_w)0); sub_menu = menu_entry->sub_menu; i = 0; do { action = ro_gui_menu_find_action(current_menu, &sub_menu->entries[i]); if (action != NO_ACTION) ro_gui_menu_prepare_action(current_menu_window, action, false); } while (!(sub_menu->entries[i++].menu_flags & wimp_MENU_LAST)); } else { ro_gui_wimp_event_register_submenu((wimp_w)menu_entry->sub_menu); action = ro_gui_menu_find_action(current_menu, menu_entry); if (action != NO_ACTION) ro_gui_menu_prepare_action(current_menu_window, action, true); /* remove the close icon */ ro_gui_wimp_update_window_furniture((wimp_w)menu_entry->sub_menu, wimp_WINDOW_CLOSE_ICON | wimp_WINDOW_BACK_ICON, 0); } /* open the sub-menu */ error = xwimp_create_sub_menu(menu_entry->sub_menu, warning->pos.x, warning->pos.y); if (error) { LOG(("xwimp_create_sub_menu: 0x%x: %s", error->errnum, error->errmess)); warn_user("MenuError", error->errmess); } } /** * Refresh a toolbar after it has been updated * * \param toolbar the toolbar to update */ void ro_gui_menu_refresh_toolbar(struct toolbar *toolbar) { assert(toolbar); toolbar->reformat_buttons = true; ro_gui_theme_process_toolbar(toolbar, -1); if (toolbar->type == THEME_BROWSER_TOOLBAR) { gui_window_update_extent(ro_gui_window_lookup(current_menu_window)); } else if (toolbar->type == THEME_HOTLIST_TOOLBAR) { tree_resized(hotlist_tree); xwimp_force_redraw((wimp_w)hotlist_tree->handle, 0,-16384, 16384, 16384); } else if (toolbar->type == THEME_HISTORY_TOOLBAR) { tree_resized(global_history_tree); xwimp_force_redraw((wimp_w)global_history_tree->handle, 0,-16384, 16384, 16384); } else if (toolbar->type == THEME_COOKIES_TOOLBAR) { tree_resized(cookies_tree); xwimp_force_redraw((wimp_w)cookies_tree->handle, 0,-16384, 16384, 16384); } } /** * Builds the URL suggestion menu */ bool ro_gui_menu_prepare_url_suggest(void) { char **suggest_text; int suggestions; int i; suggest_text = global_history_get_recent(&suggestions); if (suggestions < 1) return false; for (i = 0; i < suggestions; i++) { url_suggest_menu->entries[i].menu_flags = 0; url_suggest_menu->entries[i].data.indirected_text.text = suggest_text[i]; url_suggest_menu->entries[i].data.indirected_text.size = strlen(suggest_text[i]) + 1; } url_suggest_menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED; url_suggest_menu->entries[suggestions - 1].menu_flags |= wimp_MENU_LAST; return true; } /** * Update navigate menu status and toolbar icons. * * /param gui the gui_window to update */ void ro_gui_prepare_navigate(struct gui_window *gui) { int suggestions; ro_gui_menu_prepare_action(gui->window, HOTLIST_SHOW, false); ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_STOP, false); ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_RELOAD_ALL, false); ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_BACK, false); ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_FORWARD, false); ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_UP, false); ro_gui_menu_prepare_action(gui->window, HOTLIST_SHOW, false); ro_gui_menu_prepare_action(gui->window, BROWSER_SAVE, false); ro_gui_menu_prepare_action(gui->window, BROWSER_PRINT, false); ro_gui_menu_prepare_action(gui->window, BROWSER_SCALE_VIEW, false); ro_gui_menu_prepare_action(gui->window, BROWSER_FIND_TEXT, false); if (gui->toolbar) { global_history_get_recent(&suggestions); ro_gui_set_icon_shaded_state(gui->toolbar->toolbar_handle, ICON_TOOLBAR_SUGGEST, (suggestions <= 0)); } } /** * Prepare the page info window for use * * \param g the gui_window to set the display icons for */ void ro_gui_menu_prepare_pageinfo(struct gui_window *g) { struct content *c = g->bw->current_content; char icon_buf[20] = "file_xxx"; char enc_buf[40]; char enc_token[10] = "Encoding0"; const char *icon = icon_buf; const char *title = "-"; const char *url = "-"; const char *enc = "-"; const char *mime = "-"; assert(c); if (c->title) title = c->title; if (c->url) url = c->url; if (c->mime_type) mime = c->mime_type; sprintf(icon_buf, "file_%x", ro_content_filetype(c)); if (!ro_gui_wimp_sprite_exists(icon_buf)) sprintf(icon_buf, "file_xxx"); if (c->type == CONTENT_HTML) { if (c->data.html.encoding) { enc_token[8] = '0' + c->data.html.encoding_source; snprintf(enc_buf, sizeof enc_buf, "%s (%s)", c->data.html.encoding, messages_get(enc_token)); enc = enc_buf; } else { enc = messages_get("EncodingUnk"); } } ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ICON, icon, true); ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TITLE, title, true); ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_URL, url, true); ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ENC, enc, true); ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TYPE, mime, true); } /** * Prepare the object info window for use * * \param object the object for which information is to be displayed * \param href corresponding href, if any */ void ro_gui_menu_prepare_objectinfo(struct content *object, const char *href) { char icon_buf[20] = "file_xxx"; const char *url = "-"; const char *target = "-"; const char *mime = "-"; sprintf(icon_buf, "file_%.3x", ro_content_filetype(object)); if (!ro_gui_wimp_sprite_exists(icon_buf)) sprintf(icon_buf, "file_xxx"); if (object->url) url = object->url; if (href) target = href; if (object->mime_type) mime = object->mime_type; ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_ICON, icon_buf, true); ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_URL, url, true); ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_TARGET, target, true); ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_TYPE, mime, true); } /** * Display a menu of options for a form select control. * * \param bw browser window containing form control * \param control form control of type GADGET_SELECT */ void gui_create_form_select_menu(struct browser_window *bw, struct form_control *control) { unsigned int i, entries; char *text_convert, *temp; struct form_option *option; wimp_pointer pointer; os_error *error; bool reopen = true; utf8_convert_ret err; assert(control); for (entries = 0, option = control->data.select.items; option; option = option->next) entries++; if (entries == 0) { ro_gui_menu_closed(true); return; } if ((gui_form_select_menu) && (control != gui_form_select_control)) { for (i = 0; ; i++) { free(gui_form_select_menu->entries[i].data. indirected_text.text); if (gui_form_select_menu->entries[i].menu_flags & wimp_MENU_LAST) break; } free(gui_form_select_menu->title_data.indirected_text.text); free(gui_form_select_menu); gui_form_select_menu = 0; } if (!gui_form_select_menu) { reopen = false; gui_form_select_menu = malloc(wimp_SIZEOF_MENU(entries)); if (!gui_form_select_menu) { warn_user("NoMemory", 0); ro_gui_menu_closed(true); return; } err = utf8_to_local_encoding(messages_get("SelectMenu"), 0, &text_convert); if (err != UTF8_CONVERT_OK) { /* badenc should never happen */ assert(err != UTF8_CONVERT_BADENC); LOG(("utf8_to_local_encoding failed")); warn_user("NoMemory", 0); ro_gui_menu_closed(true); return; } gui_form_select_menu->title_data.indirected_text.text = text_convert; ro_gui_menu_init_structure(gui_form_select_menu, entries); } for (i = 0, option = control->data.select.items; option; i++, option = option->next) { gui_form_select_menu->entries[i].menu_flags = 0; if (option->selected) gui_form_select_menu->entries[i].menu_flags = wimp_MENU_TICKED; if (!reopen) { /* convert spaces to hard spaces to stop things * like 'Go Home' being treated as if 'Home' is a * keyboard shortcut and right aligned in the menu. */ temp = cnv_space2nbsp(option->text); if (!temp) { LOG(("cnv_space2nbsp failed")); warn_user("NoMemory", 0); ro_gui_menu_closed(true); return; } err = utf8_to_local_encoding(temp, 0, &text_convert); if (err != UTF8_CONVERT_OK) { /* A bad encoding should never happen, * so assert this */ assert(err != UTF8_CONVERT_BADENC); LOG(("utf8_to_enc failed")); warn_user("NoMemory", 0); ro_gui_menu_closed(true); return; } free(temp); gui_form_select_menu->entries[i].data.indirected_text.text = text_convert; gui_form_select_menu->entries[i].data.indirected_text.size = strlen(gui_form_select_menu->entries[i]. data.indirected_text.text) + 1; } } gui_form_select_menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED; gui_form_select_menu->entries[i - 1].menu_flags |= wimp_MENU_LAST; error = xwimp_get_pointer_info(&pointer); if (error) { LOG(("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); ro_gui_menu_closed(true); return; } gui_form_select_control = control; ro_gui_menu_create(gui_form_select_menu, pointer.pos.x, pointer.pos.y, bw->window->window); } /** * Creates a wimp_menu and adds it to the list to handle actions for. * * \param menu the data to create the menu with * \return the menu created, or NULL on failure */ wimp_menu *ro_gui_menu_define_menu(const struct ns_menu *menu) { struct menu_definition *definition; int entry; definition = calloc(sizeof(struct menu_definition), 1); if (!definition) { die("No memory to create menu definition."); return NULL; /* For the benefit of scan-build */ } /* link in the menu to our list */ definition->next = ro_gui_menu_definitions; ro_gui_menu_definitions = definition; /* count number of menu entries */ for (entry = 0; menu->entries[entry].text; entry++) /* do nothing */; /* create our definitions */ ro_gui_menu_define_menu_add(definition, menu, 0, NULL, 0, entry, NULL, 0); /* and translate menu into current encoding */ if (!ro_gui_menu_translate(definition)) die("No memory to translate menu."); return definition->menu; } /** * Create a wimp menu tree from ns_menu data. * This function does *not* deal with the menu textual content - it simply * creates and populates the appropriate structures. Textual content is * generated by ro_gui_menu_translate_menu() * * \param definition Top level menu definition * \param menu Menu declaration data * \param depth Depth of menu we're currently building * \param parent_entry Entry in parent menu, or NULL if root menu * \param first First index in declaration data that is used by this menu * \param last Last index in declaration data that is used by this menu * \param prefix Prefix pf menu declaration string already seen * \param prefix_length Length of prefix */ void ro_gui_menu_define_menu_add(struct menu_definition *definition, const struct ns_menu *menu, int depth, wimp_menu_entry *parent_entry, int first, int last, const char *prefix, int prefix_length) { int entry, id, cur_depth; int entries = 0; int matches[last - first + 1]; const char *match; const char *text, *menu_text; wimp_menu *new_menu; struct menu_definition_entry *definition_entry; /* step 1: store the matches for depth and subset string */ for (entry = first; entry < last; entry++) { cur_depth = 0; match = menu->entries[entry].text; /* skip specials at start of string */ while (!isalnum(*match)) match++; /* attempt prefix match */ if ((prefix) && (strncmp(match, prefix, prefix_length))) continue; /* Find depth of this entry */ while (*match) if (*match++ == '.') cur_depth++; if (depth == cur_depth) matches[entries++] = entry; } matches[entries] = last; /* no entries, so exit */ if (entries == 0) return; /* step 2: build and link the menu. we must use realloc to stop * our memory fragmenting so we can test for sub-menus easily */ new_menu = (wimp_menu *)malloc(wimp_SIZEOF_MENU(entries)); if (!new_menu) die("No memory to create menu."); if (parent_entry) { /* Fix up sub menu pointer */ parent_entry->sub_menu = new_menu; } else { /* Root menu => fill in definition struct */ definition->title_key = menu->title; definition->current_encoding = 0; definition->menu = new_menu; } /* this is fixed up in ro_gui_menu_translate() */ new_menu->title_data.indirected_text.text = NULL; /* fill in menu flags */ ro_gui_menu_init_structure(new_menu, entries); /* and then create the entries */ for (entry = 0; entry < entries; entry++) { /* add the entry */ id = matches[entry]; text = menu->entries[id].text; /* fill in menu flags from specials at start of string */ new_menu->entries[entry].menu_flags = 0; while (!isalnum(*text)) { if (*text == '_') new_menu->entries[entry].menu_flags |= wimp_MENU_SEPARATE; text++; } /* get messages key for menu entry */ menu_text = strrchr(text, '.'); if (!menu_text) /* no '.' => top-level entry */ menu_text = text; else menu_text++; /* and move past the '.' */ /* fill in submenu data */ if (menu->entries[id].sub_window) new_menu->entries[entry].sub_menu = (wimp_menu *) (*menu->entries[id].sub_window); /* this is fixed up in ro_gui_menu_translate() */ new_menu->entries[entry].data.indirected_text.text = NULL; /* create definition entry */ definition_entry = malloc(sizeof(struct menu_definition_entry)); if (!definition_entry) die("Unable to create menu definition entry"); definition_entry->action = menu->entries[id].action; definition_entry->menu_entry = &new_menu->entries[entry]; definition_entry->entry_key = menu_text; definition_entry->next = definition->entries; definition->entries = definition_entry; /* recurse */ if (new_menu->entries[entry].sub_menu == wimp_NO_SUB_MENU) { ro_gui_menu_define_menu_add(definition, menu, depth + 1, &new_menu->entries[entry], matches[entry], matches[entry + 1], text, strlen(text)); } /* give menu warnings */ if (new_menu->entries[entry].sub_menu != wimp_NO_SUB_MENU) new_menu->entries[entry].menu_flags |= wimp_MENU_GIVE_WARNING; } new_menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED; new_menu->entries[entries - 1].menu_flags |= wimp_MENU_LAST; } /** * Initialise the basic state of a menu structure so all entries are * indirected text with no flags, no submenu. */ void ro_gui_menu_init_structure(wimp_menu *menu, int entries) { int i; menu->title_fg = wimp_COLOUR_BLACK; menu->title_bg = wimp_COLOUR_LIGHT_GREY; menu->work_fg = wimp_COLOUR_BLACK; menu->work_bg = wimp_COLOUR_WHITE; menu->width = 200; menu->height = wimp_MENU_ITEM_HEIGHT; menu->gap = wimp_MENU_ITEM_GAP; for (i = 0; i < entries; i++) { menu->entries[i].menu_flags = 0; menu->entries[i].sub_menu = wimp_NO_SUB_MENU; menu->entries[i].icon_flags = DEFAULT_FLAGS | wimp_ICON_INDIRECTED; menu->entries[i].data.indirected_text.validation = (char *)-1; } menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED; menu->entries[i - 1].menu_flags |= wimp_MENU_LAST; } /** * Finds the menu_definition corresponding to a wimp_menu. * * \param menu the menu to find the definition for * \return the associated definition, or NULL if one could not be found */ struct menu_definition *ro_gui_menu_find_menu(wimp_menu *menu) { struct menu_definition *definition; if (!menu) return NULL; for (definition = ro_gui_menu_definitions; definition; definition = definition->next) if (definition->menu == menu) return definition; return NULL; } /** * Finds the key associated with a menu entry translation. * * \param menu the menu to search * \param translated the translated text * \return the original message key, or NULL if one could not be found */ const char *ro_gui_menu_find_menu_entry_key(wimp_menu *menu, const char *translated) { struct menu_definition_entry *entry; struct menu_definition *definition = ro_gui_menu_find_menu(menu); if (!definition) return NULL; for (entry = definition->entries; entry; entry = entry->next) if (!strcmp(entry->menu_entry->data.indirected_text.text, translated)) return entry->entry_key; return NULL; } /** * Finds the menu_definition_entry corresponding to an action for a wimp_menu. * * \param menu the menu to search for an action within * \param action the action to find * \return the associated menu entry, or NULL if one could not be found */ struct menu_definition_entry *ro_gui_menu_find_entry(wimp_menu *menu, menu_action action) { struct menu_definition_entry *entry; struct menu_definition *definition = ro_gui_menu_find_menu(menu); if (!definition) return NULL; for (entry = definition->entries; entry; entry = entry->next) if (entry->action == action) return entry; return NULL; } /** * Finds the action corresponding to a wimp_menu_entry for a wimp_menu. * * \param menu the menu to search for an action within * \param menu_entry the menu_entry to find * \return the associated action, or 0 if one could not be found */ menu_action ro_gui_menu_find_action(wimp_menu *menu, wimp_menu_entry *menu_entry) { struct menu_definition_entry *entry; struct menu_definition *definition = ro_gui_menu_find_menu(menu); if (!definition) return NO_ACTION; for (entry = definition->entries; entry; entry = entry->next) { if (entry->menu_entry == menu_entry) return entry->action; } return NO_ACTION; } /** * Sets an action within a menu as having a specific ticked status. * * \param menu the menu containing the action * \param action the action to tick/untick * \param ticked whether to set the item as ticked */ void ro_gui_menu_set_entry_shaded(wimp_menu *menu, menu_action action, bool shaded) { struct menu_definition_entry *entry; struct menu_definition *definition = ro_gui_menu_find_menu(menu); if (!definition) return; /* we can't use find_entry as multiple actions may appear in one menu */ for (entry = definition->entries; entry; entry = entry->next) if (entry->action == action) { if (shaded) entry->menu_entry->icon_flags |= wimp_ICON_SHADED; else entry->menu_entry->icon_flags &= ~wimp_ICON_SHADED; } } /** * Sets an action within a menu as having a specific ticked status. * * \param menu the menu containing the action * \param action the action to tick/untick * \param ticked whether to set the item as ticked */ void ro_gui_menu_set_entry_ticked(wimp_menu *menu, menu_action action, bool ticked) { struct menu_definition_entry *entry = ro_gui_menu_find_entry(menu, action); if (entry) { if (ticked) entry->menu_entry->menu_flags |= wimp_MENU_TICKED; else entry->menu_entry->menu_flags &= ~wimp_MENU_TICKED; } } /** * Handles an action. * * \param owner the window to handle the action for * \param action the action to handle * \param windows_at_pointer whether to open any windows at the pointer location */ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, bool windows_at_pointer) { wimp_window_state state; struct gui_window *g = NULL; struct browser_window *bw = NULL; struct content *c = NULL; struct toolbar *t = NULL; struct tree *tree; struct node *node; os_error *error; char url[80]; const struct url_data *data; ro_gui_menu_get_window_details(owner, &g, &bw, &c, &t, &tree); switch (action) { /* help actions */ case HELP_OPEN_CONTENTS: ro_gui_open_help_page("documentation/index"); return true; case HELP_OPEN_GUIDE: ro_gui_open_help_page("documentation/guide"); return true; case HELP_OPEN_INFORMATION: ro_gui_open_help_page("documentation/info"); return true; case HELP_OPEN_ABOUT: ro_gui_open_help_page("about/index"); return true; case HELP_LAUNCH_INTERACTIVE: if (!ro_gui_interactive_help_available()) { ro_gui_interactive_help_start(); option_interactive_help = true; } else { option_interactive_help = !option_interactive_help; } return true; /* history actions */ case HISTORY_SHOW_LOCAL: if ((!bw) || (!bw->history)) return false; ro_gui_history_open(bw, bw->history, windows_at_pointer); return true; case HISTORY_SHOW_GLOBAL: ro_gui_tree_show(global_history_tree); return true; /* hotlist actions */ case HOTLIST_ADD_URL: if ((!hotlist_tree) || (!c) || (!c->url)) return false; data = urldb_get_url_data(c->url); if (data) { node = tree_create_URL_node(hotlist_tree->root, c->url, data, data->title); if (node) { tree_redraw_area(hotlist_tree, node->box.x - NODE_INSTEP, 0, NODE_INSTEP, 16384); tree_handle_node_changed(hotlist_tree, node, false, true); ro_gui_tree_scroll_visible(hotlist_tree, &node->data); ro_gui_hotlist_save(); } } return true; case HOTLIST_SHOW: ro_gui_tree_show(hotlist_tree); return true; /* cookies actions */ case COOKIES_SHOW: ro_gui_tree_show(cookies_tree); return true; case COOKIES_DELETE: if (cookies_tree->root->child) tree_delete_node(cookies_tree, cookies_tree->root->child, true); return true; /* page actions */ case BROWSER_PAGE_INFO: if (!c) return false; ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent(g->window, dialog_pageinfo, windows_at_pointer); return true; case BROWSER_PRINT: if (!c) return false; ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent(g->window, dialog_print, windows_at_pointer); return true; case BROWSER_NEW_WINDOW: if (!c) return false; browser_window_create(c->url, bw, 0, false, false); return true; case BROWSER_VIEW_SOURCE: if (!c) return false; ro_gui_view_source(c); return true; /* object actions */ case BROWSER_OBJECT_INFO: if (!current_menu_object) return false; ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent(g->window, dialog_objinfo, windows_at_pointer); return true; case BROWSER_OBJECT_RELOAD: if (!current_menu_object) return false; current_menu_object->fresh = false; browser_window_reload(bw, false); return true; /* link actions */ case BROWSER_LINK_SAVE_URI: case BROWSER_LINK_SAVE_URL: case BROWSER_LINK_SAVE_TEXT: if (!current_menu_url) return false; ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent(owner, dialog_saveas, windows_at_pointer); break; case BROWSER_LINK_DOWNLOAD: if (!current_menu_url) return false; browser_window_download(bw, current_menu_url, c->url); break; case BROWSER_LINK_NEW_WINDOW: if (!current_menu_url) return false; browser_window_create(current_menu_url, bw, c->url, true, false); break; /* save actions */ case BROWSER_OBJECT_SAVE: case BROWSER_OBJECT_EXPORT_SPRITE: case BROWSER_OBJECT_EXPORT_DRAW: c = current_menu_object; /* Fall through */ case BROWSER_SAVE: case BROWSER_SAVE_COMPLETE: case BROWSER_EXPORT_DRAW: case BROWSER_EXPORT_PDF: case BROWSER_EXPORT_TEXT: case BROWSER_SAVE_URL_URI: case BROWSER_SAVE_URL_URL: case BROWSER_SAVE_URL_TEXT: if (!c) return false; /* Fall through */ case HOTLIST_EXPORT: case HISTORY_EXPORT: ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent(owner, dialog_saveas, windows_at_pointer); return true; /* selection actions */ case BROWSER_SELECTION_SAVE: ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent(owner, dialog_saveas, windows_at_pointer); return true; case BROWSER_SELECTION_COPY: browser_window_key_press(bw, KEY_COPY_SELECTION); break; case BROWSER_SELECTION_CUT: browser_window_key_press(bw, KEY_CUT_SELECTION); return true; case BROWSER_SELECTION_PASTE: browser_window_key_press(bw, KEY_PASTE); return true; case BROWSER_SELECTION_ALL: browser_window_key_press(bw, KEY_SELECT_ALL); break; case BROWSER_SELECTION_CLEAR: browser_window_key_press(bw, KEY_CLEAR_SELECTION); break; /* navigation actions */ case BROWSER_NAVIGATE_HOME: if (!bw) return false; if ((option_homepage_url) && (option_homepage_url[0])) { browser_window_go(g->bw, option_homepage_url, 0, true); } else { snprintf(url, sizeof url, "file:////Docs/welcome/index_%s", option_language); browser_window_go(g->bw, url, 0, true); } return true; case BROWSER_NAVIGATE_BACK: if ((!bw) || (!bw->history)) return false; history_back(bw, bw->history); return true; case BROWSER_NAVIGATE_FORWARD: if ((!bw) || (!bw->history)) return false; history_forward(bw, bw->history); return true; case BROWSER_NAVIGATE_UP: if ((!bw) || (!c)) return false; return ro_gui_window_navigate_up(bw->window, c->url); case BROWSER_NAVIGATE_RELOAD: case BROWSER_NAVIGATE_RELOAD_ALL: if (!bw) return false; browser_window_reload(bw, (action == BROWSER_NAVIGATE_RELOAD_ALL)); return true; case BROWSER_NAVIGATE_STOP: if (!bw) return false; browser_window_stop(bw); return true; case BROWSER_NAVIGATE_URL: ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent(NULL, dialog_openurl, windows_at_pointer); return true; /* browser window/display actions */ case BROWSER_SCALE_VIEW: if (!c) return false; ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent(g->window, dialog_zoom, windows_at_pointer); return true; case BROWSER_FIND_TEXT: if (!c || (c->type != CONTENT_HTML && c->type != CONTENT_TEXTPLAIN)) return false; ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent(g->window, dialog_search, windows_at_pointer); return true; case BROWSER_IMAGES_BACKGROUND: if (!g) return false; g->option.background_images = !g->option.background_images; gui_window_redraw_window(g); return true; case BROWSER_BUFFER_ANIMS: if (!g) return false; g->option.buffer_animations = !g->option.buffer_animations; break; case BROWSER_BUFFER_ALL: if (!g) return false; g->option.buffer_everything = !g->option.buffer_everything; break; case BROWSER_SAVE_VIEW: if (!bw) return false; ro_gui_window_default_options(bw); ro_gui_save_options(); return true; case BROWSER_WINDOW_DEFAULT: if (!g) return false; ro_gui_screen_size(&option_window_screen_width, &option_window_screen_height); state.w = current_menu_window; error = xwimp_get_window_state(&state); if (error) { LOG(("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } option_window_x = state.visible.x0; option_window_y = state.visible.y0; option_window_width = state.visible.x1 - state.visible.x0; option_window_height = state.visible.y1 - state.visible.y0; ro_gui_save_options(); return true; case BROWSER_WINDOW_STAGGER: option_window_stagger = !option_window_stagger; ro_gui_save_options(); return true; case BROWSER_WINDOW_COPY: option_window_size_clone = !option_window_size_clone; ro_gui_save_options(); return true; case BROWSER_WINDOW_RESET: option_window_screen_width = 0; option_window_screen_height = 0; ro_gui_save_options(); return true; /* tree actions */ case TREE_NEW_FOLDER: ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent((wimp_w)tree->handle, dialog_folder, windows_at_pointer); return true; case TREE_NEW_LINK: ro_gui_menu_prepare_action(owner, action, true); ro_gui_dialog_open_persistent((wimp_w)tree->handle, dialog_entry, windows_at_pointer); return true; case TREE_EXPAND_ALL: case TREE_EXPAND_FOLDERS: case TREE_EXPAND_LINKS: tree_handle_expansion(tree, tree->root, true, (action != TREE_EXPAND_LINKS), (action != TREE_EXPAND_FOLDERS)); return true; case TREE_COLLAPSE_ALL: case TREE_COLLAPSE_FOLDERS: case TREE_COLLAPSE_LINKS: tree_handle_expansion(tree, tree->root, false, (action != TREE_COLLAPSE_LINKS), (action != TREE_COLLAPSE_FOLDERS)); return true; case TREE_SELECTION_EDIT: return true; case TREE_SELECTION_LAUNCH: ro_gui_tree_launch_selected(tree); return true; case TREE_SELECTION_DELETE: ro_gui_tree_stop_edit(tree); tree_delete_selected_nodes(tree, tree->root); if (tree == hotlist_tree) ro_gui_hotlist_save(); ro_gui_menu_prepare_action(owner, TREE_CLEAR_SELECTION, true); ro_gui_menu_prepare_action(owner, TREE_SELECTION, true); return true; case TREE_SELECT_ALL: ro_gui_tree_stop_edit(tree); if (tree->root->child) { tree->temp_selection = NULL; tree_set_node_selected(tree, tree->root, true); } ro_gui_menu_prepare_action(owner, TREE_CLEAR_SELECTION, true); ro_gui_menu_prepare_action(owner, TREE_SELECTION, true); return true; case TREE_CLEAR_SELECTION: tree->temp_selection = NULL; ro_gui_tree_stop_edit(tree); tree_set_node_selected(tree, tree->root, false); ro_gui_menu_prepare_action(owner, TREE_CLEAR_SELECTION, true); ro_gui_menu_prepare_action(owner, TREE_SELECTION, true); return true; /* toolbar actions */ case TOOLBAR_BUTTONS: assert(t); t->display_buttons = !t->display_buttons; ro_gui_menu_refresh_toolbar(t); return true; case TOOLBAR_ADDRESS_BAR: assert(t); t->display_url = !t->display_url; ro_gui_menu_refresh_toolbar(t); if (t->display_url) ro_gui_set_caret_first(t->toolbar_handle); return true; case TOOLBAR_THROBBER: assert(t); t->display_throbber = !t->display_throbber; ro_gui_menu_refresh_toolbar(t); return true; case TOOLBAR_EDIT: assert(t); ro_gui_theme_toggle_edit(t); return true; /* misc actions */ case APPLICATION_QUIT: if (ro_gui_prequit()) { LOG(("QUIT in response to user request")); netsurf_quit = true; } return true; case CHOICES_SHOW: ro_gui_configure_show(); return true; /* unknown action */ default: return false; } return false; } /** * Prepares an action for use. * * \param owner the window to prepare the action for * \param action the action to prepare * \param windows whether to update sub-windows */ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) { struct menu_definition_entry *entry; struct gui_window *g; struct browser_window *bw; struct content *c; struct toolbar *t; struct tree *tree; struct node *node; bool result = false; int checksum = 0; os_error *error; char *parent; url_func_result res; bool compare; ro_gui_menu_get_window_details(owner, &g, &bw, &c, &t, &tree); if (current_menu_open) checksum = ro_gui_menu_get_checksum(); if (!c) { current_menu_object = NULL; current_menu_url = NULL; } switch (action) { /* help actions */ case HELP_LAUNCH_INTERACTIVE: result = ro_gui_interactive_help_available() && option_interactive_help; ro_gui_menu_set_entry_ticked(current_menu, action, result); ro_gui_save_options(); break; /* history actions */ case HISTORY_SHOW_LOCAL: ro_gui_menu_set_entry_shaded(current_menu, action, (!bw || (!bw->history) || !(c || history_back_available(bw->history) || history_forward_available(bw->history)))); break; case HISTORY_SHOW_GLOBAL: ro_gui_menu_set_entry_shaded(current_menu, action, !global_history_tree); break; /* hotlist actions */ case HOTLIST_ADD_URL: ro_gui_menu_set_entry_shaded(current_menu, action, (!c || !hotlist_tree)); break; case HOTLIST_SHOW: ro_gui_menu_set_entry_shaded(current_menu, action, !hotlist_tree); if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_BOOKMARK, !hotlist_tree); break; /* cookies actions */ case COOKIES_SHOW: ro_gui_menu_set_entry_shaded(current_menu, action, !cookies_tree); break; case COOKIES_DELETE: ro_gui_menu_set_entry_shaded(current_menu, action, !(cookies_tree && cookies_tree->root->child)); break; /* page actions */ case BROWSER_PAGE: ro_gui_menu_set_entry_shaded(current_menu, action, !c || (c->type != CONTENT_HTML && c->type != CONTENT_TEXTPLAIN)); break; case BROWSER_PAGE_INFO: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((windows) && (c)) ro_gui_menu_prepare_pageinfo(g); break; case BROWSER_PRINT: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((t) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_PRINT, !c); if ((windows) && (c)) ro_gui_print_prepare(g); if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_PRINT, !c); break; case BROWSER_NEW_WINDOW: case BROWSER_VIEW_SOURCE: ro_gui_menu_set_entry_shaded(current_menu, action, !c); break; /* object actions */ case BROWSER_OBJECT: ro_gui_menu_set_entry_shaded(current_menu, action, !current_menu_object && !current_menu_url); break; case BROWSER_OBJECT_LINK: ro_gui_menu_set_entry_shaded(current_menu, action, !current_menu_url); break; case BROWSER_OBJECT_INFO: if (windows && current_menu_object) ro_gui_menu_prepare_objectinfo(current_menu_object, current_menu_url); /* Fall through */ case BROWSER_OBJECT_RELOAD: case BROWSER_OBJECT_OBJECT: ro_gui_menu_set_entry_shaded(current_menu, action, !current_menu_object); break; case BROWSER_OBJECT_PRINT: /* not yet implemented */ ro_gui_menu_set_entry_shaded(current_menu, action, true); break; /* save actions (browser, hotlist, history) */ case BROWSER_OBJECT_SAVE: ro_gui_menu_set_entry_shaded(current_menu, action, !current_menu_object); if (windows && current_menu_object) ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG, current_menu_object, NULL, NULL, NULL); break; case BROWSER_OBJECT_EXPORT: case BROWSER_OBJECT_EXPORT_SPRITE: case BROWSER_OBJECT_EXPORT_DRAW: { bool exp_sprite = false; bool exp_draw = false; if (current_menu_object) c = current_menu_object; if (c) { switch (c->type) { /* \todo - this classification should prob be done in content_() */ /* bitmap types (Sprite export possible) */ #ifdef WITH_JPEG case CONTENT_JPEG: #endif #ifdef WITH_MNG case CONTENT_JNG: case CONTENT_MNG: #endif #ifdef WITH_GIF case CONTENT_GIF: #endif #ifdef WITH_BMP case CONTENT_BMP: case CONTENT_ICO: #endif #if defined(WITH_MNG) || defined(WITH_PNG) case CONTENT_PNG: #endif #ifdef WITH_SPRITE case CONTENT_SPRITE: #endif exp_sprite = true; break; /* vector types (Draw export possible) */ #if defined(WITH_NS_SVG) || defined(WITH_RSVG) case CONTENT_SVG: #endif #ifdef WITH_DRAW case CONTENT_DRAW: #endif exp_draw = true; break; default: break; } } switch (action) { case BROWSER_OBJECT_EXPORT_SPRITE: if (!exp_sprite) c = NULL; break; case BROWSER_OBJECT_EXPORT_DRAW: if (!exp_draw) c = NULL; break; default: if (!exp_sprite && !exp_draw) c = NULL; break; } ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, c, NULL, NULL, NULL); } break; case BROWSER_LINK_SAVE_URI: case BROWSER_LINK_SAVE_URL: case BROWSER_LINK_SAVE_TEXT: ro_gui_menu_set_entry_shaded(current_menu, action, !current_menu_url); if (windows && current_menu_url) { gui_save_type save_type; switch (action) { case BROWSER_LINK_SAVE_URI: save_type = GUI_SAVE_LINK_URI; break; case BROWSER_LINK_SAVE_URL: save_type = GUI_SAVE_LINK_URL; break; default: save_type = GUI_SAVE_LINK_TEXT; break; } ro_gui_save_prepare(save_type, NULL, NULL, current_menu_url, NULL); } break; case BROWSER_SELECTION: /* make menu available if there's anything that /could/ be selected */ ro_gui_menu_set_entry_shaded(current_menu, action, !c || (c->type != CONTENT_HTML && c->type != CONTENT_TEXTPLAIN)); break; case BROWSER_SELECTION_SAVE: if (c && (!bw->sel || !selection_defined(bw->sel))) c = NULL; ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL, bw->sel, NULL, NULL); break; case BROWSER_SELECTION_COPY: ro_gui_menu_set_entry_shaded(current_menu, action, !(c && bw->sel && selection_defined(bw->sel))); break; case BROWSER_SELECTION_CUT: ro_gui_menu_set_entry_shaded(current_menu, action, !(c && bw->sel && selection_defined(bw->sel) && !selection_read_only(bw->sel))); break; case BROWSER_SELECTION_PASTE: ro_gui_menu_set_entry_shaded(current_menu, action, !(c && bw->paste_callback)); break; case BROWSER_SAVE: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_SOURCE, c, NULL, NULL, NULL); if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_SAVE, !c); break; case BROWSER_SAVE_COMPLETE: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_COMPLETE, c, NULL, NULL, NULL); break; case BROWSER_EXPORT_DRAW: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_DRAW, c, NULL, NULL, NULL); break; case BROWSER_EXPORT_PDF: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_PDF, c, NULL, NULL, NULL); break; case BROWSER_EXPORT_TEXT: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_TEXT, c, NULL, NULL, NULL); break; case BROWSER_OBJECT_SAVE_URL_URI: if (c && c->type == CONTENT_HTML) c = current_menu_object; /* Fall through */ case BROWSER_SAVE_URL_URI: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, c->url, c->title); break; case BROWSER_OBJECT_SAVE_URL_URL: if (c && c->type == CONTENT_HTML) c = current_menu_object; /* Fall through */ case BROWSER_SAVE_URL_URL: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, c->url, c->title); break; case BROWSER_OBJECT_SAVE_URL_TEXT: c = current_menu_object; /* Fall through */ case BROWSER_SAVE_URL_TEXT: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, c->url, c->title); break; case HOTLIST_EXPORT: if ((tree) && (windows)) ro_gui_save_prepare(GUI_SAVE_HOTLIST_EXPORT_HTML, NULL, NULL, NULL, NULL); break; case HISTORY_EXPORT: if ((tree) && (windows)) ro_gui_save_prepare(GUI_SAVE_HISTORY_EXPORT_HTML, NULL, NULL, NULL, NULL); break; /* navigation actions */ case BROWSER_NAVIGATE_BACK: result = browser_window_back_available(bw); ro_gui_menu_set_entry_shaded(current_menu, action, !result); if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_BACK, !result); break; case BROWSER_NAVIGATE_FORWARD: result = browser_window_forward_available(bw); ro_gui_menu_set_entry_shaded(current_menu, action, !result); if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_FORWARD, !result); break; case BROWSER_NAVIGATE_UP: result = (bw && c); if (result) { res = url_parent(c->url, &parent); if (res == URL_FUNC_OK) { res = url_compare(c->url, parent, false, &compare); if (res == URL_FUNC_OK) result = !compare; free(parent); } else { result = false; } } ro_gui_menu_set_entry_shaded(current_menu, action, !result); if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_UP, !result); break; case BROWSER_NAVIGATE_RELOAD: case BROWSER_NAVIGATE_RELOAD_ALL: result = browser_window_reload_available(bw); ro_gui_menu_set_entry_shaded(current_menu, action, !result); if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_RELOAD, !result); break; case BROWSER_NAVIGATE_STOP: result = browser_window_stop_available(bw); ro_gui_menu_set_entry_shaded(current_menu, action, !result); if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_STOP, !result); break; case BROWSER_NAVIGATE_URL: if (windows) ro_gui_dialog_prepare_open_url(); break; /* display actions */ case BROWSER_SCALE_VIEW: ro_gui_menu_set_entry_shaded(current_menu, action, !c); if ((c) && (windows)) ro_gui_dialog_prepare_zoom(g); if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_SCALE, !c); break; case BROWSER_FIND_TEXT: result = !c || (c->type != CONTENT_HTML && c->type != CONTENT_TEXTPLAIN); ro_gui_menu_set_entry_shaded(current_menu, action, result); if ((!result) && (windows)) { ro_gui_search_prepare(g->bw); } if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_SEARCH, result); break; case BROWSER_IMAGES_FOREGROUND: ro_gui_menu_set_entry_shaded(current_menu, action, true); ro_gui_menu_set_entry_ticked(current_menu, action, true); break; case BROWSER_IMAGES_BACKGROUND: if (g) ro_gui_menu_set_entry_ticked(current_menu, action, g->option.background_images); break; case BROWSER_BUFFER_ANIMS: if (g) { ro_gui_menu_set_entry_shaded(current_menu, action, g->option.buffer_everything); ro_gui_menu_set_entry_ticked(current_menu, action, g->option.buffer_animations || g->option.buffer_everything); } break; case BROWSER_BUFFER_ALL: if (g) ro_gui_menu_set_entry_ticked(current_menu, action, g->option.buffer_everything); break; case BROWSER_WINDOW_STAGGER: ro_gui_menu_set_entry_shaded(current_menu, action, option_window_screen_width == 0); ro_gui_menu_set_entry_ticked(current_menu, action, ((option_window_screen_width == 0) || option_window_stagger)); break; case BROWSER_WINDOW_COPY: ro_gui_menu_set_entry_ticked(current_menu, action, option_window_size_clone); break; case BROWSER_WINDOW_RESET: ro_gui_menu_set_entry_shaded(current_menu, action, option_window_screen_width == 0); break; /* tree actions */ case TREE_NEW_FOLDER: ro_gui_hotlist_prepare_folder_dialog(NULL); break; case TREE_NEW_LINK: ro_gui_hotlist_prepare_entry_dialog(NULL); break; case TREE_EXPAND_ALL: case TREE_EXPAND_FOLDERS: case TREE_EXPAND_LINKS: case TREE_COLLAPSE_ALL: case TREE_COLLAPSE_FOLDERS: case TREE_COLLAPSE_LINKS: if ((tree) && (tree->root)) { ro_gui_menu_set_entry_shaded(current_menu, action, !tree->root->child); if ((t) && (!t->editor) && (t->type != THEME_BROWSER_TOOLBAR)) { ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_EXPAND, !tree->root->child); ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_OPEN, !tree->root->child); } } break; case TREE_SELECTION: if ((!tree) || (!tree->root)) break; if (tree->root->child) result = tree_has_selection(tree->root->child); ro_gui_menu_set_entry_shaded(current_menu, action, !result); if ((t) && (!t->editor) && (t->type != THEME_BROWSER_TOOLBAR)) { ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_DELETE, !result); ro_gui_set_icon_shaded_state( t->toolbar_handle, ICON_TOOLBAR_LAUNCH, !result); } break; case TREE_SELECTION_EDIT: node = tree_get_selected_node(tree->root); entry = ro_gui_menu_find_entry(current_menu, action); if ((!node) || (!entry)) break; if (node->folder) { entry->menu_entry->sub_menu = (wimp_menu *)dialog_folder; if (windows) ro_gui_hotlist_prepare_folder_dialog(node); } else { entry->menu_entry->sub_menu = (wimp_menu *)dialog_entry; if (windows) ro_gui_hotlist_prepare_entry_dialog(node); } break; case TREE_SELECTION_LAUNCH: case TREE_SELECTION_DELETE: case TREE_CLEAR_SELECTION: if ((!tree) || (!tree->root)) break; if (tree->root->child) result = tree_has_selection(tree->root->child); ro_gui_menu_set_entry_shaded(current_menu, action, !result); break; case TREE_SELECT_ALL: ro_gui_menu_set_entry_shaded(current_menu, action, !tree->root->child); break; /* toolbar actions */ case TOOLBAR_BUTTONS: ro_gui_menu_set_entry_shaded(current_menu, action, (!t || (t->editor))); ro_gui_menu_set_entry_ticked(current_menu, action, (t && ((t->display_buttons) || (t->editor)))); break; case TOOLBAR_ADDRESS_BAR: ro_gui_menu_set_entry_shaded(current_menu, action, !t); ro_gui_menu_set_entry_ticked(current_menu, action, (t && t->display_url)); break; case TOOLBAR_THROBBER: ro_gui_menu_set_entry_shaded(current_menu, action, !t); ro_gui_menu_set_entry_ticked(current_menu, action, (t && t->display_throbber)); break; case TOOLBAR_EDIT: ro_gui_menu_set_entry_shaded(current_menu, action, !t); ro_gui_menu_set_entry_ticked(current_menu, action, (t && t->editor)); break; /* unknown action */ default: return; } /* update open menus */ if ((current_menu_open) && (checksum != ro_gui_menu_get_checksum())) { error = xwimp_create_menu(current_menu, 0, 0); if (error) { LOG(("xwimp_create_menu: 0x%x: %s", error->errnum, error->errmess)); warn_user("MenuError", error->errmess); } } } /** * Gets various details relating to a window * * \param w the window to complete information for */ void ro_gui_menu_get_window_details(wimp_w w, struct gui_window **g, struct browser_window **bw, struct content **content, struct toolbar **toolbar, struct tree **tree) { *g = ro_gui_window_lookup(w); if (*g) { *bw = (*g)->bw; *toolbar = (*g)->toolbar; if (*bw) *content = (*bw)->current_content; *tree = NULL; } else { *bw = NULL; *content = NULL; if ((hotlist_tree) && (w == (wimp_w)hotlist_tree->handle)) *tree = hotlist_tree; else if ((global_history_tree) && (w == (wimp_w)global_history_tree->handle)) *tree = global_history_tree; else if ((cookies_tree) && (w == (wimp_w)cookies_tree->handle)) *tree = cookies_tree; else *tree = NULL; if (*tree) *toolbar = (*tree)->toolbar; else *toolbar = NULL; } } /** * Calculates a simple checksum for the current menu state */ int ro_gui_menu_get_checksum(void) { wimp_selection menu_tree; int i = 0, j, checksum = 0; os_error *error; wimp_menu *menu; if (!current_menu_open) return 0; error = xwimp_get_menu_state((wimp_menu_state_flags)0, &menu_tree, 0, 0); if (error) { LOG(("xwimp_get_menu_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("MenuError", error->errmess); return 0; } menu = current_menu; do { j = 0; do { if (menu->entries[j].icon_flags & wimp_ICON_SHADED) checksum ^= (1 << (i + j * 2)); if (menu->entries[j].menu_flags & wimp_MENU_TICKED) checksum ^= (2 << (i + j * 2)); } while (!(menu->entries[j++].menu_flags & wimp_MENU_LAST)); j = menu_tree.items[i++]; if (j != -1) { menu = menu->entries[j].sub_menu; if ((!menu) || (menu == wimp_NO_SUB_MENU) || (!IS_MENU(menu))) break; } } while (j != -1); return checksum; } /** * Translate a menu's textual content into the system local encoding * * \param menu The menu to translate * \return false if out of memory, true otherwise */ bool ro_gui_menu_translate(struct menu_definition *menu) { os_error *error; int alphabet; struct menu_definition_entry *entry; char *translated; utf8_convert_ret err; /* read current alphabet */ error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &alphabet); if (error) { LOG(("failed reading alphabet: 0x%x: %s", error->errnum, error->errmess)); /* assume Latin1 */ alphabet = territory_ALPHABET_LATIN1; } if (menu->current_encoding == alphabet) /* menu text is already in the correct encoding */ return true; /* translate root menu title text */ free(menu->menu->title_data.indirected_text.text); err = utf8_to_local_encoding(messages_get(menu->title_key), 0, &translated); if (err != UTF8_CONVERT_OK) { assert(err != UTF8_CONVERT_BADENC); LOG(("utf8_to_enc failed")); return false; } /* and fill in WIMP menu field */ menu->menu->title_data.indirected_text.text = translated; /* now the menu entries */ for (entry = menu->entries; entry; entry = entry->next) { wimp_menu *submenu = entry->menu_entry->sub_menu; /* tranlate menu entry text */ free(entry->menu_entry->data.indirected_text.text); err = utf8_to_local_encoding(messages_get(entry->entry_key), 0, &translated); if (err != UTF8_CONVERT_OK) { assert(err != UTF8_CONVERT_BADENC); LOG(("utf8_to_enc failed")); return false; } /* fill in WIMP menu fields */ entry->menu_entry->data.indirected_text.text = translated; entry->menu_entry->data.indirected_text.validation = (char *) -1; entry->menu_entry->data.indirected_text.size = strlen(translated); /* child menu title - this is the same as the text of * the parent menu entry, so just copy the pointer */ if (submenu != wimp_NO_SUB_MENU && IS_MENU(submenu)) { submenu->title_data.indirected_text.text = translated; } } /* finally, set the current encoding of the menu */ menu->current_encoding = alphabet; return true; }