1 /* Menu support for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2021 Free
3 Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20 #include <config.h>
21
22 #include <signal.h>
23 #include <stdio.h>
24 #include <setjmp.h>
25
26 #include "lisp.h"
27 #include "keyboard.h"
28 #include "frame.h"
29 #include "blockinput.h"
30 #include "buffer.h"
31 #include "coding.h" /* for ENCODE_SYSTEM */
32 #include "menu.h"
33 #include "pdumper.h"
34
35 /* This may include sys/types.h, and that somehow loses
36 if this is not done before the other system files. */
37 #include "w32term.h"
38
39 /* Cygwin does not support the multibyte string functions declared in
40 * mbstring.h below --- but that's okay: because Cygwin is
41 * UNICODE-only, we don't need to use these functions anyway. */
42
43 #ifndef NTGUI_UNICODE
44 #include <mbstring.h>
45 #endif /* !NTGUI_UNICODE */
46
47 /* Load sys/types.h if not already loaded.
48 In some systems loading it twice is suicidal. */
49 #ifndef makedev
50 #include <sys/types.h>
51 #endif
52
53 #include "w32common.h" /* for osinfo_cache */
54
55 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
56
57 #ifndef TRUE
58 #define TRUE 1
59 #define FALSE 0
60 #endif /* no TRUE */
61
62 HMENU current_popup_menu;
63
64 typedef BOOL (WINAPI * GetMenuItemInfoA_Proc) (
65 IN HMENU,
66 IN UINT,
67 IN BOOL,
68 IN OUT LPMENUITEMINFOA);
69 typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) (
70 IN HMENU,
71 IN UINT,
72 IN BOOL,
73 IN LPCMENUITEMINFOA);
74 typedef int (WINAPI * MessageBoxW_Proc) (
75 IN HWND window,
76 IN const WCHAR *text,
77 IN const WCHAR *caption,
78 IN UINT type);
79
80 #ifdef NTGUI_UNICODE
81 GetMenuItemInfoA_Proc get_menu_item_info = GetMenuItemInfoA;
82 SetMenuItemInfoA_Proc set_menu_item_info = SetMenuItemInfoA;
83 AppendMenuW_Proc unicode_append_menu = AppendMenuW;
84 MessageBoxW_Proc unicode_message_box = MessageBoxW;
85 #else /* !NTGUI_UNICODE */
86 GetMenuItemInfoA_Proc get_menu_item_info = NULL;
87 SetMenuItemInfoA_Proc set_menu_item_info = NULL;
88 AppendMenuW_Proc unicode_append_menu = NULL;
89 MessageBoxW_Proc unicode_message_box = NULL;
90 #endif /* NTGUI_UNICODE */
91
92 #ifdef HAVE_DIALOGS
93 static Lisp_Object w32_dialog_show (struct frame *, Lisp_Object, Lisp_Object, char **);
94 #else
95 static bool is_simple_dialog (Lisp_Object);
96 static Lisp_Object simple_dialog_show (struct frame *, Lisp_Object, Lisp_Object);
97 #endif
98
99 static void utf8to16 (unsigned char *, int, WCHAR *);
100 static int fill_in_menu (HMENU, widget_value *);
101
102 void w32_free_menu_strings (HWND);
103
104 Lisp_Object
w32_popup_dialog(struct frame * f,Lisp_Object header,Lisp_Object contents)105 w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
106 {
107
108 check_window_system (f);
109
110 #ifndef HAVE_DIALOGS
111
112 /* Handle simple Yes/No choices as MessageBox popups. */
113 if (is_simple_dialog (contents))
114 return simple_dialog_show (f, contents, header);
115 else
116 return Qunsupported__w32_dialog;
117 #else /* HAVE_DIALOGS */
118 {
119 Lisp_Object title;
120 char *error_name;
121 Lisp_Object selection;
122
123 /* Decode the dialog items from what was specified. */
124 title = Fcar (contents);
125 CHECK_STRING (title);
126
127 list_of_panes (Fcons (contents, Qnil));
128
129 /* Display them in a dialog box. */
130 block_input ();
131 selection = w32_dialog_show (f, title, header, &error_name);
132 unblock_input ();
133
134 discard_menu_items ();
135 FRAME_DISPLAY_INFO (f)->grabbed = 0;
136
137 if (error_name) error (error_name);
138 return selection;
139 }
140 #endif /* HAVE_DIALOGS */
141 }
142
143 /* Activate the menu bar of frame F.
144 This is called from keyboard.c when it gets the
145 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
146
147 To activate the menu bar, we signal to the input thread that it can
148 return from the WM_INITMENU message, allowing the normal Windows
149 processing of the menus.
150
151 But first we recompute the menu bar contents (the whole tree).
152
153 This way we can safely execute Lisp code. */
154
155 void
w32_activate_menubar(struct frame * f)156 w32_activate_menubar (struct frame *f)
157 {
158 set_frame_menubar (f, true);
159
160 /* Lock out further menubar changes while active. */
161 f->output_data.w32->menubar_active = 1;
162
163 /* Signal input thread to return from WM_INITMENU. */
164 complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
165 }
166
167 /* This callback is called from the menu bar pulldown menu
168 when the user makes a selection.
169 Figure out what the user chose
170 and put the appropriate events into the keyboard buffer. */
171 void menubar_selection_callback (struct frame *, void *);
172
173 void
menubar_selection_callback(struct frame * f,void * client_data)174 menubar_selection_callback (struct frame *f, void * client_data)
175 {
176 Lisp_Object prefix, entry;
177 Lisp_Object vector;
178 Lisp_Object *subprefix_stack;
179 int submenu_depth = 0;
180 int i;
181
182 if (!f)
183 return;
184 entry = Qnil;
185 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * word_size);
186 vector = f->menu_bar_vector;
187 prefix = Qnil;
188 i = 0;
189 while (i < f->menu_bar_items_used)
190 {
191 if (EQ (AREF (vector, i), Qnil))
192 {
193 subprefix_stack[submenu_depth++] = prefix;
194 prefix = entry;
195 i++;
196 }
197 else if (EQ (AREF (vector, i), Qlambda))
198 {
199 prefix = subprefix_stack[--submenu_depth];
200 i++;
201 }
202 else if (EQ (AREF (vector, i), Qt))
203 {
204 prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
205 i += MENU_ITEMS_PANE_LENGTH;
206 }
207 else
208 {
209 entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
210 /* The UINT_PTR cast avoids a warning. There's no problem
211 as long as pointers have enough bits to hold small integers. */
212 if ((int) (UINT_PTR) client_data == i)
213 {
214 int j;
215 struct input_event buf;
216 Lisp_Object frame;
217 EVENT_INIT (buf);
218
219 XSETFRAME (frame, f);
220 buf.kind = MENU_BAR_EVENT;
221 buf.frame_or_window = frame;
222 buf.arg = frame;
223 kbd_buffer_store_event (&buf);
224
225 for (j = 0; j < submenu_depth; j++)
226 if (!NILP (subprefix_stack[j]))
227 {
228 buf.kind = MENU_BAR_EVENT;
229 buf.frame_or_window = frame;
230 buf.arg = subprefix_stack[j];
231 kbd_buffer_store_event (&buf);
232 }
233
234 if (!NILP (prefix))
235 {
236 buf.kind = MENU_BAR_EVENT;
237 buf.frame_or_window = frame;
238 buf.arg = prefix;
239 kbd_buffer_store_event (&buf);
240 }
241
242 buf.kind = MENU_BAR_EVENT;
243 buf.frame_or_window = frame;
244 buf.arg = entry;
245 /* Free memory used by owner-drawn and help-echo strings. */
246 w32_free_menu_strings (FRAME_W32_WINDOW (f));
247 kbd_buffer_store_event (&buf);
248
249 f->output_data.w32->menubar_active = 0;
250 return;
251 }
252 i += MENU_ITEMS_ITEM_LENGTH;
253 }
254 }
255 /* Free memory used by owner-drawn and help-echo strings. */
256 w32_free_menu_strings (FRAME_W32_WINDOW (f));
257 f->output_data.w32->menubar_active = 0;
258 }
259
260
261 /* Set the contents of the menubar widgets of frame F. */
262
263 void
set_frame_menubar(struct frame * f,bool deep_p)264 set_frame_menubar (struct frame *f, bool deep_p)
265 {
266 HMENU menubar_widget = f->output_data.w32->menubar_widget;
267 Lisp_Object items;
268 widget_value *wv, *first_wv, *prev_wv = 0;
269 int i, last_i = 0;
270 int *submenu_start, *submenu_end;
271 int *submenu_top_level_items, *submenu_n_panes;
272
273 /* We must not change the menubar when actually in use. */
274 if (f->output_data.w32->menubar_active)
275 return;
276
277 XSETFRAME (Vmenu_updating_frame, f);
278
279 if (! menubar_widget)
280 deep_p = true;
281
282 if (deep_p)
283 {
284 /* Make a widget-value tree representing the entire menu trees. */
285
286 struct buffer *prev = current_buffer;
287 Lisp_Object buffer;
288 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
289 int previous_menu_items_used = f->menu_bar_items_used;
290 Lisp_Object *previous_items
291 = (Lisp_Object *) alloca (previous_menu_items_used
292 * word_size);
293
294 /* If we are making a new widget, its contents are empty,
295 do always reinitialize them. */
296 if (! menubar_widget)
297 previous_menu_items_used = 0;
298
299 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
300 specbind (Qinhibit_quit, Qt);
301 /* Don't let the debugger step into this code
302 because it is not reentrant. */
303 specbind (Qdebug_on_next_call, Qnil);
304
305 record_unwind_save_match_data ();
306
307 if (NILP (Voverriding_local_map_menu_flag))
308 {
309 specbind (Qoverriding_terminal_local_map, Qnil);
310 specbind (Qoverriding_local_map, Qnil);
311 }
312
313 set_buffer_internal_1 (XBUFFER (buffer));
314
315 /* Run the hooks. */
316 safe_run_hooks (Qactivate_menubar_hook);
317 safe_run_hooks (Qmenu_bar_update_hook);
318 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
319
320 items = FRAME_MENU_BAR_ITEMS (f);
321
322 /* Save the frame's previous menu bar contents data. */
323 if (previous_menu_items_used)
324 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
325 previous_menu_items_used * word_size);
326
327 /* Fill in menu_items with the current menu bar contents.
328 This can evaluate Lisp code. */
329 save_menu_items ();
330
331 menu_items = f->menu_bar_vector;
332 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
333 submenu_start = (int *) alloca (ASIZE (items) * sizeof (int));
334 submenu_end = (int *) alloca (ASIZE (items) * sizeof (int));
335 submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int));
336 submenu_top_level_items = (int *) alloca (ASIZE (items) * sizeof (int));
337 init_menu_items ();
338 for (i = 0; i < ASIZE (items); i += 4)
339 {
340 Lisp_Object key, string, maps;
341
342 last_i = i;
343
344 key = AREF (items, i);
345 string = AREF (items, i + 1);
346 maps = AREF (items, i + 2);
347 if (NILP (string))
348 break;
349
350 submenu_start[i] = menu_items_used;
351
352 menu_items_n_panes = 0;
353 submenu_top_level_items[i]
354 = parse_single_submenu (key, string, maps);
355 submenu_n_panes[i] = menu_items_n_panes;
356
357 submenu_end[i] = menu_items_used;
358 }
359
360 finish_menu_items ();
361
362 /* Convert menu_items into widget_value trees
363 to display the menu. This cannot evaluate Lisp code. */
364
365 wv = make_widget_value ("menubar", NULL, true, Qnil);
366 wv->button_type = BUTTON_TYPE_NONE;
367 first_wv = wv;
368
369 for (i = 0; i < last_i; i += 4)
370 {
371 menu_items_n_panes = submenu_n_panes[i];
372 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
373 submenu_top_level_items[i]);
374 if (prev_wv)
375 prev_wv->next = wv;
376 else
377 first_wv->contents = wv;
378 /* Don't set wv->name here; GC during the loop might relocate it. */
379 wv->enabled = true;
380 wv->button_type = BUTTON_TYPE_NONE;
381 prev_wv = wv;
382 }
383
384 set_buffer_internal_1 (prev);
385
386 /* If there has been no change in the Lisp-level contents
387 of the menu bar, skip redisplaying it. Just exit. */
388
389 for (i = 0; i < previous_menu_items_used; i++)
390 if (menu_items_used == i
391 || (!EQ (previous_items[i], AREF (menu_items, i))))
392 break;
393 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
394 {
395 free_menubar_widget_value_tree (first_wv);
396 discard_menu_items ();
397 unbind_to (specpdl_count, Qnil);
398 return;
399 }
400
401 fset_menu_bar_vector (f, menu_items);
402 f->menu_bar_items_used = menu_items_used;
403
404 /* This undoes save_menu_items. */
405 unbind_to (specpdl_count, Qnil);
406
407 /* Now GC cannot happen during the lifetime of the widget_value,
408 so it's safe to store data from a Lisp_String, as long as
409 local copies are made when the actual menu is created.
410 Windows takes care of this for normal string items, but
411 not for owner-drawn items or additional item-info. */
412 wv = first_wv->contents;
413 for (i = 0; i < ASIZE (items); i += 4)
414 {
415 Lisp_Object string;
416 string = AREF (items, i + 1);
417 if (NILP (string))
418 break;
419 wv->name = SSDATA (string);
420 update_submenu_strings (wv->contents);
421 wv = wv->next;
422 }
423 }
424 else
425 {
426 /* Make a widget-value tree containing
427 just the top level menu bar strings. */
428
429 wv = make_widget_value ("menubar", NULL, true, Qnil);
430 wv->button_type = BUTTON_TYPE_NONE;
431 first_wv = wv;
432
433 items = FRAME_MENU_BAR_ITEMS (f);
434 for (i = 0; i < ASIZE (items); i += 4)
435 {
436 Lisp_Object string;
437
438 string = AREF (items, i + 1);
439 if (NILP (string))
440 break;
441
442 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
443 wv->button_type = BUTTON_TYPE_NONE;
444 /* This prevents lwlib from assuming this
445 menu item is really supposed to be empty. */
446 /* The EMACS_INT cast avoids a warning.
447 This value just has to be different from small integers. */
448 wv->call_data = (void *) (EMACS_INT) (-1);
449
450 if (prev_wv)
451 prev_wv->next = wv;
452 else
453 first_wv->contents = wv;
454 prev_wv = wv;
455 }
456
457 /* Forget what we thought we knew about what is in the
458 detailed contents of the menu bar menus.
459 Changing the top level always destroys the contents. */
460 f->menu_bar_items_used = 0;
461 }
462
463 /* Create or update the menu bar widget. */
464
465 block_input ();
466
467 if (menubar_widget)
468 {
469 /* Empty current menubar, rather than creating a fresh one. */
470 while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
471 ;
472 }
473 else
474 {
475 menubar_widget = CreateMenu ();
476 }
477 fill_in_menu (menubar_widget, first_wv->contents);
478
479 free_menubar_widget_value_tree (first_wv);
480
481 {
482 HMENU old_widget = f->output_data.w32->menubar_widget;
483
484 f->output_data.w32->menubar_widget = menubar_widget;
485 SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
486 /* Causes flicker when menu bar is updated
487 DrawMenuBar (FRAME_W32_WINDOW (f)); */
488
489 /* Force the window size to be recomputed so that the frame's text
490 area remains the same, if menubar has just been created. */
491 if (old_widget == NULL)
492 {
493 windows_or_buffers_changed = 23;
494 adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
495 }
496 }
497
498 unblock_input ();
499 }
500
501 /* Called from Fx_create_frame to create the initial menubar of a frame
502 before it is mapped, so that the window is mapped with the menubar already
503 there instead of us tacking it on later and thrashing the window after it
504 is visible. */
505
506 void
initialize_frame_menubar(struct frame * f)507 initialize_frame_menubar (struct frame *f)
508 {
509 /* This function is called before the first chance to redisplay
510 the frame. It has to be, so the frame will have the right size. */
511 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
512 set_frame_menubar (f, true);
513 }
514
515 /* Get rid of the menu bar of frame F, and free its storage.
516 This is used when deleting a frame, and when turning off the menu bar. */
517
518 void
free_frame_menubar(struct frame * f)519 free_frame_menubar (struct frame *f)
520 {
521 block_input ();
522
523 {
524 HMENU old = GetMenu (FRAME_W32_WINDOW (f));
525 SetMenu (FRAME_W32_WINDOW (f), NULL);
526 f->output_data.w32->menubar_widget = NULL;
527 DestroyMenu (old);
528 }
529
530 unblock_input ();
531 }
532
533
534 /* w32_menu_show actually displays a menu using the panes and items in
535 menu_items and returns the value selected from it; we assume input
536 is blocked by the caller. */
537
538 /* F is the frame the menu is for.
539 X and Y are the frame-relative specified position,
540 relative to the inside upper left corner of the frame F.
541 Bitfield MENUFLAGS bits are:
542 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
543 MENU_KEYMAPS is set if this menu was specified with keymaps;
544 in that case, we return a list containing the chosen item's value
545 and perhaps also the pane's prefix.
546 TITLE is the specified menu title.
547 ERROR is a place to store an error message string in case of failure.
548 (We return nil on failure, but the value doesn't actually matter.) */
549
550 Lisp_Object
w32_menu_show(struct frame * f,int x,int y,int menuflags,Lisp_Object title,const char ** error)551 w32_menu_show (struct frame *f, int x, int y, int menuflags,
552 Lisp_Object title, const char **error)
553 {
554 int i;
555 int menu_item_selection;
556 HMENU menu;
557 POINT pos;
558 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
559 widget_value **submenu_stack
560 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
561 Lisp_Object *subprefix_stack
562 = (Lisp_Object *) alloca (menu_items_used * word_size);
563 int submenu_depth = 0;
564 bool first_pane;
565
566 *error = NULL;
567
568 if (menu_items_n_panes == 0)
569 return Qnil;
570
571 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
572 {
573 *error = "Empty menu";
574 return Qnil;
575 }
576
577 block_input ();
578
579 /* Create a tree of widget_value objects
580 representing the panes and their items. */
581 wv = make_widget_value ("menu", NULL, true, Qnil);
582 wv->button_type = BUTTON_TYPE_NONE;
583 first_wv = wv;
584 first_pane = true;
585
586 /* Loop over all panes and items, filling in the tree. */
587 i = 0;
588 while (i < menu_items_used)
589 {
590 if (EQ (AREF (menu_items, i), Qnil))
591 {
592 submenu_stack[submenu_depth++] = save_wv;
593 save_wv = prev_wv;
594 prev_wv = 0;
595 first_pane = false;
596 i++;
597 }
598 else if (EQ (AREF (menu_items, i), Qlambda))
599 {
600 prev_wv = save_wv;
601 save_wv = submenu_stack[--submenu_depth];
602 first_pane = false;
603 i++;
604 }
605 else if (EQ (AREF (menu_items, i), Qt)
606 && submenu_depth != 0)
607 i += MENU_ITEMS_PANE_LENGTH;
608 /* Ignore a nil in the item list.
609 It's meaningful only for dialog boxes. */
610 else if (EQ (AREF (menu_items, i), Qquote))
611 i += 1;
612 else if (EQ (AREF (menu_items, i), Qt))
613 {
614 /* Create a new pane. */
615 Lisp_Object pane_name, prefix;
616 const char *pane_string;
617 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
618 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
619
620 if (STRINGP (pane_name))
621 {
622 if (unicode_append_menu)
623 pane_name = ENCODE_UTF_8 (pane_name);
624 else if (STRING_MULTIBYTE (pane_name))
625 pane_name = ENCODE_SYSTEM (pane_name);
626
627 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
628 }
629
630 pane_string = (NILP (pane_name)
631 ? "" : SSDATA (pane_name));
632 /* If there is just one top-level pane, put all its items directly
633 under the top-level menu. */
634 if (menu_items_n_panes == 1)
635 pane_string = "";
636
637 /* If the pane has a meaningful name,
638 make the pane a top-level menu item
639 with its items as a submenu beneath it. */
640 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
641 {
642 wv = make_widget_value (pane_string, NULL, true, Qnil);
643 if (save_wv)
644 save_wv->next = wv;
645 else
646 first_wv->contents = wv;
647 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
648 wv->name++;
649 wv->button_type = BUTTON_TYPE_NONE;
650 save_wv = wv;
651 prev_wv = 0;
652 }
653 else if (first_pane)
654 {
655 save_wv = wv;
656 prev_wv = 0;
657 }
658 first_pane = false;
659 i += MENU_ITEMS_PANE_LENGTH;
660 }
661 else
662 {
663 /* Create a new item within current pane. */
664 Lisp_Object item_name, enable, descrip, def, type, selected, help;
665
666 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
667 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
668 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
669 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
670 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
671 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
672 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
673
674 if (STRINGP (item_name))
675 {
676 if (unicode_append_menu)
677 item_name = ENCODE_UTF_8 (item_name);
678 else if (STRING_MULTIBYTE (item_name))
679 item_name = ENCODE_SYSTEM (item_name);
680
681 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
682 }
683
684 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
685 {
686 descrip = ENCODE_SYSTEM (descrip);
687 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
688 }
689
690 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
691 STRINGP (help) ? help : Qnil);
692 if (prev_wv)
693 prev_wv->next = wv;
694 else
695 save_wv->contents = wv;
696 if (!NILP (descrip))
697 wv->key = SSDATA (descrip);
698 /* Use the contents index as call_data, since we are
699 restricted to 16-bits. */
700 wv->call_data = !NILP (def) ? (void *) (UINT_PTR) i : 0;
701
702 if (NILP (type))
703 wv->button_type = BUTTON_TYPE_NONE;
704 else if (EQ (type, QCtoggle))
705 wv->button_type = BUTTON_TYPE_TOGGLE;
706 else if (EQ (type, QCradio))
707 wv->button_type = BUTTON_TYPE_RADIO;
708 else
709 emacs_abort ();
710
711 wv->selected = !NILP (selected);
712
713 prev_wv = wv;
714
715 i += MENU_ITEMS_ITEM_LENGTH;
716 }
717 }
718
719 /* Deal with the title, if it is non-nil. */
720 if (!NILP (title))
721 {
722 widget_value *wv_title;
723 widget_value *wv_sep = make_widget_value ("--", NULL, false, Qnil);
724
725 /* Maybe replace this separator with a bitmap or owner-draw item
726 so that it looks better. Having two separators looks odd. */
727 wv_sep->next = first_wv->contents;
728
729 if (unicode_append_menu)
730 title = ENCODE_UTF_8 (title);
731 else if (STRING_MULTIBYTE (title))
732 title = ENCODE_SYSTEM (title);
733
734 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
735 wv_title->title = TRUE;
736 wv_title->button_type = BUTTON_TYPE_NONE;
737 wv_title->next = wv_sep;
738 first_wv->contents = wv_title;
739 }
740
741 /* No selection has been chosen yet. */
742 menu_item_selection = 0;
743
744 /* Actually create the menu. */
745 current_popup_menu = menu = CreatePopupMenu ();
746 fill_in_menu (menu, first_wv->contents);
747
748 /* Adjust coordinates to be root-window-relative. */
749 pos.x = x;
750 pos.y = y;
751 ClientToScreen (FRAME_W32_WINDOW (f), &pos);
752
753 /* Display the menu. */
754 menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
755 WM_EMACS_TRACKPOPUPMENU,
756 (WPARAM)menu, (LPARAM)&pos);
757
758 /* Clean up extraneous mouse events which might have been generated
759 during the call. */
760 discard_mouse_events ();
761 FRAME_DISPLAY_INFO (f)->grabbed = 0;
762
763 /* Free the widget_value objects we used to specify the contents. */
764 free_menubar_widget_value_tree (first_wv);
765
766 DestroyMenu (menu);
767
768 /* Free the owner-drawn and help-echo menu strings. */
769 w32_free_menu_strings (FRAME_W32_WINDOW (f));
770 f->output_data.w32->menubar_active = 0;
771
772 /* Find the selected item, and its pane, to return
773 the proper value. */
774 if (menu_item_selection != 0)
775 {
776 Lisp_Object prefix, entry;
777
778 prefix = entry = Qnil;
779 i = 0;
780 while (i < menu_items_used)
781 {
782 if (EQ (AREF (menu_items, i), Qnil))
783 {
784 subprefix_stack[submenu_depth++] = prefix;
785 prefix = entry;
786 i++;
787 }
788 else if (EQ (AREF (menu_items, i), Qlambda))
789 {
790 prefix = subprefix_stack[--submenu_depth];
791 i++;
792 }
793 else if (EQ (AREF (menu_items, i), Qt))
794 {
795 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
796 i += MENU_ITEMS_PANE_LENGTH;
797 }
798 /* Ignore a nil in the item list.
799 It's meaningful only for dialog boxes. */
800 else if (EQ (AREF (menu_items, i), Qquote))
801 i += 1;
802 else
803 {
804 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
805 if (menu_item_selection == i)
806 {
807 if (menuflags & MENU_KEYMAPS)
808 {
809 int j;
810
811 entry = Fcons (entry, Qnil);
812 if (!NILP (prefix))
813 entry = Fcons (prefix, entry);
814 for (j = submenu_depth - 1; j >= 0; j--)
815 if (!NILP (subprefix_stack[j]))
816 entry = Fcons (subprefix_stack[j], entry);
817 }
818 unblock_input ();
819 return entry;
820 }
821 i += MENU_ITEMS_ITEM_LENGTH;
822 }
823 }
824 }
825 else if (!(menuflags & MENU_FOR_CLICK))
826 {
827 unblock_input ();
828 /* Make "Cancel" equivalent to C-g. */
829 quit ();
830 }
831
832 unblock_input ();
833 return Qnil;
834 }
835
836
837 #ifdef HAVE_DIALOGS
838 /* TODO: On Windows, there are two ways of defining a dialog.
839
840 1. Create a predefined dialog resource and include it in nt/emacs.rc.
841 Using this method, we could then set the titles and make unneeded
842 buttons invisible before displaying the dialog. Everything would
843 be a fixed size though, so there is a risk that text does not
844 fit on a button.
845 2. Create the dialog template in memory on the fly. This allows us
846 to size the dialog and buttons dynamically, probably giving more
847 natural looking results for dialogs with few buttons, and eliminating
848 the problem of text overflowing the buttons. But the API for this is
849 quite complex - structures have to be allocated in particular ways,
850 text content is tacked onto the end of structures in variable length
851 arrays with further structures tacked on after these, there are
852 certain alignment requirements for all this, and we have to
853 measure all the text and convert to "dialog coordinates" to figure
854 out how big to make everything.
855
856 For now, we'll just stick with menus for dialogs that are more
857 complicated than simple yes/no type questions for which we can use
858 the MessageBox function.
859 */
860
861 static char * button_names [] = {
862 "button1", "button2", "button3", "button4", "button5",
863 "button6", "button7", "button8", "button9", "button10" };
864
865 static Lisp_Object
w32_dialog_show(struct frame * f,Lisp_Object title,Lisp_Object header,char ** error)866 w32_dialog_show (struct frame *f, Lisp_Object title,
867 Lisp_Object header, char **error)
868 {
869 int i, nb_buttons = 0;
870 char dialog_name[6];
871 int menu_item_selection;
872
873 widget_value *wv, *first_wv = 0, *prev_wv = 0;
874
875 /* Number of elements seen so far, before boundary. */
876 int left_count = 0;
877 /* true means we've seen the boundary between left-hand elts and
878 right-hand. */
879 bool boundary_seen = false;
880
881 *error = NULL;
882
883 if (menu_items_n_panes > 1)
884 {
885 *error = "Multiple panes in dialog box";
886 return Qnil;
887 }
888
889 /* Create a tree of widget_value objects
890 representing the text label and buttons. */
891 {
892 Lisp_Object pane_name;
893 char *pane_string;
894 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
895 pane_string = (NILP (pane_name)
896 ? "" : SSDATA (pane_name));
897 prev_wv = make_widget_value ("message", pane_string, true, Qnil);
898 first_wv = prev_wv;
899
900 /* Loop over all panes and items, filling in the tree. */
901 i = MENU_ITEMS_PANE_LENGTH;
902 while (i < menu_items_used)
903 {
904
905 /* Create a new item within current pane. */
906 Lisp_Object item_name, enable, descrip, help;
907
908 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
909 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
910 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
911 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
912
913 if (NILP (item_name))
914 {
915 free_menubar_widget_value_tree (first_wv);
916 *error = "Submenu in dialog items";
917 return Qnil;
918 }
919 if (EQ (item_name, Qquote))
920 {
921 /* This is the boundary between left-side elts
922 and right-side elts. Stop incrementing right_count. */
923 boundary_seen = true;
924 i++;
925 continue;
926 }
927 if (nb_buttons >= 9)
928 {
929 free_menubar_widget_value_tree (first_wv);
930 *error = "Too many dialog items";
931 return Qnil;
932 }
933
934 wv = make_widget_value (button_names[nb_buttons],
935 SSDATA (item_name),
936 !NILP (enable), Qnil);
937 prev_wv->next = wv;
938 if (!NILP (descrip))
939 wv->key = SSDATA (descrip);
940 wv->call_data = aref_addr (menu_items, i);
941 prev_wv = wv;
942
943 if (! boundary_seen)
944 left_count++;
945
946 nb_buttons++;
947 i += MENU_ITEMS_ITEM_LENGTH;
948 }
949
950 /* If the boundary was not specified,
951 by default put half on the left and half on the right. */
952 if (! boundary_seen)
953 left_count = nb_buttons - nb_buttons / 2;
954
955 wv = make_widget_value (dialog_name, NULL, false, Qnil);
956
957 /* Frame title: 'Q' = Question, 'I' = Information.
958 Can also have 'E' = Error if, one day, we want
959 a popup for errors. */
960 if (NILP (header))
961 dialog_name[0] = 'Q';
962 else
963 dialog_name[0] = 'I';
964
965 /* Dialog boxes use a really stupid name encoding
966 which specifies how many buttons to use
967 and how many buttons are on the right. */
968 dialog_name[1] = '0' + nb_buttons;
969 dialog_name[2] = 'B';
970 dialog_name[3] = 'R';
971 /* Number of buttons to put on the right. */
972 dialog_name[4] = '0' + nb_buttons - left_count;
973 dialog_name[5] = 0;
974 wv->contents = first_wv;
975 first_wv = wv;
976 }
977
978 /* Actually create the dialog. */
979 dialog_id = widget_id_tick++;
980 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
981 f->output_data.w32->widget, true, 0,
982 dialog_selection_callback, 0);
983 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
984
985 /* Free the widget_value objects we used to specify the contents. */
986 free_menubar_widget_value_tree (first_wv);
987
988 /* No selection has been chosen yet. */
989 menu_item_selection = 0;
990
991 /* Display the menu. */
992 lw_pop_up_all_widgets (dialog_id);
993
994 /* Process events that apply to the menu. */
995 popup_get_selection ((XEvent *) 0, FRAME_DISPLAY_INFO (f), dialog_id);
996
997 lw_destroy_all_widgets (dialog_id);
998
999 /* Find the selected item, and its pane, to return
1000 the proper value. */
1001 if (menu_item_selection != 0)
1002 {
1003 i = 0;
1004 while (i < menu_items_used)
1005 {
1006 Lisp_Object entry;
1007
1008 if (EQ (AREF (menu_items, i), Qt))
1009 i += MENU_ITEMS_PANE_LENGTH;
1010 else
1011 {
1012 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1013 if (menu_item_selection == i)
1014 return entry;
1015 i += MENU_ITEMS_ITEM_LENGTH;
1016 }
1017 }
1018 }
1019 else
1020 /* Make "Cancel" equivalent to C-g. */
1021 quit ();
1022
1023 return Qnil;
1024 }
1025 #else /* !HAVE_DIALOGS */
1026
1027 /* Currently we only handle Yes No dialogs (y-or-n-p and yes-or-no-p) as
1028 simple dialogs. We could handle a few more, but I'm not aware of
1029 anywhere in Emacs that uses the other specific dialog choices that
1030 MessageBox provides. */
1031
1032 static bool
is_simple_dialog(Lisp_Object contents)1033 is_simple_dialog (Lisp_Object contents)
1034 {
1035 Lisp_Object options;
1036 Lisp_Object name, yes, no, other;
1037
1038 if (!CONSP (contents))
1039 return false;
1040 options = XCDR (contents);
1041
1042 yes = build_string ("Yes");
1043 no = build_string ("No");
1044
1045 if (!CONSP (options))
1046 return false;
1047
1048 name = XCAR (options);
1049 if (!CONSP (name))
1050 return false;
1051 name = XCAR (name);
1052
1053 if (!NILP (Fstring_equal (name, yes)))
1054 other = no;
1055 else if (!NILP (Fstring_equal (name, no)))
1056 other = yes;
1057 else
1058 return false;
1059
1060 options = XCDR (options);
1061 if (!CONSP (options))
1062 return false;
1063
1064 name = XCAR (options);
1065 if (!CONSP (name))
1066 return false;
1067 name = XCAR (name);
1068 if (NILP (Fstring_equal (name, other)))
1069 return false;
1070
1071 /* Check there are no more options. */
1072 options = XCDR (options);
1073 return !(CONSP (options));
1074 }
1075
1076 static Lisp_Object
simple_dialog_show(struct frame * f,Lisp_Object contents,Lisp_Object header)1077 simple_dialog_show (struct frame *f, Lisp_Object contents, Lisp_Object header)
1078 {
1079 int answer;
1080 UINT type;
1081 Lisp_Object lispy_answer = Qnil, temp = XCAR (contents);
1082
1083 type = MB_YESNO;
1084
1085 /* Since we only handle Yes/No dialogs, and we already checked
1086 is_simple_dialog, we don't need to worry about checking contents
1087 to see what type of dialog to use. */
1088
1089 /* Use Unicode if possible, so any language can be displayed. */
1090 if (unicode_message_box)
1091 {
1092 WCHAR *text;
1093 const WCHAR *title;
1094 USE_SAFE_ALLOCA;
1095
1096 if (STRINGP (temp))
1097 {
1098 char *utf8_text = SSDATA (ENCODE_UTF_8 (temp));
1099 /* Be pessimistic about the number of characters needed.
1100 Remember characters outside the BMP will take more than
1101 one utf16 word, so we cannot simply use the character
1102 length of temp. */
1103 int utf8_len = strlen (utf8_text);
1104 text = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
1105 utf8to16 ((unsigned char *)utf8_text, utf8_len, text);
1106 }
1107 else
1108 {
1109 text = (WCHAR *)L"";
1110 }
1111
1112 if (NILP (header))
1113 {
1114 title = L"Question";
1115 type |= MB_ICONQUESTION;
1116 }
1117 else
1118 {
1119 title = L"Information";
1120 type |= MB_ICONINFORMATION;
1121 }
1122
1123 answer = unicode_message_box (FRAME_W32_WINDOW (f), text, title, type);
1124 SAFE_FREE ();
1125 }
1126 else
1127 {
1128 const char *text, *title;
1129
1130 /* Fall back on ANSI message box, but at least use system
1131 encoding so questions representable by the system codepage
1132 are encoded properly. */
1133 if (STRINGP (temp))
1134 text = SSDATA (ENCODE_SYSTEM (temp));
1135 else
1136 text = "";
1137
1138 if (NILP (header))
1139 {
1140 title = "Question";
1141 type |= MB_ICONQUESTION;
1142 }
1143 else
1144 {
1145 title = "Information";
1146 type |= MB_ICONINFORMATION;
1147 }
1148
1149 answer = MessageBox (FRAME_W32_WINDOW (f), text, title, type);
1150 }
1151
1152 if (answer == IDYES)
1153 lispy_answer = build_string ("Yes");
1154 else if (answer == IDNO)
1155 lispy_answer = build_string ("No");
1156 else
1157 quit ();
1158
1159 for (temp = XCDR (contents); CONSP (temp); temp = XCDR (temp))
1160 {
1161 Lisp_Object item, name, value;
1162 item = XCAR (temp);
1163 if (CONSP (item))
1164 {
1165 name = XCAR (item);
1166 value = XCDR (item);
1167 }
1168 else
1169 {
1170 name = item;
1171 value = Qnil;
1172 }
1173
1174 if (!NILP (Fstring_equal (name, lispy_answer)))
1175 {
1176 return value;
1177 }
1178 }
1179 return quit ();
1180 }
1181 #endif /* !HAVE_DIALOGS */
1182
1183
1184 /* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
1185 static void
utf8to16(unsigned char * src,int len,WCHAR * dest)1186 utf8to16 (unsigned char * src, int len, WCHAR * dest)
1187 {
1188 while (len > 0)
1189 {
1190 if (*src < 0x80)
1191 {
1192 *dest = (WCHAR) *src;
1193 dest++; src++; len--;
1194 }
1195 /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */
1196 else if (*src < 0xC0)
1197 {
1198 src++; len--;
1199 }
1200 /* 2 char UTF-8 sequence. */
1201 else if (*src < 0xE0)
1202 {
1203 *dest = (WCHAR) (((*src & 0x1f) << 6)
1204 | (*(src + 1) & 0x3f));
1205 src += 2; len -= 2; dest++;
1206 }
1207 else if (*src < 0xF0)
1208 {
1209 *dest = (WCHAR) (((*src & 0x0f) << 12)
1210 | ((*(src + 1) & 0x3f) << 6)
1211 | (*(src + 2) & 0x3f));
1212 src += 3; len -= 3; dest++;
1213 }
1214 else /* Not encodable. Insert Unicode Substitution char. */
1215 {
1216 *dest = (WCHAR) 0xfffd;
1217 src++; len--; dest++;
1218 }
1219 }
1220 *dest = 0;
1221 }
1222
1223 static int
add_menu_item(HMENU menu,widget_value * wv,HMENU item)1224 add_menu_item (HMENU menu, widget_value *wv, HMENU item)
1225 {
1226 UINT fuFlags;
1227 char *out_string, *p, *q;
1228 int return_value;
1229 size_t nlen, orig_len;
1230 USE_SAFE_ALLOCA;
1231
1232 if (menu_separator_name_p (wv->name))
1233 {
1234 fuFlags = MF_SEPARATOR;
1235 out_string = NULL;
1236 }
1237 else
1238 {
1239 if (wv->enabled)
1240 fuFlags = MF_STRING;
1241 else
1242 fuFlags = MF_STRING | MF_GRAYED;
1243
1244 if (wv->key != NULL)
1245 {
1246 out_string = SAFE_ALLOCA (strlen (wv->name) + strlen (wv->key) + 2);
1247 p = stpcpy (out_string, wv->name);
1248 p = stpcpy (p, "\t");
1249 strcpy (p, wv->key);
1250 }
1251 else
1252 out_string = (char *)wv->name;
1253
1254 /* Quote any special characters within the menu item's text and
1255 key binding. */
1256 nlen = orig_len = strlen (out_string);
1257 if (unicode_append_menu)
1258 {
1259 /* With UTF-8, & cannot be part of a multibyte character. */
1260 for (p = out_string; *p; p++)
1261 {
1262 if (*p == '&')
1263 nlen++;
1264 }
1265 }
1266 #ifndef NTGUI_UNICODE
1267 else
1268 {
1269 /* If encoded with the system codepage, use multibyte string
1270 functions in case of multibyte characters that contain '&'. */
1271 for (p = out_string; *p; p = _mbsinc (p))
1272 {
1273 if (_mbsnextc (p) == '&')
1274 nlen++;
1275 }
1276 }
1277 #endif /* !NTGUI_UNICODE */
1278
1279 if (nlen > orig_len)
1280 {
1281 p = out_string;
1282 out_string = SAFE_ALLOCA (nlen + 1);
1283 q = out_string;
1284 while (*p)
1285 {
1286 if (unicode_append_menu)
1287 {
1288 if (*p == '&')
1289 *q++ = *p;
1290 *q++ = *p++;
1291 }
1292 #ifndef NTGUI_UNICODE
1293 else
1294 {
1295 if (_mbsnextc (p) == '&')
1296 {
1297 _mbsncpy (q, p, 1);
1298 q = _mbsinc (q);
1299 }
1300 _mbsncpy (q, p, 1);
1301 p = _mbsinc (p);
1302 q = _mbsinc (q);
1303 }
1304 #endif /* !NTGUI_UNICODE */
1305 }
1306 *q = '\0';
1307 }
1308
1309 if (item != NULL)
1310 fuFlags = MF_POPUP;
1311 else if (wv->title || wv->call_data == 0)
1312 {
1313 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
1314 we can't deallocate the memory otherwise. */
1315 if (get_menu_item_info)
1316 {
1317 out_string = (char *) local_alloc (strlen (wv->name) + 1);
1318 strcpy (out_string, wv->name);
1319 #ifdef MENU_DEBUG
1320 DebPrint ("Menu: allocating %ld for owner-draw", out_string);
1321 #endif
1322 fuFlags = MF_OWNERDRAW | MF_DISABLED;
1323 }
1324 else
1325 fuFlags = MF_DISABLED;
1326 }
1327
1328 /* Draw radio buttons and tickboxes. */
1329 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
1330 wv->button_type == BUTTON_TYPE_RADIO))
1331 fuFlags |= MF_CHECKED;
1332 else
1333 fuFlags |= MF_UNCHECKED;
1334 }
1335
1336 if (unicode_append_menu && out_string)
1337 {
1338 /* Convert out_string from UTF-8 to UTF-16-LE. */
1339 int utf8_len = strlen (out_string);
1340 WCHAR * utf16_string;
1341 if (fuFlags & MF_OWNERDRAW)
1342 utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
1343 else
1344 utf16_string = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
1345
1346 utf8to16 ((unsigned char *)out_string, utf8_len, utf16_string);
1347 return_value = unicode_append_menu (menu, fuFlags,
1348 item != NULL ? (UINT_PTR) item
1349 : (UINT_PTR) wv->call_data,
1350 utf16_string);
1351
1352 #ifndef NTGUI_UNICODE /* Fallback does not apply when always UNICODE */
1353 if (!return_value)
1354 {
1355 /* On W9x/ME, Unicode menus are not supported, though AppendMenuW
1356 apparently does exist at least in some cases and appears to be
1357 stubbed out to do nothing. out_string is UTF-8, but since
1358 our standard menus are in English and this is only going to
1359 happen the first time a menu is used, the encoding is
1360 of minor importance compared with menus not working at all. */
1361 return_value =
1362 AppendMenu (menu, fuFlags,
1363 item != NULL ? (UINT_PTR) item: (UINT_PTR) wv->call_data,
1364 out_string);
1365 /* Don't use Unicode menus in future, unless this is Windows
1366 NT or later, where a failure of AppendMenuW does NOT mean
1367 Unicode menus are unsupported. */
1368 if (osinfo_cache.dwPlatformId != VER_PLATFORM_WIN32_NT)
1369 unicode_append_menu = NULL;
1370 }
1371 #endif /* NTGUI_UNICODE */
1372
1373 if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
1374 local_free (out_string);
1375 }
1376 else
1377 {
1378 return_value =
1379 AppendMenu (menu,
1380 fuFlags,
1381 item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data,
1382 out_string );
1383 }
1384
1385 /* This must be done after the menu item is created. */
1386 if (!wv->title && wv->call_data != 0)
1387 {
1388 if (set_menu_item_info)
1389 {
1390 MENUITEMINFO info;
1391 memset (&info, 0, sizeof (info));
1392 info.cbSize = sizeof (info);
1393 info.fMask = MIIM_DATA;
1394
1395 /* Set help string for menu item. Leave it as a pointer to
1396 a Lisp_String until it is ready to be displayed, since GC
1397 can happen while menus are active. */
1398 if (!NILP (wv->help))
1399 {
1400 /* We use XUNTAG below because in a 32-bit build
1401 --with-wide-int we cannot pass a Lisp_Object
1402 via a DWORD member of MENUITEMINFO. */
1403 /* As of Jul-2012, w32api headers say that dwItemData
1404 has DWORD type, but that's a bug: it should actually
1405 be ULONG_PTR, which is correct for 32-bit and 64-bit
1406 Windows alike. MSVC headers get it right; hopefully,
1407 MinGW headers will, too. */
1408 eassert (STRINGP (wv->help));
1409 info.dwItemData = (ULONG_PTR) XUNTAG (wv->help, Lisp_String,
1410 struct Lisp_String);
1411 }
1412 if (wv->button_type == BUTTON_TYPE_RADIO)
1413 {
1414 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
1415 RADIO items, but is not available on NT 3.51 and earlier. */
1416 info.fMask |= MIIM_TYPE | MIIM_STATE;
1417 info.fType = MFT_RADIOCHECK | MFT_STRING;
1418 info.dwTypeData = out_string;
1419 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
1420 }
1421
1422 set_menu_item_info (menu,
1423 item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data,
1424 FALSE, &info);
1425 }
1426 }
1427 SAFE_FREE ();
1428 return return_value;
1429 }
1430
1431 /* Construct native Windows menu(bar) based on widget_value tree. */
1432 static int
fill_in_menu(HMENU menu,widget_value * wv)1433 fill_in_menu (HMENU menu, widget_value *wv)
1434 {
1435 for ( ; wv != NULL; wv = wv->next)
1436 {
1437 if (wv->contents)
1438 {
1439 HMENU sub_menu = CreatePopupMenu ();
1440
1441 if (sub_menu == NULL)
1442 return 0;
1443
1444 if (!fill_in_menu (sub_menu, wv->contents) ||
1445 !add_menu_item (menu, wv, sub_menu))
1446 {
1447 DestroyMenu (sub_menu);
1448 return 0;
1449 }
1450 }
1451 else
1452 {
1453 if (!add_menu_item (menu, wv, NULL))
1454 return 0;
1455 }
1456 }
1457 return 1;
1458 }
1459
1460 /* Display help string for currently pointed to menu item. Not
1461 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
1462 available. */
1463 void w32_menu_display_help (HWND, HMENU, UINT, UINT);
1464
1465 void
w32_menu_display_help(HWND owner,HMENU menu,UINT item,UINT flags)1466 w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
1467 {
1468 if (get_menu_item_info)
1469 {
1470 struct frame *f = w32_window_to_frame (&one_w32_display_info, owner);
1471 Lisp_Object frame, help;
1472
1473 /* No help echo on owner-draw menu items, or when the keyboard
1474 is used to navigate the menus, since tooltips are distracting
1475 if they pop up elsewhere. */
1476 if ((flags & MF_OWNERDRAW) || (flags & MF_POPUP)
1477 || !(flags & MF_MOUSESELECT)
1478 /* Ignore any dwItemData for menu items whose flags don't
1479 have the MF_HILITE bit set. These are dwItemData that
1480 Windows sends our way, but they aren't pointers to our
1481 Lisp_String objects, so trying to create Lisp_Strings out
1482 of them below and pass that to the keyboard queue will
1483 crash Emacs when we try to display those "strings". It
1484 is unclear why we get these dwItemData, or what they are:
1485 sometimes they point to a wchar_t string that is the menu
1486 title, sometimes to something that doesn't look like text
1487 at all. (The problematic data also comes with the 0x0800
1488 bit set, but this bit is not documented, so we don't want
1489 to depend on it.) */
1490 || !(flags & MF_HILITE))
1491 help = Qnil;
1492 else
1493 {
1494 MENUITEMINFO info;
1495
1496 memset (&info, 0, sizeof (info));
1497 info.cbSize = sizeof (info);
1498 info.fMask = MIIM_DATA;
1499 get_menu_item_info (menu, item, FALSE, &info);
1500
1501 help =
1502 info.dwItemData
1503 ? make_lisp_ptr ((void *) info.dwItemData, Lisp_String)
1504 : Qnil;
1505 }
1506
1507 /* Store the help echo in the keyboard buffer as the X toolkit
1508 version does, rather than directly showing it. This seems to
1509 solve the GC problems that were present when we based the
1510 Windows code on the non-toolkit version. */
1511 if (f)
1512 {
1513 XSETFRAME (frame, f);
1514 kbd_buffer_store_help_event (frame, help);
1515 }
1516 else
1517 /* X version has a loop through frames here, which doesn't
1518 appear to do anything, unless it has some side effect. */
1519 show_help_echo (help, Qnil, Qnil, Qnil);
1520 }
1521 }
1522
1523 /* Free memory used by owner-drawn strings. */
1524 static void
w32_free_submenu_strings(HMENU menu)1525 w32_free_submenu_strings (HMENU menu)
1526 {
1527 int i, num = GetMenuItemCount (menu);
1528 for (i = 0; i < num; i++)
1529 {
1530 MENUITEMINFO info;
1531 memset (&info, 0, sizeof (info));
1532 info.cbSize = sizeof (info);
1533 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
1534
1535 get_menu_item_info (menu, i, TRUE, &info);
1536
1537 /* Owner-drawn names are held in dwItemData. */
1538 if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
1539 {
1540 #ifdef MENU_DEBUG
1541 DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
1542 #endif
1543 local_free (info.dwItemData);
1544 }
1545
1546 /* Recurse down submenus. */
1547 if (info.hSubMenu)
1548 w32_free_submenu_strings (info.hSubMenu);
1549 }
1550 }
1551
1552 void
w32_free_menu_strings(HWND hwnd)1553 w32_free_menu_strings (HWND hwnd)
1554 {
1555 HMENU menu = current_popup_menu;
1556
1557 if (get_menu_item_info)
1558 {
1559 /* If there is no popup menu active, free the strings from the frame's
1560 menubar. */
1561 if (!menu)
1562 menu = GetMenu (hwnd);
1563
1564 if (menu)
1565 w32_free_submenu_strings (menu);
1566 }
1567
1568 current_popup_menu = NULL;
1569 }
1570
1571 /* The following is used by delayed window autoselection. */
1572
1573 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1574 doc: /* SKIP: real doc in xmenu.c. */)
1575 (void)
1576 {
1577 struct frame *f;
1578 f = SELECTED_FRAME ();
1579 return (f->output_data.w32->menubar_active > 0) ? Qt : Qnil;
1580 }
1581
1582 void
syms_of_w32menu(void)1583 syms_of_w32menu (void)
1584 {
1585 globals_of_w32menu ();
1586
1587 current_popup_menu = NULL;
1588 PDUMPER_IGNORE (current_popup_menu);
1589
1590 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
1591 DEFSYM (Qunsupported__w32_dialog, "unsupported--w32-dialog");
1592
1593 defsubr (&Smenu_or_popup_active_p);
1594 }
1595
1596 /*
1597 globals_of_w32menu is used to initialize those global variables that
1598 must always be initialized on startup even when the global variable
1599 initialized is non zero (see the function main in emacs.c).
1600 globals_of_w32menu is called from syms_of_w32menu when the global
1601 variable initialized is 0 and directly from main when initialized
1602 is non zero.
1603 */
1604 void
globals_of_w32menu(void)1605 globals_of_w32menu (void)
1606 {
1607 #ifndef NTGUI_UNICODE
1608 /* See if Get/SetMenuItemInfo functions are available. */
1609 HMODULE user32 = GetModuleHandle ("user32.dll");
1610 get_menu_item_info = (GetMenuItemInfoA_Proc)
1611 get_proc_addr (user32, "GetMenuItemInfoA");
1612 set_menu_item_info = (SetMenuItemInfoA_Proc)
1613 get_proc_addr (user32, "SetMenuItemInfoA");
1614 unicode_append_menu = (AppendMenuW_Proc)
1615 get_proc_addr (user32, "AppendMenuW");
1616 unicode_message_box = (MessageBoxW_Proc)
1617 get_proc_addr (user32, "MessageBoxW");
1618 #endif /* !NTGUI_UNICODE */
1619 }
1620