comparison src/w32menu.c @ 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 6817f9469688
children 357d9738b63e 3219f94257bc
comparison
equal deleted inserted replaced
56896:77bbb90bd021 56897:1fa5ffcb2ac8
43 #include <sys/types.h> 43 #include <sys/types.h>
44 #endif 44 #endif
45 45
46 #include "dispextern.h" 46 #include "dispextern.h"
47 47
48 #undef HAVE_MULTILINGUAL_MENU
49 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */ 48 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
50 49
51 /******************************************************************/ 50 /******************************************************************/
52 /* Definitions copied from lwlib.h */ 51 /* Definitions copied from lwlib.h */
53 52
64 /* This structure is based on the one in ../lwlib/lwlib.h, modified 63 /* This structure is based on the one in ../lwlib/lwlib.h, modified
65 for Windows. */ 64 for Windows. */
66 typedef struct _widget_value 65 typedef struct _widget_value
67 { 66 {
68 /* name of widget */ 67 /* name of widget */
68 Lisp_Object lname;
69 char* name; 69 char* name;
70 /* value (meaning depend on widget type) */ 70 /* value (meaning depend on widget type) */
71 char* value; 71 char* value;
72 /* keyboard equivalent. no implications for XtTranslations */ 72 /* keyboard equivalent. no implications for XtTranslations */
73 Lisp_Object lkey;
73 char* key; 74 char* key;
74 /* Help string or nil if none. 75 /* Help string or nil if none.
75 GC finds this string through the frame's menu_bar_vector 76 GC finds this string through the frame's menu_bar_vector
76 or through menu_items. */ 77 or through menu_items. */
77 Lisp_Object help; 78 Lisp_Object help;
134 135
135 typedef BOOL (WINAPI * GetMenuItemInfoA_Proc) ( 136 typedef BOOL (WINAPI * GetMenuItemInfoA_Proc) (
136 IN HMENU, 137 IN HMENU,
137 IN UINT, 138 IN UINT,
138 IN BOOL, 139 IN BOOL,
139 IN OUT LPMENUITEMINFOA 140 IN OUT LPMENUITEMINFOA);
140 );
141 typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) ( 141 typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) (
142 IN HMENU, 142 IN HMENU,
143 IN UINT, 143 IN UINT,
144 IN BOOL, 144 IN BOOL,
145 IN LPCMENUITEMINFOA 145 IN LPCMENUITEMINFOA);
146 ); 146 typedef BOOL (WINAPI * AppendMenuW_Proc) (
147 147 IN HMENU,
148 GetMenuItemInfoA_Proc get_menu_item_info=NULL; 148 IN UINT,
149 SetMenuItemInfoA_Proc set_menu_item_info=NULL; 149 IN UINT_PTR,
150 IN LPCWSTR);
151
152 GetMenuItemInfoA_Proc get_menu_item_info = NULL;
153 SetMenuItemInfoA_Proc set_menu_item_info = NULL;
154 AppendMenuW_Proc unicode_append_menu = NULL;
150 155
151 Lisp_Object Vmenu_updating_frame; 156 Lisp_Object Vmenu_updating_frame;
152 157
153 Lisp_Object Qdebug_on_next_call; 158 Lisp_Object Qdebug_on_next_call;
154 159
1233 char *pane_string; 1238 char *pane_string;
1234 1239
1235 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); 1240 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1236 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); 1241 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1237 1242
1238 #ifndef HAVE_MULTILINGUAL_MENU 1243 if (STRINGP (pane_name))
1239 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1240 { 1244 {
1241 pane_name = ENCODE_SYSTEM (pane_name); 1245 if (unicode_append_menu)
1246 /* Encode as UTF-8 for now. */
1247 pane_name = ENCODE_UTF_8 (pane_name);
1248 else if (STRING_MULTIBYTE (pane_name))
1249 pane_name = ENCODE_SYSTEM (pane_name);
1250
1242 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); 1251 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1243 } 1252 }
1244 #endif 1253
1245 pane_string = (NILP (pane_name) 1254 pane_string = (NILP (pane_name)
1246 ? "" : (char *) SDATA (pane_name)); 1255 ? "" : (char *) SDATA (pane_name));
1247 /* If there is just one top-level pane, put all its items directly 1256 /* If there is just one top-level pane, put all its items directly
1248 under the top-level menu. */ 1257 under the top-level menu. */
1249 if (menu_items_n_panes == 1) 1258 if (menu_items_n_panes == 1)
1257 wv = xmalloc_widget_value (); 1266 wv = xmalloc_widget_value ();
1258 if (save_wv) 1267 if (save_wv)
1259 save_wv->next = wv; 1268 save_wv->next = wv;
1260 else 1269 else
1261 first_wv->contents = wv; 1270 first_wv->contents = wv;
1262 wv->name = pane_string; 1271 wv->lname = pane_name;
1263 /* Ignore the @ that means "separate pane". 1272 /* Set value to 1 so update_submenu_strings can handle '@' */
1264 This is a kludge, but this isn't worth more time. */ 1273 wv->value = (char *) 1;
1265 if (!NILP (prefix) && wv->name[0] == '@')
1266 wv->name++;
1267 wv->value = 0;
1268 wv->enabled = 1; 1274 wv->enabled = 1;
1269 wv->button_type = BUTTON_TYPE_NONE; 1275 wv->button_type = BUTTON_TYPE_NONE;
1270 wv->help = Qnil; 1276 wv->help = Qnil;
1271 } 1277 }
1272 save_wv = wv; 1278 save_wv = wv;
1285 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION); 1291 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1286 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE); 1292 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1287 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED); 1293 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1288 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); 1294 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1289 1295
1290 #ifndef HAVE_MULTILINGUAL_MENU 1296 if (STRINGP (item_name))
1291 if (STRING_MULTIBYTE (item_name))
1292 { 1297 {
1293 item_name = ENCODE_SYSTEM (item_name); 1298 if (unicode_append_menu)
1299 item_name = ENCODE_UTF_8 (item_name);
1300 else if (STRING_MULTIBYTE (item_name))
1301 item_name = ENCODE_SYSTEM (item_name);
1302
1294 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); 1303 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1295 } 1304 }
1296 1305
1297 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) 1306 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1298 { 1307 {
1299 descrip = ENCODE_SYSTEM (descrip); 1308 descrip = ENCODE_SYSTEM (descrip);
1300 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); 1309 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1301 } 1310 }
1302 #endif /* not HAVE_MULTILINGUAL_MENU */
1303 1311
1304 wv = xmalloc_widget_value (); 1312 wv = xmalloc_widget_value ();
1305 if (prev_wv) 1313 if (prev_wv)
1306 prev_wv->next = wv; 1314 prev_wv->next = wv;
1307 else 1315 else
1308 save_wv->contents = wv; 1316 save_wv->contents = wv;
1309 1317
1310 wv->name = (char *) SDATA (item_name); 1318 wv->lname = item_name;
1311 if (!NILP (descrip)) 1319 if (!NILP (descrip))
1312 wv->key = (char *) SDATA (descrip); 1320 wv->lkey = descrip;
1313 wv->value = 0; 1321 wv->value = 0;
1314 /* The EMACS_INT cast avoids a warning. There's no problem 1322 /* The EMACS_INT cast avoids a warning. There's no problem
1315 as long as pointers have enough bits to hold small integers. */ 1323 as long as pointers have enough bits to hold small integers. */
1316 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0); 1324 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
1317 wv->enabled = !NILP (enable); 1325 wv->enabled = !NILP (enable);
1346 return wv; 1354 return wv;
1347 } 1355 }
1348 1356
1349 return first_wv; 1357 return first_wv;
1350 } 1358 }
1359
1360
1361 /* Walk through the widget_value tree starting at FIRST_WV and update
1362 the char * pointers from the corresponding lisp values.
1363 We do this after building the whole tree, since GC may happen while the
1364 tree is constructed, and small strings are relocated. So we must wait
1365 until no GC can happen before storing pointers into lisp values. */
1366 static void
1367 update_submenu_strings (first_wv)
1368 widget_value *first_wv;
1369 {
1370 widget_value *wv;
1371
1372 for (wv = first_wv; wv; wv = wv->next)
1373 {
1374 if (wv->lname && ! NILP (wv->lname))
1375 {
1376 wv->name = SDATA (wv->lname);
1377
1378 /* Ignore the @ that means "separate pane".
1379 This is a kludge, but this isn't worth more time. */
1380 if (wv->value == (char *)1)
1381 {
1382 if (wv->name[0] == '@')
1383 wv->name++;
1384 wv->value = 0;
1385 }
1386 }
1387
1388 if (wv->lkey && ! NILP (wv->lkey))
1389 wv->key = SDATA (wv->lkey);
1390
1391 if (wv->contents)
1392 update_submenu_strings (wv->contents);
1393 }
1394 }
1395
1351 1396
1352 /* Set the contents of the menubar widgets of frame F. 1397 /* Set the contents of the menubar widgets of frame F.
1353 The argument FIRST_TIME is currently ignored; 1398 The argument FIRST_TIME is currently ignored;
1354 it is set the first time this is called, from initialize_frame_menubar. */ 1399 it is set the first time this is called, from initialize_frame_menubar. */
1355 1400
1514 Lisp_Object string; 1559 Lisp_Object string;
1515 string = AREF (items, i + 1); 1560 string = AREF (items, i + 1);
1516 if (NILP (string)) 1561 if (NILP (string))
1517 break; 1562 break;
1518 wv->name = (char *) SDATA (string); 1563 wv->name = (char *) SDATA (string);
1564 update_submenu_strings (wv->contents);
1519 wv = wv->next; 1565 wv = wv->next;
1520 } 1566 }
1521 1567
1522 f->menu_bar_vector = menu_items; 1568 f->menu_bar_vector = menu_items;
1523 f->menu_bar_items_used = menu_items_used; 1569 f->menu_bar_items_used = menu_items_used;
1727 /* Create a new pane. */ 1773 /* Create a new pane. */
1728 Lisp_Object pane_name, prefix; 1774 Lisp_Object pane_name, prefix;
1729 char *pane_string; 1775 char *pane_string;
1730 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); 1776 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1731 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); 1777 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1732 #ifndef HAVE_MULTILINGUAL_MENU 1778
1733 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) 1779 if (STRINGP (pane_name))
1734 { 1780 {
1735 pane_name = ENCODE_SYSTEM (pane_name); 1781 if (unicode_append_menu)
1782 pane_name = ENCODE_UTF_8 (pane_name);
1783 else if (STRING_MULTIBYTE (pane_name))
1784 pane_name = ENCODE_SYSTEM (pane_name);
1785
1736 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); 1786 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1737 } 1787 }
1738 #endif 1788
1739 pane_string = (NILP (pane_name) 1789 pane_string = (NILP (pane_name)
1740 ? "" : (char *) SDATA (pane_name)); 1790 ? "" : (char *) SDATA (pane_name));
1741 /* If there is just one top-level pane, put all its items directly 1791 /* If there is just one top-level pane, put all its items directly
1742 under the top-level menu. */ 1792 under the top-level menu. */
1743 if (menu_items_n_panes == 1) 1793 if (menu_items_n_panes == 1)
1782 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION); 1832 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1783 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE); 1833 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1784 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED); 1834 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1785 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); 1835 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1786 1836
1787 #ifndef HAVE_MULTILINGUAL_MENU 1837 if (STRINGP (item_name))
1788 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1789 { 1838 {
1790 item_name = ENCODE_SYSTEM (item_name); 1839 if (unicode_append_menu)
1840 item_name = ENCODE_UTF_8 (item_name);
1841 else if (STRING_MULTIBYTE (item_name))
1842 item_name = ENCODE_SYSTEM (item_name);
1843
1791 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); 1844 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1792 } 1845 }
1793 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) 1846
1847 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1794 { 1848 {
1795 descrip = ENCODE_SYSTEM (descrip); 1849 descrip = ENCODE_SYSTEM (descrip);
1796 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); 1850 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1797 } 1851 }
1798 #endif /* not HAVE_MULTILINGUAL_MENU */
1799 1852
1800 wv = xmalloc_widget_value (); 1853 wv = xmalloc_widget_value ();
1801 if (prev_wv) 1854 if (prev_wv)
1802 prev_wv->next = wv; 1855 prev_wv->next = wv;
1803 else 1856 else
1842 so that it looks better. Having two separators looks odd. */ 1895 so that it looks better. Having two separators looks odd. */
1843 wv_sep->name = "--"; 1896 wv_sep->name = "--";
1844 wv_sep->next = first_wv->contents; 1897 wv_sep->next = first_wv->contents;
1845 wv_sep->help = Qnil; 1898 wv_sep->help = Qnil;
1846 1899
1847 #ifndef HAVE_MULTILINGUAL_MENU 1900 if (unicode_append_menu)
1848 if (STRING_MULTIBYTE (title)) 1901 title = ENCODE_UTF_8 (title);
1902 else if (STRING_MULTIBYTE (title))
1849 title = ENCODE_SYSTEM (title); 1903 title = ENCODE_SYSTEM (title);
1850 #endif 1904
1851 wv_title->name = (char *) SDATA (title); 1905 wv_title->name = (char *) SDATA (title);
1852 wv_title->enabled = TRUE; 1906 wv_title->enabled = TRUE;
1853 wv_title->title = TRUE; 1907 wv_title->title = TRUE;
1854 wv_title->button_type = BUTTON_TYPE_NONE; 1908 wv_title->button_type = BUTTON_TYPE_NONE;
1855 wv_title->help = Qnil; 1909 wv_title->help = Qnil;
2148 add_left_right_boundary (HMENU menu) 2202 add_left_right_boundary (HMENU menu)
2149 { 2203 {
2150 return AppendMenu (menu, MF_MENUBARBREAK, 0, NULL); 2204 return AppendMenu (menu, MF_MENUBARBREAK, 0, NULL);
2151 } 2205 }
2152 2206
2207 /* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
2208 static void
2209 utf8to16 (unsigned char * src, int len, WCHAR * dest)
2210 {
2211 while (len > 0)
2212 {
2213 int utf16;
2214 if (*src < 0x80)
2215 {
2216 *dest = (WCHAR) *src;
2217 dest++; src++; len--;
2218 }
2219 /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */
2220 else if (*src < 0xC0)
2221 {
2222 src++; len--;
2223 }
2224 /* 2 char UTF-8 sequence. */
2225 else if (*src < 0xE0)
2226 {
2227 *dest = (WCHAR) (((*src & 0x1f) << 6)
2228 | (*(src + 1) & 0x3f));
2229 src += 2; len -= 2; dest++;
2230 }
2231 else if (*src < 0xF0)
2232 {
2233 *dest = (WCHAR) (((*src & 0x0f) << 12)
2234 | ((*(src + 1) & 0x3f) << 6)
2235 | (*(src + 2) & 0x3f));
2236 src += 3; len -= 3; dest++;
2237 }
2238 else /* Not encodable. Insert Unicode Substitution char. */
2239 {
2240 *dest = (WCHAR) 0xfffd;
2241 src++; len--; dest++;
2242 }
2243 }
2244 *dest = 0;
2245 }
2246
2153 static int 2247 static int
2154 add_menu_item (HMENU menu, widget_value *wv, HMENU item) 2248 add_menu_item (HMENU menu, widget_value *wv, HMENU item)
2155 { 2249 {
2156 UINT fuFlags; 2250 UINT fuFlags;
2157 char *out_string; 2251 char *out_string;
2204 fuFlags |= MF_CHECKED; 2298 fuFlags |= MF_CHECKED;
2205 else 2299 else
2206 fuFlags |= MF_UNCHECKED; 2300 fuFlags |= MF_UNCHECKED;
2207 } 2301 }
2208 2302
2209 return_value = 2303 if (unicode_append_menu && out_string)
2210 AppendMenu (menu, 2304 {
2211 fuFlags, 2305 /* Convert out_string from UTF-8 to UTF-16-LE. */
2212 item != NULL ? (UINT) item : (UINT) wv->call_data, 2306 int utf8_len = strlen (out_string);
2213 out_string ); 2307 WCHAR * utf16_string;
2308 if (fuFlags & MF_OWNERDRAW)
2309 utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
2310 else
2311 utf16_string = alloca ((utf8_len + 1) * sizeof (WCHAR));
2312
2313 utf8to16 (out_string, utf8_len, utf16_string);
2314 return_value = unicode_append_menu (menu, fuFlags,
2315 item != NULL ? (UINT) item
2316 : (UINT) wv->call_data,
2317 utf16_string);
2318 if (fuFlags & MF_OWNERDRAW)
2319 local_free (out_string);
2320 }
2321 else
2322 {
2323 return_value =
2324 AppendMenu (menu,
2325 fuFlags,
2326 item != NULL ? (UINT) item : (UINT) wv->call_data,
2327 out_string );
2328 }
2214 2329
2215 /* This must be done after the menu item is created. */ 2330 /* This must be done after the menu item is created. */
2216 if (!wv->title && wv->call_data != 0) 2331 if (!wv->title && wv->call_data != 0)
2217 { 2332 {
2218 if (set_menu_item_info) 2333 if (set_menu_item_info)
2296 if (get_menu_item_info) 2411 if (get_menu_item_info)
2297 { 2412 {
2298 struct frame *f = x_window_to_frame (&one_w32_display_info, owner); 2413 struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
2299 Lisp_Object frame, help; 2414 Lisp_Object frame, help;
2300 2415
2301 // No help echo on owner-draw menu items. 2416 /* No help echo on owner-draw menu items. */
2302 if (flags & MF_OWNERDRAW || flags & MF_POPUP) 2417 if (flags & MF_OWNERDRAW || flags & MF_POPUP)
2303 help = Qnil; 2418 help = Qnil;
2304 else 2419 else
2305 { 2420 {
2306 MENUITEMINFO info; 2421 MENUITEMINFO info;
2420 { 2535 {
2421 /* See if Get/SetMenuItemInfo functions are available. */ 2536 /* See if Get/SetMenuItemInfo functions are available. */
2422 HMODULE user32 = GetModuleHandle ("user32.dll"); 2537 HMODULE user32 = GetModuleHandle ("user32.dll");
2423 get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA"); 2538 get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA");
2424 set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA"); 2539 set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA");
2540 unicode_append_menu = (AppendMenuW_Proc) GetProcAddress (user32, "AppendMenuW");
2425 } 2541 }
2426 2542
2427 /* arch-tag: 0eaed431-bb4e-4aac-a527-95a1b4f1fed0 2543 /* arch-tag: 0eaed431-bb4e-4aac-a527-95a1b4f1fed0
2428 (do not change this comment) */ 2544 (do not change this comment) */