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 */