Mercurial > hg > xemacs-beta
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 */ |