From f4ecaaed31db0aa5d71c05dd3f04dc2833ad29fe Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Sat, 16 Jul 2005 14:35:25 +0000 Subject: [project @ 2005-07-16 14:35:20 by jmb] - Convert Messages files to UTF-8 encoding. - Replace local_encoding_name() with platform specific utf8_[to,from]_local_encoding() functions - this allows mapping of 8bit characters 0x80->0x9f (inclusive). - All text that is rendered by the RISC OS Wimp is now converted to the system local encoding prior to display. - Lose the horrendous hack that was messages_get_key() - Menu text is now translated to system local encoding on the fly (if necessary) rather than at menu creation time. This allows the system alphabet to change under us and our menus remain usable. - The Languages menu now lists all languages that are present in the LangNames file. In the case of selecting the UI language, those languages which are not available are shaded. svn path=/import/netsurf/; revision=1796 --- riscos/dialog.c | 62 +++-- riscos/download.c | 51 +++- riscos/gui.h | 2 +- riscos/help.c | 24 +- riscos/menus.c | 751 ++++++++++++++++++++++++++++++++++++----------------- riscos/save.c | 33 ++- riscos/ucstables.c | 281 +++++++++++++++++++- riscos/wimp.c | 78 +++++- riscos/wimp.h | 2 + riscos/window.c | 23 +- 10 files changed, 989 insertions(+), 318 deletions(-) (limited to 'riscos') diff --git a/riscos/dialog.c b/riscos/dialog.c index 4baea65d0..505c09b4e 100644 --- a/riscos/dialog.c +++ b/riscos/dialog.c @@ -430,14 +430,14 @@ bool ro_gui_dialog_keypress(wimp_key *key) pointer.w = key->w; pointer.i = ICON_OPENURL_OPEN; pointer.buttons = wimp_CLICK_SELECT; - ro_gui_dialog_click_open_url(&pointer); + ro_gui_dialog_click_open_url(&pointer); } } #ifdef WITH_AUTH if (key->w == dialog_401li) return ro_gui_401login_keypress(key); #endif - + return false; } @@ -838,46 +838,44 @@ void ro_gui_save_options(void) void ro_gui_dialog_click_config_br(wimp_pointer *pointer) { switch (pointer->i) { - case ICON_CONFIG_BR_LANG_PICK: - /* drop through */ - case ICON_CONFIG_BR_ALANG_PICK: - config_br_icon = pointer->i; - ro_gui_popup_menu(languages_menu, dialog_config_br, - pointer->i); - break; + case ICON_CONFIG_BR_LANG_PICK: + ro_gui_menu_prepare_languages(false, ro_gui_choices_lang); + config_br_icon = pointer->i; + ro_gui_popup_menu(languages_menu, dialog_config_br, + pointer->i); + break; + case ICON_CONFIG_BR_ALANG_PICK: + ro_gui_menu_prepare_languages(true, ro_gui_choices_alang); + config_br_icon = pointer->i; + ro_gui_popup_menu(languages_menu, dialog_config_br, + pointer->i); + break; } } /** * Handle a selection from the language selection popup menu. * - * \param lang The language name (as returned by messages_get) + * \param lang The language messages key */ -void ro_gui_dialog_languages_menu_selection(char *lang) +void ro_gui_dialog_languages_menu_selection(const char *lang) { int offset = strlen("lang_"); - const char *temp = messages_get_key(lang); - if (temp == NULL) { - warn_user("MiscError", "Failed to retrieve message key"); - config_br_icon = -1; - return; - } - switch (config_br_icon) { - case ICON_CONFIG_BR_LANG_PICK: - ro_gui_choices_lang = temp + offset; - ro_gui_set_icon_string(dialog_config_br, - ICON_CONFIG_BR_LANG, - lang); - break; - case ICON_CONFIG_BR_ALANG_PICK: - ro_gui_choices_alang = temp + offset; - ro_gui_set_icon_string(dialog_config_br, - ICON_CONFIG_BR_ALANG, - lang); - break; + case ICON_CONFIG_BR_LANG_PICK: + ro_gui_choices_lang = lang + offset; + ro_gui_set_icon_string(dialog_config_br, ICON_CONFIG_BR_LANG, + messages_get(lang)); + ro_gui_menu_prepare_languages(false, ro_gui_choices_lang); + break; + case ICON_CONFIG_BR_ALANG_PICK: + ro_gui_choices_alang = lang + offset; + ro_gui_set_icon_string(dialog_config_br, + ICON_CONFIG_BR_ALANG, messages_get(lang)); + ro_gui_menu_prepare_languages(true, ro_gui_choices_alang); + break; } } @@ -1266,7 +1264,7 @@ void ro_gui_dialog_click_open_url(wimp_pointer *pointer) bool reopen_window = false; wimp_caret caret; os_error *error; - + if (pointer->i == ICON_OPENURL_MENU) { /* we can't have two open menus, so we close the iconbar menu * and detach our window from it */ @@ -1315,7 +1313,7 @@ void ro_gui_dialog_click_open_url(wimp_pointer *pointer) ro_gui_popup_menu(url_suggest_menu, dialog_openurl, ICON_OPENURL_MENU); - return; + return; } if ((pointer->i != ICON_OPENURL_OPEN) && diff --git a/riscos/download.c b/riscos/download.c index 3f64cd315..02c226c05 100644 --- a/riscos/download.c +++ b/riscos/download.c @@ -38,6 +38,7 @@ #include "netsurf/utils/log.h" #include "netsurf/utils/messages.h" #include "netsurf/utils/url.h" +#include "netsurf/utils/utf8.h" #include "netsurf/utils/utils.h" @@ -385,6 +386,8 @@ void ro_gui_download_update_status(struct gui_download_window *dw) float rate; os_error *error; int width; + char *local_status; + utf8_convert_ret err; gettimeofday(&t, 0); dt = (t.tv_sec + 0.000001 * t.tv_usec) - (dw->last_time.tv_sec + @@ -405,18 +408,47 @@ void ro_gui_download_update_status(struct gui_download_window *dw) left = (dw->total_size - dw->received) / rate; sprintf(time, "%u:%.2u", left / 60, left % 60); } - snprintf(dw->status, sizeof dw->status, + + /* convert to local encoding */ + err = utf8_to_local_encoding( + messages_get("Download"), 0, &local_status); + if (err != UTF8_CONVERT_OK) { + /* badenc should never happen */ + assert(err != UTF8_CONVERT_BADENC); + /* hide nomem error */ + snprintf(dw->status, sizeof dw->status, messages_get("Download"), received, total_size, speed, time); + } + else { + snprintf(dw->status, sizeof dw->status, + local_status, + received, total_size, speed, time); + free(local_status); + } f = (float) dw->received / (float) dw->total_size; width = download_progress_width * f; } else { left = t.tv_sec - dw->start_time.tv_sec; sprintf(time, "%u:%.2u", left / 60, left % 60); - snprintf(dw->status, sizeof dw->status, + + err = utf8_to_local_encoding( + messages_get("DownloadU"), 0, &local_status); + if (err != UTF8_CONVERT_OK) { + /* badenc should never happen */ + assert(err != UTF8_CONVERT_BADENC); + /* hide nomem error */ + snprintf(dw->status, sizeof dw->status, messages_get("DownloadU"), received, speed, time); + } + else { + snprintf(dw->status, sizeof dw->status, + local_status, + received, speed, time); + free(local_status); + } /* length unknown, stay at 0 til finished */ width = 0; @@ -428,9 +460,22 @@ void ro_gui_download_update_status(struct gui_download_window *dw) rate = (float) dw->received / (float) left; sprintf(time, "%u:%.2u", left / 60, left % 60); speed = human_friendly_bytesize(rate); - snprintf(dw->status, sizeof dw->status, + + err = utf8_to_local_encoding(messages_get("DownloadU"), 0, + &local_status); + if (err != UTF8_CONVERT_OK) { + /* badenc should never happen */ + assert(err != UTF8_CONVERT_BADENC); + /* hide nomem error */ + snprintf(dw->status, sizeof dw->status, messages_get("Downloaded"), total_size, speed, time); + } + else { + snprintf(dw->status, sizeof dw->status, local_status, + total_size, speed, time); + free(local_status); + } /* all done */ width = download_progress_width; diff --git a/riscos/gui.h b/riscos/gui.h index 2ab7f7084..3b24d0738 100644 --- a/riscos/gui.h +++ b/riscos/gui.h @@ -115,7 +115,7 @@ void ro_gui_dialog_close(wimp_w close); void ro_gui_dialog_open_config(void); void ro_gui_dialog_proxyauth_menu_selection(int item); void ro_gui_dialog_image_menu_selection(int item); -void ro_gui_dialog_languages_menu_selection(char *lang); +void ro_gui_dialog_languages_menu_selection(const char *lang); void ro_gui_dialog_font_menu_selection(int item); void ro_gui_dialog_redraw(wimp_draw *redraw); diff --git a/riscos/help.c b/riscos/help.c index bc5494c45..50f6912ce 100644 --- a/riscos/help.c +++ b/riscos/help.c @@ -9,6 +9,7 @@ * Interactive help (implementation). */ +#include #include #include #include "oslib/help.h" @@ -24,6 +25,7 @@ #include "netsurf/riscos/wimp.h" #include "netsurf/utils/messages.h" #include "netsurf/utils/log.h" +#include "netsurf/utils/utf8.h" #include "netsurf/utils/utils.h" @@ -158,7 +160,7 @@ void ro_gui_interactive_help_request(wimp_message *message) { sprintf(message_token, "HelpToolbar%i", (int)icon); } else if ((g = ro_gui_status_lookup(window)) != NULL) sprintf(message_token, "HelpStatus%i", (int)icon); - + /* change toolbars to editors where appropriate */ if ((toolbar) && (toolbar->editor)) sprintf(message_token, "HelpEditToolbar%i", (int)icon); @@ -233,7 +235,9 @@ static void ro_gui_interactive_help_broadcast(wimp_message *message, const char *translated_token; help_full_message_reply *reply; char *base_token; + char *local_token; os_error *error; + utf8_convert_ret err; /* start off with an empty reply */ reply = (help_full_message_reply *)message; @@ -260,8 +264,20 @@ static void ro_gui_interactive_help_broadcast(wimp_message *message, /* copy our message string */ if (translated_token != token) { - reply->reply[235] = 0; - strncpy(reply->reply, translated_token, 235); + /* convert to local encoding */ + err = utf8_to_local_encoding(translated_token, 0, + &local_token); + if (err != UTF8_CONVERT_OK) { + /* badenc should never happen */ + assert(err != UTF8_CONVERT_BADENC); + /* simply use UTF-8 string */ + strncpy(reply->reply, translated_token, 235); + } + else { + strncpy(reply->reply, local_token, 235); + free(local_token); + } + reply->reply[235] = '\0'; } /* broadcast the help reply */ @@ -303,7 +319,7 @@ bool ro_gui_interactive_help_available(void) { error->errnum, error->errmess)); warn_user("MiscError", error->errmess); } - + /* we can't just use strcmp due to string termination issues */ if (!strncmp(task.name, "Help", 4) && (task.name[4] < 32)) diff --git a/riscos/menus.c b/riscos/menus.c index 86272a112..c294b9869 100644 --- a/riscos/menus.c +++ b/riscos/menus.c @@ -12,10 +12,13 @@ * Menu creation and handling (implementation). */ +#include #include #include #include "oslib/os.h" +#include "oslib/osbyte.h" #include "oslib/osgbpb.h" +#include "oslib/territory.h" #include "oslib/wimp.h" #include "netsurf/desktop/gui.h" #include "netsurf/render/box.h" @@ -56,11 +59,14 @@ struct ns_menu { struct menu_definition_entry { menu_action action; /**< menu action */ wimp_menu_entry *menu_entry; /**< corresponding menu entry */ + const char *entry_key; /**< Messages key for entry text */ struct menu_definition_entry *next; /**< next menu entry */ }; struct menu_definition { wimp_menu *menu; /**< corresponding menu */ + const char *title_key; /**< Messages key for title text */ + int current_encoding; /**< Identifier for current text encoding of menu text (as per OS_Byte,71,127) */ struct menu_definition_entry *entries; /**< menu entries */ struct menu_definition *next; /**< next menu */ }; @@ -68,7 +74,8 @@ struct menu_definition { static wimp_menu *ro_gui_menu_define_menu(struct ns_menu *menu); static void ro_gui_menu_define_menu_add(struct menu_definition *definition, - struct ns_menu *menu, int depth, wimp_menu_entry *link, + struct ns_menu *menu, int depth, + wimp_menu_entry *parent_entry, int first, int last, const char *prefix, int prefix_length); static struct menu_definition *ro_gui_menu_find_menu(wimp_menu *menu); static struct menu_definition_entry *ro_gui_menu_find_entry(wimp_menu *menu, @@ -87,6 +94,7 @@ static bool ro_gui_menu_prepare_url_suggest(void); static void ro_gui_menu_prepare_pageinfo(struct gui_window *g); static void ro_gui_menu_prepare_objectinfo(struct box *box); static void ro_gui_menu_refresh_toolbar(struct toolbar *toolbar); +static bool ro_gui_menu_translate(struct menu_definition *menu); /* default menu item flags */ @@ -119,18 +127,16 @@ wimp_menu *iconbar_menu, *browser_menu, *hotlist_menu, *global_history_menu, static wimp_MENU(GLOBAL_HISTORY_RECENT_URLS) url_suggest; wimp_menu *url_suggest_menu = (wimp_menu *)&url_suggest; +/* the values given in PRM 3-157 for how to check menus/windows are + * incorrect so we use a hack of checking if the sub-menu is within + * 256KB of its parent */ +#define IS_MENU(menu, submenu) (abs((int)(submenu) - (int)(menu)) < 0x40000) /** * Create menu structures. */ -void ro_gui_menu_init(void) { - int context = 0, read_count, entries = 0; - os_error *error; - osgbpb_INFO(100) info; - char lang[8] = {0}; - char *lang_name; - void *temp; - +void ro_gui_menu_init(void) +{ /* iconbar menu */ NS_MENU(9) iconbar_definition = { "NetSurf", { @@ -162,7 +168,7 @@ void ro_gui_menu_init(void) { { "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.Print", BROWSER_PRINT, dialog_print }, { "Page.NewWindow", BROWSER_NEW_WINDOW, 0 }, { "Page.ViewSrc", BROWSER_VIEW_SOURCE, 0 }, { "Object", BROWSER_OBJECT, 0 }, @@ -170,7 +176,7 @@ void ro_gui_menu_init(void) { { "Object.ObjSave", BROWSER_OBJECT_SAVE, dialog_saveas }, { "Object.Export", NO_ACTION, 0 }, { "Object.Export.Sprite", BROWSER_OBJECT_EXPORT_SPRITE, dialog_saveas }, - { "Object.SaveURL_", NO_ACTION, 0 }, + { "_Object.SaveURL", NO_ACTION, 0 }, { "Object.SaveURL.URI", BROWSER_OBJECT_SAVE_URL_URI, dialog_saveas }, { "Object.SaveURL.URL", BROWSER_OBJECT_SAVE_URL_URL, dialog_saveas }, { "Object.SaveURL.LinkText", BROWSER_OBJECT_SAVE_URL_TEXT, dialog_saveas }, @@ -178,7 +184,7 @@ void ro_gui_menu_init(void) { { "Navigate", NO_ACTION, 0 }, { "Navigate.Home", BROWSER_NAVIGATE_HOME, 0 }, { "Navigate.Back", BROWSER_NAVIGATE_BACK, 0 }, - { "Navigate.Forward_", BROWSER_NAVIGATE_FORWARD, 0 }, + { "_Navigate.Forward", BROWSER_NAVIGATE_FORWARD, 0 }, { "Navigate.Reload", BROWSER_NAVIGATE_RELOAD_ALL, 0 }, { "Navigate.Stop", BROWSER_NAVIGATE_STOP, 0 }, { "View", NO_ACTION, 0 }, @@ -190,9 +196,9 @@ void ro_gui_menu_init(void) { { "View.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, { "View.Toolbars.ToolAddress", TOOLBAR_ADDRESS_BAR, 0 }, { "View.Toolbars.ToolThrob", TOOLBAR_THROBBER, 0 }, - { "View.Toolbars.ToolStatus_", TOOLBAR_STATUS_BAR, 0 }, + { "_View.Toolbars.ToolStatus", TOOLBAR_STATUS_BAR, 0 }, { "View.Toolbars.EditToolbar", TOOLBAR_EDIT, 0 }, - { "View.Render_", NO_ACTION, 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 }, @@ -207,13 +213,13 @@ void ro_gui_menu_init(void) { { "Utilities.Window", NO_ACTION, 0 }, { "Utilities.Window.WindowSave", BROWSER_WINDOW_DEFAULT, 0 }, { "Utilities.Window.WindowStagr", BROWSER_WINDOW_STAGGER, 0 }, - { "Utilities.Window.WindowSize_", BROWSER_WINDOW_COPY, 0 }, + { "_Utilities.Window.WindowSize", BROWSER_WINDOW_COPY, 0 }, { "Utilities.Window.WindowReset", BROWSER_WINDOW_RESET, 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.HelpInfo", HELP_OPEN_INFORMATION, 0 }, + { "_Help.HelpAbout", HELP_OPEN_ABOUT, 0 }, { "Help.HelpInter", HELP_LAUNCH_INTERACTIVE, 0 }, {NULL, 0, 0} } @@ -228,7 +234,7 @@ void ro_gui_menu_init(void) { { "Hotlist.New", NO_ACTION, 0 }, { "Hotlist.New.Folder", TREE_NEW_FOLDER, dialog_folder }, { "Hotlist.New.Link", TREE_NEW_LINK, dialog_entry }, - { "Hotlist.Export_", HOTLIST_EXPORT, dialog_saveas }, + { "_Hotlist.Export", HOTLIST_EXPORT, dialog_saveas }, { "Hotlist.Expand", TREE_EXPAND_ALL, 0 }, { "Hotlist.Expand.All", TREE_EXPAND_ALL, 0 }, { "Hotlist.Expand.Folders", TREE_EXPAND_FOLDERS, 0 }, @@ -238,7 +244,7 @@ void ro_gui_menu_init(void) { { "Hotlist.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 }, { "Hotlist.Collapse.Links", TREE_COLLAPSE_LINKS, 0 }, { "Hotlist.Toolbars", NO_ACTION, 0 }, - { "Hotlist.Toolbars.ToolButtons_", TOOLBAR_BUTTONS, 0 }, + { "_Hotlist.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, { "Hotlist.Toolbars.EditToolbar", TOOLBAR_EDIT, 0 }, { "Selection", TREE_SELECTION, 0 }, { "Selection.Edit", TREE_SELECTION_EDIT, (wimp_w)1 }, @@ -257,7 +263,7 @@ void ro_gui_menu_init(void) { NS_MENU(19) global_history_definition = { "History", { { "History", NO_ACTION, 0 }, - { "History.Export_", HISTORY_EXPORT, dialog_saveas }, + { "_History.Export", HISTORY_EXPORT, dialog_saveas }, { "History.Expand", TREE_EXPAND_ALL, 0 }, { "History.Expand.All", TREE_EXPAND_ALL, 0 }, { "History.Expand.Folders", TREE_EXPAND_FOLDERS, 0 }, @@ -267,7 +273,7 @@ void ro_gui_menu_init(void) { { "History.Collapse.Folders", TREE_COLLAPSE_FOLDERS, 0 }, { "History.Collapse.Links", TREE_COLLAPSE_LINKS, 0 }, { "History.Toolbars", NO_ACTION, 0 }, - { "History.Toolbars.ToolButtons_", TOOLBAR_BUTTONS, 0 }, + { "_History.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 }, { "History.Toolbars.EditToolbar",TOOLBAR_EDIT, 0 }, { "Selection", TREE_SELECTION, 0 }, { "Selection.Launch", TREE_SELECTION_LAUNCH, 0 }, @@ -343,56 +349,62 @@ void ro_gui_menu_init(void) { url_suggest_menu->height = wimp_MENU_ITEM_HEIGHT; url_suggest_menu->gap = wimp_MENU_ITEM_GAP; - /* language menu */ - languages_menu = calloc(1, wimp_SIZEOF_MENU(1)); - if (!languages_menu) - die("Insufficient memory for languages menu."); - languages_menu->title_data.indirected_text.text = - messages_get("Languages"); - languages_menu->title_fg = wimp_COLOUR_BLACK; - languages_menu->title_bg = wimp_COLOUR_LIGHT_GREY; - languages_menu->work_fg = wimp_COLOUR_BLACK; - languages_menu->work_bg = wimp_COLOUR_WHITE; - languages_menu->width = 200; - languages_menu->height = wimp_MENU_ITEM_HEIGHT; - languages_menu->gap = wimp_MENU_ITEM_GAP; - - while (context != -1) { - error = xosgbpb_dir_entries_info(".Resources", - (osgbpb_info_list*)&info, 1, context, - sizeof(info), 0, &read_count, &context); - if (error) - die(error->errmess); - if ((read_count == 0) || (info.obj_type != fileswitch_IS_DIR)) - continue; - - snprintf(lang, sizeof lang, "lang_%2s", info.name); - /* we can't duplicate the string returned from our messages as - * it causes value->key lookups to fail */ - lang_name = messages_get(lang); - if ((lang_name == lang) || (strlen(info.name) != 2)) - continue; - - temp = realloc(languages_menu, wimp_SIZEOF_MENU(entries + 1)); - if (!temp) - die("Insufficient memory for languages menu"); - - languages_menu = temp; - languages_menu->entries[entries].menu_flags = 0; - languages_menu->entries[entries].sub_menu = wimp_NO_SUB_MENU; - languages_menu->entries[entries].icon_flags = DEFAULT_FLAGS | - wimp_ICON_INDIRECTED; - languages_menu->entries[entries].data.indirected_text.text = - lang_name; - languages_menu->entries[entries].data.indirected_text. - validation = (char *)-1; - languages_menu->entries[entries].data.indirected_text.size = - strlen(lang_name) + 1; - entries++; - } + /* Note: This table *must* be kept in sync with the LangNames file */ + NS_MENU(48) lang_definition = { + "Languages", { + { "lang_af", NO_ACTION, 0 }, + { "lang_bm", NO_ACTION, 0 }, + { "lang_ca", NO_ACTION, 0 }, + { "lang_cs", NO_ACTION, 0 }, + { "lang_cy", NO_ACTION, 0 }, + { "lang_da", NO_ACTION, 0 }, + { "lang_de", NO_ACTION, 0 }, + { "lang_en", NO_ACTION, 0 }, + { "lang_es", NO_ACTION, 0 }, + { "lang_et", NO_ACTION, 0 }, + { "lang_eu", NO_ACTION, 0 }, + { "lang_ff", NO_ACTION, 0 }, + { "lang_fi", NO_ACTION, 0 }, + { "lang_fr", NO_ACTION, 0 }, + { "lang_ga", NO_ACTION, 0 }, + { "lang_gl", NO_ACTION, 0 }, + { "lang_ha", NO_ACTION, 0 }, + { "lang_hr", NO_ACTION, 0 }, + { "lang_hu", NO_ACTION, 0 }, + { "lang_id", NO_ACTION, 0 }, + { "lang_is", NO_ACTION, 0 }, + { "lang_it", NO_ACTION, 0 }, + { "lang_lt", NO_ACTION, 0 }, + { "lang_lv", NO_ACTION, 0 }, + { "lang_ms", NO_ACTION, 0 }, + { "lang_mt", NO_ACTION, 0 }, + { "lang_nl", NO_ACTION, 0 }, + { "lang_no", NO_ACTION, 0 }, + { "lang_pl", NO_ACTION, 0 }, + { "lang_pt", NO_ACTION, 0 }, + { "lang_rn", NO_ACTION, 0 }, + { "lang_ro", NO_ACTION, 0 }, + { "lang_rw", NO_ACTION, 0 }, + { "lang_sk", NO_ACTION, 0 }, + { "lang_sl", NO_ACTION, 0 }, + { "lang_so", NO_ACTION, 0 }, + { "lang_sq", NO_ACTION, 0 }, + { "lang_sr", NO_ACTION, 0 }, + { "lang_sv", NO_ACTION, 0 }, + { "lang_sw", NO_ACTION, 0 }, + { "lang_tr", NO_ACTION, 0 }, + { "lang_uz", NO_ACTION, 0 }, + { "lang_vi", NO_ACTION, 0 }, + { "lang_wo", NO_ACTION, 0 }, + { "lang_xs", NO_ACTION, 0 }, + { "lang_yo", NO_ACTION, 0 }, + { "lang_zu", NO_ACTION, 0 }, + { NULL, 0, 0 } + } + }; - languages_menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED; - languages_menu->entries[entries-1].menu_flags |= wimp_MENU_LAST; + languages_menu = ro_gui_menu_define_menu( + (struct ns_menu *)&lang_definition); } @@ -406,6 +418,17 @@ void ro_gui_menu_create(wimp_menu *menu, int x, int y, wimp_w w) { os_error *error; int i; menu_action action; + struct menu_definition *definition; + + /* translate menu, if necessary (this returns quickly + * if there's nothing to be done) */ + definition = ro_gui_menu_find_menu(menu); + if (definition) { + if (!ro_gui_menu_translate(definition)) { + warn_user("NoMemory", 0); + return; + } + } /* read the object under the pointer for a new gui_window menu */ if ((!current_menu) && (menu == browser_menu)) { @@ -555,8 +578,9 @@ void ro_gui_menu_selection(wimp_selection *selection) { wimp_menu *menu; os_error *error; - /* if we are using gui_multitask then menu selection events may be delivered - * after the menu has been closed. As such, we simply ignore these events. */ + /* if we are using gui_multitask then menu selection events + * may be delivered after the menu has been closed. As such, + * we simply ignore these events. */ if (!current_menu) return assert(current_menu_window); @@ -595,9 +619,18 @@ void ro_gui_menu_selection(wimp_selection *selection) { } else if (current_menu == image_quality_menu) { ro_gui_dialog_image_menu_selection(selection->items[0]); } else if (current_menu == languages_menu) { - ro_gui_dialog_languages_menu_selection(languages_menu-> - entries[selection->items[0]]. - data.indirected_text.text); + struct menu_definition *desc; + struct menu_definition_entry *entry; + + /* find the relevant menu definition entry */ + desc = ro_gui_menu_find_menu(current_menu); + for (entry = desc->entries; entry; entry = entry->next) + if (entry->menu_entry == menu_entry) + break; + if (entry) + /* found it, so handle the seletion */ + ro_gui_dialog_languages_menu_selection( + entry->entry_key); } else if (current_menu == font_menu) { ro_gui_dialog_font_menu_selection(selection->items[0]); } else if ((current_menu == gui_form_select_menu) && @@ -660,7 +693,6 @@ void ro_gui_menu_warning(wimp_message_menu_warning *warning) { wimp_menu_entry *menu_entry; wimp_menu *sub_menu; os_error *error; - int menu_check; assert(current_menu); assert(current_menu_window); @@ -673,11 +705,7 @@ void ro_gui_menu_warning(wimp_message_menu_warning *warning) { menu_entry = &menu_entry->sub_menu-> entries[warning->selection.items[i]]; - /* the values given in PRM 3-157 for how to check menus/windows are - * incorrect so we use a hack of checking if the sub-menu is within - * 256KB of its parent */ - menu_check = abs((int)menu_entry->sub_menu - (int)menu_entry); - if (menu_check < 0x40000) { + if (IS_MENU(menu_entry, menu_entry->sub_menu)) { sub_menu = menu_entry->sub_menu; i = 0; do { @@ -778,9 +806,11 @@ void ro_gui_prepare_navigate(struct gui_window *gui) { ro_gui_menu_prepare_action(gui->window, HOTLIST_SHOW, false); ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_STOP, false); - ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_RELOAD_ALL, false); + ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_RELOAD_ALL, + false); ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_BACK, false); - ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_FORWARD, false); + ro_gui_menu_prepare_action(gui->window, BROWSER_NAVIGATE_FORWARD, + false); ro_gui_menu_prepare_action(gui->window, HOTLIST_SHOW, false); ro_gui_menu_prepare_action(gui->window, BROWSER_SAVE, false); ro_gui_menu_prepare_action(gui->window, BROWSER_PRINT, false); @@ -893,6 +923,40 @@ void ro_gui_menu_prepare_objectinfo(struct box *box) { } +/** + * Prepare languages menu for use + * + * \param accept For Accept-Languages selection + * \param lang Currently selected language + */ +void ro_gui_menu_prepare_languages(bool accept, const char *lang) +{ + struct menu_definition *menu; + struct menu_definition_entry *entry; + char path_buf[40]; + int offset = strlen("lang_"); + + menu = ro_gui_menu_find_menu(languages_menu); + for (entry = menu->entries; entry; entry = entry->next) { + if (!accept) { + snprintf(path_buf, sizeof path_buf, + ".Resources.%.2s", + entry->entry_key + offset); + + entry->menu_entry->icon_flags |= is_dir(path_buf) ? + 0 : wimp_ICON_SHADED; + } + else + entry->menu_entry->icon_flags &= ~wimp_ICON_SHADED; + + /* set ticked status */ + if (strncmp(lang, entry->entry_key + offset, 2) == 0) + entry->menu_entry->menu_flags |= wimp_MENU_TICKED; + else + entry->menu_entry->menu_flags &= ~wimp_MENU_TICKED; + } +} + /** * Display a menu of options for a form select control. * @@ -902,7 +966,7 @@ void ro_gui_menu_prepare_objectinfo(struct box *box) { void gui_create_form_select_menu(struct browser_window *bw, struct form_control *control) { unsigned int i = 0, j; - char *text_convert; + char *text_convert, *temp, *s; struct form_option *option; wimp_pointer pointer; os_error *error; @@ -911,7 +975,8 @@ void gui_create_form_select_menu(struct browser_window *bw, assert(control); - for (option = control->data.select.items; option; option = option->next) + for (option = control->data.select.items; option; + option = option->next) i++; if (i == 0) { ro_gui_menu_closed(); @@ -926,6 +991,7 @@ void gui_create_form_select_menu(struct browser_window *bw, wimp_MENU_LAST) break; } + free(gui_form_select_menu->title_data.indirected_text.text); free(gui_form_select_menu); gui_form_select_menu = 0; } @@ -938,8 +1004,18 @@ void gui_create_form_select_menu(struct browser_window *bw, ro_gui_menu_closed(); return; } + err = utf8_to_local_encoding(messages_get("SelectMenu"), 0, + &text_convert); + if (err != UTF8_CONVERT_OK) { + /* badenc should never happen */ + assert(err != UTF8_CONVERT_BADENC); + LOG(("utf8_to_local_encoding failed")); + warn_user("NoMemory", 0); + ro_gui_menu_closed(); + return; + } gui_form_select_menu->title_data.indirected_text.text = - messages_get("SelectMenu"); + text_convert; gui_form_select_menu->title_fg = wimp_COLOUR_BLACK; gui_form_select_menu->title_bg = wimp_COLOUR_LIGHT_GREY; gui_form_select_menu->work_fg = wimp_COLOUR_BLACK; @@ -963,8 +1039,24 @@ void gui_create_form_select_menu(struct browser_window *bw, wimp_ICON_FG_COLOUR_SHIFT) | (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT); - err = utf8_to_enc(option->text, - local_encoding_name(), 0, &text_convert); + temp = cnv_space2nbsp(option->text); + if (!temp) { + LOG(("cnv_space2nbsp failed")); + warn_user("NoMemory", 0); + ro_gui_menu_closed(); + return; + } + + /* 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. + */ + for (s = temp; *s != '\0'; s++) + if (*s == 0x20) + *s = 0xa0; + + err = utf8_to_local_encoding(option->text, + 0, &text_convert); if (err != UTF8_CONVERT_OK) { /* A bad encoding should never happen, * so assert this */ @@ -975,15 +1067,11 @@ void gui_create_form_select_menu(struct browser_window *bw, return; } + free(temp); + gui_form_select_menu->entries[i].data.indirected_text.text = text_convert; - /* 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. */ - text_convert -= 1; - while (*++text_convert != '\0') - if (*text_convert == 0x20) - *text_convert = 0xa0; + gui_form_select_menu->entries[i].data.indirected_text. validation = (char *)-1; gui_form_select_menu->entries[i].data.indirected_text.size = @@ -1029,22 +1117,45 @@ wimp_menu *ro_gui_menu_define_menu(struct ns_menu *menu) { definition->next = ro_gui_menu_definitions; ro_gui_menu_definitions = definition; + /* count number of menu entries */ + for (entry = 0; menu->entries[entry].text; entry++) + /* do nothing */; + /* create our definitions */ - for (entry = 0; menu->entries[entry].text; entry++); ro_gui_menu_define_menu_add(definition, menu, 0, NULL, 0, entry, NULL, 0); + + /* and translate menu into current encoding */ + if (!ro_gui_menu_translate(definition)) + die("No memory to translate menu."); + return definition->menu; } +/** + * Create a wimp menu tree from ns_menu data. + * This function does *not* deal with the menu textual content - it simply + * creates and populates the appropriate structures. Textual content is + * generated by ro_gui_menu_translate_menu() + * + * \param definition Top level menu definition + * \param menu Menu declaration data + * \param depth Depth of menu we're currently building + * \param parent_entry Entry in parent menu, or NULL if root menu + * \param first First index in declaration data that is used by this menu + * \param last Last index in declaration data that is used by this menu + * \param prefix Prefix pf menu declaration string already seen + * \param prefix_length Length of prefix + */ void ro_gui_menu_define_menu_add(struct menu_definition *definition, - struct ns_menu *menu, int depth, wimp_menu_entry *link, - int first, int last, const char *prefix, int prefix_length) { - int entry, id, cur_depth, new_prefix_length; + struct ns_menu *menu, int depth, + wimp_menu_entry *parent_entry, int first, int last, + const char *prefix, int prefix_length) { + int entry, id, cur_depth; int entries = 0; int matches[last - first + 1]; const char *match; - char *text, *menu_text, *search; - char *title, *translated; + const char *text, *menu_text; wimp_menu *new_menu; struct menu_definition_entry *definition_entry; @@ -1052,33 +1163,49 @@ void ro_gui_menu_define_menu_add(struct menu_definition *definition, for (entry = first; entry < last; entry++) { cur_depth = 0; match = menu->entries[entry].text; + + /* skip specials at start of string */ + while (!isalnum(*match)) + match++; + + /* attempt prefix match */ if ((prefix) && (strncmp(match, prefix, prefix_length))) continue; + + /* Find depth of this entry */ while (*match) if (*match++ == '.') cur_depth++; + if (depth == cur_depth) matches[entries++] = entry; } matches[entries] = last; - /* step 2: build and link the menu. we must use realloc to stop - * our memory fragmenting so we can test for sub-menus easily */ + /* no entries, so exit */ if (entries == 0) return; + + /* step 2: build and link the menu. we must use realloc to stop + * our memory fragmenting so we can test for sub-menus easily */ new_menu = (wimp_menu *)malloc(wimp_SIZEOF_MENU(entries)); if (!new_menu) die("No memory to create menu."); - if (link) { - title = link->data.indirected_text.text; - link->sub_menu = new_menu; + + if (parent_entry) { + /* Fix up sub menu pointer */ + parent_entry->sub_menu = new_menu; } else { - title = messages_get(menu->title); - if (!title) - die("No memory to translate root menu title"); + /* Root menu => fill in definition struct */ + definition->title_key = menu->title; + definition->current_encoding = 0; definition->menu = new_menu; } - new_menu->title_data.indirected_text.text = title; + + /* this is fixed up in ro_gui_menu_translate() */ + new_menu->title_data.indirected_text.text = NULL; + + /* fill in menu flags */ new_menu->title_fg = wimp_COLOUR_BLACK; new_menu->title_bg = wimp_COLOUR_LIGHT_GREY; new_menu->work_fg = wimp_COLOUR_BLACK; @@ -1086,71 +1213,70 @@ void ro_gui_menu_define_menu_add(struct menu_definition *definition, new_menu->width = 200; new_menu->height = wimp_MENU_ITEM_HEIGHT; new_menu->gap = wimp_MENU_ITEM_GAP; + + /* and then create the entries */ for (entry = 0; entry < entries; entry++) { /* add the entry */ id = matches[entry]; - text = strdup(menu->entries[id].text); - if (!text) - die("No memory to examine menu text"); - search = menu_text = text; - while (*search) - if (*search++ == '.') - menu_text = search; + + text = menu->entries[id].text; + + /* fill in menu flags from specials at start of string */ new_menu->entries[entry].menu_flags = 0; - search = menu_text; - while (*search) - if (*search++ == '_') { + while (!isalnum(*text)) { + if (*text == '_') new_menu->entries[entry].menu_flags |= - wimp_MENU_SEPARATE; - search[-1] = 0; - break; - } + wimp_MENU_SEPARATE; + text++; + } + + /* get messages key for menu entry */ + menu_text = strrchr(text, '.'); + if (!menu_text) + /* no '.' => top-level entry */ + menu_text = text; + else + menu_text++; /* and move past the '.' */ + + /* fill in submenu data */ if (menu->entries[id].sub_window) - new_menu->entries[entry].sub_menu = (wimp_menu *)menu-> - entries[id].sub_window; + new_menu->entries[entry].sub_menu = + (wimp_menu *)menu->entries[id].sub_window; else new_menu->entries[entry].sub_menu = wimp_NO_SUB_MENU; + + /* icon flags */ new_menu->entries[entry].icon_flags = DEFAULT_FLAGS | wimp_ICON_INDIRECTED; - translated = messages_get(menu_text); - if (translated != menu_text) - free(text); - new_menu->entries[entry].data.indirected_text.text = translated; - new_menu->entries[entry].data.indirected_text.validation = - (char *)-1; - new_menu->entries[entry].data.indirected_text.size = - strlen(translated); - /* store action */ - if (menu->entries[id].action != NO_ACTION) { - definition_entry = malloc( - sizeof(struct menu_definition_entry)); - if (!definition_entry) - die("Unable to create menu definition entry"); - definition_entry->action = menu->entries[id].action; - definition_entry->menu_entry = - &new_menu->entries[entry]; - definition_entry->next = definition->entries; - definition->entries = definition_entry; - } + /* this is fixed up in ro_gui_menu_translate() */ + new_menu->entries[entry].data.indirected_text.text = NULL; + + /* create definition entry */ + definition_entry = + malloc(sizeof(struct menu_definition_entry)); + if (!definition_entry) + die("Unable to create menu definition entry"); + definition_entry->action = menu->entries[id].action; + definition_entry->menu_entry = &new_menu->entries[entry]; + definition_entry->entry_key = menu_text; + definition_entry->next = definition->entries; + definition->entries = definition_entry; /* recurse */ if (new_menu->entries[entry].sub_menu == wimp_NO_SUB_MENU) { - new_prefix_length = strlen(menu->entries[id].text); - if (menu->entries[id].text[new_prefix_length - 1] == '_') - new_prefix_length--; - ro_gui_menu_define_menu_add(definition, menu, depth + 1, - &new_menu->entries[entry], + ro_gui_menu_define_menu_add(definition, menu, + depth + 1, &new_menu->entries[entry], matches[entry], matches[entry + 1], - menu->entries[id].text, - new_prefix_length); + text, strlen(text)); } /* give menu warnings */ if (new_menu->entries[entry].sub_menu != wimp_NO_SUB_MENU) new_menu->entries[entry].menu_flags |= - wimp_MENU_GIVE_WARNING; + wimp_MENU_GIVE_WARNING; } + new_menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED; new_menu->entries[entries - 1].menu_flags |= wimp_MENU_LAST; } @@ -1268,7 +1394,8 @@ void ro_gui_menu_set_entry_ticked(wimp_menu *menu, menu_action action, * \param windows_at_pointer whether to open any windows at the pointer location */ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, - bool windows_at_pointer) { + bool windows_at_pointer) +{ wimp_window_state state; struct gui_window *g = NULL; struct browser_window *bw = NULL; @@ -1296,7 +1423,8 @@ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, ro_gui_open_help_page("info"); return true; case HELP_OPEN_ABOUT: - browser_window_create("file://Docs/about", + browser_window_create( + "file://Docs/about", 0, 0); return true; case HELP_LAUNCH_INTERACTIVE: @@ -1307,7 +1435,8 @@ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, case HISTORY_SHOW_LOCAL: if ((!bw) || (!bw->history)) return false; - ro_gui_history_open(bw, bw->history, windows_at_pointer); + ro_gui_history_open(bw, bw->history, + windows_at_pointer); return true; case HISTORY_SHOW_GLOBAL: ro_gui_tree_show(global_history_tree); @@ -1323,7 +1452,8 @@ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, return false; } node = tree_create_URL_node(hotlist_tree->root, - c->title, norm_url, ro_content_filetype(c), + c->title, norm_url, + ro_content_filetype(c), time(NULL), -1, 0); free(norm_url); if (node) { @@ -1346,15 +1476,15 @@ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, if (!c) return false; ro_gui_menu_prepare_action(owner, action, true); - ro_gui_dialog_open_persistent(g->window, dialog_pageinfo, - windows_at_pointer); + ro_gui_dialog_open_persistent(g->window, + dialog_pageinfo, windows_at_pointer); return true; case BROWSER_PRINT: if (!c) return false; ro_gui_menu_prepare_action(owner, action, true); - ro_gui_dialog_open_persistent(g->window, dialog_print, - windows_at_pointer); + ro_gui_dialog_open_persistent(g->window, + dialog_print, windows_at_pointer); return true; case BROWSER_NEW_WINDOW: if (!c) @@ -1372,8 +1502,8 @@ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, if (!current_menu_object_box) return false; ro_gui_menu_prepare_action(owner, action, true); - ro_gui_dialog_open_persistent(g->window, dialog_objinfo, - windows_at_pointer); + ro_gui_dialog_open_persistent(g->window, + dialog_objinfo, windows_at_pointer); return true; case BROWSER_OBJECT_RELOAD: if (!current_menu_object_box) @@ -1410,8 +1540,10 @@ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, case BROWSER_NAVIGATE_HOME: if (!bw) return false; - if ((option_homepage_url) && (option_homepage_url[0])) { - browser_window_go(g->bw, option_homepage_url, 0); + if ((option_homepage_url) && + (option_homepage_url[0])) { + browser_window_go(g->bw, + option_homepage_url, 0); } else { snprintf(url, sizeof url, "file://Docs/intro_%s", @@ -1459,24 +1591,27 @@ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, if (!c || c->type != CONTENT_HTML) return false; ro_gui_menu_prepare_action(owner, action, true); - ro_gui_dialog_open_persistent(g->window, dialog_search, - windows_at_pointer); + ro_gui_dialog_open_persistent(g->window, + dialog_search, windows_at_pointer); return true; case BROWSER_IMAGES_BACKGROUND: if (!g) return false; - g->option.background_images = !g->option.background_images; + g->option.background_images = + !g->option.background_images; gui_window_redraw_window(g); return true; case BROWSER_BUFFER_ANIMS: if (!g) return false; - g->option.buffer_animations = !g->option.buffer_animations; + g->option.buffer_animations = + !g->option.buffer_animations; break; case BROWSER_BUFFER_ALL: if (!g) return false; - g->option.buffer_everything = !g->option.buffer_everything; + g->option.buffer_everything = + !g->option.buffer_everything; break; case BROWSER_SAVE_VIEW: if (!bw) @@ -1493,13 +1628,16 @@ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, error = xwimp_get_window_state(&state); if (error) { LOG(("xwimp_get_window_state: 0x%x: %s", - error->errnum, error->errmess)); + 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; + option_window_width = + state.visible.x1 - state.visible.x0; + option_window_height = + state.visible.y1 - state.visible.y0; return true; case BROWSER_WINDOW_STAGGER: option_window_stagger = !option_window_stagger; @@ -1610,7 +1748,9 @@ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action, * \param action the action to prepare * \param windows whether to update sub-windows */ -void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) { +void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, + bool windows) +{ struct menu_definition_entry *entry; struct gui_window *g; struct browser_window *bw; @@ -1631,8 +1771,10 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) /* help actions */ case HELP_LAUNCH_INTERACTIVE: result = ro_gui_interactive_help_available(); - ro_gui_menu_set_entry_shaded(current_menu, action, result); - ro_gui_menu_set_entry_ticked(current_menu, action, result); + ro_gui_menu_set_entry_shaded(current_menu, + action, result); + ro_gui_menu_set_entry_ticked(current_menu, + action, result); break; /* history actions */ @@ -1655,39 +1797,49 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) case HOTLIST_SHOW: ro_gui_menu_set_entry_shaded(current_menu, action, !hotlist_tree); - if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) - ro_gui_set_icon_shaded_state(t->toolbar_handle, - ICON_TOOLBAR_BOOKMARK, !hotlist_tree); + if ((t) && (!t->editor) && + (t->type == THEME_BROWSER_TOOLBAR)) + ro_gui_set_icon_shaded_state( + t->toolbar_handle, + ICON_TOOLBAR_BOOKMARK, + !hotlist_tree); break; /* page actions */ case BROWSER_PAGE_INFO: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((windows) && (c)) ro_gui_menu_prepare_pageinfo(g); break; case BROWSER_PRINT: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((t) && (t->type == THEME_BROWSER_TOOLBAR)) - ro_gui_set_icon_shaded_state(t->toolbar_handle, + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_PRINT, !c); if ((windows) && (c)) ro_gui_print_prepare(g); - if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) - ro_gui_set_icon_shaded_state(t->toolbar_handle, + if ((t) && (!t->editor) && + (t->type == THEME_BROWSER_TOOLBAR)) + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_PRINT, !c); break; case BROWSER_PAGE: case BROWSER_NEW_WINDOW: case BROWSER_VIEW_SOURCE: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); break; /* object actions */ case BROWSER_OBJECT: c = current_menu_object_box ? current_menu_object_box->object : NULL; - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); break; case BROWSER_OBJECT_INFO: if ((windows) && (current_menu_object_box)) @@ -1702,37 +1854,45 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) case BROWSER_OBJECT_SAVE: c = current_menu_object_box ? current_menu_object_box->object : NULL; - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG, c); break; case BROWSER_OBJECT_EXPORT_SPRITE: c = current_menu_object_box ? current_menu_object_box->object : NULL; - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE, c); break; case BROWSER_SAVE: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_SOURCE, c); - if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) - ro_gui_set_icon_shaded_state(t->toolbar_handle, + if ((t) && (!t->editor) && + (t->type == THEME_BROWSER_TOOLBAR)) + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_SAVE, !c); break; case BROWSER_SAVE_COMPLETE: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_COMPLETE, c); break; case BROWSER_EXPORT_DRAW: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_DRAW, c); break; case BROWSER_EXPORT_TEXT: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_TEXT, c); break; @@ -1740,7 +1900,8 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) c = current_menu_object_box ? current_menu_object_box->object : NULL; case BROWSER_SAVE_URL_URI: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_LINK_URI, c); break; @@ -1748,7 +1909,8 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) c = current_menu_object_box ? current_menu_object_box->object : NULL; case BROWSER_SAVE_URL_URL: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_LINK_URL, c); break; @@ -1756,7 +1918,8 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) c = current_menu_object_box ? current_menu_object_box->object : NULL; case BROWSER_SAVE_URL_TEXT: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((c) && (windows)) ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, c); break; @@ -1775,34 +1938,46 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) case BROWSER_NAVIGATE_BACK: result = (!bw || !bw->history || !history_back_available(bw->history)); - ro_gui_menu_set_entry_shaded(current_menu, action, result); - if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) - ro_gui_set_icon_shaded_state(t->toolbar_handle, + ro_gui_menu_set_entry_shaded(current_menu, + action, result); + if ((t) && (!t->editor) && + (t->type == THEME_BROWSER_TOOLBAR)) + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_BACK, result); break; case BROWSER_NAVIGATE_FORWARD: result = (!bw || !bw->history || !history_forward_available(bw->history)); - ro_gui_menu_set_entry_shaded(current_menu, action, result); - if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) - ro_gui_set_icon_shaded_state(t->toolbar_handle, + ro_gui_menu_set_entry_shaded(current_menu, + action, result); + if ((t) && (!t->editor) && + (t->type == THEME_BROWSER_TOOLBAR)) + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_FORWARD, result); break; case BROWSER_NAVIGATE_RELOAD: case BROWSER_NAVIGATE_RELOAD_ALL: result = (bw->current_content && !bw->loading_content); - ro_gui_menu_set_entry_shaded(current_menu, action, !result); - if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) - ro_gui_set_icon_shaded_state(t->toolbar_handle, + ro_gui_menu_set_entry_shaded(current_menu, + action, !result); + if ((t) && (!t->editor) && + (t->type == THEME_BROWSER_TOOLBAR)) + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_RELOAD, !result); break; case BROWSER_NAVIGATE_STOP: result = (bw->loading_content || (bw->current_content && (bw->current_content->status != CONTENT_STATUS_DONE))); - ro_gui_menu_set_entry_shaded(current_menu, action, !result); - if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) - ro_gui_set_icon_shaded_state(t->toolbar_handle, + ro_gui_menu_set_entry_shaded(current_menu, + action, !result); + if ((t) && (!t->editor) && + (t->type == THEME_BROWSER_TOOLBAR)) + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_STOP, !result); break; case BROWSER_NAVIGATE_URL: @@ -1812,44 +1987,53 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) /* display actions */ case BROWSER_SCALE_VIEW: - ro_gui_menu_set_entry_shaded(current_menu, action, !c); + ro_gui_menu_set_entry_shaded(current_menu, + action, !c); if ((c) && (windows)) ro_gui_dialog_prepare_zoom(g); - if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) - ro_gui_set_icon_shaded_state(t->toolbar_handle, + if ((t) && (!t->editor) && + (t->type == THEME_BROWSER_TOOLBAR)) + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_SCALE, !c); break; case BROWSER_FIND_TEXT: result = !c || c->type != CONTENT_HTML; - ro_gui_menu_set_entry_shaded(current_menu, action, result); + ro_gui_menu_set_entry_shaded(current_menu, + action, result); if ((c) && (windows)) ro_gui_search_prepare(g); - if ((t) && (!t->editor) && (t->type == THEME_BROWSER_TOOLBAR)) - ro_gui_set_icon_shaded_state(t->toolbar_handle, + if ((t) && (!t->editor) && + (t->type == THEME_BROWSER_TOOLBAR)) + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_SEARCH, result); break; case BROWSER_IMAGES_FOREGROUND: - ro_gui_menu_set_entry_shaded(current_menu, action, true); - ro_gui_menu_set_entry_ticked(current_menu, action, true); + ro_gui_menu_set_entry_shaded(current_menu, + action, true); + ro_gui_menu_set_entry_ticked(current_menu, + action, true); break; case BROWSER_IMAGES_BACKGROUND: if (g) - ro_gui_menu_set_entry_ticked(current_menu, action, - g->option.background_images); + ro_gui_menu_set_entry_ticked(current_menu, + action, g->option.background_images); break; case BROWSER_BUFFER_ANIMS: if (g) { - ro_gui_menu_set_entry_shaded(current_menu, action, - g->option.buffer_everything); - ro_gui_menu_set_entry_ticked(current_menu, action, + ro_gui_menu_set_entry_shaded(current_menu, + action, g->option.buffer_everything); + ro_gui_menu_set_entry_ticked(current_menu, + action, g->option.buffer_animations || g->option.buffer_everything); } break; case BROWSER_BUFFER_ALL: if (g) - ro_gui_menu_set_entry_ticked(current_menu, action, - g->option.buffer_everything); + ro_gui_menu_set_entry_ticked(current_menu, + action, g->option.buffer_everything); break; case BROWSER_WINDOW_STAGGER: ro_gui_menu_set_entry_shaded(current_menu, action, @@ -1881,19 +2065,23 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) case TREE_COLLAPSE_FOLDERS: case TREE_COLLAPSE_LINKS: if ((tree) && (tree->root)) - ro_gui_menu_set_entry_shaded(current_menu, action, - !tree->root->child); + ro_gui_menu_set_entry_shaded(current_menu, + action, !tree->root->child); break; case TREE_SELECTION: if ((!tree) || (!tree->root)) break; if (tree->root->child) result = tree_has_selection(tree->root->child); - ro_gui_menu_set_entry_shaded(current_menu, action, !result); - if ((t) && (!t->editor) && (t->type != THEME_BROWSER_TOOLBAR)) { - ro_gui_set_icon_shaded_state(t->toolbar_handle, + ro_gui_menu_set_entry_shaded(current_menu, + action, !result); + if ((t) && (!t->editor) && + (t->type != THEME_BROWSER_TOOLBAR)) { + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_DELETE, !result); - ro_gui_set_icon_shaded_state(t->toolbar_handle, + ro_gui_set_icon_shaded_state( + t->toolbar_handle, ICON_TOOLBAR_LAUNCH, !result); } break; @@ -1921,7 +2109,8 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) break; if (tree->root->child) result = tree_has_selection(tree->root->child); - ro_gui_menu_set_entry_shaded(current_menu, action, !result); + ro_gui_menu_set_entry_shaded(current_menu, + action, !result); break; case TREE_SELECT_ALL: ro_gui_menu_set_entry_shaded(current_menu, action, @@ -1932,33 +2121,39 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action, bool windows) break; if (tree->root->child) result = tree_has_selection(tree->root->child); - ro_gui_menu_set_entry_shaded(current_menu, action, !result); + ro_gui_menu_set_entry_shaded(current_menu, + action, !result); break; /* toolbar actions */ case TOOLBAR_BUTTONS: - ro_gui_menu_set_entry_shaded(current_menu, action, (!t || - (t->editor))); - ro_gui_menu_set_entry_ticked(current_menu, action, (t && + ro_gui_menu_set_entry_shaded(current_menu, + action, (!t || (t->editor))); + ro_gui_menu_set_entry_ticked(current_menu, + action, (t && ((t->display_buttons) || (t->editor)))); break; case TOOLBAR_ADDRESS_BAR: - ro_gui_menu_set_entry_shaded(current_menu, action, !t); + ro_gui_menu_set_entry_shaded(current_menu, + action, !t); ro_gui_menu_set_entry_ticked(current_menu, action, (t && t->display_url)); break; case TOOLBAR_THROBBER: - ro_gui_menu_set_entry_shaded(current_menu, action, !t); + ro_gui_menu_set_entry_shaded(current_menu, + action, !t); ro_gui_menu_set_entry_ticked(current_menu, action, (t && t->display_throbber)); break; case TOOLBAR_STATUS_BAR: - ro_gui_menu_set_entry_shaded(current_menu, action, !t); + ro_gui_menu_set_entry_shaded(current_menu, + action, !t); ro_gui_menu_set_entry_ticked(current_menu, action, (t && t->display_status)); break; case TOOLBAR_EDIT: - ro_gui_menu_set_entry_shaded(current_menu, action, !t); + ro_gui_menu_set_entry_shaded(current_menu, + action, !t); ro_gui_menu_set_entry_ticked(current_menu, action, (t && t->editor)); break; @@ -2053,3 +2248,79 @@ int ro_gui_menu_get_checksum(void) { return checksum; } + +/** + * Translate a menu's textual content into the system local encoding + * + * \param menu The menu to translate + * \return false if out of memory, true otherwise + */ +bool ro_gui_menu_translate(struct menu_definition *menu) +{ + os_error *error; + int alphabet; + struct menu_definition_entry *entry; + char *translated; + utf8_convert_ret err; + + /* read current alphabet */ + error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &alphabet); + if (error) { + LOG(("failed reading alphabet: 0x%x: %s", + error->errnum, error->errmess)); + /* assume Latin1 */ + alphabet = territory_ALPHABET_LATIN1; + } + + if (menu->current_encoding == alphabet) + /* menu text is already in the correct encoding */ + return true; + + /* translate root menu title text */ + free(menu->menu->title_data.indirected_text.text); + err = utf8_to_local_encoding(messages_get(menu->title_key), + 0, &translated); + if (err != UTF8_CONVERT_OK) { + assert(err != UTF8_CONVERT_BADENC); + LOG(("utf8_to_enc failed")); + return false; + } + + /* and fill in WIMP menu field */ + menu->menu->title_data.indirected_text.text = translated; + + /* now the menu entries */ + for (entry = menu->entries; entry; entry = entry->next) { + wimp_menu *submenu = entry->menu_entry->sub_menu; + + /* tranlate menu entry text */ + free(entry->menu_entry->data.indirected_text.text); + err = utf8_to_local_encoding(messages_get(entry->entry_key), + 0, &translated); + if (err != UTF8_CONVERT_OK) { + assert(err != UTF8_CONVERT_BADENC); + LOG(("utf8_to_enc failed")); + return false; + } + + /* fill in WIMP menu fields */ + entry->menu_entry->data.indirected_text.text = translated; + entry->menu_entry->data.indirected_text.validation = + (char *) -1; + entry->menu_entry->data.indirected_text.size = + strlen(translated); + + /* child menu title - this is the same as the text of + * the parent menu entry, so just copy the pointer */ + if (submenu != wimp_NO_SUB_MENU && + IS_MENU(entry->menu_entry, submenu)) { + submenu->title_data.indirected_text.text = + translated; + } + } + + /* finally, set the current encoding of the menu */ + menu->current_encoding = alphabet; + + return true; +} diff --git a/riscos/save.c b/riscos/save.c index 0c4f8ea0b..807b45549 100644 --- a/riscos/save.c +++ b/riscos/save.c @@ -37,6 +37,7 @@ #include "netsurf/utils/log.h" #include "netsurf/utils/messages.h" #include "netsurf/utils/url.h" +#include "netsurf/utils/utf8.h" #include "netsurf/utils/utils.h" @@ -192,7 +193,8 @@ void ro_gui_save_prepare(gui_save_type save_type, struct content *c) ro_gui_save_set_state(c, save_type, name_buf, icon_buf); - ro_gui_set_icon_string(dialog_saveas, ICON_SAVE_ICON, icon_buf); + ro_gui_set_icon_sprite(dialog_saveas, ICON_SAVE_ICON, saveas_area, + icon_buf); ro_gui_set_icon_string(dialog_saveas, ICON_SAVE_PATH, name_buf); } @@ -435,6 +437,8 @@ void ro_gui_save_drag_end(wimp_dragged *drag) wimp_message message; os_error *error; char *dp, *ep; + char *local_name = NULL; + utf8_convert_ret err; if (using_dragasprite) { error = xdragasprite_stop(); @@ -466,8 +470,15 @@ void ro_gui_save_drag_end(wimp_dragged *drag) return; if (!saving_from_dialog) { - /* saving directly from browser window, choose a name based upon the URL */ - name = save_leafname; + /* saving directly from browser window, choose a + * name based upon the URL */ + err = utf8_to_local_encoding(save_leafname, 0, &local_name); + if (err != UTF8_CONVERT_OK) { + /* badenc should never happen */ + assert(err != UTF8_CONVERT_BADENC); + local_name = NULL; + } + name = local_name ? local_name : save_leafname; } else { char *dot; @@ -502,6 +513,8 @@ void ro_gui_save_drag_end(wimp_dragged *drag) wimp_send_message_to_window(wimp_USER_MESSAGE, &message, pointer.w, pointer.i); + + free(local_name); } @@ -871,6 +884,8 @@ void ro_gui_save_set_state(struct content *c, gui_save_type save_type, char *lea url_func_result res; bool done = false; char *nice = NULL; + utf8_convert_ret err; + char *local_name; /* parameters that we need to remember */ gui_save_current_type = save_type; @@ -886,8 +901,19 @@ void ro_gui_save_set_state(struct content *c, gui_save_type save_type, char *lea name = nice; else name = messages_get(name); + + /* filename is utf8 */ strcpy(leaf_buf, name); + err = utf8_to_local_encoding(name, 0, &local_name); + if (err != UTF8_CONVERT_OK) { + /* badenc should never happen */ + assert(err != UTF8_CONVERT_BADENC); + local_name = NULL; + } + + name = local_name ? local_name : name; + /* sprite name used for icon and dragging */ if (save_type == GUI_SAVE_COMPLETE) { int index; @@ -933,6 +959,7 @@ void ro_gui_save_set_state(struct content *c, gui_save_type save_type, char *lea } } + free(local_name); free(nice); } diff --git a/riscos/ucstables.c b/riscos/ucstables.c index b744e9c6a..ef103f367 100644 --- a/riscos/ucstables.c +++ b/riscos/ucstables.c @@ -6,12 +6,17 @@ */ /** \file - * UCS conversion tables + * UCS conversion tables and RISC OS-specific UTF-8 text handling */ +#include +#include +#include #include "oslib/osbyte.h" #include "oslib/territory.h" + #include "netsurf/riscos/ucstables.h" +#include "netsurf/utils/utf8.h" #include "netsurf/utils/utils.h" /* Common values (ASCII) */ @@ -334,15 +339,16 @@ int *ucstable_from_alphabet(int alphabet) return ucstable; } + static const char *localencodings[] = { "ISO-8859-1", /* BFont - 100 - just use Latin1, instead */ - "ISO-8859-1", /* do we want to use Acorn Latin1, instead? */ + "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", - "ISO-8869-7", + "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-IR-182", @@ -354,21 +360,272 @@ static const char *localencodings[] = { "CP866" /* Cyrillic2 - 120 */ }; +static const struct special { + char local; /**< Local 8bit representation */ + char len; /**< Length (in bytes) of UTF-8 character */ + const char *utf; /**< UTF-8 representation */ +} special_chars[] = { + { 0x80, 3, "\xE2\x82\xAC" }, /* EURO SIGN */ + { 0x81, 2, "\xC5\xB4" }, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */ + { 0x82, 2, "\xC5\xB5" }, /* LATIN SMALL LETTER W WITH CIRCUMFLEX */ + { 0x84, 3, "\xE2\x9C\x98" }, /* HEAVY BALLOT X */ + { 0x85, 2, "\xC5\xB6" }, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */ + { 0x86, 2, "\xC5\xB7" }, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX */ + { 0x88, 3, "\xE2\x87\x90" }, /* LEFTWARDS DOUBLE ARROW */ + { 0x89, 3, "\xE2\x87\x92" }, /* RIGHTWARDS DOUBLE ARROW */ + { 0x8a, 3, "\xE2\x87\x93" }, /* DOWNWARDS DOUBLE ARROW */ + { 0x8b, 3, "\xE2\x87\x91" }, /* UPWARDS DOUBLE ARROW */ + { 0x8c, 3, "\xE2\x80\xA6" }, /* HORIZONTAL ELLIPSIS */ + { 0x8d, 3, "\xE2\x84\xA2" }, /* TRADE MARK SIGN */ + { 0x8e, 3, "\xE2\x80\xB0" }, /* PER MILLE SIGN */ + { 0x8f, 3, "\xE2\x80\xA2" }, /* BULLET */ + { 0x90, 3, "\xE2\x80\x98" }, /* LEFT SINGLE QUOTATION MARK */ + { 0x91, 3, "\xE2\x80\x99" }, /* RIGHT SINGLE QUOTATION MARK */ + { 0x92, 3, "\xE2\x80\xB9" }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */ + { 0x93, 3, "\xE2\x80\xBA" }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */ + { 0x94, 3, "\xE2\x80\x9C" }, /* LEFT DOUBLE QUOTATION MARK */ + { 0x95, 3, "\xE2\x80\x9D" }, /* RIGHT DOUBLE QUOTATION MARK */ + { 0x96, 3, "\xE2\x80\x9E" }, /* DOUBLE LOW-9 QUOTATION MARK */ + { 0x97, 3, "\xE2\x80\x93" }, /* EN DASH */ + { 0x98, 3, "\xE2\x80\x94" }, /* EM DASH */ + { 0x99, 3, "\xE2\x88\x92" }, /* MINUS SIGN */ + { 0x9a, 2, "\xC5\x92" }, /* LATIN CAPITAL LIGATURE OE */ + { 0x9b, 2, "\xC5\x93" }, /* LATIN SMALL LIGATURE OE */ + { 0x9c, 3, "\xE2\x80\xA0" }, /* DAGGER */ + { 0x9d, 3, "\xE2\x80\xA1" }, /* DOUBLE DAGGER */ + { 0x9e, 3, "\xEF\xAC\x81" }, /* LATIN SMALL LIGATURE FI */ + { 0x9f, 3, "\xEF\xAC\x82" } /* LATIN SMALL LIGATURE FL */ +}; + + /** - * Retrieve local encoding name, suitable for passing to iconv + * Convert a UTF-8 encoded string into the system local encoding + * + * \param string The string to convert + * \param len The length (in bytes) of the string, or 0 + * \param result Pointer to location in which to store result + * \return The appropriate utf8_convert_ret value */ -const char *local_encoding_name(void) +utf8_convert_ret utf8_to_local_encoding(const char *string, size_t len, + char **result) { os_error *error; - int alphabet; + int alphabet, i, offset_count = 0; + struct { + const struct special *local; /* local character */ + size_t offset; /* byte offset into string */ + } offsets[CHAR_MAX]; + size_t off; + char *temp; + const char *enc; + utf8_convert_ret err; + + assert(string && result); + + /* get length, if necessary */ + if (len == 0) + len = strlen(string); + /* read system alphabet */ error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &alphabet); - if (!error) { - if (alphabet < 116) - return localencodings[alphabet - 100]; - else if (alphabet == 120) - return localencodings[16]; + if (error) + alphabet = territory_ALPHABET_LATIN1; + + /* UTF-8 -> simply copy string */ + if (alphabet == 111 /* UTF-8 */) { + *result = strndup(string, len); + return UTF8_CONVERT_OK; + } + + /* get encoding name */ + enc = (alphabet < 116 ? localencodings[alphabet - 100] + : (alphabet == 120 ? localencodings[16] + : localencodings[0])); + + /* populate offsets array with details of characters that + * will be stripped by iconv */ + for (off = 0; off < len; off = utf8_next(string, len, off)) { + if (string[off] != 0xE2 && + string[off] != 0xC5 && string[off] != 0xEF) + continue; + + for (i = 0; i != NOF_ELEMENTS(special_chars); i++) { + if (strncmp(string + off, special_chars[i].utf, + special_chars[i].len) == 0) { + /* ensure we don't overflow our buffer */ + assert(offset_count < CHAR_MAX - 1); + offsets[offset_count].local = + &special_chars[i]; + offsets[offset_count].offset = off; + offset_count++; + break; + } + } + } + + if (offset_count == 0) { + /* No substitutions are required, so exit here */ + return utf8_to_enc(string, enc, len, result); + } + + /* create output buffer */ + *(result) = malloc(len + 1); + if (!(*result)) + return UTF8_CONVERT_NOMEM; + *(*result) = '\0'; + + /* convert the chunks between offsets, then copy stripped + * character into output string */ + for (i = 0; i != offset_count; i++) { + off = (i > 0 ? offsets[i-1].offset + offsets[i-1].local->len + : 0); + + err = utf8_to_enc(string + off, enc, + offsets[i].offset - off, &temp); + if (err != UTF8_CONVERT_OK) { + assert(err != UTF8_CONVERT_BADENC); + free(*result); + return UTF8_CONVERT_NOMEM; + } + + strcat((*result), temp); + off = strlen(*result); + (*result)[off] = offsets[i].local->local; + (*result)[off+1] = '\0'; + + free(temp); + } + + /* handle last chunk */ + if (offsets[offset_count - 1].offset < len) { + off = offsets[offset_count - 1].offset + + offsets[offset_count - 1].local->len; + + err = utf8_to_enc(string + off, enc, len - off, &temp); + if (err != UTF8_CONVERT_OK) { + assert(err != UTF8_CONVERT_BADENC); + free(*result); + return UTF8_CONVERT_NOMEM; + } + + strcat((*result), temp); + + free(temp); + } + + return UTF8_CONVERT_OK; +} + +/** + * Convert a string encoded in the system local encoding to UTF-8 + * + * \param string The string to convert + * \param len The length (in bytes) of the string, or 0 + * \param result Pointer to location in which to store result + * \return The appropriate utf8_convert_ret value + */ +utf8_convert_ret utf8_from_local_encoding(const char *string, size_t len, + char **result) +{ + os_error *error; + int alphabet, i, offset_count = 0; + struct { + const struct special *local; /* utf character */ + size_t offset; /* byte offset into string */ + } offsets[CHAR_MAX]; + size_t off; + char *temp; + const char *enc; + utf8_convert_ret err; + + assert(string && result); + + /* get length, if necessary */ + if (len == 0) + len = strlen(string); + + /* read system alphabet */ + error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &alphabet); + if (error) + alphabet = territory_ALPHABET_LATIN1; + + /* UTF-8 -> simply copy string */ + if (alphabet == 111 /* UTF-8 */) { + *result = strndup(string, len); + return UTF8_CONVERT_OK; + } + + /* get encoding name */ + enc = (alphabet < 116 ? localencodings[alphabet - 100] + : (alphabet == 120 ? localencodings[16] + : localencodings[0])); + + /* populate offsets array with details of characters that + * will be stripped by iconv */ + for (off = 0; off < len; off++) { + if (string[off] < 0x80 || string[off] > 0x9f) + continue; + + for (i = 0; i != NOF_ELEMENTS(special_chars); i++) { + if (string[off] == special_chars[i].local) { + /* ensure we don't overflow our buffer */ + assert(offset_count < CHAR_MAX - 1); + offsets[offset_count].local = + &special_chars[i]; + offsets[offset_count].offset = off; + offset_count++; + break; + } + } + } + + if (offset_count == 0) { + /* No substitutions are required, so exit here */ + return utf8_from_enc(string, enc, len, result); + } + + /* create output buffer (oversized, but not by much) */ + *(result) = malloc(len + (3 * offset_count) + 1); + if (!(*result)) + return UTF8_CONVERT_NOMEM; + *(*result) = '\0'; + + /* convert the chunks between offsets, then copy stripped + * UTF-8 character into output string */ + for (i = 0; i != offset_count; i++) { + off = (i > 0 ? offsets[i-1].offset + offsets[i-1].local->len + : 0); + + err = utf8_from_enc(string + off, enc, + offsets[i].offset - off, &temp); + if (err != UTF8_CONVERT_OK) { + assert(err != UTF8_CONVERT_BADENC); + free(*result); + return UTF8_CONVERT_NOMEM; + } + + strcat((*result), temp); + strcat((*result), offsets[i].local->utf); + + free(temp); + } + + /* handle last chunk */ + if (offsets[offset_count - 1].offset < len) { + off = offsets[offset_count - 1].offset + + offsets[offset_count - 1].local->len; + + err = utf8_from_enc(string + off, enc, len - off, &temp); + if (err != UTF8_CONVERT_OK) { + assert(err != UTF8_CONVERT_BADENC); + free(*result); + return UTF8_CONVERT_NOMEM; + } + + strcat((*result), temp); + + free(temp); } - return localencodings[0]; + return UTF8_CONVERT_OK; } diff --git a/riscos/wimp.c b/riscos/wimp.c index ec12545df..8d1c641d3 100644 --- a/riscos/wimp.c +++ b/riscos/wimp.c @@ -25,6 +25,7 @@ #include "netsurf/riscos/gui.h" #include "netsurf/riscos/wimp.h" #include "netsurf/utils/log.h" +#include "netsurf/utils/utf8.h" #include "netsurf/utils/utils.h" static void ro_gui_wimp_cache_furniture_sizes(wimp_w w); @@ -205,13 +206,15 @@ char *ro_gui_get_icon_string(wimp_w w, wimp_i i) { * * \param w window handle * \param i icon handle - * \param text string (copied) + * \param text string (UTF-8 encoded) (copied) */ void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text) { wimp_caret caret; wimp_icon_state ic; os_error *error; int old_len, len; + char *local_text; + utf8_convert_ret err; /* get the icon data */ ic.w = w; @@ -224,17 +227,27 @@ void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text) { return; } + /* convert text to local encoding */ + err = utf8_to_local_encoding(text, 0, &local_text); + if (err != UTF8_CONVERT_OK) { + /* A bad encoding should never happen, so assert this */ + assert(err != UTF8_CONVERT_BADENC); + LOG(("utf8_to_enc failed")); + return; + } + /* check that the existing text is not the same as the updated text * to stop flicker */ if (ic.icon.data.indirected_text.size && - !strncmp(ic.icon.data.indirected_text.text, text, + !strncmp(ic.icon.data.indirected_text.text, + local_text, (unsigned int)ic.icon.data.indirected_text.size - 1)) return; /* copy the text across */ old_len = strlen(ic.icon.data.indirected_text.text); if (ic.icon.data.indirected_text.size) { - strncpy(ic.icon.data.indirected_text.text, text, + strncpy(ic.icon.data.indirected_text.text, local_text, (unsigned int)ic.icon.data.indirected_text.size - 1); ic.icon.data.indirected_text.text[ ic.icon.data.indirected_text.size - 1] = '\0'; @@ -249,7 +262,7 @@ void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text) { return; } if ((caret.w == w) && (caret.i == i)) { - len = strlen(text); + len = strlen(local_text); if ((caret.index > len) || (caret.index == old_len)) caret.index = len; error = xwimp_set_caret_position(w, i, caret.pos.x, caret.pos.y, @@ -261,6 +274,8 @@ void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text) { } } ro_gui_redraw_icon(w, i); + + free(local_text); } @@ -373,6 +388,45 @@ void ro_gui_set_icon_button_type(wimp_w w, wimp_i i, int type) { } +/** + * Set an icon's sprite + * + * \param w window handle + * \param i icon handle + * \param area sprite area containing sprite + * \param name name of sprite in area (in local encoding) + */ +void ro_gui_set_icon_sprite(wimp_w w, wimp_i i, osspriteop_area *area, + const char *name) +{ + wimp_icon_state ic; + os_error *error; + + /* get the icon data */ + ic.w = w; + ic.i = i; + error = xwimp_get_icon_state(&ic); + if (error) { + LOG(("xwimp_get_icon_state: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } + + /* copy the name across */ + if (ic.icon.data.indirected_text.size) { + strncpy(ic.icon.data.indirected_text.text, name, + (unsigned int)ic.icon.data.indirected_text.size - 1); + ic.icon.data.indirected_text.text[ + ic.icon.data.indirected_text.size - 1] = '\0'; + } + + ic.icon.data.indirected_sprite.area = area; + + ro_gui_redraw_icon(w, i); +} + + /** * Set a window title (does *not* redraw the title) * @@ -382,6 +436,8 @@ void ro_gui_set_icon_button_type(wimp_w w, wimp_i i, int type) { void ro_gui_set_window_title(wimp_w w, const char *text) { wimp_window_info_base window; os_error *error; + char *title_local_enc; + utf8_convert_ret err; /* Get the window details */ @@ -394,9 +450,19 @@ void ro_gui_set_window_title(wimp_w w, const char *text) { return; } + /* convert text to local encoding */ + err = utf8_to_local_encoding(text, 0, &title_local_enc); + if (err != UTF8_CONVERT_OK) { + /* A bad encoding should never happen, + * so assert this */ + assert(err != UTF8_CONVERT_BADENC); + LOG(("utf8_to_enc failed")); + return; + } + /* Set the title string */ - strncpy(window.title_data.indirected_text.text, text, + strncpy(window.title_data.indirected_text.text, title_local_enc, (unsigned int)window.title_data.indirected_text.size - 1); window.title_data.indirected_text.text[ @@ -411,6 +477,8 @@ void ro_gui_set_window_title(wimp_w w, const char *text) { warn_user("WimpError", error->errmess); return; } + + free(title_local_enc); } diff --git a/riscos/wimp.h b/riscos/wimp.h index b26f8dc72..cc587c39b 100644 --- a/riscos/wimp.h +++ b/riscos/wimp.h @@ -37,6 +37,8 @@ bool ro_gui_get_icon_selected_state(wimp_w w, wimp_i i); void ro_gui_set_icon_shaded_state(wimp_w w, wimp_i i, bool state); bool ro_gui_get_icon_shaded_state(wimp_w w, wimp_i i); void ro_gui_set_icon_button_type(wimp_w w, wimp_i i, int type); +void ro_gui_set_icon_sprite(wimp_w w, wimp_i i, osspriteop_area *area, + const char *name); void ro_gui_set_window_title(wimp_w w, const char *title); void ro_gui_set_caret_first(wimp_w w); void ro_gui_open_window_centre(wimp_w parent, wimp_w child); diff --git a/riscos/window.c b/riscos/window.c index 8abc6c9ed..867382565 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -909,24 +909,11 @@ void gui_window_set_extent(struct gui_window *g, int width, int height) void gui_window_set_status(struct gui_window *g, const char *text) { - char *local_text; - utf8_convert_ret err; - if ((!g->toolbar) || (!g->toolbar->status_handle)) return; - /* convert text to local encoding */ - err = utf8_to_enc(text, local_encoding_name(), 0, &local_text); - if (err != UTF8_CONVERT_OK) { - /* A bad encoding should never happen, so assert this */ - assert(err != UTF8_CONVERT_BADENC); - LOG(("utf8_to_enc failed")); - return; - } - ro_gui_set_icon_string(g->toolbar->status_handle, - ICON_STATUS_TEXT, local_text); - free(local_text); + ICON_STATUS_TEXT, text); } @@ -1904,14 +1891,14 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar) } return true; - case wimp_KEY_CONTROL + wimp_KEY_SHIFT + wimp_KEY_F9: - talloc_report_full(0, stderr); - return true; - case wimp_KEY_CONTROL + wimp_KEY_F9: /* Dump url_store. */ url_store_dump(); return true; + case wimp_KEY_CONTROL + wimp_KEY_SHIFT + wimp_KEY_F9: + talloc_report_full(0, stderr); + return true; + case wimp_KEY_F11: /* Zoom */ return ro_gui_menu_handle_action(g->window, BROWSER_SCALE_VIEW, false); -- cgit v1.2.3