Mercurial > hg > xemacs-beta
comparison src/menubar-msw.c @ 404:2f8bb876ab1d r21-2-32
Import from CVS: tag r21-2-32
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:16:07 +0200 |
parents | a86b2b5e0111 |
children | de805c49cfc1 |
comparison
equal
deleted
inserted
replaced
403:9f011ab08d48 | 404:2f8bb876ab1d |
---|---|
1 /* Implements an elisp-programmable menubar -- Win32 | 1 /* Implements an elisp-programmable menubar -- Win32 |
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc. | 2 Copyright (C) 1993, 1994 Free Software Foundation, Inc. |
3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp. | 3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp. |
4 Copyright (C) 1997 Kirill M. Katsnelson <kkm@kis.ru> | 4 Copyright (C) 1997 Kirill M. Katsnelson <kkm@kis.ru>. |
5 Copyright (C) 2000 Ben Wing. | |
5 | 6 |
6 This file is part of XEmacs. | 7 This file is part of XEmacs. |
7 | 8 |
8 XEmacs is free software; you can redistribute it and/or modify it | 9 XEmacs is free software; you can redistribute it and/or modify it |
9 under the terms of the GNU General Public License as published by the | 10 under the terms of the GNU General Public License as published by the |
68 * that to cleanup the popup menu hash table, but this is not honestly | 69 * that to cleanup the popup menu hash table, but this is not honestly |
69 * doable using *documented* sequence of messages. Sticking to | 70 * doable using *documented* sequence of messages. Sticking to |
70 * particular knowledge is bad because this may break in Windows NT | 71 * particular knowledge is bad because this may break in Windows NT |
71 * 5.0, or Windows 98, or other future version. Instead, I allow the | 72 * 5.0, or Windows 98, or other future version. Instead, I allow the |
72 * hash tables to hang around, and not clear them, unless WM_COMMAND is | 73 * hash tables to hang around, and not clear them, unless WM_COMMAND is |
73 * received. This is worthy some memory but more safe. Hacks welcome, | 74 * received. This is worth some memory but more safe. Hacks welcome, |
74 * anyways! | 75 * anyways! |
75 * | 76 * |
76 */ | 77 */ |
77 | 78 |
78 #include <config.h> | 79 #include <config.h> |
91 #include "menubar-msw.h" | 92 #include "menubar-msw.h" |
92 #include "opaque.h" | 93 #include "opaque.h" |
93 #include "window.h" | 94 #include "window.h" |
94 | 95 |
95 /* #### */ | 96 /* #### */ |
96 #define REPLACE_ME_WITH_GLOBAL_VARIABLE_WHICH_CONTROLS_RIHGT_FLUSH 0 | 97 #define REPLACE_ME_WITH_GLOBAL_VARIABLE_WHICH_CONTROLS_RIGHT_FLUSH 0 |
97 | 98 |
98 #define EMPTY_ITEM_ID ((UINT)LISP_TO_VOID (Qunbound)) | 99 #define EMPTY_ITEM_ID ((UINT)LISP_TO_VOID (Qunbound)) |
99 #define EMPTY_ITEM_NAME "(empty)" | 100 #define EMPTY_ITEM_NAME "(empty)" |
100 | 101 |
101 /* Current menu (bar or popup) descriptor. gcpro'ed */ | 102 /* Current menu (bar or popup) descriptor. gcpro'ed */ |
114 #define MENU_ITEM_ID_MIN 0x8000 | 115 #define MENU_ITEM_ID_MIN 0x8000 |
115 #define MENU_ITEM_ID_MAX 0xFFFF | 116 #define MENU_ITEM_ID_MAX 0xFFFF |
116 #define MENU_ITEM_ID_BITS(x) (((x) & 0x7FFF) | 0x8000) | 117 #define MENU_ITEM_ID_BITS(x) (((x) & 0x7FFF) | 0x8000) |
117 static HMENU top_level_menu; | 118 static HMENU top_level_menu; |
118 | 119 |
120 /* Translate (in place) %_ to &, %% to %. | |
121 Return new length, and (through accel) the accelerator character. | |
122 (If there is no accelerator, it will be added on the first character.) | |
123 len = number of bytes (not including zero terminator). | |
124 maxlen = size of buffer. | |
125 We assume and maintain zero-termination. To be absolutely sure | |
126 of not hitting an error, maxlen should be >= 2*len + 3. */ | |
127 | |
128 Bytecount | |
129 msw_translate_menu_or_dialog_item (Bufbyte *item, Bytecount len, | |
130 Bytecount maxlen, Emchar *accel, | |
131 Lisp_Object error_name) | |
132 { | |
133 Bufbyte *ptr; | |
134 | |
135 *accel = '\0'; | |
136 | |
137 /* Escape '&' as '&&' */ | |
138 | |
139 ptr = item; | |
140 while ((ptr = (Bufbyte *) memchr (ptr, '&', len - (ptr - item))) != NULL) | |
141 { | |
142 if (len + 2 > maxlen) | |
143 signal_simple_error ("Menu item produces too long displayable string", | |
144 error_name); | |
145 memmove (ptr + 1, ptr, (len - (ptr - item)) + 1); | |
146 len++; | |
147 ptr += 2; | |
148 } | |
149 | |
150 /* Replace XEmacs accelerator '%_' with Windows accelerator '&' | |
151 and `%%' with `%'. */ | |
152 ptr = item; | |
153 while ((ptr = memchr (ptr, '%', len - (ptr - item))) != NULL) | |
154 { | |
155 if (*(ptr + 1) == '_') | |
156 { | |
157 *ptr = '&'; | |
158 if (!*accel) | |
159 /* #### urk ! We need a reference translation table for | |
160 case changes that aren't buffer-specific. */ | |
161 *accel = DOWNCASE (current_buffer, charptr_emchar (ptr + 2)); | |
162 memmove (ptr + 1, ptr + 2, len - (ptr - item + 2) + 1); | |
163 len--; | |
164 } | |
165 else if (*(ptr + 1) == '%') | |
166 { | |
167 memmove (ptr + 1, ptr + 2, len - (ptr - item + 2) + 1); | |
168 len--; | |
169 } | |
170 ptr++; | |
171 } | |
172 | |
173 if (!*accel) | |
174 { | |
175 if (len + 2 > maxlen) | |
176 signal_simple_error ("Menu item produces too long displayable string", | |
177 error_name); | |
178 ptr = item; | |
179 memmove (ptr + 1, ptr, len + 1); | |
180 /* #### urk ! We need a reference translation table for | |
181 case changes that aren't buffer-specific. */ | |
182 *accel = DOWNCASE (current_buffer, charptr_emchar (ptr + 1)); | |
183 *ptr = '&'; | |
184 | |
185 len++; | |
186 } | |
187 | |
188 return len; | |
189 } | |
190 | |
119 /* | 191 /* |
120 * This returns Windows-style menu item string: | 192 * This returns Windows-style menu item string: |
121 * "Left Flush\tRight Flush" | 193 * "Left Flush\tRight Flush" |
122 */ | 194 */ |
195 | |
196 /* #### This is junk. Need correct handling of sizes. Use a Bufbyte_dynarr, | |
197 not a static buffer. */ | |
123 static char* | 198 static char* |
124 displayable_menu_item (Lisp_Object gui_item, int bar_p) | 199 displayable_menu_item (Lisp_Object gui_item, int bar_p, Emchar *accel) |
125 { | 200 { |
201 unsigned int ll; | |
202 | |
126 /* We construct the name in a static buffer. That's fine, because | 203 /* We construct the name in a static buffer. That's fine, because |
127 menu items longer than 128 chars are probably programming errors, | 204 menu items longer than 128 chars are probably programming errors, |
128 and better be caught than displayed! */ | 205 and better be caught than displayed! */ |
129 | 206 |
130 static char buf[MAX_MENUITEM_LENGTH+2]; | 207 static char buf[MAX_MENUITEM_LENGTH+2]; |
131 char *ptr; | |
132 unsigned int ll, lr; | |
133 | 208 |
134 /* Left flush part of the string */ | 209 /* Left flush part of the string */ |
135 ll = gui_item_display_flush_left (gui_item, buf, MAX_MENUITEM_LENGTH); | 210 ll = gui_item_display_flush_left (gui_item, buf, MAX_MENUITEM_LENGTH); |
136 | 211 |
137 /* Escape '&' as '&&' */ | 212 ll = msw_translate_menu_or_dialog_item ((Bufbyte *) buf, ll, |
138 ptr = buf; | 213 MAX_MENUITEM_LENGTH, accel, |
139 while ((ptr = (char*) memchr (ptr, '&', ll - (ptr - buf))) != NULL) | 214 XGUI_ITEM (gui_item)->name); |
140 { | |
141 if (ll + 2 >= MAX_MENUITEM_LENGTH) | |
142 signal_simple_error ("Menu item produces too long displayable string", | |
143 XGUI_ITEM (gui_item)->name); | |
144 memmove (ptr + 1, ptr, (ll - (ptr - buf)) + 1); | |
145 ll++; | |
146 ptr += 2; | |
147 } | |
148 | |
149 /* Replace XEmacs accelerator '%_' with Windows accelerator '&' */ | |
150 ptr = buf; | |
151 while ((ptr = (char*) memchr (ptr, '%', ll - (ptr - buf))) != NULL) | |
152 { | |
153 if (*(ptr + 1) == '_') | |
154 { | |
155 *ptr = '&'; | |
156 memmove (ptr + 1, ptr + 2, ll - (ptr - buf + 2)); | |
157 ll--; | |
158 } | |
159 ptr++; | |
160 } | |
161 | 215 |
162 /* Right flush part, unless we're at the top-level where it's not allowed */ | 216 /* Right flush part, unless we're at the top-level where it's not allowed */ |
163 if (!bar_p) | 217 if (!bar_p) |
164 { | 218 { |
219 unsigned int lr; | |
220 | |
165 assert (MAX_MENUITEM_LENGTH > ll + 1); | 221 assert (MAX_MENUITEM_LENGTH > ll + 1); |
166 lr = gui_item_display_flush_right (gui_item, buf + ll + 1, | 222 lr = gui_item_display_flush_right (gui_item, buf + ll + 1, |
167 MAX_MENUITEM_LENGTH - ll - 1); | 223 MAX_MENUITEM_LENGTH - ll - 1); |
168 if (lr) | 224 if (lr) |
169 buf [ll] = '\t'; | 225 buf [ll] = '\t'; |
249 } | 305 } |
250 | 306 |
251 static void | 307 static void |
252 populate_menu_add_item (HMENU menu, Lisp_Object path, | 308 populate_menu_add_item (HMENU menu, Lisp_Object path, |
253 Lisp_Object hash_tab, Lisp_Object item, | 309 Lisp_Object hash_tab, Lisp_Object item, |
310 Lisp_Object *accel_list, | |
254 int flush_right, int bar_p) | 311 int flush_right, int bar_p) |
255 { | 312 { |
256 MENUITEMINFO item_info; | 313 MENUITEMINFO item_info; |
257 | 314 |
258 item_info.cbSize = sizeof (item_info); | 315 item_info.cbSize = sizeof (item_info); |
276 else if (CONSP (item)) | 333 else if (CONSP (item)) |
277 { | 334 { |
278 /* Submenu */ | 335 /* Submenu */ |
279 HMENU submenu; | 336 HMENU submenu; |
280 Lisp_Object gui_item = allocate_gui_item (); | 337 Lisp_Object gui_item = allocate_gui_item (); |
281 Lisp_Gui_Item* pgui_item = XGUI_ITEM (gui_item); | 338 Lisp_Gui_Item *pgui_item = XGUI_ITEM (gui_item); |
282 struct gcpro gcpro1; | 339 struct gcpro gcpro1, gcpro2, gcpro3; |
283 | 340 Emchar accel; |
284 GCPRO1 (gui_item); | 341 |
342 GCPRO3 (gui_item, path, *accel_list); | |
285 | 343 |
286 menu_parse_submenu_keywords (item, gui_item); | 344 menu_parse_submenu_keywords (item, gui_item); |
287 | 345 |
288 if (!STRINGP (pgui_item->name)) | 346 if (!STRINGP (pgui_item->name)) |
289 signal_simple_error ("Menu name (first element) must be a string", item); | 347 signal_simple_error ("Menu name (first element) must be a string", |
348 item); | |
290 | 349 |
291 if (!gui_item_included_p (gui_item, Vmenubar_configuration)) | 350 if (!gui_item_included_p (gui_item, Vmenubar_configuration)) |
292 return; | 351 { |
352 UNGCPRO; | |
353 goto done; | |
354 } | |
293 | 355 |
294 if (!gui_item_active_p (gui_item)) | 356 if (!gui_item_active_p (gui_item)) |
295 item_info.fState = MFS_GRAYED; | 357 item_info.fState = MFS_GRAYED; |
296 /* Temptation is to put 'else' right here. Although, the | 358 /* Temptation is to put 'else' right here. Although, the |
297 displayed item won't have an arrow indicating that it is a | 359 displayed item won't have an arrow indicating that it is a |
298 popup. So we go ahead a little bit more and create a popup */ | 360 popup. So we go ahead a little bit more and create a popup */ |
299 submenu = create_empty_popup_menu(); | 361 submenu = create_empty_popup_menu (); |
300 | 362 |
301 item_info.fMask |= MIIM_SUBMENU; | 363 item_info.fMask |= MIIM_SUBMENU; |
302 item_info.dwTypeData = displayable_menu_item (gui_item, bar_p); | 364 item_info.dwTypeData = displayable_menu_item (gui_item, bar_p, &accel); |
303 item_info.hSubMenu = submenu; | 365 item_info.hSubMenu = submenu; |
366 | |
367 if (accel && bar_p) | |
368 *accel_list = Fcons (make_char (accel), *accel_list); | |
304 | 369 |
305 if (!(item_info.fState & MFS_GRAYED)) | 370 if (!(item_info.fState & MFS_GRAYED)) |
306 { | 371 { |
307 /* Now add the full submenu path as a value to the hash table, | 372 /* Now add the full submenu path as a value to the hash table, |
308 keyed by menu handle */ | 373 keyed by menu handle */ |
309 if (NILP(path)) | 374 if (NILP(path)) |
310 /* list1 cannot GC */ | |
311 path = list1 (pgui_item->name); | 375 path = list1 (pgui_item->name); |
312 else | 376 else |
313 { | 377 { |
314 Lisp_Object arg[2]; | 378 Lisp_Object arg[2]; |
315 arg[0] = path; | 379 arg[0] = path; |
316 arg[1] = list1 (pgui_item->name); | 380 arg[1] = list1 (pgui_item->name); |
317 /* Fappend gcpro'es its arg */ | |
318 path = Fappend (2, arg); | 381 path = Fappend (2, arg); |
319 } | 382 } |
320 | 383 |
321 /* Fputhash GCPRO'es PATH */ | |
322 Fputhash (hmenu_to_lisp_object (submenu), path, hash_tab); | 384 Fputhash (hmenu_to_lisp_object (submenu), path, hash_tab); |
323 } | 385 } |
324 UNGCPRO; /* gui_item */ | 386 UNGCPRO; |
325 } | 387 } |
326 else if (VECTORP (item)) | 388 else if (VECTORP (item)) |
327 { | 389 { |
328 /* An ordinary item */ | 390 /* An ordinary item */ |
329 Lisp_Object style, id; | 391 Lisp_Object style, id; |
330 Lisp_Object gui_item = gui_parse_item_keywords (item); | 392 Lisp_Object gui_item = gui_parse_item_keywords (item); |
331 Lisp_Gui_Item* pgui_item = XGUI_ITEM (gui_item); | 393 Lisp_Gui_Item *pgui_item = XGUI_ITEM (gui_item); |
332 struct gcpro gcpro1; | 394 struct gcpro gcpro1, gcpro2; |
333 | 395 Emchar accel; |
334 GCPRO1 (gui_item); | 396 |
397 GCPRO2 (gui_item, *accel_list); | |
335 | 398 |
336 if (!gui_item_included_p (gui_item, Vmenubar_configuration)) | 399 if (!gui_item_included_p (gui_item, Vmenubar_configuration)) |
337 return; | 400 { |
401 UNGCPRO; | |
402 goto done; | |
403 } | |
404 | |
405 if (!STRINGP (pgui_item->name)) | |
406 pgui_item->name = Feval (pgui_item->name); | |
338 | 407 |
339 if (!gui_item_active_p (gui_item)) | 408 if (!gui_item_active_p (gui_item)) |
340 item_info.fState = MFS_GRAYED; | 409 item_info.fState = MFS_GRAYED; |
341 | 410 |
342 style = (NILP (pgui_item->selected) || NILP (Feval (pgui_item->selected)) | 411 style = (NILP (pgui_item->selected) || NILP (Feval (pgui_item->selected)) |
354 | 423 |
355 id = allocate_menu_item_id (path, pgui_item->name, | 424 id = allocate_menu_item_id (path, pgui_item->name, |
356 pgui_item->suffix); | 425 pgui_item->suffix); |
357 Fputhash (id, pgui_item->callback, hash_tab); | 426 Fputhash (id, pgui_item->callback, hash_tab); |
358 | 427 |
359 item_info.wID = (UINT) XINT(id); | 428 item_info.wID = (UINT) XINT (id); |
360 item_info.fType |= MFT_STRING; | 429 item_info.fType |= MFT_STRING; |
361 item_info.dwTypeData = displayable_menu_item (gui_item, bar_p); | 430 item_info.dwTypeData = displayable_menu_item (gui_item, bar_p, &accel); |
362 | 431 |
363 UNGCPRO; /* gui_item */ | 432 if (accel && bar_p) |
433 *accel_list = Fcons (make_char (accel), *accel_list); | |
434 | |
435 UNGCPRO; | |
364 } | 436 } |
365 else | 437 else |
366 { | 438 { |
367 signal_simple_error ("Malformed menu item descriptor", item); | 439 signal_simple_error ("Malformed menu item descriptor", item); |
368 } | 440 } |
369 | 441 |
370 if (flush_right) | 442 if (flush_right) |
371 item_info.fType |= MFT_RIGHTJUSTIFY; | 443 item_info.fType |= MFT_RIGHTJUSTIFY; |
372 | 444 |
373 InsertMenuItem (menu, UINT_MAX, TRUE, &item_info); | 445 InsertMenuItem (menu, UINT_MAX, TRUE, &item_info); |
446 | |
447 done:; | |
374 } | 448 } |
375 | 449 |
376 /* | 450 /* |
377 * This function is called from populate_menu and checksum_menu. | 451 * This function is called from populate_menu and checksum_menu. |
378 * When called to populate, MENU is a menu handle, PATH is a | 452 * When called to populate, MENU is a menu handle, PATH is a |
388 populate_or_checksum_helper (HMENU menu, Lisp_Object path, Lisp_Object desc, | 462 populate_or_checksum_helper (HMENU menu, Lisp_Object path, Lisp_Object desc, |
389 Lisp_Object hash_tab, int bar_p, int populate_p) | 463 Lisp_Object hash_tab, int bar_p, int populate_p) |
390 { | 464 { |
391 Lisp_Object item_desc; | 465 Lisp_Object item_desc; |
392 int deep_p, flush_right; | 466 int deep_p, flush_right; |
393 struct gcpro gcpro1; | 467 struct gcpro gcpro1, gcpro2, gcpro3; |
394 unsigned long checksum; | 468 unsigned long checksum; |
395 Lisp_Object gui_item = allocate_gui_item (); | 469 Lisp_Object gui_item = allocate_gui_item (); |
396 Lisp_Gui_Item* pgui_item = XGUI_ITEM (gui_item); | 470 Lisp_Object accel_list = Qnil; |
397 GCPRO1 (gui_item); | 471 Lisp_Gui_Item *pgui_item = XGUI_ITEM (gui_item); |
472 | |
473 GCPRO3 (gui_item, accel_list, desc); | |
398 | 474 |
399 /* We are sometimes called with the menubar unchanged, and with changed | 475 /* We are sometimes called with the menubar unchanged, and with changed |
400 right flush. We have to update the menubar in this case, | 476 right flush. We have to update the menubar in this case, |
401 so account for the compliance setting in the hash value */ | 477 so account for the compliance setting in the hash value */ |
402 checksum = REPLACE_ME_WITH_GLOBAL_VARIABLE_WHICH_CONTROLS_RIHGT_FLUSH; | 478 checksum = REPLACE_ME_WITH_GLOBAL_VARIABLE_WHICH_CONTROLS_RIGHT_FLUSH; |
403 | 479 |
404 /* Will initially contain only "(empty)" */ | 480 /* Will initially contain only "(empty)" */ |
405 if (populate_p) | 481 if (populate_p) |
406 empty_menu (menu, 1); | 482 empty_menu (menu, 1); |
407 | 483 |
424 EXTERNAL_LIST_LOOP (item_desc, desc) | 500 EXTERNAL_LIST_LOOP (item_desc, desc) |
425 { | 501 { |
426 if (NILP (XCAR (item_desc))) | 502 if (NILP (XCAR (item_desc))) |
427 { | 503 { |
428 /* Do not flush right menubar items when MS style compliant */ | 504 /* Do not flush right menubar items when MS style compliant */ |
429 if (bar_p && !REPLACE_ME_WITH_GLOBAL_VARIABLE_WHICH_CONTROLS_RIHGT_FLUSH) | 505 if (bar_p && !REPLACE_ME_WITH_GLOBAL_VARIABLE_WHICH_CONTROLS_RIGHT_FLUSH) |
430 flush_right = 1; | 506 flush_right = 1; |
431 if (!populate_p) | 507 if (!populate_p) |
432 checksum = HASH2 (checksum, LISP_HASH (Qnil)); | 508 checksum = HASH2 (checksum, LISP_HASH (Qnil)); |
433 } | 509 } |
434 else if (populate_p) | 510 else if (populate_p) |
435 populate_menu_add_item (menu, path, hash_tab, | 511 populate_menu_add_item (menu, path, hash_tab, |
436 XCAR (item_desc), flush_right, bar_p); | 512 XCAR (item_desc), &accel_list, |
513 flush_right, bar_p); | |
437 else | 514 else |
438 checksum = HASH2 (checksum, | 515 checksum = HASH2 (checksum, |
439 checksum_menu_item (XCAR (item_desc))); | 516 checksum_menu_item (XCAR (item_desc))); |
440 } | 517 } |
441 | 518 |
445 if (GetMenuItemCount (menu) > 1) | 522 if (GetMenuItemCount (menu) > 1) |
446 RemoveMenu (menu, EMPTY_ITEM_ID, MF_BYCOMMAND); | 523 RemoveMenu (menu, EMPTY_ITEM_ID, MF_BYCOMMAND); |
447 | 524 |
448 /* Add the header to the popup, if told so. The same as in X - an | 525 /* Add the header to the popup, if told so. The same as in X - an |
449 insensitive item, and a separator (Seems to me, there were | 526 insensitive item, and a separator (Seems to me, there were |
450 two separators in X... In Windows this looks ugly, anyways. */ | 527 two separators in X... In Windows this looks ugly, anyways.) */ |
451 if (!bar_p && !deep_p && popup_menu_titles && !NILP(pgui_item->name)) | 528 if (!bar_p && !deep_p && popup_menu_titles && !NILP (pgui_item->name)) |
452 { | 529 { |
453 CHECK_STRING (pgui_item->name); | 530 CHECK_STRING (pgui_item->name); |
454 InsertMenu (menu, 0, MF_BYPOSITION | MF_STRING | MF_DISABLED, | 531 InsertMenu (menu, 0, MF_BYPOSITION | MF_STRING | MF_DISABLED, |
455 0, XSTRING_DATA(pgui_item->name)); | 532 0, XSTRING_DATA(pgui_item->name)); |
456 InsertMenu (menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); | 533 InsertMenu (menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); |
457 SetMenuDefaultItem (menu, 0, MF_BYPOSITION); | 534 SetMenuDefaultItem (menu, 0, MF_BYPOSITION); |
458 } | 535 } |
459 } | 536 } |
460 UNGCPRO; /* gui_item */ | 537 |
538 if (bar_p) | |
539 Fputhash (Qt, accel_list, hash_tab); | |
540 | |
541 UNGCPRO; | |
461 return checksum; | 542 return checksum; |
462 } | 543 } |
463 | 544 |
464 static void | 545 static void |
465 populate_menu (HMENU menu, Lisp_Object path, Lisp_Object desc, | 546 populate_menu (HMENU menu, Lisp_Object path, Lisp_Object desc, |
466 Lisp_Object hash_tab, int bar_p) | 547 Lisp_Object hash_tab, int bar_p) |
467 { | 548 { |
468 populate_or_checksum_helper (menu, path, desc, hash_tab, bar_p, 1); | 549 populate_or_checksum_helper (menu, path, desc, hash_tab, bar_p, 1); |
469 } | 550 } |
470 | 551 |
471 static unsigned long | 552 static unsigned long |
473 { | 554 { |
474 return populate_or_checksum_helper (NULL, Qnil, desc, Qunbound, 0, 0); | 555 return populate_or_checksum_helper (NULL, Qnil, desc, Qunbound, 0, 0); |
475 } | 556 } |
476 | 557 |
477 static void | 558 static void |
478 update_frame_menubar_maybe (struct frame* f) | 559 update_frame_menubar_maybe (struct frame *f) |
479 { | 560 { |
480 HMENU menubar = GetMenu (FRAME_MSWINDOWS_HANDLE (f)); | 561 HMENU menubar = GetMenu (FRAME_MSWINDOWS_HANDLE (f)); |
481 struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f)); | 562 struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f)); |
482 Lisp_Object desc = (!NILP (w->menubar_visible_p) | 563 Lisp_Object desc = (!NILP (w->menubar_visible_p) |
483 ? symbol_value_in_buffer (Qcurrent_menubar, w->buffer) | 564 ? symbol_value_in_buffer (Qcurrent_menubar, w->buffer) |
484 : Qnil); | 565 : Qnil); |
566 struct gcpro gcpro1; | |
567 | |
568 GCPRO1 (desc); /* it's safest to do this, just in case some filter | |
569 or something changes the value of current-menubar */ | |
485 | 570 |
486 top_level_menu = menubar; | 571 top_level_menu = menubar; |
487 | 572 |
488 if (NILP (desc) && menubar != NULL) | 573 if (NILP (desc) && menubar != NULL) |
489 { | 574 { |
490 /* Menubar has gone */ | 575 /* Menubar has gone */ |
491 FRAME_MSWINDOWS_MENU_HASH_TABLE(f) = Qnil; | 576 FRAME_MSWINDOWS_MENU_HASH_TABLE (f) = Qnil; |
492 SetMenu (FRAME_MSWINDOWS_HANDLE (f), NULL); | 577 SetMenu (FRAME_MSWINDOWS_HANDLE (f), NULL); |
493 DestroyMenu (menubar); | 578 DestroyMenu (menubar); |
494 DrawMenuBar (FRAME_MSWINDOWS_HANDLE (f)); | 579 DrawMenuBar (FRAME_MSWINDOWS_HANDLE (f)); |
580 UNGCPRO; | |
495 return; | 581 return; |
496 } | 582 } |
497 | 583 |
498 if (!NILP (desc) && menubar == NULL) | 584 if (!NILP (desc) && menubar == NULL) |
499 { | 585 { |
503 } | 589 } |
504 | 590 |
505 if (NILP (desc)) | 591 if (NILP (desc)) |
506 { | 592 { |
507 /* We did not have the bar and are not going to */ | 593 /* We did not have the bar and are not going to */ |
594 UNGCPRO; | |
508 return; | 595 return; |
509 } | 596 } |
510 | 597 |
511 /* Now we bail out if the menubar has not changed */ | 598 /* Now we bail out if the menubar has not changed */ |
512 if (FRAME_MSWINDOWS_MENU_CHECKSUM(f) == checksum_menu (desc)) | 599 if (FRAME_MSWINDOWS_MENU_CHECKSUM (f) == checksum_menu (desc)) |
513 return; | 600 { |
601 UNGCPRO; | |
602 return; | |
603 } | |
514 | 604 |
515 populate: | 605 populate: |
516 /* Come with empty hash table */ | 606 /* Come with empty hash table */ |
517 if (NILP (FRAME_MSWINDOWS_MENU_HASH_TABLE(f))) | 607 if (NILP (FRAME_MSWINDOWS_MENU_HASH_TABLE (f))) |
518 FRAME_MSWINDOWS_MENU_HASH_TABLE(f) = | 608 FRAME_MSWINDOWS_MENU_HASH_TABLE (f) = |
519 make_lisp_hash_table (50, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL); | 609 make_lisp_hash_table (50, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL); |
520 else | 610 else |
521 Fclrhash (FRAME_MSWINDOWS_MENU_HASH_TABLE(f)); | 611 Fclrhash (FRAME_MSWINDOWS_MENU_HASH_TABLE (f)); |
522 | 612 |
523 Fputhash (hmenu_to_lisp_object (menubar), Qnil, | 613 Fputhash (hmenu_to_lisp_object (menubar), Qnil, |
524 FRAME_MSWINDOWS_MENU_HASH_TABLE(f)); | 614 FRAME_MSWINDOWS_MENU_HASH_TABLE (f)); |
525 populate_menu (menubar, Qnil, desc, | 615 populate_menu (menubar, Qnil, desc, |
526 FRAME_MSWINDOWS_MENU_HASH_TABLE(f), 1); | 616 FRAME_MSWINDOWS_MENU_HASH_TABLE (f), 1); |
527 SetMenu (FRAME_MSWINDOWS_HANDLE (f), menubar); | 617 SetMenu (FRAME_MSWINDOWS_HANDLE (f), menubar); |
528 DrawMenuBar (FRAME_MSWINDOWS_HANDLE (f)); | 618 DrawMenuBar (FRAME_MSWINDOWS_HANDLE (f)); |
529 | 619 |
530 FRAME_MSWINDOWS_MENU_CHECKSUM(f) = checksum_menu (desc); | 620 FRAME_MSWINDOWS_MENU_CHECKSUM (f) = checksum_menu (desc); |
621 | |
622 UNGCPRO; | |
531 } | 623 } |
532 | 624 |
533 static void | 625 static void |
534 prune_menubar (struct frame *f) | 626 prune_menubar (struct frame *f) |
535 { | 627 { |
536 HMENU menubar = GetMenu (FRAME_MSWINDOWS_HANDLE (f)); | 628 HMENU menubar = GetMenu (FRAME_MSWINDOWS_HANDLE (f)); |
537 Lisp_Object desc = current_frame_menubar (f); | 629 Lisp_Object desc = current_frame_menubar (f); |
630 struct gcpro gcpro1; | |
631 | |
538 if (menubar == NULL) | 632 if (menubar == NULL) |
539 return; | 633 return; |
540 | 634 |
541 /* #### If a filter function has set desc to Qnil, this abort() | 635 /* #### If a filter function has set desc to Qnil, this abort() |
542 triggers. To resolve, we must prevent filters explicitly from | 636 triggers. To resolve, we must prevent filters explicitly from |
543 mangling with the active menu. In apply_filter probably? | 637 mangling with the active menu. In apply_filter probably? |
544 Is copy-tree on the whole menu too expensive? */ | 638 Is copy-tree on the whole menu too expensive? */ |
545 if (NILP(desc)) | 639 if (NILP (desc)) |
546 /* abort(); */ | 640 /* abort(); */ |
547 return; | 641 return; |
548 | 642 |
643 GCPRO1 (desc); /* just to be safe -- see above */ | |
549 /* We do the trick by removing all items and re-populating top level */ | 644 /* We do the trick by removing all items and re-populating top level */ |
550 empty_menu (menubar, 0); | 645 empty_menu (menubar, 0); |
551 | 646 |
552 assert (HASH_TABLEP (FRAME_MSWINDOWS_MENU_HASH_TABLE(f))); | 647 assert (HASH_TABLEP (FRAME_MSWINDOWS_MENU_HASH_TABLE (f))); |
553 Fclrhash (FRAME_MSWINDOWS_MENU_HASH_TABLE(f)); | 648 Fclrhash (FRAME_MSWINDOWS_MENU_HASH_TABLE (f)); |
554 | 649 |
555 Fputhash (hmenu_to_lisp_object (menubar), Qnil, | 650 Fputhash (hmenu_to_lisp_object (menubar), Qnil, |
556 FRAME_MSWINDOWS_MENU_HASH_TABLE(f)); | 651 FRAME_MSWINDOWS_MENU_HASH_TABLE (f)); |
557 populate_menu (menubar, Qnil, desc, | 652 populate_menu (menubar, Qnil, desc, |
558 FRAME_MSWINDOWS_MENU_HASH_TABLE(f), 1); | 653 FRAME_MSWINDOWS_MENU_HASH_TABLE (f), 1); |
654 UNGCPRO; | |
559 } | 655 } |
560 | 656 |
561 /* | 657 /* |
562 * This is called when cleanup is possible. It is better not to | 658 * This is called when cleanup is possible. It is better not to |
563 * clean things up at all than do it too early! | 659 * clean things up at all than do it too early! |
568 /* This function can GC */ | 664 /* This function can GC */ |
569 current_menudesc = Qnil; | 665 current_menudesc = Qnil; |
570 current_hash_table = Qnil; | 666 current_hash_table = Qnil; |
571 prune_menubar (f); | 667 prune_menubar (f); |
572 } | 668 } |
669 | |
670 int | |
671 msw_char_is_accelerator (struct frame *f, Emchar ch) | |
672 { | |
673 Lisp_Object hash = FRAME_MSWINDOWS_MENU_HASH_TABLE (f); | |
674 | |
675 assert (HASH_TABLEP (hash)); | |
676 /* !!#### not Mule-ized */ | |
677 return !NILP (memq_no_quit (make_char (tolower (ch)), | |
678 Fgethash (Qt, hash, Qnil))); | |
679 } | |
573 | 680 |
574 | 681 |
575 /*------------------------------------------------------------------------*/ | 682 /*------------------------------------------------------------------------*/ |
576 /* Message handlers */ | 683 /* Message handlers */ |
577 /*------------------------------------------------------------------------*/ | 684 /*------------------------------------------------------------------------*/ |
578 static Lisp_Object | 685 static Lisp_Object |
579 unsafe_handle_wm_initmenupopup_1 (HMENU menu, struct frame* f) | 686 unsafe_handle_wm_initmenupopup_1 (HMENU menu, struct frame *f) |
580 { | 687 { |
581 /* This function can call lisp, beat dogs and stick chewing gum to | 688 /* This function can call lisp, beat dogs and stick chewing gum to |
582 everything! */ | 689 everything! */ |
583 | 690 |
584 Lisp_Object path, desc; | 691 Lisp_Object path, desc; |
606 UNGCPRO; | 713 UNGCPRO; |
607 return Qt; | 714 return Qt; |
608 } | 715 } |
609 | 716 |
610 static Lisp_Object | 717 static Lisp_Object |
611 unsafe_handle_wm_initmenu_1 (struct frame* f) | 718 unsafe_handle_wm_initmenu_1 (struct frame *f) |
612 { | 719 { |
613 /* This function can call lisp */ | 720 /* This function can call lisp */ |
614 | 721 |
615 /* NOTE: This is called for the bar only, WM_INITMENU | 722 /* NOTE: This is called for the bar only, WM_INITMENU |
616 for popups is filtered out */ | 723 for popups is filtered out */ |
623 run_hook (Qactivate_menubar_hook); | 730 run_hook (Qactivate_menubar_hook); |
624 | 731 |
625 update_frame_menubar_maybe (f); | 732 update_frame_menubar_maybe (f); |
626 | 733 |
627 current_menudesc = current_frame_menubar (f); | 734 current_menudesc = current_frame_menubar (f); |
628 current_hash_table = FRAME_MSWINDOWS_MENU_HASH_TABLE(f); | 735 current_hash_table = FRAME_MSWINDOWS_MENU_HASH_TABLE (f); |
629 assert (HASH_TABLEP (current_hash_table)); | 736 assert (HASH_TABLEP (current_hash_table)); |
630 | 737 |
631 return Qt; | 738 return Qt; |
632 } | 739 } |
633 | 740 |
636 * or Qnil if id has not been mapped to a callback. | 743 * or Qnil if id has not been mapped to a callback. |
637 * Window procedure may try other targets to route the | 744 * Window procedure may try other targets to route the |
638 * command if we return nil | 745 * command if we return nil |
639 */ | 746 */ |
640 Lisp_Object | 747 Lisp_Object |
641 mswindows_handle_wm_command (struct frame* f, WORD id) | 748 mswindows_handle_wm_command (struct frame *f, WORD id) |
642 { | 749 { |
643 /* Try to map the command id through the proper hash table */ | 750 /* Try to map the command id through the proper hash table */ |
644 Lisp_Object data, fn, arg, frame; | 751 Lisp_Object data, fn, arg, frame; |
645 struct gcpro gcpro1; | 752 struct gcpro gcpro1; |
646 | 753 |
678 /*------------------------------------------------------------------------*/ | 785 /*------------------------------------------------------------------------*/ |
679 /* Message handling proxies */ | 786 /* Message handling proxies */ |
680 /*------------------------------------------------------------------------*/ | 787 /*------------------------------------------------------------------------*/ |
681 | 788 |
682 static HMENU wm_initmenu_menu; | 789 static HMENU wm_initmenu_menu; |
683 static struct frame* wm_initmenu_frame; | 790 static struct frame *wm_initmenu_frame; |
684 | 791 |
685 static Lisp_Object | 792 static Lisp_Object |
686 unsafe_handle_wm_initmenupopup (Lisp_Object u_n_u_s_e_d) | 793 unsafe_handle_wm_initmenupopup (Lisp_Object u_n_u_s_e_d) |
687 { | 794 { |
688 return unsafe_handle_wm_initmenupopup_1 (wm_initmenu_menu, wm_initmenu_frame); | 795 return unsafe_handle_wm_initmenupopup_1 (wm_initmenu_menu, wm_initmenu_frame); |
693 { | 800 { |
694 return unsafe_handle_wm_initmenu_1 (wm_initmenu_frame); | 801 return unsafe_handle_wm_initmenu_1 (wm_initmenu_frame); |
695 } | 802 } |
696 | 803 |
697 Lisp_Object | 804 Lisp_Object |
698 mswindows_handle_wm_initmenupopup (HMENU hmenu, struct frame* frm) | 805 mswindows_handle_wm_initmenupopup (HMENU hmenu, struct frame *frm) |
699 { | 806 { |
700 /* We cannot pass hmenu as a lisp object. Use static var */ | 807 /* We cannot pass hmenu as a lisp object. Use static var */ |
701 wm_initmenu_menu = hmenu; | 808 wm_initmenu_menu = hmenu; |
702 wm_initmenu_frame = frm; | 809 wm_initmenu_frame = frm; |
703 return mswindows_protect_modal_loop (unsafe_handle_wm_initmenupopup, Qnil); | 810 return mswindows_protect_modal_loop (unsafe_handle_wm_initmenupopup, Qnil); |
704 } | 811 } |
705 | 812 |
706 Lisp_Object | 813 Lisp_Object |
707 mswindows_handle_wm_initmenu (HMENU hmenu, struct frame* f) | 814 mswindows_handle_wm_initmenu (HMENU hmenu, struct frame *f) |
708 { | 815 { |
709 /* Handle only frame menubar, ignore if from popup or system menu */ | 816 /* Handle only frame menubar, ignore if from popup or system menu */ |
710 if (GetMenu (FRAME_MSWINDOWS_HANDLE(f)) == hmenu) | 817 if (GetMenu (FRAME_MSWINDOWS_HANDLE (f)) == hmenu) |
711 { | 818 { |
712 wm_initmenu_frame = f; | 819 wm_initmenu_frame = f; |
713 return mswindows_protect_modal_loop (unsafe_handle_wm_initmenu, Qnil); | 820 return mswindows_protect_modal_loop (unsafe_handle_wm_initmenu, Qnil); |
714 } | 821 } |
715 return Qt; | 822 return Qt; |
719 /*------------------------------------------------------------------------*/ | 826 /*------------------------------------------------------------------------*/ |
720 /* Methods */ | 827 /* Methods */ |
721 /*------------------------------------------------------------------------*/ | 828 /*------------------------------------------------------------------------*/ |
722 | 829 |
723 static void | 830 static void |
724 mswindows_update_frame_menubars (struct frame* f) | 831 mswindows_update_frame_menubars (struct frame *f) |
725 { | 832 { |
726 update_frame_menubar_maybe (f); | 833 update_frame_menubar_maybe (f); |
727 } | 834 } |
728 | 835 |
729 static void | 836 static void |
730 mswindows_free_frame_menubars (struct frame* f) | 837 mswindows_free_frame_menubars (struct frame *f) |
731 { | 838 { |
732 FRAME_MSWINDOWS_MENU_HASH_TABLE(f) = Qnil; | 839 FRAME_MSWINDOWS_MENU_HASH_TABLE (f) = Qnil; |
733 } | 840 } |
734 | 841 |
735 static void | 842 static void |
736 mswindows_popup_menu (Lisp_Object menu_desc, Lisp_Object event) | 843 mswindows_popup_menu (Lisp_Object menu_desc, Lisp_Object event) |
737 { | 844 { |
738 struct frame *f = selected_frame (); | 845 struct frame *f = selected_frame (); |
739 Lisp_Event *eev = NULL; | 846 Lisp_Event *eev = NULL; |
740 HMENU menu; | 847 HMENU menu; |
741 POINT pt; | 848 POINT pt; |
742 int ok; | 849 int ok; |
850 struct gcpro gcpro1; | |
851 | |
852 GCPRO1 (menu_desc); /* to be safe -- see above */ | |
743 | 853 |
744 if (!NILP (event)) | 854 if (!NILP (event)) |
745 { | 855 { |
746 CHECK_LIVE_EVENT (event); | 856 CHECK_LIVE_EVENT (event); |
747 eev = XEVENT (event); | 857 eev = XEVENT (event); |
775 CHECK_STRING (XCAR (menu_desc)); | 885 CHECK_STRING (XCAR (menu_desc)); |
776 | 886 |
777 current_menudesc = menu_desc; | 887 current_menudesc = menu_desc; |
778 current_hash_table = | 888 current_hash_table = |
779 make_lisp_hash_table (10, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL); | 889 make_lisp_hash_table (10, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL); |
780 menu = create_empty_popup_menu(); | 890 menu = create_empty_popup_menu (); |
781 Fputhash (hmenu_to_lisp_object (menu), Qnil, current_hash_table); | 891 Fputhash (hmenu_to_lisp_object (menu), Qnil, current_hash_table); |
782 top_level_menu = menu; | 892 top_level_menu = menu; |
783 | 893 |
784 /* see comments in menubar-x.c */ | 894 /* see comments in menubar-x.c */ |
785 if (zmacs_regions) | 895 if (zmacs_regions) |
794 | 904 |
795 /* Signal a signal if caught by Track...() modal loop */ | 905 /* Signal a signal if caught by Track...() modal loop */ |
796 mswindows_unmodalize_signal_maybe (); | 906 mswindows_unmodalize_signal_maybe (); |
797 | 907 |
798 /* This is probably the only real reason for failure */ | 908 /* This is probably the only real reason for failure */ |
799 if (!ok) { | 909 if (!ok) |
800 menu_cleanup (f); | 910 { |
801 signal_simple_error ("Cannot track popup menu while in menu", | 911 menu_cleanup (f); |
802 menu_desc); | 912 signal_simple_error ("Cannot track popup menu while in menu", |
803 } | 913 menu_desc); |
914 } | |
915 UNGCPRO; | |
804 } | 916 } |
805 | 917 |
806 | 918 |
807 /*------------------------------------------------------------------------*/ | 919 /*------------------------------------------------------------------------*/ |
808 /* Initialization */ | 920 /* Initialization */ |