netsurf/riscos/menus.c

2656 lines
76 KiB
C

/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2005 Richard Wilson <info@tinct.net>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/** \file
* Menu creation and handling (implementation).
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "oslib/os.h"
#include "oslib/osbyte.h"
#include "oslib/osgbpb.h"
#include "oslib/territory.h"
#include "oslib/wimp.h"
#include "content/content.h"
#include "content/hlcache.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, hlcache_handle **h,
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(hlcache_handle *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 hlcache_handle *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)) {
hlcache_handle *h;
g = ro_gui_window_lookup(w);
h = g->bw->current_content;
if (!ro_gui_window_to_window_pos(g, x, y, &pos))
return;
current_menu_object = NULL;
current_menu_url = NULL;
if (h) {
switch (content_get_type(h)) {
case CONTENT_HTML: {
struct box *box;
box = box_object_at_point(h, pos.x,
pos.y);
current_menu_object = box ?
box->object : NULL;
box = box_href_at_point(h, pos.x,
pos.y);
current_menu_url = box ?
box->href : NULL;
}
break;
case CONTENT_TEXTPLAIN:
/* no object, no url */
break;
default:
current_menu_object = h;
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;
hlcache_handle *h;
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, &h, &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 = &current_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 = &current_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)
{
hlcache_handle *h = 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, *url, *mime;
const char *enc = "-";
assert(h);
title = content_get_title(h);
if (title == NULL)
title = "-";
url = content_get_url(h);
if (url == NULL)
url = "-";
mime = content_get_mime_type(h);
if (mime == NULL)
mime = "-";
sprintf(icon_buf, "file_%x", ro_content_filetype(h));
if (!ro_gui_wimp_sprite_exists(icon_buf))
sprintf(icon_buf, "file_xxx");
if (content_get_type(h) == CONTENT_HTML) {
if (html_get_encoding(h)) {
enc_token[8] = '0' + html_get_encoding_source(h);
snprintf(enc_buf, sizeof enc_buf, "%s (%s)",
html_get_encoding(h),
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(hlcache_handle *object, const char *href)
{
char icon_buf[20] = "file_xxx";
const char *url, *mime;
const char *target = "-";
sprintf(icon_buf, "file_%.3x",
ro_content_filetype(object));
if (!ro_gui_wimp_sprite_exists(icon_buf))
sprintf(icon_buf, "file_xxx");
url = content_get_url(object);
if (url == NULL)
url = "-";
mime = content_get_mime_type(object);
if (mime == NULL)
mime = "-";
if (href)
target = href;
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;
hlcache_handle *h = 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, &h, &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) || (!h) || (!content_get_url(h)))
return false;
data = urldb_get_url_data(content_get_url(h));
if (data) {
node = tree_create_URL_node(hotlist_tree->root,
content_get_url(h),
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 (!h)
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 (!h)
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 (!h)
return false;
browser_window_create(content_get_url(h), bw, 0, false,
false);
return true;
case BROWSER_VIEW_SOURCE:
if (!h)
return false;
ro_gui_view_source(h);
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;
content_invalidate_reuse_data(current_menu_object);
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,
content_get_url(h));
break;
case BROWSER_LINK_NEW_WINDOW:
if (!current_menu_url)
return false;
browser_window_create(current_menu_url, bw,
content_get_url(h), true, false);
break;
/* save actions */
case BROWSER_OBJECT_SAVE:
case BROWSER_OBJECT_EXPORT_SPRITE:
case BROWSER_OBJECT_EXPORT_DRAW:
h = 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 (!h)
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:///<NetSurf$Dir>/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) || (!h))
return false;
return ro_gui_window_navigate_up(bw->window,
content_get_url(h));
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 (!h)
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 (!h || (content_get_type(h) != CONTENT_TEXTPLAIN &&
content_get_type(h) != CONTENT_HTML))
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;
hlcache_handle *h;
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, &h, &t, &tree);
if (current_menu_open)
checksum = ro_gui_menu_get_checksum();
if (!h) {
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) ||
!(h || 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,
(!h || !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, !h ||
(content_get_type(h) != CONTENT_HTML &&
content_get_type(h) != CONTENT_TEXTPLAIN));
break;
case BROWSER_PAGE_INFO:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((windows) && (h))
ro_gui_menu_prepare_pageinfo(g);
break;
case BROWSER_PRINT:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((t) && (t->type == THEME_BROWSER_TOOLBAR))
ro_gui_set_icon_shaded_state(
t->toolbar_handle,
ICON_TOOLBAR_PRINT, !h);
if ((windows) && (h))
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, !h);
break;
case BROWSER_NEW_WINDOW:
case BROWSER_VIEW_SOURCE:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
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)
h = current_menu_object;
if (h) {
switch (content_get_type(h)) {
/* \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)
h = NULL;
break;
case BROWSER_OBJECT_EXPORT_DRAW:
if (!exp_draw)
h = NULL;
break;
default:
if (!exp_sprite && !exp_draw)
h = NULL;
break;
}
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((h) && (windows))
ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, h, 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,
!h || (content_get_type(h) != CONTENT_HTML &&
content_get_type(h) != CONTENT_TEXTPLAIN));
break;
case BROWSER_SELECTION_SAVE:
if (h && (!bw->sel || !selection_defined(bw->sel)))
h = NULL;
ro_gui_menu_set_entry_shaded(current_menu, action, !h);
if ((h) && (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,
!(h && bw->sel && selection_defined(bw->sel)));
break;
case BROWSER_SELECTION_CUT:
ro_gui_menu_set_entry_shaded(current_menu, action,
!(h && 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,
!(h && bw->paste_callback));
break;
case BROWSER_SAVE:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((h) && (windows))
ro_gui_save_prepare(GUI_SAVE_SOURCE, h, NULL, NULL, NULL);
if ((t) && (!t->editor) &&
(t->type == THEME_BROWSER_TOOLBAR))
ro_gui_set_icon_shaded_state(
t->toolbar_handle,
ICON_TOOLBAR_SAVE, !h);
break;
case BROWSER_SAVE_COMPLETE:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((h) && (windows))
ro_gui_save_prepare(GUI_SAVE_COMPLETE, h, NULL, NULL, NULL);
break;
case BROWSER_EXPORT_DRAW:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((h) && (windows))
ro_gui_save_prepare(GUI_SAVE_DRAW, h, NULL, NULL, NULL);
break;
case BROWSER_EXPORT_PDF:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((h) && (windows))
ro_gui_save_prepare(GUI_SAVE_PDF, h, NULL, NULL, NULL);
break;
case BROWSER_EXPORT_TEXT:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((h) && (windows))
ro_gui_save_prepare(GUI_SAVE_TEXT, h, NULL, NULL, NULL);
break;
case BROWSER_OBJECT_SAVE_URL_URI:
if (h && content_get_type(h) == CONTENT_HTML)
h = current_menu_object;
/* Fall through */
case BROWSER_SAVE_URL_URI:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((h) && (windows))
ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL,
NULL,
content_get_url(h),
content_get_title(h));
break;
case BROWSER_OBJECT_SAVE_URL_URL:
if (h && content_get_type(h) == CONTENT_HTML)
h = current_menu_object;
/* Fall through */
case BROWSER_SAVE_URL_URL:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((h) && (windows))
ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL,
NULL,
content_get_url(h),
content_get_title(h));
break;
case BROWSER_OBJECT_SAVE_URL_TEXT:
h = current_menu_object;
/* Fall through */
case BROWSER_SAVE_URL_TEXT:
ro_gui_menu_set_entry_shaded(current_menu,
action, !h);
if ((h) && (windows))
ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL,
NULL,
content_get_url(h),
content_get_title(h));
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 && h);
if (result) {
res = url_parent(content_get_url(h), &parent);
if (res == URL_FUNC_OK) {
res = url_compare(content_get_url(h),
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, !h);
if ((h) && (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, !h);
break;
case BROWSER_FIND_TEXT:
result = !h || (content_get_type(h) != CONTENT_HTML &&
content_get_type(h) != 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, hlcache_handle **h,
struct toolbar **toolbar, struct tree **tree)
{
*g = ro_gui_window_lookup(w);
if (*g) {
*bw = (*g)->bw;
*toolbar = (*g)->toolbar;
if (*bw)
*h = (*bw)->current_content;
*tree = NULL;
} else {
*bw = NULL;
*h = 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;
}