diff options
Diffstat (limited to 'riscos/window.c')
-rw-r--r-- | riscos/window.c | 4217 |
1 files changed, 2971 insertions, 1246 deletions
diff --git a/riscos/window.c b/riscos/window.c index 1aa2a82f2..3f07e793d 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -5,7 +5,7 @@ * Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk> * Copyright 2005 Richard Wilson <info@tinct.net> * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net> - * Copyright 2010 Stephen Fryatt <stevef@netsurf-browser.org> + * Copyright 2010, 2011 Stephen Fryatt <stevef@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -46,9 +46,13 @@ #include "content/urldb.h" #include "css/css.h" #include "desktop/browser.h" +#include "desktop/cookies.h" #include "desktop/frames.h" +#include "desktop/history_core.h" +#include "desktop/hotlist.h" #include "desktop/mouse.h" #include "desktop/plotters.h" +#include "desktop/selection.h" #include "desktop/textinput.h" #include "desktop/thumbnail.h" #include "desktop/tree.h" @@ -57,21 +61,26 @@ #include "render/form.h" #include "riscos/bitmap.h" #include "riscos/buffer.h" +#include "riscos/cookies.h" #include "riscos/dialog.h" #include "riscos/global_history.h" #include "riscos/gui.h" #include "riscos/gui/status_bar.h" +#include "riscos/help.h" +#include "riscos/hotlist.h" #include "riscos/menus.h" #include "riscos/options.h" #include "riscos/oslib_pre7.h" #include "riscos/save.h" #include "riscos/sprite.h" -#include "riscos/theme.h" +#include "riscos/toolbar.h" #include "riscos/thumbnail.h" #include "riscos/url_complete.h" +#include "riscos/url_suggest.h" #include "riscos/wimp.h" #include "riscos/wimp_event.h" #include "riscos/wimputils.h" +#include "riscos/window.h" #include "utils/log.h" #include "utils/talloc.h" #include "utils/url.h" @@ -79,6 +88,66 @@ #include "utils/utils.h" #include "utils/messages.h" + +static void gui_window_set_extent(struct gui_window *g, int width, int height); + +static void ro_gui_window_redraw(wimp_draw *redraw); +static void ro_gui_window_open(wimp_open *open); +static void ro_gui_window_close(wimp_w w); +static bool ro_gui_window_click(wimp_pointer *mouse); +static bool ro_gui_window_keypress(wimp_key *key); +static void ro_gui_window_toolbar_keypress(void *data, wimp_key *key); +static void ro_gui_window_handle_local_keypress(struct gui_window *g, + wimp_key *key, bool is_toolbar); +static bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu, + wimp_pointer *pointer); +static void ro_gui_window_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu, + wimp_selection *selection, menu_action action); +static bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, + wimp_selection *selection, menu_action action); +static void ro_gui_window_menu_close(wimp_w w, wimp_i i, wimp_menu *menu); + +static void ro_gui_window_toolbar_click(void *data, + toolbar_action_type action_type, union toolbar_action action); + +static bool ro_gui_window_content_export_types(hlcache_handle *h, + bool *export_draw, bool *export_sprite); +static bool ro_gui_window_up_available(struct browser_window *bw); +static void ro_gui_window_prepare_pageinfo(struct gui_window *g); +static void ro_gui_window_prepare_objectinfo(hlcache_handle *object, + const char *href); + +static void ro_gui_window_launch_url(struct gui_window *g, const char *url); +static bool ro_gui_window_navigate_up(struct gui_window *g, const char *url); +static void ro_gui_window_action_home(struct gui_window *g); +static void ro_gui_window_action_new_window(struct gui_window *g); +static void ro_gui_window_action_local_history(struct gui_window *g); +static void ro_gui_window_action_navigate_back_new(struct gui_window *g); +static void ro_gui_window_action_navigate_forward_new(struct gui_window *g); +static void ro_gui_window_action_save(struct gui_window *g, + gui_save_type save_type); +static void ro_gui_window_action_search(struct gui_window *g); +static void ro_gui_window_action_zoom(struct gui_window *g); +static void ro_gui_window_action_add_bookmark(struct gui_window *g); +static void ro_gui_window_action_print(struct gui_window *g); +static void ro_gui_window_action_page_info(struct gui_window *g); + +static void ro_gui_window_remove_update_boxes(struct gui_window *g); +static void ro_gui_window_update_toolbar_buttons(struct gui_window *g); +static void ro_gui_window_update_toolbar(void *data); +static void ro_gui_window_save_toolbar_buttons(void *data, char *config); +static void ro_gui_window_update_theme(void *data, bool ok); + +static bool ro_gui_window_import_text(struct gui_window *g, + const char *filename, bool toolbar); +static void ro_gui_window_clone_options(struct browser_window *new_bw, + struct browser_window *old_bw); + +static bool ro_gui_window_prepare_form_select_menu(struct browser_window *bw, + struct form_control *control); +static void ro_gui_window_process_form_select_menu(struct gui_window *g, + wimp_selection *selection); + #ifndef wimp_KEY_END #define wimp_KEY_END wimp_KEY_COPY #endif @@ -99,17 +168,25 @@ static bool mouse_drag_select; static bool mouse_drag_adjust; /** List of all browser windows. */ -static struct gui_window *window_list = 0; +static struct gui_window *window_list = 0; /** GUI window which is being redrawn. Valid only during redraw. */ -struct gui_window *ro_gui_current_redraw_gui; +struct gui_window *ro_gui_current_redraw_gui; +/** Form control which gui_form_select_menu is for. */ +static struct form_control *gui_form_select_control; +/** The browser window menu handle. */ +static wimp_menu *ro_gui_browser_window_menu = NULL; +/** Menu of options for form select controls. */ +static wimp_menu *gui_form_select_menu = NULL; +/** 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; static float scale_snap_to[] = {0.10, 0.125, 0.25, 0.333, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 8.0, 12.0, 16.0}; #define SCALE_SNAP_TO_SIZE (sizeof scale_snap_to) / (sizeof(float)) - - /** An entry in ro_gui_pointer_table. */ struct ro_gui_pointer_entry { bool wimp_area; /** The pointer is in the Wimp's sprite area. */ @@ -142,20 +219,6 @@ struct ro_gui_pointer_entry ro_gui_pointer_table[] = { { false, "ptr_progress", 0, 0 }, }; - -static void ro_gui_window_remove_update_boxes(struct gui_window *g); -static void gui_window_set_extent(struct gui_window *g, int width, int height); -static void ro_gui_window_open(wimp_open *open); -static void ro_gui_window_close(wimp_w w); -static void ro_gui_window_redraw(wimp_draw *redraw); -static bool ro_gui_window_click(wimp_pointer *mouse); -static bool ro_gui_window_keypress(wimp_key *key); -static void ro_gui_window_launch_url(struct gui_window *g, const char *url); -static void ro_gui_window_clone_options(struct browser_window *new_bw, - struct browser_window *old_bw); -static bool ro_gui_window_import_text(struct gui_window *g, - const char *filename, bool toolbar); - struct update_box { int x0; int y0; @@ -170,6 +233,129 @@ struct update_box { struct update_box *pending_updates; #define MARGIN 4 +static const struct toolbar_callbacks ro_gui_window_toolbar_callbacks = { + ro_gui_window_update_theme, + ro_gui_window_update_toolbar, + (void (*)(void *)) ro_gui_window_update_toolbar_buttons, + ro_gui_window_toolbar_click, + ro_gui_window_toolbar_keypress, + ro_gui_window_save_toolbar_buttons +}; + + +/** + * Initialise the browser window module and its menus. + */ + +void ro_gui_window_initialise(void) +{ + /* Build the browser window 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} + } + }; + ro_gui_browser_window_menu = + ro_gui_menu_define_menu(&browser_definition); + +} + + +/* + * Interface With Core + */ /** * Create and open a new browser window. @@ -203,8 +389,6 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw, g->old_height = 0; g->update_extent = true; strcpy(g->title, "NetSurf"); - g->throbber = 0; - g->throbtime = 0; g->iconise_icon = -1; /* Set the window position */ @@ -365,27 +549,47 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw, /* Add in a toolbar and status bar */ if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) { g->status_bar = ro_gui_status_bar_create(g->window, option_toolbar_status_width); - g->toolbar = ro_gui_theme_create_toolbar(NULL, THEME_BROWSER_TOOLBAR); - ro_gui_theme_attach_toolbar(g->toolbar, g->window); + g->toolbar = ro_toolbar_create(NULL, g->window, + THEME_STYLE_BROWSER_TOOLBAR, TOOLBAR_FLAGS_NONE, + &ro_gui_window_toolbar_callbacks, g, + "HelpToolbar"); + if (g->toolbar != NULL) { + ro_toolbar_add_buttons(g->toolbar, + brower_toolbar_buttons, + option_toolbar_browser); + ro_toolbar_add_url(g->toolbar); + ro_toolbar_add_throbber(g->toolbar); + ro_toolbar_rebuild(g->toolbar); + } } else { g->toolbar = NULL; } - /* Set the window options */ - bw->window = g; - ro_gui_window_clone_options(bw, clone); - ro_gui_prepare_navigate(g); - - /* Register event handlers */ + /* Register event handlers. Do this quickly, as some of the things + * that follow will indirectly look up our user data: this MUST + * be set first! + */ ro_gui_wimp_event_set_user_data(g->window, g); ro_gui_wimp_event_register_open_window(g->window, ro_gui_window_open); ro_gui_wimp_event_register_close_window(g->window, ro_gui_window_close); ro_gui_wimp_event_register_redraw_window(g->window, ro_gui_window_redraw); ro_gui_wimp_event_register_keypress(g->window, ro_gui_window_keypress); - if (g->toolbar) - ro_gui_wimp_event_register_keypress(g->toolbar->toolbar_handle, - ro_gui_window_keypress); ro_gui_wimp_event_register_mouse_click(g->window, ro_gui_window_click); + ro_gui_wimp_event_register_menu(g->window, ro_gui_browser_window_menu, + true, false); + ro_gui_wimp_event_register_menu_prepare(g->window, + ro_gui_window_menu_prepare); + ro_gui_wimp_event_register_menu_selection(g->window, + ro_gui_window_menu_select); + ro_gui_wimp_event_register_menu_warning(g->window, + ro_gui_window_menu_warning); + ro_gui_wimp_event_register_menu_close(g->window, + ro_gui_window_menu_close); + + /* Set the window options */ + bw->window = g; + ro_gui_window_clone_options(bw, clone); + ro_gui_window_update_toolbar_buttons(g); /* Open the window at the top of the stack */ state.w = g->window; @@ -417,17 +621,9 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw, /* Claim the caret for top-level windows */ if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) { - if (g->toolbar && g->toolbar->display_url) { - error = xwimp_set_caret_position( - g->toolbar->toolbar_handle, - ICON_TOOLBAR_URL, -1, -1, -1, 0); - ro_gui_url_complete_start(g); - if (error) { - LOG(("xwimp_set_caret_position: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - } - } else + if (ro_toolbar_take_caret(g->toolbar)) + ro_gui_url_complete_start(g->toolbar); + else gui_window_place_caret(g, -100, -100, 0); } return g; @@ -463,15 +659,15 @@ void gui_window_destroy(struct gui_window *g) /* destroy toolbar */ if (g->toolbar) - ro_gui_theme_destroy_toolbar(g->toolbar); + ro_toolbar_destroy(g->toolbar); if (g->status_bar) ro_gui_status_bar_destroy(g->status_bar); w = g->window; - ro_gui_url_complete_close(NULL, 0); + ro_gui_url_complete_close(); ro_gui_dialog_close_persistent(w); if (current_menu_window == w) - ro_gui_menu_closed(true); + ro_gui_menu_closed(); ro_gui_window_remove_update_boxes(g); /* delete window */ @@ -659,7 +855,7 @@ bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) } if (g->toolbar) - toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar); + toolbar_height = ro_toolbar_full_height(g->toolbar); *sx = state.xscroll / (2 * g->bw->scale); *sy = -(state.yscroll - toolbar_height) / (2 * g->bw->scale); return true; @@ -693,7 +889,7 @@ void gui_window_set_scroll(struct gui_window *g, int sx, int sy) state.xscroll = sx * 2 * g->bw->scale; state.yscroll = -sy * 2 * g->bw->scale; if (g->toolbar) - state.yscroll += ro_gui_theme_toolbar_full_height(g->toolbar); + state.yscroll += ro_toolbar_full_height(g->toolbar); ro_gui_window_open(PTR_WIMP_OPEN(&state)); } @@ -728,7 +924,7 @@ void gui_window_scroll_visible(struct gui_window *g, int x0, int y0, int x1, int } if (g->toolbar) - toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar); + toolbar_height = ro_toolbar_full_height(g->toolbar); x0 = x0 * 2 * g->bw->scale; y0 = y0 * 2 * g->bw->scale; @@ -898,25 +1094,27 @@ void gui_window_get_dimensions(struct gui_window *g, int *width, int *height, bo /** - * Update the extent of the inside of a browser window to that of the current content. + * Update the extent of the inside of a browser window to that of the + * current content. * - * \param g gui_window to update the extent of + * \param g gui_window to update the extent of */ void gui_window_update_extent(struct gui_window *g) { - os_error *error; - wimp_window_state state; - bool update; - unsigned int flags; - int scroll = 0; + os_error *error; + wimp_window_info info; + wimp_window_state state; + bool update; + unsigned int flags; + int scroll = 0; assert(g); - state.w = g->window; - error = xwimp_get_window_state(&state); + info.w = g->window; + error = xwimp_get_window_info_header_only(&info); if (error) { - LOG(("xwimp_get_window_state: 0x%x: %s", + LOG(("xwimp_get_window_info_header_only: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); return; @@ -924,15 +1122,15 @@ void gui_window_update_extent(struct gui_window *g) /* scroll on toolbar height change */ if (g->toolbar) { - scroll = ro_gui_theme_height_change(g->toolbar); - state.yscroll -= scroll; + scroll = ro_toolbar_height(g->toolbar) - info.extent.y1; + info.yscroll += scroll; } /* only allow a further reformat if we've gained/lost scrollbars */ - flags = state.flags & (wimp_WINDOW_HSCROLL | wimp_WINDOW_VSCROLL); + flags = info.flags & (wimp_WINDOW_HSCROLL | wimp_WINDOW_VSCROLL); update = g->bw->reformat_pending; g->update_extent = true; - ro_gui_window_open(PTR_WIMP_OPEN(&state)); + ro_gui_window_open(PTR_WIMP_OPEN(&info)); state.w = g->window; error = xwimp_get_window_state(&state); @@ -1033,41 +1231,11 @@ void gui_window_hide_pointer(struct gui_window *g) void gui_window_set_url(struct gui_window *g, const char *url) { - wimp_caret caret; - os_error *error; - const char *toolbar_url; - if (!g->toolbar) return; - ro_gui_set_icon_string(g->toolbar->toolbar_handle, - ICON_TOOLBAR_URL, url, true); - ro_gui_force_redraw_icon(g->toolbar->toolbar_handle, - ICON_TOOLBAR_FAVICON); - - /* if the caret is in the address bar, move it to the end */ - error = xwimp_get_caret_position(&caret); - if (error) { - LOG(("xwimp_get_caret_position: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - return; - } - - if (!(caret.w == g->toolbar->toolbar_handle && - caret.i == ICON_TOOLBAR_URL)) - return; - - toolbar_url = ro_gui_get_icon_string(g->toolbar->toolbar_handle, - ICON_TOOLBAR_URL); - error = xwimp_set_caret_position(g->toolbar->toolbar_handle, - ICON_TOOLBAR_URL, 0, 0, -1, (int)strlen(toolbar_url)); - if (error) { - LOG(("xwimp_set_caret_position: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - } - ro_gui_url_complete_start(g); + ro_toolbar_set_url(g->toolbar, url, true, false); + ro_gui_url_complete_start(g->toolbar); } @@ -1079,10 +1247,10 @@ void gui_window_set_url(struct gui_window *g, const char *url) void gui_window_start_throbber(struct gui_window *g) { - ro_gui_menu_objects_moved(); - ro_gui_prepare_navigate(g); - xos_read_monotonic_time(&g->throbtime); - g->throbber = 0; + ro_gui_window_update_toolbar_buttons(g); + ro_gui_menu_refresh(ro_gui_browser_window_menu); + if (g->toolbar != NULL) + ro_toolbar_start_throbbing(g->toolbar); } @@ -1095,24 +1263,22 @@ void gui_window_start_throbber(struct gui_window *g) void gui_window_stop_throbber(struct gui_window *g) { - char throb_buf[12]; - ro_gui_prepare_navigate(g); - g->throbber = 0; - if (g->toolbar) { - strcpy(throb_buf, "throbber0"); - ro_gui_set_icon_string(g->toolbar->toolbar_handle, - ICON_TOOLBAR_THROBBER, throb_buf, true); - if ((g->toolbar->descriptor) && (g->toolbar->descriptor->throbber_redraw)) - ro_gui_force_redraw_icon(g->toolbar->toolbar_handle, - ICON_TOOLBAR_THROBBER); - } + ro_gui_window_update_toolbar_buttons(g); + ro_gui_menu_refresh(ro_gui_browser_window_menu); + if (g->toolbar != NULL) + ro_toolbar_stop_throbbing(g->toolbar); } /** * set favicon */ + void gui_window_set_icon(struct gui_window *g, hlcache_handle *icon) { + if (g == NULL || g->toolbar == NULL) + return; + + ro_toolbar_set_site_favicon(g->toolbar, icon); } /** @@ -1185,9 +1351,10 @@ void gui_window_remove_caret(struct gui_window *g) void gui_window_new_content(struct gui_window *g) { - ro_gui_menu_objects_moved(); - ro_gui_prepare_navigate(g); + ro_gui_menu_refresh(ro_gui_browser_window_menu); + ro_gui_window_update_toolbar_buttons(g); ro_gui_dialog_close_persistent(g->window); + ro_toolbar_set_content_favicon(g->toolbar, g->bw->current_content); } @@ -1233,7 +1400,7 @@ bool gui_window_scroll_start(struct gui_window *g) drag.bbox.y1 = drag.bbox.y0 + (height - (info.visible.y1 - info.visible.y0)); if (g->toolbar) { - int tbar_height = ro_gui_theme_toolbar_full_height(g->toolbar); + int tbar_height = ro_toolbar_full_height(g->toolbar); drag.bbox.y0 -= tbar_height; drag.bbox.y1 -= tbar_height; } @@ -1339,7 +1506,7 @@ bool gui_window_frame_resize_start(struct gui_window *g) /* convert to screen co-ordinates */ top = browser_window_owner(bw); if (top->window->toolbar) - toolbar_height = ro_gui_theme_toolbar_full_height(top->window->toolbar); + toolbar_height = ro_toolbar_full_height(top->window->toolbar); state.w = top->window->window; error = xwimp_get_window_state(&state); if (error) { @@ -1422,16 +1589,111 @@ void gui_window_set_scale(struct gui_window *g, float scale) /** - * Redraws the content for all windows. + * Updates a windows extent. + * + * \param g the gui_window to update + * \param width the minimum width, or -1 to use window width + * \param height the minimum height, or -1 to use window height */ -void ro_gui_window_redraw_all(void) +void gui_window_set_extent(struct gui_window *g, int width, int height) { - struct gui_window *g; - for (g = window_list; g; g = g->next) - gui_window_redraw_window(g); + int screen_width; + int toolbar_height = 0; + hlcache_handle *h; + wimp_window_state state; + os_error *error; + + h = g->bw->current_content; + if (g->toolbar) + toolbar_height = ro_toolbar_full_height(g->toolbar); + + /* get the current state */ + if ((height == -1) || (width == -1)) { + state.w = g->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); + return; + } + if (width == -1) + width = state.visible.x1 - state.visible.x0; + if (height == -1) { + height = state.visible.y1 - state.visible.y0; + height -= toolbar_height; + } + } + + /* the top-level framed window is a total pain. to get it to maximise + * to the top of the screen we need to fake it having a suitably large + * extent */ + if (g->bw->children && + (g->bw->browser_window_type == BROWSER_WINDOW_NORMAL)) { + ro_gui_screen_size(&screen_width, &height); + if (g->toolbar) + height -= ro_toolbar_full_height(g->toolbar); + height -= ro_get_hscroll_height(g->window); + height -= ro_get_title_height(g->window); + } + if (h) { + width = max(width, content_get_width(h) * 2 * g->bw->scale); + height = max(height, content_get_height(h) * 2 * g->bw->scale); + } + os_box extent = { 0, -height, width, toolbar_height }; + error = xwimp_set_extent(g->window, &extent); + if (error) { + LOG(("xwimp_set_extent: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } +} + + +/** + * 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) +{ + os_error *error; + wimp_pointer pointer; + + /* The first time the menu is opened, control bypasses the normal + * Menu Prepare event and so we prepare here. On any re-opens, + * ro_gui_window_prepare_form_select_menu() is called from the + * normal wimp event. + */ + + if (!ro_gui_window_prepare_form_select_menu(bw, control)) + return; + + 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(); + return; + } + + gui_form_select_control = control; + ro_gui_menu_create(gui_form_select_menu, + pointer.pos.x, pointer.pos.y, bw->window->window); } + +/* + * RISC OS Wimp Event Handlers + */ + + /** * Handle a Redraw_Window_Request for a browser window. */ @@ -1512,218 +1774,6 @@ void ro_gui_window_redraw(wimp_draw *redraw) } - -/** - * Remove all pending update boxes for a window - * - * \param g gui_window - */ -void ro_gui_window_remove_update_boxes(struct gui_window *g) { - struct update_box *cur; - - for (cur = pending_updates; cur != NULL; cur = cur->next) { - if (cur->g == g) - cur->g = NULL; - } -} - - -/** - * Redraw any pending update boxes. - */ -void ro_gui_window_update_boxes(void) { - osbool more; - bool use_buffer; - wimp_draw update; - struct rect clip; - os_error *error; - struct update_box *cur; - struct gui_window *g; - const union content_msg_data *data; - - for (cur = pending_updates; cur != NULL; cur = cur->next) { - g = cur->g; - if (!g) - continue; - - data = &cur->data; - use_buffer = cur->use_buffer; - - update.w = g->window; - update.box.x0 = cur->x0; - update.box.y0 = cur->y0; - update.box.x1 = cur->x1; - update.box.y1 = cur->y1; - - error = xwimp_update_window(&update, &more); - if (error) { - LOG(("xwimp_update_window: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - continue; - } - - /* Set the current redraw gui_window to get options from */ - ro_gui_current_redraw_gui = g; - current_redraw_browser = g->bw; - - plot = ro_plotters; - ro_plot_origin_x = update.box.x0 - update.xscroll; - ro_plot_origin_y = update.box.y1 - update.yscroll; - ro_plot_set_scale(g->bw->scale); - - while (more) { - clip.x0 = (update.clip.x0 - ro_plot_origin_x) / 2; - clip.y0 = (ro_plot_origin_y - update.clip.y1) / 2; - clip.x1 = (update.clip.x1 - ro_plot_origin_x) / 2; - clip.y1 = (ro_plot_origin_y - update.clip.y0) / 2; - - if (use_buffer) - ro_gui_buffer_open(&update); - - browser_window_redraw(g->bw, 0, 0, &clip); - - if (use_buffer) - ro_gui_buffer_close(); - - error = xwimp_get_rectangle(&update, &more); - /* RISC OS 3.7 returns an error here if enough buffer - * was claimed to cause a new dynamic area to be - * created. It doesn't actually stop anything working, - * so we mask it out for now until a better fix is - * found. This appears to be a bug in RISC OS. */ - if (error && !(use_buffer && - error->errnum == error_WIMP_GET_RECT)) { - LOG(("xwimp_get_rectangle: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - ro_gui_current_redraw_gui = NULL; - current_redraw_browser = NULL; - continue; - } - } - - /* Reset the current redraw gui_window to prevent - * thumbnails from retaining options */ - ro_gui_current_redraw_gui = NULL; - current_redraw_browser = NULL; - } - while (pending_updates) { - cur = pending_updates; - pending_updates = pending_updates->next; - free(cur); - } - -} - - -/** - * Launch a new url in the given window. - * - * \param g gui_window to update - * \param url url to be launched - */ - -void ro_gui_window_launch_url(struct gui_window *g, const char *url) -{ - url_func_result res; - char *url_norm; - - ro_gui_url_complete_close(NULL, 0); - res = url_normalize(url, &url_norm); - if (res == URL_FUNC_OK) { - gui_window_set_url(g, url_norm); - browser_window_go(g->bw, url_norm, 0, true); - free(url_norm); - } -} - - -/** - * Forces all windows to be set to the current theme - */ -void ro_gui_window_update_theme(void) { - struct gui_window *g; - for (g = window_list; g; g = g->next) { - if (g->toolbar) { - if (g->toolbar->editor) - if (!ro_gui_theme_update_toolbar(NULL, g->toolbar->editor)) - g->toolbar->editor = NULL; - if (!ro_gui_theme_update_toolbar(NULL, g->toolbar)) { - ro_gui_theme_destroy_toolbar(g->toolbar); - g->toolbar = NULL; - } - ro_gui_theme_toolbar_editor_sync(g->toolbar); - gui_window_update_extent(g); - } - } -} - - -/** - * Updates a windows extent. - * - * \param g the gui_window to update - * \param width the minimum width, or -1 to use window width - * \param height the minimum height, or -1 to use window height - */ - -void gui_window_set_extent(struct gui_window *g, int width, int height) -{ - int screen_width; - int toolbar_height = 0; - hlcache_handle *h; - wimp_window_state state; - os_error *error; - - h = g->bw->current_content; - if (g->toolbar) - toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar); - - /* get the current state */ - if ((height == -1) || (width == -1)) { - state.w = g->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); - return; - } - if (width == -1) - width = state.visible.x1 - state.visible.x0; - if (height == -1) { - height = state.visible.y1 - state.visible.y0; - height -= toolbar_height; - } - } - - /* the top-level framed window is a total pain. to get it to maximise - * to the top of the screen we need to fake it having a suitably large - * extent */ - if (g->bw->children && - (g->bw->browser_window_type == BROWSER_WINDOW_NORMAL)) { - ro_gui_screen_size(&screen_width, &height); - if (g->toolbar) - height -= ro_gui_theme_toolbar_full_height(g->toolbar); - height -= ro_get_hscroll_height(g->window); - height -= ro_get_title_height(g->window); - } - if (h) { - width = max(width, content_get_width(h) * 2 * g->bw->scale); - height = max(height, content_get_height(h) * 2 * g->bw->scale); - } - os_box extent = { 0, -height, width, toolbar_height }; - error = xwimp_set_extent(g->window, &extent); - if (error) { - LOG(("xwimp_set_extent: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - return; - } -} - - /** * Open a window using the given wimp_open, handling toolbars and resizing. */ @@ -1762,7 +1812,7 @@ void ro_gui_window_open(wimp_open *open) /* account for toolbar height, if present */ if (g->toolbar) - toolbar_height = ro_gui_theme_toolbar_full_height(g->toolbar); + toolbar_height = ro_toolbar_full_height(g->toolbar); height -= toolbar_height; /* work with the state from now on so we can modify flags */ @@ -1871,7 +1921,7 @@ void ro_gui_window_open(wimp_open *open) } /* first resize stops any flickering by making the URL window on top */ - ro_gui_url_complete_resize(g, PTR_WIMP_OPEN(&state)); + ro_gui_url_complete_resize(g->toolbar, PTR_WIMP_OPEN(&state)); error = xwimp_open_window_nested_with_flags(&state, parent, linkage); if (error) { @@ -1885,9 +1935,9 @@ void ro_gui_window_open(wimp_open *open) if (g->status_bar) ro_gui_status_bar_resize(g->status_bar); if (g->toolbar) { - ro_gui_theme_process_toolbar(g->toolbar, -1); + ro_toolbar_process(g->toolbar, -1, false); /* second resize updates to the new URL bar width */ - ro_gui_url_complete_resize(g, open); + ro_gui_url_complete_resize(g->toolbar, open); } /* set the new scale from a ctrl-resize. this must be done at the end as @@ -1901,7 +1951,9 @@ void ro_gui_window_open(wimp_open *open) /** * Handle wimp closing event */ -void ro_gui_window_close(wimp_w w) { + +void ro_gui_window_close(wimp_w w) +{ struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(w); wimp_pointer pointer; os_error *error; @@ -1950,9 +2002,11 @@ void ro_gui_window_close(wimp_w w) { } else { /* this is pointless if we are about to close the * window */ - if (!destroy) - ro_gui_menu_handle_action(w, - BROWSER_NAVIGATE_UP, true); + if (!destroy && g->bw != NULL && + g->bw->current_content != NULL) + ro_gui_window_navigate_up(g->bw->window, + content_get_url( + g->bw->current_content)); } } else @@ -1964,606 +2018,347 @@ void ro_gui_window_close(wimp_w w) { /** - * Destroy all browser windows. - */ - -void ro_gui_window_quit(void) -{ - struct gui_window *cur; - - while (window_list) { - cur = window_list; - window_list = window_list->next; - - /* framesets and iframes are destroyed by their parents */ - if (!cur->bw->parent) - browser_window_destroy(cur->bw); - } -} - - -/** - * Animate the "throbbers" of all browser windows. - */ - -void ro_gui_throb(void) -{ - os_t t; - struct gui_window *g, *top_g; - struct browser_window *top; - char throb_buf[12]; - - xos_read_monotonic_time(&t); - - for (g = window_list; g; g = g->next) { - if (!g->bw->throbbing) - continue; - for (top = g->bw; top->parent; top = top->parent); - top_g = top->window; - if (!top_g->toolbar || !top_g->toolbar->display_throbber || - !top_g->toolbar->descriptor || - !top_g->toolbar->descriptor->theme || - (t < top_g->throbtime + 10)) - continue; - top_g->throbtime = t; - top_g->throbber++; - if (top_g->toolbar->descriptor->theme->throbber_frames < top_g->throbber) - top_g->throbber = 1; - sprintf(throb_buf, "throbber%i", top_g->throbber); - ro_gui_set_icon_string(top_g->toolbar->toolbar_handle, - ICON_TOOLBAR_THROBBER, throb_buf, true); - if (top_g->toolbar->descriptor->throbber_redraw) - ro_gui_force_redraw_icon(top_g->toolbar->toolbar_handle, - ICON_TOOLBAR_THROBBER); - } -} - - -/** - * Convert a RISC OS window handle to a gui_window. + * Handle Mouse_Click events in a browser window. This should never see + * Menu clicks, as these will be routed to the menu handlers. * - * \param w RISC OS window handle - * \return pointer to a structure if found, 0 otherwise + * \param *pointer details of mouse click + * \return true if click handled, false otherwise */ -struct gui_window *ro_gui_window_lookup(wimp_w window) +bool ro_gui_window_click(wimp_pointer *pointer) { struct gui_window *g; - for (g = window_list; g; g = g->next) - if (g->window == window) - return g; - return 0; -} + os_coord pos; + /* We should never see Menu clicks. */ -/** - * Convert a toolbar RISC OS window handle to a gui_window. - * - * \param w RISC OS window handle of a toolbar - * \return pointer to a structure if found, 0 otherwise - */ - -struct gui_window *ro_gui_toolbar_lookup(wimp_w window) -{ - struct gui_window *g; - for (g = window_list; g; g = g->next) { - if ((g->toolbar) && ((g->toolbar->toolbar_handle == window) || - ((g->toolbar->editor) && - (g->toolbar->editor->toolbar_handle == window)))) - return g; - } - return 0; -} + if (pointer->buttons == wimp_CLICK_MENU) + return false; + g = (struct gui_window *) ro_gui_wimp_event_get_user_data(pointer->w); -/** - * Handle pointer movements in a browser window. - * - * \param g browser window that the pointer is in - * \param pointer new mouse position - */ + /* try to close url-completion */ + ro_gui_url_complete_close(); -void ro_gui_window_mouse_at(struct gui_window *g, wimp_pointer *pointer) -{ - os_coord pos; + /* set input focus */ + if (pointer->buttons == wimp_CLICK_SELECT || + pointer->buttons == wimp_CLICK_ADJUST) + gui_window_place_caret(g, -100, -100, 0); if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos)) - browser_window_mouse_track(g->bw, - ro_gui_mouse_drag_state(pointer->buttons, - wimp_BUTTON_CLICK_DRAG), + browser_window_mouse_click(g->bw, + ro_gui_mouse_click_state(pointer->buttons, + wimp_BUTTON_CLICK_DRAG), pos.x, pos.y); + + return true; } /** - * Process Mouse_Click events in a toolbar. + * Process Key_Pressed events in a browser window. */ -bool ro_gui_toolbar_click(wimp_pointer *pointer) +bool ro_gui_window_keypress(wimp_key *key) { - struct gui_window *g = ro_gui_toolbar_lookup(pointer->w); - struct browser_window *new_bw; - - /* toolbars in the options window have no gui_window */ - if (!g) - return true; - - /* try to close url-completion */ - ro_gui_url_complete_close(g, pointer->i); + struct gui_window *g; + hlcache_handle *h; + os_error *error; + wimp_pointer pointer; + uint32_t c = (uint32_t) key->c; + + g = (struct gui_window *) ro_gui_wimp_event_get_user_data(key->w); + if (g == NULL) + return false; - /* Handle Menu clicks */ - if (pointer->buttons == wimp_CLICK_MENU) { - ro_gui_menu_create(browser_toolbar_menu, pointer->pos.x, - pointer->pos.y, g->window, true); - return true; - } + h = g->bw->current_content; - /* Handle toolbar edits */ - if ((g->toolbar->editor) && (pointer->i < ICON_TOOLBAR_URL)) { - ro_gui_theme_toolbar_editor_click(g->toolbar, pointer); - return true; + error = xwimp_get_pointer_info(&pointer); + if (error) { + LOG(("xwimp_get_pointer_info: 0x%x: %s\n", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return false; } - /* Handle the buttons appropriately */ - switch (pointer->i) { - case ICON_TOOLBAR_BACK: - if (pointer->buttons == wimp_CLICK_ADJUST) { - new_bw = browser_window_create(NULL, - g->bw, NULL, false, false); - ro_gui_menu_handle_action( - new_bw->window->window, - BROWSER_NAVIGATE_BACK, true); - } else { - ro_gui_menu_handle_action(g->window, - BROWSER_NAVIGATE_BACK, true); - } - break; - - case ICON_TOOLBAR_FORWARD: - if (pointer->buttons == wimp_CLICK_ADJUST) { - new_bw = browser_window_create(NULL, - g->bw, NULL, false, false); - ro_gui_menu_handle_action( - new_bw->window->window, - BROWSER_NAVIGATE_FORWARD, true); - } else { - ro_gui_menu_handle_action(g->window, - BROWSER_NAVIGATE_FORWARD, true); - } - break; + /* First send the key to the browser window, eg. form fields. */ - case ICON_TOOLBAR_STOP: - ro_gui_menu_handle_action(g->window, - BROWSER_NAVIGATE_STOP, true); - break; + if ((unsigned)c < 0x20 || (0x7f <= c && c <= 0x9f) || + (c & IS_WIMP_KEY)) { + /* Munge control keys into unused control chars */ + /* We can't map onto 1->26 (reserved for ctrl+<qwerty> + That leaves 27->31 and 128->159 */ + switch (c & ~IS_WIMP_KEY) { + case wimp_KEY_TAB: c = 9; break; + case wimp_KEY_SHIFT | wimp_KEY_TAB: c = 11; break; - case ICON_TOOLBAR_RELOAD: - if (pointer->buttons == wimp_CLICK_SELECT) - ro_gui_menu_handle_action(g->window, - BROWSER_NAVIGATE_RELOAD, true); - else if (pointer->buttons == wimp_CLICK_ADJUST) - ro_gui_menu_handle_action(g->window, - BROWSER_NAVIGATE_RELOAD_ALL, - true); + /* cursor movement keys */ + case wimp_KEY_HOME: + case wimp_KEY_CONTROL | wimp_KEY_LEFT: + c = KEY_LINE_START; break; - - case ICON_TOOLBAR_HISTORY: - if (pointer->buttons == wimp_CLICK_SELECT) - ro_gui_menu_handle_action(g->window, - HISTORY_SHOW_LOCAL, true); + case wimp_KEY_END: + if (os_version >= RISCOS5) + c = KEY_LINE_END; else - ro_gui_menu_handle_action(g->window, - HISTORY_SHOW_GLOBAL, true); + c = KEY_DELETE_RIGHT; break; - case ICON_TOOLBAR_HOME: - ro_gui_menu_handle_action(g->window, - BROWSER_NAVIGATE_HOME, true); + case wimp_KEY_CONTROL | wimp_KEY_RIGHT: c = KEY_LINE_END; break; + case wimp_KEY_CONTROL | wimp_KEY_UP: c = KEY_TEXT_START; break; + case wimp_KEY_CONTROL | wimp_KEY_DOWN: c = KEY_TEXT_END; break; + case wimp_KEY_SHIFT | wimp_KEY_LEFT: c = KEY_WORD_LEFT ; break; + case wimp_KEY_SHIFT | wimp_KEY_RIGHT: c = KEY_WORD_RIGHT; break; + case wimp_KEY_SHIFT | wimp_KEY_UP: c = KEY_PAGE_UP; break; + case wimp_KEY_SHIFT | wimp_KEY_DOWN: c = KEY_PAGE_DOWN; break; + case wimp_KEY_LEFT: c = KEY_LEFT; break; + case wimp_KEY_RIGHT: c = KEY_RIGHT; break; + case wimp_KEY_UP: c = KEY_UP; break; + case wimp_KEY_DOWN: c = KEY_DOWN; break; + + /* editing */ + case wimp_KEY_CONTROL | wimp_KEY_END: + c = KEY_DELETE_LINE_END; break; - case ICON_TOOLBAR_SEARCH: - ro_gui_menu_handle_action(g->window, - BROWSER_FIND_TEXT, true); - break; - case ICON_TOOLBAR_SCALE: - ro_gui_menu_handle_action(g->window, - BROWSER_SCALE_VIEW, true); + case wimp_KEY_DELETE: + if (ro_gui_ctrl_pressed()) + c = KEY_DELETE_LINE_START; + else if (os_version < RISCOS5) + c = KEY_DELETE_LEFT; break; - case ICON_TOOLBAR_BOOKMARK: - if (pointer->buttons == wimp_CLICK_ADJUST) - ro_gui_menu_handle_action(g->window, - HOTLIST_ADD_URL, true); - else - ro_gui_menu_handle_action(g->window, - HOTLIST_SHOW, true); + default: break; + } + } - case ICON_TOOLBAR_SAVE: - if (pointer->buttons == wimp_CLICK_ADJUST) - ro_gui_menu_handle_action(g->window, - BROWSER_SAVE_COMPLETE, true); - else - ro_gui_menu_handle_action(g->window, - BROWSER_SAVE, true); - break; - case ICON_TOOLBAR_PRINT: - ro_gui_menu_handle_action(g->window, - BROWSER_PRINT, true); - break; - case ICON_TOOLBAR_UP: - if (pointer->buttons == wimp_CLICK_ADJUST) { - if (g->bw && g->bw->current_content) { - hlcache_handle *h = - g->bw->current_content; - new_bw = browser_window_create(NULL, - g->bw, NULL, false, - false); - /* do it without loading the content - * into the new window */ - ro_gui_window_navigate_up( - new_bw->window, - content_get_url(h)); - } - } else { - ro_gui_menu_handle_action(g->window, - BROWSER_NAVIGATE_UP, true); - } - break; - case ICON_TOOLBAR_URL: - if (pointer->buttons & - (wimp_DRAG_SELECT | wimp_DRAG_ADJUST)) { - if (g->bw->current_content) { - hlcache_handle *h = - g->bw->current_content; - gui_save_type save_type; - - if (ro_gui_shift_pressed()) - save_type = GUI_SAVE_LINK_URL; - else - save_type = GUI_SAVE_LINK_TEXT; - - ro_gui_drag_save_link(save_type, - content_get_url(h), - content_get_title(h), - g); - } - } - else - ro_gui_url_complete_start(g); - break; - case ICON_TOOLBAR_SUGGEST: - ro_gui_popup_menu(url_suggest_menu, - g->toolbar->toolbar_handle, - ICON_TOOLBAR_SUGGEST); - break; + if (!(c & IS_WIMP_KEY)) { + if (browser_window_key_press(g->bw, c)) + return true; } + + ro_gui_window_handle_local_keypress(g, key, false); + return true; } /** - * Handle Mouse_Click events in a browser window. + * Callback handler for keypresses within browser window toolbars. * - * \param pointer details of mouse click - * \return true if click handled, false otherwise + * \param *data Client data, pointing to the GUI Window. + * \param *key The keypress data. */ -bool ro_gui_window_click(wimp_pointer *pointer) +void ro_gui_window_toolbar_keypress(void *data, wimp_key *key) { - struct gui_window *g; - os_coord pos; - - g = (struct gui_window *)ro_gui_wimp_event_get_user_data(pointer->w); - - /* try to close url-completion */ - ro_gui_url_complete_close(g, pointer->i); + struct gui_window *g = (struct gui_window *) data; - /* set input focus */ - if (pointer->buttons == wimp_CLICK_SELECT || - pointer->buttons == wimp_CLICK_ADJUST) - gui_window_place_caret(g, -100, -100, 0); - - if (pointer->buttons == wimp_CLICK_MENU) { - ro_gui_menu_create(browser_menu, pointer->pos.x, pointer->pos.y, pointer->w, true); - } else { - if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos)) - browser_window_mouse_click(g->bw, - ro_gui_mouse_click_state(pointer->buttons, - wimp_BUTTON_CLICK_DRAG), - pos.x, pos.y); - } - return true; + if (g != NULL) + ro_gui_window_handle_local_keypress(g, key, true); } /** - * Process Key_Pressed events in a browser window. + * Handle keypresses within the RISC OS GUI: this is to be called after the + * core has been given a chance to act, or on keypresses in the toolbar where + * the core doesn't get involved. + * + * \param *g The gui window to which the keypress applies. + * \param *key The keypress data. + * \param is_toolbar true if the keypress is from a toolbar; + * else false. */ -bool ro_gui_window_keypress(wimp_key *key) +void ro_gui_window_handle_local_keypress(struct gui_window *g, wimp_key *key, + bool is_toolbar) { - struct gui_window *g; - bool toolbar; - hlcache_handle *h; - wimp_window_state state; - int y; - const char *toolbar_url; - os_error *error; - wimp_pointer pointer; - float scale; - uint32_t c = (uint32_t) key->c; - - /* Find gui window */ - if ((g = ro_gui_window_lookup(key->w)) != NULL) { - toolbar = false; - } else if ((g = ro_gui_toolbar_lookup(key->w)) != NULL) { - toolbar = true; - } else { - /* nothing to do with us */ - return false; - } + hlcache_handle *h; + wimp_window_state state; + int y; + const char *toolbar_url; + os_error *error; + float scale; + uint32_t c = (uint32_t) key->c; + + if (g == NULL) + return; h = g->bw->current_content; - error = xwimp_get_pointer_info(&pointer); - if (error) { - LOG(("xwimp_get_pointer_info: 0x%x: %s\n", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - return false; - } + switch (c) { + case IS_WIMP_KEY + wimp_KEY_F1: /* Help. */ + ro_gui_open_help_page("documentation/index"); + return; - /* First send the key to the browser window, eg. form fields. */ - if (!toolbar) { - if ((unsigned)c < 0x20 || (0x7f <= c && c <= 0x9f) || - (c & IS_WIMP_KEY)) { - /* Munge control keys into unused control chars */ - /* We can't map onto 1->26 (reserved for ctrl+<qwerty> - That leaves 27->31 and 128->159 */ - switch (c & ~IS_WIMP_KEY) { - case wimp_KEY_TAB: c = 9; break; - case wimp_KEY_SHIFT | wimp_KEY_TAB: c = 11; break; - - /* cursor movement keys */ - case wimp_KEY_HOME: - case wimp_KEY_CONTROL | wimp_KEY_LEFT: - c = KEY_LINE_START; - break; - case wimp_KEY_END: - if (os_version >= RISCOS5) - c = KEY_LINE_END; - else - c = KEY_DELETE_RIGHT; - break; - case wimp_KEY_CONTROL | wimp_KEY_RIGHT: c = KEY_LINE_END; break; - case wimp_KEY_CONTROL | wimp_KEY_UP: c = KEY_TEXT_START; break; - case wimp_KEY_CONTROL | wimp_KEY_DOWN: c = KEY_TEXT_END; break; - case wimp_KEY_SHIFT | wimp_KEY_LEFT: c = KEY_WORD_LEFT ; break; - case wimp_KEY_SHIFT | wimp_KEY_RIGHT: c = KEY_WORD_RIGHT; break; - case wimp_KEY_SHIFT | wimp_KEY_UP: c = KEY_PAGE_UP; break; - case wimp_KEY_SHIFT | wimp_KEY_DOWN: c = KEY_PAGE_DOWN; break; - case wimp_KEY_LEFT: c = KEY_LEFT; break; - case wimp_KEY_RIGHT: c = KEY_RIGHT; break; - case wimp_KEY_UP: c = KEY_UP; break; - case wimp_KEY_DOWN: c = KEY_DOWN; break; - - /* editing */ - case wimp_KEY_CONTROL | wimp_KEY_END: - c = KEY_DELETE_LINE_END; - break; - case wimp_KEY_DELETE: - if (ro_gui_ctrl_pressed()) - c = KEY_DELETE_LINE_START; - else if (os_version < RISCOS5) - c = KEY_DELETE_LEFT; - break; + case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F1: + ro_gui_window_action_page_info(g); + return; - default: - break; - } - } + case IS_WIMP_KEY + wimp_KEY_F2: + if (g->toolbar == NULL) + return; + ro_gui_url_complete_close(); + ro_toolbar_set_url(g->toolbar, "www.", true, true); + ro_gui_url_complete_start(g->toolbar); + ro_gui_url_complete_keypress(g->toolbar, wimp_KEY_DOWN); + return; - if (!(c & IS_WIMP_KEY)) { - if (browser_window_key_press(g->bw, c)) - return true; - } + case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F2: + /* Close window. */ + ro_gui_url_complete_close(); + browser_window_destroy(g->bw); + return; - /* Reset c to incoming character / key code - * as we may have corrupted it above */ - c = (uint32_t) key->c; - } + case 19: /* Ctrl + S */ + case IS_WIMP_KEY + wimp_KEY_F3: + ro_gui_window_action_save(g, GUI_SAVE_SOURCE); + return; - switch (c) { - case IS_WIMP_KEY + wimp_KEY_F1: /* Help. */ - return ro_gui_menu_handle_action(g->window, - HELP_OPEN_CONTENTS, false); + case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F3: + ro_gui_window_action_save(g, GUI_SAVE_TEXT); + return; - case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F1: - return ro_gui_menu_handle_action(g->window, - BROWSER_PAGE_INFO, false); + case IS_WIMP_KEY + wimp_KEY_SHIFT + wimp_KEY_F3: + ro_gui_window_action_save(g, GUI_SAVE_COMPLETE); + return; - case IS_WIMP_KEY + wimp_KEY_F2: - if (!g->toolbar) - return false; - ro_gui_url_complete_close(NULL, 0); - ro_gui_set_icon_string(g->toolbar->toolbar_handle, - ICON_TOOLBAR_URL, "www.", true); - xwimp_set_caret_position(g->toolbar->toolbar_handle, - ICON_TOOLBAR_URL, 0, 0, -1, 4); - ro_gui_url_complete_start(g); - ro_gui_url_complete_keypress(g, wimp_KEY_DOWN); - return true; + case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_SHIFT + wimp_KEY_F3: + ro_gui_window_action_save(g, GUI_SAVE_DRAW); + return; - case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F2: - /* Close window. */ - ro_gui_url_complete_close(NULL, 0); - browser_window_destroy(g->bw); - return true; + case 6: /* Ctrl + F */ + case IS_WIMP_KEY + wimp_KEY_F4: /* Search */ + ro_gui_window_action_search(g); + return; - case 19: /* Ctrl + S */ - case IS_WIMP_KEY + wimp_KEY_F3: - return ro_gui_menu_handle_action(g->window, - BROWSER_SAVE, false); - - case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F3: - return ro_gui_menu_handle_action(g->window, - BROWSER_EXPORT_TEXT, false); - - case IS_WIMP_KEY + wimp_KEY_SHIFT + wimp_KEY_F3: - return ro_gui_menu_handle_action(g->window, - BROWSER_SAVE_COMPLETE, false); - - case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_SHIFT + - wimp_KEY_F3: - return ro_gui_menu_handle_action(g->window, - BROWSER_EXPORT_DRAW, false); - - case 6: /* Ctrl + F */ - case IS_WIMP_KEY + wimp_KEY_F4: /* Search */ - return ro_gui_menu_handle_action(g->window, - BROWSER_FIND_TEXT, false); - - case IS_WIMP_KEY + wimp_KEY_F5: /* Reload */ - return ro_gui_menu_handle_action(g->window, - BROWSER_NAVIGATE_RELOAD, false); - - case 18: /* Ctrl+R (Full reload) */ - case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F5: - /* Full reload */ - return ro_gui_menu_handle_action(g->window, - BROWSER_NAVIGATE_RELOAD_ALL, false); - - case IS_WIMP_KEY + wimp_KEY_F6: /* Hotlist */ - return ro_gui_menu_handle_action(g->window, - HOTLIST_SHOW, false); - - case IS_WIMP_KEY + wimp_KEY_F7: /* Show local history */ - return ro_gui_menu_handle_action(g->window, - HISTORY_SHOW_LOCAL, false); - - case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F7: - /* Show global history */ - return ro_gui_menu_handle_action(g->window, - HISTORY_SHOW_GLOBAL, false); - - case IS_WIMP_KEY + wimp_KEY_F8: /* View source */ - ro_gui_view_source(h); - return true; + case IS_WIMP_KEY + wimp_KEY_F5: /* Reload */ + if (g->bw != NULL) + browser_window_reload(g->bw, false); + return; - case IS_WIMP_KEY + wimp_KEY_F9: - /* Dump content for debugging. */ - ro_gui_dump_content(h); - return true; + case 18: /* Ctrl+R (Full reload) */ + case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F5: + if (g->bw != NULL) + browser_window_reload(g->bw, true); + return; - case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F9: - urldb_dump(); - return true; + case IS_WIMP_KEY + wimp_KEY_F6: /* Hotlist */ + ro_gui_hotlist_open(); + return; - case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_SHIFT + - wimp_KEY_F9: - talloc_report_full(0, stderr); - return true; + case IS_WIMP_KEY + wimp_KEY_F7: /* Show local history */ + ro_gui_window_action_local_history(g); + return; - case IS_WIMP_KEY + wimp_KEY_F11: /* Zoom */ - return ro_gui_menu_handle_action(g->window, - BROWSER_SCALE_VIEW, false); + case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F7: + /* Show global history */ + ro_gui_global_history_open(); + return; - case IS_WIMP_KEY + wimp_KEY_SHIFT + wimp_KEY_F11: - /* Toggle display of box outlines. */ - html_redraw_debug = !html_redraw_debug; - gui_window_redraw_window(g); - return true; + case IS_WIMP_KEY + wimp_KEY_F8: /* View source */ + ro_gui_view_source(h); + return; - case wimp_KEY_RETURN: - if (!toolbar) - break; - toolbar_url = ro_gui_get_icon_string( - g->toolbar->toolbar_handle, - ICON_TOOLBAR_URL); - ro_gui_window_launch_url(g, toolbar_url); - return true; + case IS_WIMP_KEY + wimp_KEY_F9: + /* Dump content for debugging. */ + ro_gui_dump_content(h); + return; - case wimp_KEY_ESCAPE: - if (ro_gui_url_complete_close(NULL, 0)) { - ro_gui_url_complete_start(g); - return true; - } - return ro_gui_menu_handle_action(g->window, - BROWSER_NAVIGATE_STOP, false); + case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_F9: + urldb_dump(); + return; - case 8: /* CTRL+H / Backspace */ - if (toolbar) - return ro_gui_url_complete_keypress(g, c); - break; + case IS_WIMP_KEY + wimp_KEY_CONTROL + wimp_KEY_SHIFT + wimp_KEY_F9: + talloc_report_full(0, stderr); + return; - case 14: /* CTRL+N */ - return ro_gui_menu_handle_action(g->window, - BROWSER_NEW_WINDOW, false); + case IS_WIMP_KEY + wimp_KEY_F11: /* Zoom */ + ro_gui_window_action_zoom(g); + return; - case 17: /* CTRL+Q (Zoom out) */ - case 23: /* CTRL+W (Zoom in) */ - if (!h) - break; - scale = g->bw->scale; - if (ro_gui_shift_pressed() && c == 17) - scale = g->bw->scale - 0.1; - else if (ro_gui_shift_pressed() && c == 23) - scale = g->bw->scale + 0.1; - else if (c == 17) { - for (int i = SCALE_SNAP_TO_SIZE - 1; - i >= 0; i--) - if (scale_snap_to[i] < - g->bw->scale) { - scale = scale_snap_to[i]; - break; - } - } else { - for (unsigned int i = 0; - i < SCALE_SNAP_TO_SIZE; i++) - if (scale_snap_to[i] > - g->bw->scale) { - scale = scale_snap_to[i]; - break; - } - } - if (scale < scale_snap_to[0]) - scale = scale_snap_to[0]; - if (scale > scale_snap_to[SCALE_SNAP_TO_SIZE - 1]) - scale = scale_snap_to[SCALE_SNAP_TO_SIZE - 1]; - if (g->bw->scale != scale) { - browser_window_set_scale(g->bw, scale, true); -// g->reformat_pending = true; -// if ((h) && (content_get_type(h) != CONTENT_HTML)) -// browser_window_update(g->bw, false); -// browser_reformat_pending = true; - } - return true; + case IS_WIMP_KEY + wimp_KEY_SHIFT + wimp_KEY_F11: + /* Toggle display of box outlines. */ + html_redraw_debug = !html_redraw_debug; + gui_window_redraw_window(g); + return; - case IS_WIMP_KEY + wimp_KEY_PRINT: - return ro_gui_menu_handle_action(g->window, - BROWSER_PRINT, false); + case wimp_KEY_RETURN: + if (is_toolbar) { + toolbar_url = ro_toolbar_get_url(g->toolbar); + if (toolbar_url != NULL) + ro_gui_window_launch_url(g, toolbar_url); + } + return; - case IS_WIMP_KEY | wimp_KEY_LEFT: - case IS_WIMP_KEY | wimp_KEY_RIGHT: - case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_LEFT: - case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_RIGHT: - if (toolbar) - return false; - break; - case IS_WIMP_KEY + wimp_KEY_UP: - case IS_WIMP_KEY + wimp_KEY_DOWN: - case IS_WIMP_KEY + wimp_KEY_PAGE_UP: - case IS_WIMP_KEY + wimp_KEY_PAGE_DOWN: - case wimp_KEY_HOME: - case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_UP: - case IS_WIMP_KEY + wimp_KEY_END: - case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_DOWN: - if (toolbar) - return ro_gui_url_complete_keypress(g, c); + case wimp_KEY_ESCAPE: + if (ro_gui_url_complete_close()) { + ro_gui_url_complete_start(g->toolbar); + return; + } + + if (g->bw != NULL) + browser_window_stop(g->bw); + return; + + case 14: /* CTRL+N */ + ro_gui_window_action_new_window(g); + return; + + case 17: /* CTRL+Q (Zoom out) */ + case 23: /* CTRL+W (Zoom in) */ + if (!h) break; - default: - if (toolbar) - return ro_gui_url_complete_keypress(g, c); - return false; + scale = g->bw->scale; + if (ro_gui_shift_pressed() && c == 17) + scale = g->bw->scale - 0.1; + else if (ro_gui_shift_pressed() && c == 23) + scale = g->bw->scale + 0.1; + else if (c == 17) { + for (int i = SCALE_SNAP_TO_SIZE - 1; i >= 0; i--) + if (scale_snap_to[i] < g->bw->scale) { + scale = scale_snap_to[i]; + break; + } + } else { + for (unsigned int i = 0; i < SCALE_SNAP_TO_SIZE; i++) + if (scale_snap_to[i] > g->bw->scale) { + scale = scale_snap_to[i]; + break; + } + } + if (scale < scale_snap_to[0]) + scale = scale_snap_to[0]; + if (scale > scale_snap_to[SCALE_SNAP_TO_SIZE - 1]) + scale = scale_snap_to[SCALE_SNAP_TO_SIZE - 1]; + if (g->bw->scale != scale) { + browser_window_set_scale(g->bw, scale, true); +// g->reformat_pending = true; +// if ((h) && (content_get_type(h) != CONTENT_HTML)) +// browser_window_update(g->bw, false); +// browser_reformat_pending = true; + } + return; + + case IS_WIMP_KEY + wimp_KEY_PRINT: + ro_gui_window_action_print(g); + return; + + case IS_WIMP_KEY | wimp_KEY_LEFT: + case IS_WIMP_KEY | wimp_KEY_RIGHT: + case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_LEFT: + case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_RIGHT: + if (is_toolbar) + return; + break; + case IS_WIMP_KEY + wimp_KEY_UP: + case IS_WIMP_KEY + wimp_KEY_DOWN: + case IS_WIMP_KEY + wimp_KEY_PAGE_UP: + case IS_WIMP_KEY + wimp_KEY_PAGE_DOWN: + case wimp_KEY_HOME: + case IS_WIMP_KEY | wimp_KEY_CONTROL | wimp_KEY_UP: + case IS_WIMP_KEY + wimp_KEY_END: + default: + break; } state.w = g->window; @@ -2571,12 +2366,12 @@ bool ro_gui_window_keypress(wimp_key *key) if (error) { LOG(("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess)); - return true; + return; } y = state.visible.y1 - state.visible.y0 - 32; if (g->toolbar) - y -= ro_gui_theme_toolbar_full_height(g->toolbar); + y -= ro_toolbar_full_height(g->toolbar); switch (c) { case IS_WIMP_KEY | wimp_KEY_LEFT: @@ -2618,17 +2413,870 @@ bool ro_gui_window_keypress(wimp_key *key) LOG(("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess)); } +} + + +/** + * Prepare the browser window menu for (re-)opening + * + * \param w The window owning the menu. + * \param i The icon owning the menu. + * \param *menu The menu about to be opened. + * \param *pointer Pointer to the relevant wimp event block, or + * NULL for an Adjust click. + * \return true if the event was handled; else false. + */ + +bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu, + wimp_pointer *pointer) +{ + struct gui_window *g; + struct browser_window *bw; + hlcache_handle *h; + struct toolbar *toolbar; + bool export_sprite, export_draw; + os_coord pos; + + g = (struct gui_window *) ro_gui_wimp_event_get_user_data(w); + toolbar = g->toolbar; + bw = g->bw; + h = bw->current_content; + + /* If this is the form select menu, handle it now and then exit. + * Otherwise, carry on to the main browser window menu. + */ + + if (menu == gui_form_select_menu) { + return ro_gui_window_prepare_form_select_menu(g->bw, + gui_form_select_control); + } + + if (menu != ro_gui_browser_window_menu) + return false; + + /* If this is a new opening for the browser window menu (ie. not for a + * toolbar menu), get details of the object under the pointer. + */ + + if (pointer != NULL && g->window == w) { + ro_gui_url_complete_close(); + + current_menu_object = NULL; + current_menu_url = NULL; + + if (h != NULL && + ro_gui_window_to_window_pos(g, pointer->pos.x, + pointer->pos.y, &pos)) { + 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; + } + } + } + + /* Shade menu entries according to the state of the window and object + * under the pointer. + */ + + /* Toolbar (Sub)Menu */ + + ro_gui_menu_set_entry_shaded(menu, TOOLBAR_BUTTONS, + ro_toolbar_menu_option_shade(toolbar)); + ro_gui_menu_set_entry_ticked(menu, TOOLBAR_BUTTONS, + ro_toolbar_menu_buttons_tick(toolbar)); + + ro_gui_menu_set_entry_shaded(menu, TOOLBAR_ADDRESS_BAR, + ro_toolbar_menu_edit_shade(toolbar)); + ro_gui_menu_set_entry_ticked(menu, TOOLBAR_ADDRESS_BAR, + ro_toolbar_menu_url_tick(toolbar)); + + ro_gui_menu_set_entry_shaded(menu, TOOLBAR_THROBBER, + ro_toolbar_menu_edit_shade(toolbar)); + ro_gui_menu_set_entry_ticked(menu, TOOLBAR_THROBBER, + ro_toolbar_menu_throbber_tick(toolbar)); + + ro_gui_menu_set_entry_shaded(menu, TOOLBAR_EDIT, + ro_toolbar_menu_edit_shade(toolbar)); + ro_gui_menu_set_entry_ticked(menu, TOOLBAR_EDIT, + ro_toolbar_menu_edit_tick(toolbar)); + + /* Page Submenu */ + + ro_gui_menu_set_entry_shaded(menu, BROWSER_PAGE, h == NULL || + (content_get_type(h) != CONTENT_HTML && + content_get_type(h) != CONTENT_TEXTPLAIN)); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_PAGE_INFO, h == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_PRINT, h == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_NEW_WINDOW, h == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_FIND_TEXT, + h == NULL || (content_get_type(h) != CONTENT_HTML && + content_get_type(h) != CONTENT_TEXTPLAIN)); + + + ro_gui_menu_set_entry_shaded(menu, BROWSER_VIEW_SOURCE, h == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_SAVE_URL_URI, h == NULL); + ro_gui_menu_set_entry_shaded(menu, BROWSER_SAVE_URL_URL, h == NULL); + ro_gui_menu_set_entry_shaded(menu, BROWSER_SAVE_URL_TEXT, h == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_SAVE, h == NULL); + ro_gui_menu_set_entry_shaded(menu, BROWSER_SAVE_COMPLETE, h == NULL); + ro_gui_menu_set_entry_shaded(menu, BROWSER_EXPORT_DRAW, h == NULL); + ro_gui_menu_set_entry_shaded(menu, BROWSER_EXPORT_PDF, h == NULL); + ro_gui_menu_set_entry_shaded(menu, BROWSER_EXPORT_TEXT, h == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_LINK_SAVE_URI, + !current_menu_url); + ro_gui_menu_set_entry_shaded(menu, BROWSER_LINK_SAVE_URL, + !current_menu_url); + ro_gui_menu_set_entry_shaded(menu, BROWSER_LINK_SAVE_TEXT, + !current_menu_url); + + + + /* Object Submenu */ + + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT, + current_menu_object == NULL && + current_menu_url == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_LINK, + current_menu_url == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_INFO, + current_menu_object == NULL); + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_RELOAD, + current_menu_object == NULL); + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_OBJECT, + current_menu_object == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_PRINT, true); + /* Not yet implemented */ + + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_SAVE, + current_menu_object == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_SAVE_URL_URI, + current_menu_object == NULL); + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_SAVE_URL_URL, + current_menu_object == NULL); + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_SAVE_URL_TEXT, + current_menu_object == NULL); + + if (current_menu_object != NULL) + ro_gui_window_content_export_types(current_menu_object, + &export_draw, &export_sprite); + else + ro_gui_window_content_export_types(h, + &export_draw, &export_sprite); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_EXPORT, + (h == NULL && current_menu_object == NULL) + || !(export_sprite || export_draw)); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_EXPORT_SPRITE, + (h == NULL && current_menu_object == NULL) + || !export_sprite); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_EXPORT_DRAW, + (h == NULL && current_menu_object == NULL) + || !export_draw); + + + /* Selection Submenu */ + + ro_gui_menu_set_entry_shaded(menu, BROWSER_SELECTION, + h == NULL || (content_get_type(h) != CONTENT_HTML && + content_get_type(h) != CONTENT_TEXTPLAIN)); + /* make menu available if there's anything that /could/ + * be selected */ + + ro_gui_menu_set_entry_shaded(menu, BROWSER_SELECTION_SAVE, h == NULL || + bw->sel == NULL || !selection_defined(bw->sel)); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_SELECTION_COPY, h == NULL || + bw->sel == NULL || !selection_defined(bw->sel)); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_SELECTION_CUT, h == NULL || + bw->sel == NULL || !selection_defined(bw->sel) || + selection_read_only(bw->sel)); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_SELECTION_PASTE, + h == NULL || bw->paste_callback == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_SELECTION_CLEAR, h == NULL || + bw->sel == NULL || !selection_defined(bw->sel)); + + + /* Navigate Submenu */ + + ro_gui_menu_set_entry_shaded(menu, BROWSER_NAVIGATE_BACK, + !browser_window_back_available(bw)); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_NAVIGATE_FORWARD, + !browser_window_forward_available(bw)); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_NAVIGATE_RELOAD_ALL, + !browser_window_reload_available(bw)); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_NAVIGATE_STOP, + !browser_window_stop_available(bw)); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_NAVIGATE_UP, + !ro_gui_window_up_available(bw)); + + + + /* View Submenu */ + + ro_gui_menu_set_entry_shaded(menu, BROWSER_IMAGES_FOREGROUND, true); + ro_gui_menu_set_entry_ticked(menu, BROWSER_IMAGES_FOREGROUND, true); + /* Not yet implemented. */ + + ro_gui_menu_set_entry_ticked(menu, BROWSER_IMAGES_BACKGROUND, + g != NULL && g->option.background_images); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_BUFFER_ANIMS, + g == NULL || g->option.buffer_everything); + ro_gui_menu_set_entry_ticked(menu, BROWSER_BUFFER_ANIMS, g != NULL && + (g->option.buffer_animations || + g->option.buffer_everything)); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_BUFFER_ALL, g == NULL); + ro_gui_menu_set_entry_ticked(menu, BROWSER_BUFFER_ALL, + g != NULL && g->option.buffer_everything); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_SCALE_VIEW, h == NULL); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_WINDOW_STAGGER, + option_window_screen_width == 0); + ro_gui_menu_set_entry_ticked(menu, BROWSER_WINDOW_STAGGER, + ((option_window_screen_width == 0) || + option_window_stagger)); + + ro_gui_menu_set_entry_ticked(menu, BROWSER_WINDOW_COPY, + option_window_size_clone); + + ro_gui_menu_set_entry_shaded(menu, BROWSER_WINDOW_RESET, + option_window_screen_width == 0); + + + /* Utilities Submenu */ + + ro_gui_menu_set_entry_shaded(menu, HOTLIST_ADD_URL, h == NULL); + + ro_gui_menu_set_entry_shaded(menu, HISTORY_SHOW_LOCAL, + (bw == NULL || (bw->history == NULL) || + !(h != NULL || history_back_available(bw->history) || + history_forward_available(bw->history)))); + + + /* Help Submenu */ + + ro_gui_menu_set_entry_ticked(menu, HELP_LAUNCH_INTERACTIVE, + ro_gui_interactive_help_available() && + option_interactive_help); return true; } /** + * Handle submenu warnings for a browser window menu + * + * \param w The window owning the menu. + * \param i The icon owning the menu. + * \param *menu The menu to which the warning applies. + * \param *selection The wimp menu selection data. + * \param action The selected menu action. + */ + +void ro_gui_window_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu, + wimp_selection *selection, menu_action action) +{ + struct gui_window *g; + struct browser_window *bw; + hlcache_handle *h; + struct toolbar *toolbar; + bool export; + + if (menu != ro_gui_browser_window_menu) + return; + + g = (struct gui_window *) ro_gui_wimp_event_get_user_data(w); + toolbar = g->toolbar; + bw = g->bw; + h = bw->current_content; + + switch (action) { + case BROWSER_PAGE_INFO: + if (h != NULL) + ro_gui_window_prepare_pageinfo(g); + break; + + case BROWSER_FIND_TEXT: + if (h != NULL && (content_get_type(h) == CONTENT_HTML || + content_get_type(h) == CONTENT_TEXTPLAIN)) + ro_gui_search_prepare(g->bw); + break; + + case BROWSER_SCALE_VIEW: + if (h != NULL) + ro_gui_dialog_prepare_zoom(g); + break; + + case BROWSER_PRINT: + if (h != NULL) + ro_gui_print_prepare(g); + break; + + case BROWSER_OBJECT_INFO: + if (current_menu_object != NULL) + ro_gui_window_prepare_objectinfo(current_menu_object, + current_menu_url); + break; + + case BROWSER_OBJECT_SAVE: + if (current_menu_object != NULL) + ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG, + current_menu_object, NULL, NULL, NULL); + break; + + case BROWSER_SELECTION_SAVE: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL, + bw->sel, NULL, NULL); + break; + + case BROWSER_SAVE_URL_URI: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, + content_get_url(h), + content_get_title(h)); + break; + + case BROWSER_SAVE_URL_URL: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, + content_get_url(h), + content_get_title(h)); + break; + + case BROWSER_SAVE_URL_TEXT: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, + content_get_url(h), + content_get_title(h)); + break; + + case BROWSER_OBJECT_SAVE_URL_URI: + if (current_menu_object != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, + content_get_url(current_menu_object), + content_get_title(current_menu_object)); + break; + + case BROWSER_OBJECT_SAVE_URL_URL: + if (current_menu_object != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, + content_get_url(current_menu_object), + content_get_title(current_menu_object)); + break; + + case BROWSER_OBJECT_SAVE_URL_TEXT: + if (current_menu_object != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, + content_get_url(current_menu_object), + content_get_title(current_menu_object)); + break; + + case BROWSER_SAVE: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_SOURCE, h, NULL, NULL, NULL); + break; + + case BROWSER_SAVE_COMPLETE: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_COMPLETE, h, NULL, NULL, NULL); + break; + + case BROWSER_EXPORT_DRAW: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_DRAW, h, NULL, NULL, NULL); + break; + + case BROWSER_EXPORT_PDF: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_PDF, h, NULL, NULL, NULL); + break; + + case BROWSER_EXPORT_TEXT: + if (h != NULL) + ro_gui_save_prepare(GUI_SAVE_TEXT, h, NULL, NULL, NULL); + break; + + case BROWSER_LINK_SAVE_URI: + if (current_menu_url != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, + current_menu_url, NULL); + break; + + case BROWSER_LINK_SAVE_URL: + if (current_menu_url != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, + current_menu_url, NULL); + break; + + case BROWSER_LINK_SAVE_TEXT: + if (current_menu_url != NULL) + ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, + current_menu_url, NULL); + break; + + case BROWSER_OBJECT_EXPORT_SPRITE: + if (current_menu_object != NULL) { + ro_gui_window_content_export_types(current_menu_object, + NULL, &export); + + if (export) + ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, + current_menu_object, + NULL, NULL, NULL); + } else if (h != NULL) { + ro_gui_window_content_export_types(h, NULL, &export); + + if (export) + ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, + h, NULL, NULL, NULL); + } + break; + + case BROWSER_OBJECT_EXPORT_DRAW: + if (current_menu_object != NULL) { + ro_gui_window_content_export_types(current_menu_object, + &export, NULL); + + if (export) + ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, + current_menu_object, + NULL, NULL, NULL); + } else if (h != NULL) { + ro_gui_window_content_export_types(h, &export, NULL); + + if (export) + ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, + h, NULL, NULL, NULL); + } + break; + + default: + break; + } +} + + +/** + * Handle selections from a browser window menu + * + * \param w The window owning the menu. + * \param i The icon owning the menu. + * \param *menu The menu from which the selection was made. + * \param *selection The wimp menu selection data. + * \param action The selected menu action. + * \return true if action accepted; else false. + */ + +bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, + wimp_selection *selection, menu_action action) +{ + struct gui_window *g; + struct browser_window *bw; + hlcache_handle *h; + struct toolbar *toolbar; + wimp_window_state state; + os_error *error; + + g = (struct gui_window *) ro_gui_wimp_event_get_user_data(w); + toolbar = g->toolbar; + bw = g->bw; + h = bw->current_content; + + /* If this is a form menu from the core, handle it now and then exit. + * Otherwise, carry on to the main browser window menu. + */ + + if (menu == gui_form_select_menu && w == g->window) { + ro_gui_window_process_form_select_menu(g, selection); + + return true; + } + + /* We're now safe to assume that this is either the browser or + * toolbar window menu. + */ + + switch (action) { + + /* help actions */ + case HELP_OPEN_CONTENTS: + ro_gui_open_help_page("documentation/index"); + break; + case HELP_OPEN_GUIDE: + ro_gui_open_help_page("documentation/guide"); + break; + case HELP_OPEN_INFORMATION: + ro_gui_open_help_page("documentation/info"); + break; + case HELP_OPEN_ABOUT: + ro_gui_open_help_page("about/index"); + break; + 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; + } + break; + + /* history actions */ + case HISTORY_SHOW_LOCAL: + ro_gui_window_action_local_history(g); + break; + case HISTORY_SHOW_GLOBAL: + ro_gui_global_history_open(); + break; + + /* hotlist actions */ + case HOTLIST_ADD_URL: + ro_gui_window_action_add_bookmark(g); + break; + case HOTLIST_SHOW: + ro_gui_hotlist_open(); + break; + + /* cookies actions */ + case COOKIES_SHOW: + ro_gui_cookies_open(); + break; + + case COOKIES_DELETE: + cookies_delete_all(); + break; + + /* page actions */ + case BROWSER_PAGE_INFO: + ro_gui_window_action_page_info(g); + break; + case BROWSER_PRINT: + ro_gui_window_action_print(g); + break; + case BROWSER_NEW_WINDOW: + ro_gui_window_action_new_window(g); + break; + case BROWSER_VIEW_SOURCE: + if (h != NULL) + ro_gui_view_source(h); + break; + + /* object actions */ + case BROWSER_OBJECT_INFO: + if (current_menu_object != NULL) { + ro_gui_window_prepare_objectinfo(current_menu_object, + current_menu_url); + ro_gui_dialog_open_persistent(g->window, + dialog_objinfo, false); + } + break; + case BROWSER_OBJECT_RELOAD: + if (current_menu_object != NULL) { + content_invalidate_reuse_data(current_menu_object); + browser_window_reload(bw, false); + } + break; + + /* link actions */ + case BROWSER_LINK_SAVE_URI: + if (current_menu_url != NULL) { + ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL, + current_menu_url, NULL); + ro_gui_dialog_open_persistent(g->window, dialog_saveas, + false); + } + break; + case BROWSER_LINK_SAVE_URL: + if (current_menu_url != NULL) { + ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, + current_menu_url, NULL); + ro_gui_dialog_open_persistent(g->window, dialog_saveas, + false); + } + break; + case BROWSER_LINK_SAVE_TEXT: + if (current_menu_url != NULL) { + ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL, + current_menu_url, NULL); + ro_gui_dialog_open_persistent(g->window, dialog_saveas, + false); + } + break; + case BROWSER_LINK_DOWNLOAD: + if (current_menu_url != NULL) + browser_window_download(bw, current_menu_url, + content_get_url(h)); + break; + case BROWSER_LINK_NEW_WINDOW: + if (current_menu_url != NULL) + browser_window_create(current_menu_url, bw, + content_get_url(h), true, false); + break; + + /* save actions */ + case BROWSER_OBJECT_SAVE: + if (current_menu_object != NULL) { + ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG, + current_menu_object, NULL, NULL, NULL); + ro_gui_dialog_open_persistent(g->window, dialog_saveas, + false); + } + break; + case BROWSER_OBJECT_EXPORT_SPRITE: + if (current_menu_object != NULL) { + ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, + current_menu_object, NULL, NULL, NULL); + ro_gui_dialog_open_persistent(g->window, dialog_saveas, + false); + } + break; + case BROWSER_OBJECT_EXPORT_DRAW: + if (current_menu_object != NULL) { + ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, + current_menu_object, NULL, NULL, NULL); + ro_gui_dialog_open_persistent(g->window, dialog_saveas, + false); + } + break; + case BROWSER_SAVE: + ro_gui_window_action_save(g, GUI_SAVE_SOURCE); + break; + case BROWSER_SAVE_COMPLETE: + ro_gui_window_action_save(g, GUI_SAVE_COMPLETE); + break; + case BROWSER_EXPORT_DRAW: + ro_gui_window_action_save(g, GUI_SAVE_DRAW); + break; + case BROWSER_EXPORT_PDF: + ro_gui_window_action_save(g, GUI_SAVE_PDF); + break; + case BROWSER_EXPORT_TEXT: + ro_gui_window_action_save(g, GUI_SAVE_TEXT); + break; + case BROWSER_SAVE_URL_URI: + ro_gui_window_action_save(g, GUI_SAVE_LINK_URI); + break; + case BROWSER_SAVE_URL_URL: + ro_gui_window_action_save(g, GUI_SAVE_LINK_URL); + break; + case BROWSER_SAVE_URL_TEXT: + ro_gui_window_action_save(g, GUI_SAVE_LINK_TEXT); + break; + + /* selection actions */ + case BROWSER_SELECTION_SAVE: + if (h != NULL) { + ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL, + bw->sel, NULL, NULL); + ro_gui_dialog_open_persistent(g->window, dialog_saveas, + false); + } + break; + 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); + break; + case BROWSER_SELECTION_PASTE: + browser_window_key_press(bw, KEY_PASTE); + break; + 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: + ro_gui_window_action_home(g); + break; + case BROWSER_NAVIGATE_BACK: + if (bw != NULL && bw->history != NULL) + history_back(bw, bw->history); + break; + case BROWSER_NAVIGATE_FORWARD: + if (bw != NULL && bw->history != NULL) + history_forward(bw, bw->history); + break; + case BROWSER_NAVIGATE_UP: + if (bw != NULL && h != NULL) + ro_gui_window_navigate_up(bw->window, + content_get_url(h)); + break; + case BROWSER_NAVIGATE_RELOAD_ALL: + if (bw != NULL) + browser_window_reload(bw, true); + break; + case BROWSER_NAVIGATE_STOP: + if (bw != NULL) + browser_window_stop(bw); + break; + + /* browser window/display actions */ + case BROWSER_SCALE_VIEW: + ro_gui_window_action_zoom(g); + break; + case BROWSER_FIND_TEXT: + ro_gui_window_action_search(g); + break; + case BROWSER_IMAGES_BACKGROUND: + if (g != NULL) { + g->option.background_images = + !g->option.background_images; + gui_window_redraw_window(g); + } + break; + case BROWSER_BUFFER_ANIMS: + if (g != NULL) + g->option.buffer_animations = + !g->option.buffer_animations; + break; + case BROWSER_BUFFER_ALL: + if (g != NULL) + g->option.buffer_everything = + !g->option.buffer_everything; + break; + case BROWSER_SAVE_VIEW: + if (bw != NULL) { + ro_gui_window_default_options(bw); + ro_gui_save_options(); + } + break; + case BROWSER_WINDOW_DEFAULT: + if (g != NULL) { + ro_gui_screen_size(&option_window_screen_width, + &option_window_screen_height); + state.w = w; + 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(); + } + break; + case BROWSER_WINDOW_STAGGER: + option_window_stagger = !option_window_stagger; + ro_gui_save_options(); + break; + case BROWSER_WINDOW_COPY: + option_window_size_clone = !option_window_size_clone; + ro_gui_save_options(); + break; + case BROWSER_WINDOW_RESET: + option_window_screen_width = 0; + option_window_screen_height = 0; + ro_gui_save_options(); + break; + + /* toolbar actions */ + case TOOLBAR_BUTTONS: + assert(toolbar); + ro_toolbar_set_display_buttons(toolbar, + !ro_toolbar_get_display_buttons(toolbar)); + break; + case TOOLBAR_ADDRESS_BAR: + assert(toolbar); + ro_toolbar_set_display_url(toolbar, + !ro_toolbar_get_display_url(toolbar)); + if (ro_toolbar_get_display_url(toolbar)) + ro_toolbar_take_caret(toolbar); + break; + case TOOLBAR_THROBBER: + assert(toolbar); + ro_toolbar_set_display_throbber(toolbar, + !ro_toolbar_get_display_throbber(toolbar)); + break; + case TOOLBAR_EDIT: + assert(toolbar); + ro_toolbar_toggle_edit(toolbar); + break; + + default: + return false; + } + + return true; +} + + +/** + * Handle the closure of a browser window menu + * + * \param w The window owning the menu. + * \param i The icon owning the menu. + * \param *menu The menu that is being closed. + */ + +void ro_gui_window_menu_close(wimp_w w, wimp_i i, wimp_menu *menu) +{ + if (menu == ro_gui_browser_window_menu) { + current_menu_object = NULL; + current_menu_url = NULL; + } else if (menu == gui_form_select_menu) { + gui_form_select_control = NULL; + } +} + + +/** * Process Scroll_Request events. + * + * \TODO -- This handles Scroll Events for all windows, not just browser + * windows. Either it needs to move somewhere else, or the + * code needs to be split and Scroll Events dispatched via the + * Wimp_Event module. Currently it doesn't properly handle + * events affecting treeview windows, anyway. */ + void ro_gui_scroll_request(wimp_scroll *scroll) { - struct gui_window *g = ro_gui_window_lookup(scroll->w); + struct gui_window *g = ro_gui_window_lookup(scroll->w); + struct toolbar *toolbar; if (g && g->bw->current_content && ro_gui_shift_pressed()) { /* extended scroll request with shift held down; change zoom */ @@ -2656,8 +3304,12 @@ void ro_gui_scroll_request(wimp_scroll *scroll) int y = scroll->visible.y1 - scroll->visible.y0 - 32; os_error *error; - if (g && g->toolbar) - y -= ro_gui_theme_toolbar_full_height(g->toolbar); + /* This has to handle all windows, not just browser ones. */ + toolbar = ro_toolbar_parent_window_lookup(scroll->w); + assert(g == NULL || g->toolbar == NULL || + g->toolbar == toolbar); + if (toolbar != NULL) + y -= ro_toolbar_full_height(toolbar); switch (scroll->xmin) { case wimp_SCROLL_PAGE_LEFT: @@ -2705,70 +3357,6 @@ void ro_gui_scroll_request(wimp_scroll *scroll) /** - * Convert x,y screen co-ordinates into window co-ordinates. - * - * \param g gui window - * \param x x ordinate - * \param y y ordinate - * \param pos receives position in window co-ordinatates - * \return true iff conversion successful - */ - -bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, - os_coord *pos) -{ - wimp_window_state state; - os_error *error; - - assert(g); - - state.w = g->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); - return false; - } - pos->x = (x - (state.visible.x0 - state.xscroll)) / 2 / g->bw->scale; - pos->y = ((state.visible.y1 - state.yscroll) - y) / 2 / g->bw->scale; - return true; -} - - -/** - * Convert x,y window co-ordinates into screen co-ordinates. - * - * \param g gui window - * \param x x ordinate - * \param y y ordinate - * \param pos receives position in screen co-ordinatates - * \return true iff conversion successful - */ - -bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y, - os_coord *pos) -{ - wimp_window_state state; - os_error *error; - - assert(g); - - state.w = g->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); - return false; - } - pos->x = (x * 2 * g->bw->scale) + (state.visible.x0 - state.xscroll); - pos->y = (state.visible.y1 - state.yscroll) - (y * 2 * g->bw->scale); - return true; -} - - -/** * Handle Message_DataLoad (file dragged in) for a window. * * \param g window @@ -2884,8 +3472,366 @@ bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message) /** + * Handle pointer movements in a browser window. + * + * \param g browser window that the pointer is in + * \param pointer new mouse position + */ + +void ro_gui_window_mouse_at(struct gui_window *g, wimp_pointer *pointer) +{ + os_coord pos; + + if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos)) + browser_window_mouse_track(g->bw, + ro_gui_mouse_drag_state(pointer->buttons, + wimp_BUTTON_CLICK_DRAG), + pos.x, pos.y); +} + + +/** + * Window is being iconised. Create a suitable thumbnail sprite + * (which, sadly, must be in the Wimp sprite pool), and return + * the sprite name and truncated title to the iconiser + * + * \param g the gui window being iconised + * \param wi the WindowInfo message from the iconiser + */ + +void ro_gui_window_iconise(struct gui_window *g, + wimp_full_message_window_info *wi) +{ + /* sadly there is no 'legal' way to get the sprite into + * the Wimp sprite pool other than via a filing system */ + const char *temp_fname = "Pipe:$._tmpfile"; + struct browser_window *bw = g->bw; + osspriteop_header *overlay = NULL; + osspriteop_header *sprite_header; + struct bitmap *bitmap; + osspriteop_area *area; + int width = 34, height = 34; + hlcache_handle *h; + os_error *error; + int len, id; + + assert(bw); + + h = bw->current_content; + if (!h) return; + + /* if an overlay sprite is defined, locate it and gets its dimensions + * so that we can produce a thumbnail with the same dimensions */ + if (!ro_gui_wimp_get_sprite("ic_netsfxx", &overlay)) { + error = xosspriteop_read_sprite_info(osspriteop_PTR, + (osspriteop_area *)0x100, + (osspriteop_id)overlay, &width, &height, NULL, + NULL); + if (error) { + LOG(("xosspriteop_read_sprite_info: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("MiscError", error->errmess); + overlay = NULL; + } + else if (sprite_bpp(overlay) != 8) { + LOG(("overlay sprite is not 8bpp")); + overlay = NULL; + } + } + + /* create the thumbnail sprite */ + bitmap = bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE | + BITMAP_CLEAR_MEMORY); + if (!bitmap) { + LOG(("Thumbnail initialisation failed.")); + return; + } + thumbnail_create(h, bitmap, NULL); + if (overlay) + bitmap_overlay_sprite(bitmap, overlay); + area = thumbnail_convert_8bpp(bitmap); + bitmap_destroy(bitmap); + if (!area) { + LOG(("Thumbnail conversion failed.")); + return; + } + + /* choose a suitable sprite name */ + id = 0; + while (iconise_used[id]) + if ((unsigned)++id >= NOF_ELEMENTS(iconise_used)) { + id = iconise_next; + if ((unsigned)++iconise_next >= + NOF_ELEMENTS(iconise_used)) + iconise_next = 0; + break; + } + + sprite_header = (osspriteop_header *)(area + 1); + len = sprintf(sprite_header->name, "ic_netsf%.2d", id); + + error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, + area, temp_fname); + if (error) { + LOG(("xosspriteop_save_sprite_file: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("MiscError", error->errmess); + free(area); + return; + } + + error = xwimpspriteop_merge_sprite_file(temp_fname); + if (error) { + LOG(("xwimpspriteop_merge_sprite_file: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + remove(temp_fname); + free(area); + return; + } + + memcpy(wi->sprite_name, sprite_header->name + 3, len - 2); /* inc NUL */ + strncpy(wi->title, g->title, sizeof(wi->title)); + wi->title[sizeof(wi->title) - 1] = '\0'; + + if (wimptextop_string_width(wi->title, 0) > 182) { + /* work around bug in Pinboard where it will fail to display + * the icon if the text is very wide */ + if (strlen(wi->title) > 10) + wi->title[10] = '\0'; /* pinboard does this anyway */ + while (wimptextop_string_width(wi->title, 0) > 182) + wi->title[strlen(wi->title) - 1] = '\0'; + } + + wi->size = sizeof(wimp_full_message_window_info); + wi->your_ref = wi->my_ref; + error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)wi, + wi->sender); + if (error) { + LOG(("xwimp_send_message: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + else { + g->iconise_icon = id; + iconise_used[id] = true; + } + + free(area); +} + + +/** + * Completes scrolling of a browser window + * + * \param g gui window + */ + +void ro_gui_window_scroll_end(struct gui_window *g, wimp_dragged *drag) +{ + wimp_pointer pointer; + os_error *error; + os_coord pos; + + gui_current_drag_type = GUI_DRAG_NONE; + if (!g) + return; + + error = xwimp_drag_box((wimp_drag*)-1); + if (error) { + LOG(("xwimp_drag_box: 0x%x : %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + + 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); + return; + } + + error = xwimpspriteop_set_pointer_shape("ptr_default", 0x31, 0, 0, 0, 0); + if (error) { + LOG(("xwimpspriteop_set_pointer_shape: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + } + + if (ro_gui_window_to_window_pos(g, drag->final.x0, drag->final.y0, &pos)) + browser_window_mouse_drag_end(g->bw, + ro_gui_mouse_click_state(pointer.buttons, + wimp_BUTTON_CLICK_DRAG), + pos.x, pos.y); +} + + +/** + * Completes resizing of a browser frame + * + * \param g gui window + */ + +void ro_gui_window_frame_resize_end(struct gui_window *g, wimp_dragged *drag) +{ + /* our clean-up is the same as for page scrolling */ + ro_gui_window_scroll_end(g, drag); +} + + +/** + * Process Mouse_Click events in a toolbar's button bar. This does not handle + * other clicks in a toolbar: these are handled by the toolbar module itself. + * + * \param *data The GUI window associated with the click. + * \param action_type The action type to be handled. + * \param action The action to process. + */ + +void ro_gui_window_toolbar_click(void *data, + toolbar_action_type action_type, union toolbar_action action) +{ + struct gui_window *g = data; + struct browser_window *new_bw; + gui_save_type save_type; + + if (g == NULL) + return; + + + if (action_type == TOOLBAR_ACTION_URL && + action.url == TOOLBAR_URL_DRAG_URL) { + if (g->bw->current_content) { + hlcache_handle *h = g->bw->current_content; + + if (ro_gui_shift_pressed()) + save_type = GUI_SAVE_LINK_URL; + else + save_type = GUI_SAVE_LINK_TEXT; + + ro_gui_drag_save_link(save_type, content_get_url(h), + content_get_title(h), g); + } + + return; + } + + + /* By now, the only valid action left is a button click. If it isn't + * one of those, give up. + */ + + if (action_type != TOOLBAR_ACTION_BUTTON) + return; + + switch (action.button) { + case TOOLBAR_BUTTON_BACK: + if (g->bw != NULL && g->bw->history != NULL) + history_back(g->bw, g->bw->history); + break; + + case TOOLBAR_BUTTON_BACK_NEW: + ro_gui_window_action_navigate_back_new(g); + break; + + case TOOLBAR_BUTTON_FORWARD: + if (g->bw != NULL && g->bw->history != NULL) + history_forward(g->bw, g->bw->history); + break; + + case TOOLBAR_BUTTON_FORWARD_NEW: + ro_gui_window_action_navigate_forward_new(g); + break; + + case TOOLBAR_BUTTON_STOP: + if (g->bw != NULL) + browser_window_stop(g->bw); + break; + + case TOOLBAR_BUTTON_RELOAD: + if (g->bw != NULL) + browser_window_reload(g->bw, false); + break; + + case TOOLBAR_BUTTON_RELOAD_ALL: + if (g->bw != NULL) + browser_window_reload(g->bw, true); + break; + + case TOOLBAR_BUTTON_HISTORY_LOCAL: + ro_gui_window_action_local_history(g); + break; + + case TOOLBAR_BUTTON_HISTORY_GLOBAL: + ro_gui_global_history_open(); + break; + + case TOOLBAR_BUTTON_HOME: + ro_gui_window_action_home(g); + break; + + case TOOLBAR_BUTTON_SEARCH: + ro_gui_window_action_search(g); + break; + + case TOOLBAR_BUTTON_SCALE: + ro_gui_window_action_zoom(g); + break; + + case TOOLBAR_BUTTON_BOOKMARK_OPEN: + ro_gui_hotlist_open(); + break; + + case TOOLBAR_BUTTON_BOOKMARK_ADD: + ro_gui_window_action_add_bookmark(g); + break; + + case TOOLBAR_BUTTON_SAVE_SOURCE: + ro_gui_window_action_save(g, GUI_SAVE_SOURCE); + break; + + case TOOLBAR_BUTTON_SAVE_COMPLETE: + ro_gui_window_action_save(g, GUI_SAVE_COMPLETE); + break; + + case TOOLBAR_BUTTON_PRINT: + ro_gui_window_action_print(g); + break; + + case TOOLBAR_BUTTON_UP: + if (g->bw != NULL && g->bw->current_content != NULL) + ro_gui_window_navigate_up(g->bw->window, + content_get_url(g->bw->current_content)); + break; + + case TOOLBAR_BUTTON_UP_NEW: + if (g->bw && g->bw->current_content) { + hlcache_handle *h = g->bw->current_content; + new_bw = browser_window_create(NULL, + g->bw, NULL, false, + false); + /* do it without loading the content + * into the new window */ + ro_gui_window_navigate_up(new_bw->window, + content_get_url(h)); + } + break; + + default: + break; + } + + ro_gui_window_update_toolbar_buttons(g); +} + + +/** * Handle Message_DataLoad (file dragged in) for a toolbar * + * \TODO -- This belongs in the toolbar module, and should be moved there + * once the module is able to usefully handle its own events. + * * \param g window * \param message Message_DataLoad block * \return true if the load was processed @@ -2913,6 +3859,591 @@ bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message) } +/* + * Helper code for the Wimp Event Handlers. + */ + +/** + * Check if a particular menu handle is a browser window menu + * + * \param *menu The menu in question. + * \return true if this menu is a browser window menu + */ + +bool ro_gui_window_check_menu(wimp_menu *menu) +{ + return (ro_gui_browser_window_menu == menu) ? true : false; +} + + +/** + * Return boolean flags to show what RISC OS types we can sensibly convert + * the given object into. + * + * \TODO -- This should probably be somewhere else but in window.c, and + * should probably even be done in content_(). + * + * \param *h The object to test. + * \param *export_draw true on exit if a drawfile would be possible. + * \param *export_sprite true on exit if a sprite would be possible. + * \return true if valid data is returned; else false. + */ + +bool ro_gui_window_content_export_types(hlcache_handle *h, + bool *export_draw, bool *export_sprite) +{ + bool found_type = false; + + if (export_draw != NULL) + *export_draw = false; + if (export_sprite != NULL) + *export_sprite = false; + + if (h != NULL) { + switch (content_get_type(h)) { + /* 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 + found_type = true; + if (export_sprite != NULL) + *export_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 + found_type = true; + if (export_draw != NULL) + *export_draw = true; + break; + + default: + break; + } + } + + return found_type; +} + + +/** + * Return true if a browser window can navigate upwards. + * + * \TODO -- This should probably be somewhere else but in window.c. + * + * \param *bw the browser window to test. + * \return true if navigation up is possible; else false. + */ + +bool ro_gui_window_up_available(struct browser_window *bw) +{ + bool result = false, compare; + char *parent; + url_func_result res; + + if (bw != NULL && bw->current_content != NULL) { + res = url_parent(content_get_url(bw->current_content), &parent); + + if (res == URL_FUNC_OK) { + res = url_compare(content_get_url(bw->current_content), + parent, false, &compare); + if (res == URL_FUNC_OK) + result = !compare; + free(parent); + } else { + result = false; + } + } + + return result; +} + + +/** + * Prepare the page info window for use. + * + * \param *g The GUI window block to use. + */ + +void ro_gui_window_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_window_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); +} + + +/* + * User Actions in the browser window + */ + +/** + * Launch a new url in the given window. + * + * \param g gui_window to update + * \param url url to be launched + */ + +void ro_gui_window_launch_url(struct gui_window *g, const char *url) +{ + url_func_result res; + char *url_norm; + + ro_gui_url_complete_close(); + res = url_normalize(url, &url_norm); + if (res == URL_FUNC_OK) { + gui_window_set_url(g, url_norm); + browser_window_go(g->bw, url_norm, 0, true); + free(url_norm); + } +} + + +/** + * Navigate up one level + * + * \param g the gui_window to open the parent link in + * \param url the URL to open the parent of + */ +bool ro_gui_window_navigate_up(struct gui_window *g, const char *url) { + char *parent; + url_func_result res; + bool compare; + + if (!g || (!g->bw)) + return false; + + res = url_parent(url, &parent); + if (res == URL_FUNC_OK) { + res = url_compare(url, parent, false, &compare); + if ((res == URL_FUNC_OK) && !compare) + browser_window_go(g->bw, parent, 0, true); + free(parent); + } + return true; +} + + +/** + * Perform a Navigate Home action on a browser window. + * + * \param *g The browser window to act on. + */ + +void ro_gui_window_action_home(struct gui_window *g) +{ + char url[80]; + + if (g == NULL || g->bw == NULL) + return; + + 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); + } +} + + +/** + * Navigate back from a browser window into a new window. + * + * \param *g The browser window to act on. + */ + +void ro_gui_window_action_navigate_back_new(struct gui_window *g) +{ + struct browser_window *new_bw; + + if (g == NULL || g->bw == NULL) + return; + + new_bw = browser_window_create(NULL, g->bw, NULL, false, false); + + if (new_bw != NULL && new_bw->history != NULL) + history_back(new_bw, new_bw->history); +} + + +/** + * Navigate forward from a browser window into a new window. + * + * \param *g The browser window to act on. + */ + +void ro_gui_window_action_navigate_forward_new(struct gui_window *g) +{ + struct browser_window *new_bw; + + if (g == NULL || g->bw == NULL) + return; + + new_bw = browser_window_create(NULL, g->bw, NULL, false, false); + + if (new_bw != NULL && new_bw->history != NULL) + history_forward(new_bw, new_bw->history); +} + + +/** + * Open a new browser window. + * + * \param *g The browser window to act on. + */ + +void ro_gui_window_action_new_window(struct gui_window *g) +{ + if (g == NULL || g->bw == NULL || g->bw->current_content == NULL) + return; + + browser_window_create(content_get_url(g->bw->current_content), g->bw, + 0, false, false); +} + + +/** + * Open a local history pane for a browser window. + * + * \param *g The browser window to act on. + */ + +void ro_gui_window_action_local_history(struct gui_window *g) +{ + if (g != NULL && g->bw != NULL && g->bw->history != NULL) + ro_gui_history_open(g->bw, g->bw->history, true); +} + + +/** + * Open a save dialogue for a browser window contents. + * + * \param *g The browser window to act on. + * \param save_type The type of save to open. + */ + +void ro_gui_window_action_save(struct gui_window *g, gui_save_type save_type) +{ + if (g == NULL || g->bw == NULL || g->bw->current_content == NULL) + return; + + ro_gui_save_prepare(save_type, g->bw->current_content, + NULL, NULL, NULL); + ro_gui_dialog_open_persistent(g->window, dialog_saveas, true); +} + + +/** + * Open a text search dialogue for a browser window. + * + * \param *g The browser window to act on. + */ + +void ro_gui_window_action_search(struct gui_window *g) +{ + if (g == NULL || g->bw == NULL || g->bw->current_content == NULL || + (content_get_type(g->bw->current_content) != + CONTENT_HTML && + content_get_type(g->bw->current_content) != + CONTENT_TEXTPLAIN)) + return; + + ro_gui_search_prepare(g->bw); + ro_gui_dialog_open_persistent(g->window, dialog_search, true); +} + + +/** + * Open a zoom dialogue for a browser window. + * + * \param *g The browser window to act on. + */ + +void ro_gui_window_action_zoom(struct gui_window *g) +{ + if (g == NULL) + return; + + ro_gui_dialog_prepare_zoom(g); + ro_gui_dialog_open_persistent(g->window, dialog_zoom, true); +} + + +/** + * Add a hotlist entry for a browser window. + * + * \param *g The browser window to act on. + */ + +void ro_gui_window_action_add_bookmark(struct gui_window *g) +{ + if (g == NULL || g->bw == NULL || g->bw->current_content == NULL || + content_get_url(g->bw->current_content) == NULL) + return; + + hotlist_add_page(content_get_url(g->bw->current_content)); +} + + +/** + * Open a print dialogue for a browser window. + * + * \param *g The browser window to act on. + */ + +void ro_gui_window_action_print(struct gui_window *g) +{ + if (g == NULL) + return; + + ro_gui_print_prepare(g); + ro_gui_dialog_open_persistent(g->window, dialog_print, true); +} + + +/** + * Open a page info box for a browser window. + * + * \param *g The browser window to act on. + */ + +void ro_gui_window_action_page_info(struct gui_window *g) +{ + if (g == NULL || g->bw == NULL || g->bw->current_content == NULL) + return; + + ro_gui_window_prepare_pageinfo(g); + ro_gui_dialog_open_persistent(g->window, dialog_pageinfo, false); +} + + +/* + * Window and Toolbar Redraw and Update + */ + +/** + * Redraws the content for all windows. + */ + +void ro_gui_window_redraw_all(void) +{ + struct gui_window *g; + for (g = window_list; g; g = g->next) + gui_window_redraw_window(g); +} + + +/** + * Remove all pending update boxes for a window + * + * \param g gui_window + */ +void ro_gui_window_remove_update_boxes(struct gui_window *g) +{ + struct update_box *cur; + + for (cur = pending_updates; cur != NULL; cur = cur->next) { + if (cur->g == g) + cur->g = NULL; + } +} + + +/** + * Redraw any pending update boxes. + */ +void ro_gui_window_update_boxes(void) +{ + osbool more; + bool use_buffer; + wimp_draw update; + struct rect clip; + os_error *error; + struct update_box *cur; + struct gui_window *g; + const union content_msg_data *data; + + for (cur = pending_updates; cur != NULL; cur = cur->next) { + g = cur->g; + if (!g) + continue; + + data = &cur->data; + use_buffer = cur->use_buffer; + + update.w = g->window; + update.box.x0 = cur->x0; + update.box.y0 = cur->y0; + update.box.x1 = cur->x1; + update.box.y1 = cur->y1; + + error = xwimp_update_window(&update, &more); + if (error) { + LOG(("xwimp_update_window: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + continue; + } + + /* Set the current redraw gui_window to get options from */ + ro_gui_current_redraw_gui = g; + current_redraw_browser = g->bw; + + plot = ro_plotters; + ro_plot_origin_x = update.box.x0 - update.xscroll; + ro_plot_origin_y = update.box.y1 - update.yscroll; + ro_plot_set_scale(g->bw->scale); + + while (more) { + clip.x0 = (update.clip.x0 - ro_plot_origin_x) / 2; + clip.y0 = (ro_plot_origin_y - update.clip.y1) / 2; + clip.x1 = (update.clip.x1 - ro_plot_origin_x) / 2; + clip.y1 = (ro_plot_origin_y - update.clip.y0) / 2; + + if (use_buffer) + ro_gui_buffer_open(&update); + + browser_window_redraw(g->bw, 0, 0, &clip); + + if (use_buffer) + ro_gui_buffer_close(); + + error = xwimp_get_rectangle(&update, &more); + /* RISC OS 3.7 returns an error here if enough buffer + * was claimed to cause a new dynamic area to be + * created. It doesn't actually stop anything working, + * so we mask it out for now until a better fix is + * found. This appears to be a bug in RISC OS. */ + if (error && !(use_buffer && + error->errnum == error_WIMP_GET_RECT)) { + LOG(("xwimp_get_rectangle: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + ro_gui_current_redraw_gui = NULL; + current_redraw_browser = NULL; + continue; + } + } + + /* Reset the current redraw gui_window to prevent + * thumbnails from retaining options */ + ro_gui_current_redraw_gui = NULL; + current_redraw_browser = NULL; + } + while (pending_updates) { + cur = pending_updates; + pending_updates = pending_updates->next; + free(cur); + } +} + + /** * Process pending reformats */ @@ -2934,6 +4465,237 @@ void ro_gui_window_process_reformats(void) /** + * Destroy all browser windows. + */ + +void ro_gui_window_quit(void) +{ + struct gui_window *cur; + + while (window_list) { + cur = window_list; + window_list = window_list->next; + + /* framesets and iframes are destroyed by their parents */ + if (!cur->bw->parent) + browser_window_destroy(cur->bw); + } +} + + +/** + * Animate the "throbbers" of all browser windows. + */ + +void ro_gui_throb(void) +{ + struct gui_window *g; + struct browser_window *top; + + for (g = window_list; g; g = g->next) { + if (!g->bw->throbbing) + continue; + for (top = g->bw; top->parent; top = top->parent); + if (top->window != NULL && top->window->toolbar != NULL) + ro_toolbar_throb(top->window->toolbar); + } +} + + +/** + * Update the toolbar buttons for a given browser window to reflect the + * current state of its contents. + * + * Note that the parameters to this function are arranged so that it can be + * supplied to the toolbar module as an button state update callback. + * + * \param *g The browser window to update. + */ + +void ro_gui_window_update_toolbar_buttons(struct gui_window *g) +{ + struct browser_window *bw; + hlcache_handle *h; + struct toolbar *toolbar; + + if (g == NULL || g->toolbar == NULL) + return; + + bw = g->bw; + h = bw->current_content; + toolbar = g->toolbar; + + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_RELOAD, + !browser_window_reload_available(bw)); + + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_STOP, + !browser_window_stop_available(bw)); + + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_BACK, + !browser_window_back_available(bw)); + + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_FORWARD, + !browser_window_forward_available(bw)); + + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_UP, + !ro_gui_window_up_available(bw)); + + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SEARCH, + h == NULL || (content_get_type(h) != CONTENT_HTML && + content_get_type(h) != CONTENT_TEXTPLAIN)); + + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SCALE, + h == NULL); + + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_PRINT, + h == NULL); + + ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SAVE_SOURCE, + h == NULL); + + ro_toolbar_update_urlsuggest(toolbar); +} + + +/** + * Update a window to reflect a change in toolbar size: used as a callback by + * the toolbar module when a toolbar height changes. + * + * \param *data void pointer the window's gui_window struct + */ + +void ro_gui_window_update_toolbar(void *data) +{ + struct gui_window *g = (struct gui_window *) data; + + if (g != NULL) + gui_window_update_extent(g); +} + + +/** + * Save a new toolbar button configuration: used as a callback by the toolbar + * module when a buttonbar edit has finished. + * + * \param *data void pointer to the window's gui_window struct + * \param *config pointer to a malloc()'d button config string. + */ + +void ro_gui_window_save_toolbar_buttons(void *data, char *config) +{ + if (option_toolbar_browser != NULL) + free(option_toolbar_browser); + option_toolbar_browser = config; + ro_gui_save_options(); +} + + +/** + * Update a window and its toolbar to reflect a new theme: used as a callback + * by the toolbar module when a theme change affects a toolbar. + * + * \param *data void pointer to the window's gui_window struct + * \param ok true if the bar still exists; else false. + */ + +void ro_gui_window_update_theme(void *data, bool ok) +{ + struct gui_window *g = (struct gui_window *) data; + + if (g != NULL && g->toolbar != NULL) { + if (ok) { + gui_window_update_extent(g); + } else { + g->toolbar = NULL; + } + } +} + + +/* + * General Window Support + */ + +/** + * Import text file into window or its toolbar + * + * \param g gui window containing textarea + * \param filename pathname of file to be imported + * \param toolbar true iff imported to toolbar rather than main window + * \return true iff successful + */ + +bool ro_gui_window_import_text(struct gui_window *g, const char *filename, + bool toolbar) +{ + fileswitch_object_type obj_type; + os_error *error; + char *buf, *utf8_buf; + int size; + utf8_convert_ret ret; + + error = xosfile_read_stamped(filename, &obj_type, NULL, NULL, + &size, NULL, NULL); + if (error) { + LOG(("xosfile_read_stamped: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("FileError", error->errmess); + return true; /* was for us, but it didn't work! */ + } + + buf = malloc(size); + if (!buf) { + warn_user("NoMemory", NULL); + return true; + } + + error = xosfile_load_stamped(filename, (byte*)buf, + NULL, NULL, NULL, NULL, NULL); + if (error) { + LOG(("xosfile_load_stamped: 0x%x:%s", + error->errnum, error->errmess)); + warn_user("LoadError", error->errmess); + free(buf); + return true; + } + + ret = utf8_from_local_encoding(buf, size, &utf8_buf); + if (ret != UTF8_CONVERT_OK) { + /* bad encoding shouldn't happen */ + assert(ret != UTF8_CONVERT_BADENC); + LOG(("utf8_from_local_encoding failed")); + free(buf); + warn_user("NoMemory", NULL); + return true; + } + size = strlen(utf8_buf); + + if (toolbar) { + const char *ep = utf8_buf + size; + const char *sp; + char *p = utf8_buf; + + /* skip leading whitespace */ + while (isspace(*p)) p++; + + sp = p; + while (*p && *p != '\r' && *p != '\n') + p += utf8_next(p, ep - p, 0); + *p = '\0'; + + if (p > sp) + ro_gui_window_launch_url(g, sp); + } + else + browser_window_paste_text(g->bw, utf8_buf, size, true); + + free(buf); + free(utf8_buf); + return true; +} + + +/** * Clones a browser window's options. * * \param new_bw the new browser window @@ -2941,7 +4703,8 @@ void ro_gui_window_process_reformats(void) */ void ro_gui_window_clone_options(struct browser_window *new_bw, - struct browser_window *old_bw) { + struct browser_window *old_bw) +{ struct gui_window *old_gui = NULL; struct gui_window *new_gui; @@ -2968,15 +4731,23 @@ void ro_gui_window_clone_options(struct browser_window *new_bw, /* Set up the toolbar */ if (new_gui->toolbar) { - new_gui->toolbar->display_buttons = option_toolbar_show_buttons; - new_gui->toolbar->display_url = option_toolbar_show_address; - new_gui->toolbar->display_throbber = option_toolbar_show_throbber; + ro_toolbar_set_display_buttons(new_gui->toolbar, + option_toolbar_show_buttons); + ro_toolbar_set_display_url(new_gui->toolbar, + option_toolbar_show_address); + ro_toolbar_set_display_throbber(new_gui->toolbar, + option_toolbar_show_throbber); if ((old_gui) && (old_gui->toolbar)) { - new_gui->toolbar->display_buttons = old_gui->toolbar->display_buttons; - new_gui->toolbar->display_url = old_gui->toolbar->display_url; - new_gui->toolbar->display_throbber = old_gui->toolbar->display_throbber; - new_gui->toolbar->reformat_buttons = true; - ro_gui_theme_process_toolbar(new_gui->toolbar, -1); + ro_toolbar_set_display_buttons(new_gui->toolbar, + ro_toolbar_get_display_buttons( + old_gui->toolbar)); + ro_toolbar_set_display_url(new_gui->toolbar, + ro_toolbar_get_display_url( + old_gui->toolbar)); + ro_toolbar_set_display_throbber(new_gui->toolbar, + ro_toolbar_get_display_throbber( + old_gui->toolbar)); + ro_toolbar_process(new_gui->toolbar, -1, true); } } } @@ -2988,7 +4759,8 @@ void ro_gui_window_clone_options(struct browser_window *new_bw, * \param bw the browser window to read options from */ -void ro_gui_window_default_options(struct browser_window *bw) { +void ro_gui_window_default_options(struct browser_window *bw) +{ struct gui_window *gui; assert(bw); @@ -3006,33 +4778,277 @@ void ro_gui_window_default_options(struct browser_window *bw) { /* Set up the toolbar */ - if (gui->toolbar) { - option_toolbar_show_buttons = gui->toolbar->display_buttons; - option_toolbar_show_address = gui->toolbar->display_url; - option_toolbar_show_throbber = gui->toolbar->display_throbber; + if (gui->toolbar != NULL) { + option_toolbar_show_buttons = + ro_toolbar_get_display_buttons(gui->toolbar); + option_toolbar_show_address = + ro_toolbar_get_display_url(gui->toolbar); + option_toolbar_show_throbber = + ro_toolbar_get_display_throbber(gui->toolbar); } - if (gui->status_bar) - option_toolbar_status_width = ro_gui_status_bar_get_width(gui->status_bar); + if (gui->status_bar != NULL) + option_toolbar_status_width = + ro_gui_status_bar_get_width(gui->status_bar); } +/* + * Custom Menu Support + */ +/** + * Prepare or reprepare a form select menu, setting up the menu handle + * global in the process. + * + * \param *bw The browser window to contain the menu. + * \param *control The form control needing a menu. + * \return true if the menu is OK to be opened; else false. + */ + +bool ro_gui_window_prepare_form_select_menu(struct browser_window *bw, + struct form_control *control) +{ + unsigned int i, entries; + char *text_convert, *temp; + struct form_option *option; + 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(); + return false; + } + + 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(); + return false; + } + 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(); + return false; + } + 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(); + return false; + } + + 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(); + return false; + } + + 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; + + return true; +} /** - * Updates the navigation controls for all toolbars; + * Process selections from a form select menu, passing them back to the core. * - * \param g the gui_window to launch the URL into - * \param url the URL to launch, or NULL to simply update the suggestion icon + * \param *g The browser window affected by the menu. + * \param *selection The menu selection. */ -void ro_gui_window_prepare_navigate_all(void) { - struct gui_window *g; +void ro_gui_window_process_form_select_menu(struct gui_window *g, + wimp_selection *selection) +{ + assert(g != NULL); + + if (selection->items[0] >= 0) + form_select_process_selection(g->bw->current_content, + gui_form_select_control, + selection->items[0]); +} + + +/* + * Window and Toolbar Lookup + */ + +/** + * Convert a RISC OS window handle to a gui_window. + * + * \param w RISC OS window handle + * \return pointer to a structure if found, 0 otherwise + */ + +struct gui_window *ro_gui_window_lookup(wimp_w window) +{ + struct gui_window *g; for (g = window_list; g; g = g->next) - ro_gui_prepare_navigate(g); + if (g->window == window) + return g; + return 0; } /** + * Convert a toolbar RISC OS window handle to a gui_window. + * + * \param w RISC OS window handle of a toolbar + * \return pointer to a structure if found, 0 otherwise + */ + +struct gui_window *ro_gui_toolbar_lookup(wimp_w window) +{ + struct gui_window *g = NULL; + struct toolbar *toolbar; + wimp_w parent; + + toolbar = ro_toolbar_window_lookup(window); + + if (toolbar != NULL) { + parent = ro_toolbar_get_parent_window(toolbar); + g = ro_gui_window_lookup(parent); + } + + return g; +} + + +/* + * Core to RISC OS Conversions + */ + +/** + * Convert x,y screen co-ordinates into window co-ordinates. + * + * \param g gui window + * \param x x ordinate + * \param y y ordinate + * \param pos receives position in window co-ordinatates + * \return true iff conversion successful + */ + +bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, + os_coord *pos) +{ + wimp_window_state state; + os_error *error; + + assert(g); + + state.w = g->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); + return false; + } + pos->x = (x - (state.visible.x0 - state.xscroll)) / 2 / g->bw->scale; + pos->y = ((state.visible.y1 - state.yscroll) - y) / 2 / g->bw->scale; + return true; +} + + +/** + * Convert x,y window co-ordinates into screen co-ordinates. + * + * \param g gui window + * \param x x ordinate + * \param y y ordinate + * \param pos receives position in screen co-ordinatates + * \return true iff conversion successful + */ + +bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y, + os_coord *pos) +{ + wimp_window_state state; + os_error *error; + + assert(g); + + state.w = g->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); + return false; + } + pos->x = (x * 2 * g->bw->scale) + (state.visible.x0 - state.xscroll); + pos->y = (state.visible.y1 - state.yscroll) - (y * 2 * g->bw->scale); + return true; +} + + +/* + * Miscellaneous Functions + * + * \TODO -- These items might well belong elsewhere. + */ + +/** * Returns the state of the mouse buttons and modifiers keys for a * mouse action, suitable for passing to the OS-independent * browser window/ treeview/ etc code. @@ -3099,6 +5115,7 @@ browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons, return state; } + /** * Returns the state of the mouse buttons and modifiers keys whilst * dragging, for passing to the OS-independent browser window/ treeview/ @@ -3173,295 +5190,3 @@ bool ro_gui_alt_pressed(void) return (alt == 0xff); } - -/** - * Completes scrolling of a browser window - * - * \param g gui window - */ - -void ro_gui_window_scroll_end(struct gui_window *g, wimp_dragged *drag) -{ - wimp_pointer pointer; - os_error *error; - os_coord pos; - - gui_current_drag_type = GUI_DRAG_NONE; - if (!g) - return; - - error = xwimp_drag_box((wimp_drag*)-1); - if (error) { - LOG(("xwimp_drag_box: 0x%x : %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - } - - 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); - return; - } - - error = xwimpspriteop_set_pointer_shape("ptr_default", 0x31, 0, 0, 0, 0); - if (error) { - LOG(("xwimpspriteop_set_pointer_shape: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - } - - if (ro_gui_window_to_window_pos(g, drag->final.x0, drag->final.y0, &pos)) - browser_window_mouse_drag_end(g->bw, - ro_gui_mouse_click_state(pointer.buttons, - wimp_BUTTON_CLICK_DRAG), - pos.x, pos.y); -} - - -/** - * Completes resizing of a browser frame - * - * \param g gui window - */ - -void ro_gui_window_frame_resize_end(struct gui_window *g, wimp_dragged *drag) -{ - /* our clean-up is the same as for page scrolling */ - ro_gui_window_scroll_end(g, drag); -} - -/** - * Import text file into window or its toolbar - * - * \param g gui window containing textarea - * \param filename pathname of file to be imported - * \param toolbar true iff imported to toolbar rather than main window - * \return true iff successful - */ - -bool ro_gui_window_import_text(struct gui_window *g, const char *filename, - bool toolbar) -{ - fileswitch_object_type obj_type; - os_error *error; - char *buf, *utf8_buf; - int size; - utf8_convert_ret ret; - - error = xosfile_read_stamped(filename, &obj_type, NULL, NULL, - &size, NULL, NULL); - if (error) { - LOG(("xosfile_read_stamped: 0x%x:%s", - error->errnum, error->errmess)); - warn_user("FileError", error->errmess); - return true; /* was for us, but it didn't work! */ - } - - buf = malloc(size); - if (!buf) { - warn_user("NoMemory", NULL); - return true; - } - - error = xosfile_load_stamped(filename, (byte*)buf, - NULL, NULL, NULL, NULL, NULL); - if (error) { - LOG(("xosfile_load_stamped: 0x%x:%s", - error->errnum, error->errmess)); - warn_user("LoadError", error->errmess); - free(buf); - return true; - } - - ret = utf8_from_local_encoding(buf, size, &utf8_buf); - if (ret != UTF8_CONVERT_OK) { - /* bad encoding shouldn't happen */ - assert(ret != UTF8_CONVERT_BADENC); - LOG(("utf8_from_local_encoding failed")); - free(buf); - warn_user("NoMemory", NULL); - return true; - } - size = strlen(utf8_buf); - - if (toolbar) { - const char *ep = utf8_buf + size; - const char *sp; - char *p = utf8_buf; - - /* skip leading whitespace */ - while (isspace(*p)) p++; - - sp = p; - while (*p && *p != '\r' && *p != '\n') - p += utf8_next(p, ep - p, 0); - *p = '\0'; - - if (p > sp) - ro_gui_window_launch_url(g, sp); - } - else - browser_window_paste_text(g->bw, utf8_buf, size, true); - - free(buf); - free(utf8_buf); - return true; -} - - -/** - * Window is being iconised. Create a suitable thumbnail sprite - * (which, sadly, must be in the Wimp sprite pool), and return - * the sprite name and truncated title to the iconiser - * - * \param g the gui window being iconised - * \param wi the WindowInfo message from the iconiser - */ - -void ro_gui_window_iconise(struct gui_window *g, - wimp_full_message_window_info *wi) -{ - /* sadly there is no 'legal' way to get the sprite into - * the Wimp sprite pool other than via a filing system */ - const char *temp_fname = "Pipe:$._tmpfile"; - struct browser_window *bw = g->bw; - osspriteop_header *overlay = NULL; - osspriteop_header *sprite_header; - struct bitmap *bitmap; - osspriteop_area *area; - int width = 34, height = 34; - hlcache_handle *h; - os_error *error; - int len, id; - - assert(bw); - - h = bw->current_content; - if (!h) return; - - /* if an overlay sprite is defined, locate it and gets its dimensions - * so that we can produce a thumbnail with the same dimensions */ - if (!ro_gui_wimp_get_sprite("ic_netsfxx", &overlay)) { - error = xosspriteop_read_sprite_info(osspriteop_PTR, - (osspriteop_area *)0x100, - (osspriteop_id)overlay, &width, &height, NULL, - NULL); - if (error) { - LOG(("xosspriteop_read_sprite_info: 0x%x: %s", - error->errnum, error->errmess)); - warn_user("MiscError", error->errmess); - overlay = NULL; - } - else if (sprite_bpp(overlay) != 8) { - LOG(("overlay sprite is not 8bpp")); - overlay = NULL; - } - } - - /* create the thumbnail sprite */ - bitmap = bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE | - BITMAP_CLEAR_MEMORY); - if (!bitmap) { - LOG(("Thumbnail initialisation failed.")); - return; - } - thumbnail_create(h, bitmap, NULL); - if (overlay) - bitmap_overlay_sprite(bitmap, overlay); - area = thumbnail_convert_8bpp(bitmap); - bitmap_destroy(bitmap); - if (!area) { - LOG(("Thumbnail conversion failed.")); - return; - } - - /* choose a suitable sprite name */ - id = 0; - while (iconise_used[id]) - if ((unsigned)++id >= NOF_ELEMENTS(iconise_used)) { - id = iconise_next; - if ((unsigned)++iconise_next >= - NOF_ELEMENTS(iconise_used)) - iconise_next = 0; - break; - } - - sprite_header = (osspriteop_header *)(area + 1); - len = sprintf(sprite_header->name, "ic_netsf%.2d", id); - - error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, - area, temp_fname); - if (error) { - LOG(("xosspriteop_save_sprite_file: 0x%x:%s", - error->errnum, error->errmess)); - warn_user("MiscError", error->errmess); - free(area); - return; - } - - error = xwimpspriteop_merge_sprite_file(temp_fname); - if (error) { - LOG(("xwimpspriteop_merge_sprite_file: 0x%x:%s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - remove(temp_fname); - free(area); - return; - } - - memcpy(wi->sprite_name, sprite_header->name + 3, len - 2); /* inc NUL */ - strncpy(wi->title, g->title, sizeof(wi->title)); - wi->title[sizeof(wi->title) - 1] = '\0'; - - if (wimptextop_string_width(wi->title, 0) > 182) { - /* work around bug in Pinboard where it will fail to display - * the icon if the text is very wide */ - if (strlen(wi->title) > 10) - wi->title[10] = '\0'; /* pinboard does this anyway */ - while (wimptextop_string_width(wi->title, 0) > 182) - wi->title[strlen(wi->title) - 1] = '\0'; - } - - wi->size = sizeof(wimp_full_message_window_info); - wi->your_ref = wi->my_ref; - error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)wi, - wi->sender); - if (error) { - LOG(("xwimp_send_message: 0x%x:%s", - error->errnum, error->errmess)); - warn_user("WimpError", error->errmess); - } - else { - g->iconise_icon = id; - iconise_used[id] = true; - } - - free(area); -} - - -/** - * Navigate up one level - * - * \param g the gui_window to open the parent link in - * \param url the URL to open the parent of - */ -bool ro_gui_window_navigate_up(struct gui_window *g, const char *url) { - char *parent; - url_func_result res; - bool compare; - - if (!g || (!g->bw)) - return false; - - res = url_parent(url, &parent); - if (res == URL_FUNC_OK) { - res = url_compare(url, parent, false, &compare); - if ((res == URL_FUNC_OK) && !compare) - browser_window_go(g->bw, parent, 0, true); - free(parent); - } - return true; -} |