Mercurial > emacs
changeset 56897:1fa5ffcb2ac8
(_widget_value): Added lname and lkey.
(digest_single_submenu): Set lname and lkey in widget_value
instead of name and key.
(update_submenu_strings): New function.
(set_frame_menubar): Remove call to inhibit_garbage_collection,
call update_submenu_strings.
(globals_of_w32menu): Check for Unicode API.
(digest_single_submenu, w32_menu_show): Encode menu strings as
UTF-8 if Unicode API is available.
(utf8to16): New function.
(add_menu_item): Use it when calling Unicode API.
author | Jason Rumney <jasonr@gnu.org> |
---|---|
date | Thu, 02 Sep 2004 23:22:58 +0000 |
parents | 77bbb90bd021 |
children | 621733a9d27b |
files | src/w32menu.c |
diffstat | 1 files changed, 157 insertions(+), 41 deletions(-) [+] |
line wrap: on
line diff
--- a/src/w32menu.c Thu Sep 02 22:56:22 2004 +0000 +++ b/src/w32menu.c Thu Sep 02 23:22:58 2004 +0000 @@ -45,7 +45,6 @@ #include "dispextern.h" -#undef HAVE_MULTILINGUAL_MENU #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */ /******************************************************************/ @@ -66,10 +65,12 @@ typedef struct _widget_value { /* name of widget */ + Lisp_Object lname; char* name; /* value (meaning depend on widget type) */ char* value; /* keyboard equivalent. no implications for XtTranslations */ + Lisp_Object lkey; char* key; /* Help string or nil if none. GC finds this string through the frame's menu_bar_vector @@ -136,17 +137,21 @@ IN HMENU, IN UINT, IN BOOL, - IN OUT LPMENUITEMINFOA - ); + IN OUT LPMENUITEMINFOA); typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) ( IN HMENU, IN UINT, IN BOOL, - IN LPCMENUITEMINFOA - ); + IN LPCMENUITEMINFOA); +typedef BOOL (WINAPI * AppendMenuW_Proc) ( + IN HMENU, + IN UINT, + IN UINT_PTR, + IN LPCWSTR); -GetMenuItemInfoA_Proc get_menu_item_info=NULL; -SetMenuItemInfoA_Proc set_menu_item_info=NULL; +GetMenuItemInfoA_Proc get_menu_item_info = NULL; +SetMenuItemInfoA_Proc set_menu_item_info = NULL; +AppendMenuW_Proc unicode_append_menu = NULL; Lisp_Object Vmenu_updating_frame; @@ -1235,13 +1240,17 @@ pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); -#ifndef HAVE_MULTILINGUAL_MENU - if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) + if (STRINGP (pane_name)) { - pane_name = ENCODE_SYSTEM (pane_name); + if (unicode_append_menu) + /* Encode as UTF-8 for now. */ + pane_name = ENCODE_UTF_8 (pane_name); + else if (STRING_MULTIBYTE (pane_name)) + pane_name = ENCODE_SYSTEM (pane_name); + ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); } -#endif + pane_string = (NILP (pane_name) ? "" : (char *) SDATA (pane_name)); /* If there is just one top-level pane, put all its items directly @@ -1259,12 +1268,9 @@ save_wv->next = wv; else first_wv->contents = wv; - wv->name = pane_string; - /* Ignore the @ that means "separate pane". - This is a kludge, but this isn't worth more time. */ - if (!NILP (prefix) && wv->name[0] == '@') - wv->name++; - wv->value = 0; + wv->lname = pane_name; + /* Set value to 1 so update_submenu_strings can handle '@' */ + wv->value = (char *) 1; wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; wv->help = Qnil; @@ -1287,10 +1293,13 @@ selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED); help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); -#ifndef HAVE_MULTILINGUAL_MENU - if (STRING_MULTIBYTE (item_name)) + if (STRINGP (item_name)) { - item_name = ENCODE_SYSTEM (item_name); + if (unicode_append_menu) + item_name = ENCODE_UTF_8 (item_name); + else if (STRING_MULTIBYTE (item_name)) + item_name = ENCODE_SYSTEM (item_name); + ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); } @@ -1299,7 +1308,6 @@ descrip = ENCODE_SYSTEM (descrip); ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); } -#endif /* not HAVE_MULTILINGUAL_MENU */ wv = xmalloc_widget_value (); if (prev_wv) @@ -1307,9 +1315,9 @@ else save_wv->contents = wv; - wv->name = (char *) SDATA (item_name); + wv->lname = item_name; if (!NILP (descrip)) - wv->key = (char *) SDATA (descrip); + wv->lkey = descrip; wv->value = 0; /* The EMACS_INT cast avoids a warning. There's no problem as long as pointers have enough bits to hold small integers. */ @@ -1348,6 +1356,43 @@ return first_wv; } + + +/* Walk through the widget_value tree starting at FIRST_WV and update + the char * pointers from the corresponding lisp values. + We do this after building the whole tree, since GC may happen while the + tree is constructed, and small strings are relocated. So we must wait + until no GC can happen before storing pointers into lisp values. */ +static void +update_submenu_strings (first_wv) + widget_value *first_wv; +{ + widget_value *wv; + + for (wv = first_wv; wv; wv = wv->next) + { + if (wv->lname && ! NILP (wv->lname)) + { + wv->name = SDATA (wv->lname); + + /* Ignore the @ that means "separate pane". + This is a kludge, but this isn't worth more time. */ + if (wv->value == (char *)1) + { + if (wv->name[0] == '@') + wv->name++; + wv->value = 0; + } + } + + if (wv->lkey && ! NILP (wv->lkey)) + wv->key = SDATA (wv->lkey); + + if (wv->contents) + update_submenu_strings (wv->contents); + } +} + /* Set the contents of the menubar widgets of frame F. The argument FIRST_TIME is currently ignored; @@ -1516,6 +1561,7 @@ if (NILP (string)) break; wv->name = (char *) SDATA (string); + update_submenu_strings (wv->contents); wv = wv->next; } @@ -1729,13 +1775,17 @@ char *pane_string; pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); -#ifndef HAVE_MULTILINGUAL_MENU - if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) + + if (STRINGP (pane_name)) { - pane_name = ENCODE_SYSTEM (pane_name); + if (unicode_append_menu) + pane_name = ENCODE_UTF_8 (pane_name); + else if (STRING_MULTIBYTE (pane_name)) + pane_name = ENCODE_SYSTEM (pane_name); + ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); } -#endif + pane_string = (NILP (pane_name) ? "" : (char *) SDATA (pane_name)); /* If there is just one top-level pane, put all its items directly @@ -1784,18 +1834,21 @@ selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED); help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); -#ifndef HAVE_MULTILINGUAL_MENU - if (STRINGP (item_name) && STRING_MULTIBYTE (item_name)) + if (STRINGP (item_name)) { - item_name = ENCODE_SYSTEM (item_name); + if (unicode_append_menu) + item_name = ENCODE_UTF_8 (item_name); + else if (STRING_MULTIBYTE (item_name)) + item_name = ENCODE_SYSTEM (item_name); + ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); } - if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) + + if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) { descrip = ENCODE_SYSTEM (descrip); ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); } -#endif /* not HAVE_MULTILINGUAL_MENU */ wv = xmalloc_widget_value (); if (prev_wv) @@ -1844,10 +1897,11 @@ wv_sep->next = first_wv->contents; wv_sep->help = Qnil; -#ifndef HAVE_MULTILINGUAL_MENU - if (STRING_MULTIBYTE (title)) + if (unicode_append_menu) + title = ENCODE_UTF_8 (title); + else if (STRING_MULTIBYTE (title)) title = ENCODE_SYSTEM (title); -#endif + wv_title->name = (char *) SDATA (title); wv_title->enabled = TRUE; wv_title->title = TRUE; @@ -2150,6 +2204,46 @@ return AppendMenu (menu, MF_MENUBARBREAK, 0, NULL); } +/* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */ +static void +utf8to16 (unsigned char * src, int len, WCHAR * dest) +{ + while (len > 0) + { + int utf16; + if (*src < 0x80) + { + *dest = (WCHAR) *src; + dest++; src++; len--; + } + /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */ + else if (*src < 0xC0) + { + src++; len--; + } + /* 2 char UTF-8 sequence. */ + else if (*src < 0xE0) + { + *dest = (WCHAR) (((*src & 0x1f) << 6) + | (*(src + 1) & 0x3f)); + src += 2; len -= 2; dest++; + } + else if (*src < 0xF0) + { + *dest = (WCHAR) (((*src & 0x0f) << 12) + | ((*(src + 1) & 0x3f) << 6) + | (*(src + 2) & 0x3f)); + src += 3; len -= 3; dest++; + } + else /* Not encodable. Insert Unicode Substitution char. */ + { + *dest = (WCHAR) 0xfffd; + src++; len--; dest++; + } + } + *dest = 0; +} + static int add_menu_item (HMENU menu, widget_value *wv, HMENU item) { @@ -2206,11 +2300,32 @@ fuFlags |= MF_UNCHECKED; } - return_value = - AppendMenu (menu, - fuFlags, - item != NULL ? (UINT) item : (UINT) wv->call_data, - out_string ); + if (unicode_append_menu && out_string) + { + /* Convert out_string from UTF-8 to UTF-16-LE. */ + int utf8_len = strlen (out_string); + WCHAR * utf16_string; + if (fuFlags & MF_OWNERDRAW) + utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR)); + else + utf16_string = alloca ((utf8_len + 1) * sizeof (WCHAR)); + + utf8to16 (out_string, utf8_len, utf16_string); + return_value = unicode_append_menu (menu, fuFlags, + item != NULL ? (UINT) item + : (UINT) wv->call_data, + utf16_string); + if (fuFlags & MF_OWNERDRAW) + local_free (out_string); + } + else + { + return_value = + AppendMenu (menu, + fuFlags, + item != NULL ? (UINT) item : (UINT) wv->call_data, + out_string ); + } /* This must be done after the menu item is created. */ if (!wv->title && wv->call_data != 0) @@ -2298,7 +2413,7 @@ struct frame *f = x_window_to_frame (&one_w32_display_info, owner); Lisp_Object frame, help; - // No help echo on owner-draw menu items. + /* No help echo on owner-draw menu items. */ if (flags & MF_OWNERDRAW || flags & MF_POPUP) help = Qnil; else @@ -2422,6 +2537,7 @@ HMODULE user32 = GetModuleHandle ("user32.dll"); get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA"); set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA"); + unicode_append_menu = (AppendMenuW_Proc) GetProcAddress (user32, "AppendMenuW"); } /* arch-tag: 0eaed431-bb4e-4aac-a527-95a1b4f1fed0