diff options
Diffstat (limited to 'riscos')
-rw-r--r-- | riscos/dialog.c | 62 | ||||
-rw-r--r-- | riscos/download.c | 51 | ||||
-rw-r--r-- | riscos/gui.h | 2 | ||||
-rw-r--r-- | riscos/help.c | 24 | ||||
-rw-r--r-- | riscos/menus.c | 751 | ||||
-rw-r--r-- | riscos/save.c | 33 | ||||
-rw-r--r-- | riscos/ucstables.c | 281 | ||||
-rw-r--r-- | riscos/wimp.c | 78 | ||||
-rw-r--r-- | riscos/wimp.h | 2 | ||||
-rw-r--r-- | riscos/window.c | 23 |
10 files changed, 989 insertions, 318 deletions
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 <assert.h> #include <stdbool.h> #include <stdio.h> #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 <ctype.h> #include <stdlib.h> #include <string.h> #include "oslib/os.h" +#include "oslib/osbyte.h" #include "oslib/osgbpb.h" +#include "oslib/territory.h" #include "oslib/wimp.h" #include "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("<NetSurf$Dir>.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); @@ -894,6 +924,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, + "<NetSurf$Dir>.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. * * \param bw browser window containing form 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:/<NetSurf$Dir>/Docs/about", + browser_window_create( + "file:/<NetSurf$Dir>/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:/<NetSurf$Dir>/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 <assert.h> +#include <limits.h> +#include <string.h> #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); } @@ -374,6 +389,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) * * \param w window handle @@ -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); |