comparison src/menubar-msw.c @ 412:697ef44129c6 r21-2-14

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