1 /* Menu support for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2012
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
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
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
31 #include "termhooks.h"
33 #include "blockinput.h"
34 #include "character.h"
40 /* This may include sys/types.h, and that somehow loses
41 if this is not done before the other system files. */
44 /* Load sys/types.h if not already loaded.
45 In some systems loading it twice is suicidal. */
47 #include <sys/types.h>
50 #include "dispextern.h"
52 #include "w32heap.h" /* for osinfo_cache */
54 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
61 HMENU current_popup_menu
;
63 void syms_of_w32menu (void);
64 void globals_of_w32menu (void);
66 typedef BOOL (WINAPI
* GetMenuItemInfoA_Proc
) (
70 IN OUT LPMENUITEMINFOA
);
71 typedef BOOL (WINAPI
* SetMenuItemInfoA_Proc
) (
76 typedef int (WINAPI
* MessageBoxW_Proc
) (
82 GetMenuItemInfoA_Proc get_menu_item_info
= NULL
;
83 SetMenuItemInfoA_Proc set_menu_item_info
= NULL
;
84 AppendMenuW_Proc unicode_append_menu
= NULL
;
85 MessageBoxW_Proc unicode_message_box
= NULL
;
87 Lisp_Object Qdebug_on_next_call
;
89 void set_frame_menubar (FRAME_PTR
, int, int);
92 static Lisp_Object
w32_dialog_show (FRAME_PTR
, int, Lisp_Object
, char**);
94 static int is_simple_dialog (Lisp_Object
);
95 static Lisp_Object
simple_dialog_show (FRAME_PTR
, Lisp_Object
, Lisp_Object
);
98 static void utf8to16 (unsigned char *, int, WCHAR
*);
99 static int fill_in_menu (HMENU
, widget_value
*);
101 void w32_free_menu_strings (HWND
);
104 /* This is set nonzero after the user activates the menu bar, and set
105 to zero again after the menu bars are redisplayed by prepare_menu_bar.
106 While it is nonzero, all calls to set_frame_menubar go deep.
108 I don't understand why this is needed, but it does seem to be
109 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
111 int pending_menu_activation
;
115 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
116 doc
: /* Pop up a dialog box and return user's selection.
117 POSITION specifies which frame to use.
118 This is normally a mouse button event or a window or frame.
119 If POSITION is t, it means to use the frame the mouse is on.
120 The dialog box appears in the middle of the specified frame.
122 CONTENTS specifies the alternatives to display in the dialog box.
123 It is a list of the form (TITLE ITEM1 ITEM2...).
124 Each ITEM is a cons cell (STRING . VALUE).
125 The return value is VALUE from the chosen item.
127 An ITEM may also be just a string--that makes a nonselectable item.
128 An ITEM may also be nil--that means to put all preceding items
129 on the left of the dialog box and all following items on the right.
130 \(By default, approximately half appear on each side.)
132 If HEADER is non-nil, the frame title for the box is "Information",
133 otherwise it is "Question". */)
134 (Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
141 /* Decode the first argument: find the window or frame to use. */
142 if (EQ (position
, Qt
)
143 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
144 || EQ (XCAR (position
), Qtool_bar
))))
146 #if 0 /* Using the frame the mouse is on may not be right. */
147 /* Use the mouse's current position. */
148 FRAME_PTR new_f
= SELECTED_FRAME ();
149 Lisp_Object bar_window
;
150 enum scroll_bar_part part
;
154 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
157 XSETFRAME (window
, new_f
);
159 window
= selected_window
;
161 window
= selected_window
;
163 else if (CONSP (position
))
166 tem
= Fcar (position
);
168 window
= Fcar (Fcdr (position
));
171 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
172 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
175 else if (WINDOWP (position
) || FRAMEP (position
))
180 /* Decode where to put the menu. */
184 else if (WINDOWP (window
))
186 CHECK_LIVE_WINDOW (window
);
187 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
190 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
191 but I don't want to make one now. */
192 CHECK_WINDOW (window
);
197 /* Handle simple Yes/No choices as MessageBox popups. */
198 if (is_simple_dialog (contents
))
199 return simple_dialog_show (f
, contents
, header
);
202 /* Display a menu with these alternatives
203 in the middle of frame F. */
204 Lisp_Object x
, y
, frame
, newpos
;
205 XSETFRAME (frame
, f
);
206 XSETINT (x
, x_pixel_width (f
) / 2);
207 XSETINT (y
, x_pixel_height (f
) / 2);
208 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
209 return Fx_popup_menu (newpos
,
210 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
213 #else /* HAVE_DIALOGS */
217 Lisp_Object selection
;
219 /* Decode the dialog items from what was specified. */
220 title
= Fcar (contents
);
221 CHECK_STRING (title
);
223 list_of_panes (Fcons (contents
, Qnil
));
225 /* Display them in a dialog box. */
227 selection
= w32_dialog_show (f
, 0, title
, header
, &error_name
);
230 discard_menu_items ();
231 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
233 if (error_name
) error (error_name
);
236 #endif /* HAVE_DIALOGS */
239 /* Activate the menu bar of frame F.
240 This is called from keyboard.c when it gets the
241 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
243 To activate the menu bar, we signal to the input thread that it can
244 return from the WM_INITMENU message, allowing the normal Windows
245 processing of the menus.
247 But first we recompute the menu bar contents (the whole tree).
249 This way we can safely execute Lisp code. */
252 x_activate_menubar (FRAME_PTR f
)
254 set_frame_menubar (f
, 0, 1);
256 /* Lock out further menubar changes while active. */
257 f
->output_data
.w32
->menubar_active
= 1;
259 /* Signal input thread to return from WM_INITMENU. */
260 complete_deferred_msg (FRAME_W32_WINDOW (f
), WM_INITMENU
, 0);
263 /* This callback is called from the menu bar pulldown menu
264 when the user makes a selection.
265 Figure out what the user chose
266 and put the appropriate events into the keyboard buffer. */
269 menubar_selection_callback (FRAME_PTR f
, void * client_data
)
271 Lisp_Object prefix
, entry
;
273 Lisp_Object
*subprefix_stack
;
274 int submenu_depth
= 0;
280 subprefix_stack
= (Lisp_Object
*) alloca (f
->menu_bar_items_used
* sizeof (Lisp_Object
));
281 vector
= f
->menu_bar_vector
;
284 while (i
< f
->menu_bar_items_used
)
286 if (EQ (AREF (vector
, i
), Qnil
))
288 subprefix_stack
[submenu_depth
++] = prefix
;
292 else if (EQ (AREF (vector
, i
), Qlambda
))
294 prefix
= subprefix_stack
[--submenu_depth
];
297 else if (EQ (AREF (vector
, i
), Qt
))
299 prefix
= AREF (vector
, i
+ MENU_ITEMS_PANE_PREFIX
);
300 i
+= MENU_ITEMS_PANE_LENGTH
;
304 entry
= AREF (vector
, i
+ MENU_ITEMS_ITEM_VALUE
);
305 /* The EMACS_INT cast avoids a warning. There's no problem
306 as long as pointers have enough bits to hold small integers. */
307 if ((int) (EMACS_INT
) client_data
== i
)
310 struct input_event buf
;
314 XSETFRAME (frame
, f
);
315 buf
.kind
= MENU_BAR_EVENT
;
316 buf
.frame_or_window
= frame
;
318 kbd_buffer_store_event (&buf
);
320 for (j
= 0; j
< submenu_depth
; j
++)
321 if (!NILP (subprefix_stack
[j
]))
323 buf
.kind
= MENU_BAR_EVENT
;
324 buf
.frame_or_window
= frame
;
325 buf
.arg
= subprefix_stack
[j
];
326 kbd_buffer_store_event (&buf
);
331 buf
.kind
= MENU_BAR_EVENT
;
332 buf
.frame_or_window
= frame
;
334 kbd_buffer_store_event (&buf
);
337 buf
.kind
= MENU_BAR_EVENT
;
338 buf
.frame_or_window
= frame
;
340 /* Free memory used by owner-drawn and help-echo strings. */
341 w32_free_menu_strings (FRAME_W32_WINDOW (f
));
342 kbd_buffer_store_event (&buf
);
344 f
->output_data
.w32
->menubar_active
= 0;
347 i
+= MENU_ITEMS_ITEM_LENGTH
;
350 /* Free memory used by owner-drawn and help-echo strings. */
351 w32_free_menu_strings (FRAME_W32_WINDOW (f
));
352 f
->output_data
.w32
->menubar_active
= 0;
356 /* Set the contents of the menubar widgets of frame F.
357 The argument FIRST_TIME is currently ignored;
358 it is set the first time this is called, from initialize_frame_menubar. */
361 set_frame_menubar (FRAME_PTR f
, int first_time
, int deep_p
)
363 HMENU menubar_widget
= f
->output_data
.w32
->menubar_widget
;
365 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
367 int *submenu_start
, *submenu_end
;
368 int *submenu_top_level_items
, *submenu_n_panes
;
370 /* We must not change the menubar when actually in use. */
371 if (f
->output_data
.w32
->menubar_active
)
374 XSETFRAME (Vmenu_updating_frame
, f
);
376 if (! menubar_widget
)
378 else if (pending_menu_activation
&& !deep_p
)
383 /* Make a widget-value tree representing the entire menu trees. */
385 struct buffer
*prev
= current_buffer
;
387 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
388 int previous_menu_items_used
= f
->menu_bar_items_used
;
389 Lisp_Object
*previous_items
390 = (Lisp_Object
*) alloca (previous_menu_items_used
391 * sizeof (Lisp_Object
));
393 /* If we are making a new widget, its contents are empty,
394 do always reinitialize them. */
395 if (! menubar_widget
)
396 previous_menu_items_used
= 0;
398 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
399 specbind (Qinhibit_quit
, Qt
);
400 /* Don't let the debugger step into this code
401 because it is not reentrant. */
402 specbind (Qdebug_on_next_call
, Qnil
);
404 record_unwind_save_match_data ();
406 if (NILP (Voverriding_local_map_menu_flag
))
408 specbind (Qoverriding_terminal_local_map
, Qnil
);
409 specbind (Qoverriding_local_map
, Qnil
);
412 set_buffer_internal_1 (XBUFFER (buffer
));
415 safe_run_hooks (Qactivate_menubar_hook
);
416 safe_run_hooks (Qmenu_bar_update_hook
);
417 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
419 items
= FRAME_MENU_BAR_ITEMS (f
);
421 /* Save the frame's previous menu bar contents data. */
422 if (previous_menu_items_used
)
423 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
424 previous_menu_items_used
* sizeof (Lisp_Object
));
426 /* Fill in menu_items with the current menu bar contents.
427 This can evaluate Lisp code. */
430 menu_items
= f
->menu_bar_vector
;
431 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
432 submenu_start
= (int *) alloca (ASIZE (items
) * sizeof (int));
433 submenu_end
= (int *) alloca (ASIZE (items
) * sizeof (int));
434 submenu_n_panes
= (int *) alloca (ASIZE (items
) * sizeof (int));
435 submenu_top_level_items
= (int *) alloca (ASIZE (items
) * sizeof (int));
437 for (i
= 0; i
< ASIZE (items
); i
+= 4)
439 Lisp_Object key
, string
, maps
;
443 key
= AREF (items
, i
);
444 string
= AREF (items
, i
+ 1);
445 maps
= AREF (items
, i
+ 2);
449 submenu_start
[i
] = menu_items_used
;
451 menu_items_n_panes
= 0;
452 submenu_top_level_items
[i
]
453 = parse_single_submenu (key
, string
, maps
);
454 submenu_n_panes
[i
] = menu_items_n_panes
;
456 submenu_end
[i
] = menu_items_used
;
459 finish_menu_items ();
461 /* Convert menu_items into widget_value trees
462 to display the menu. This cannot evaluate Lisp code. */
464 wv
= xmalloc_widget_value ();
465 wv
->name
= "menubar";
468 wv
->button_type
= BUTTON_TYPE_NONE
;
472 for (i
= 0; i
< last_i
; i
+= 4)
474 menu_items_n_panes
= submenu_n_panes
[i
];
475 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
476 submenu_top_level_items
[i
]);
480 first_wv
->contents
= wv
;
481 /* Don't set wv->name here; GC during the loop might relocate it. */
483 wv
->button_type
= BUTTON_TYPE_NONE
;
487 set_buffer_internal_1 (prev
);
489 /* If there has been no change in the Lisp-level contents
490 of the menu bar, skip redisplaying it. Just exit. */
492 for (i
= 0; i
< previous_menu_items_used
; i
++)
493 if (menu_items_used
== i
494 || (!EQ (previous_items
[i
], AREF (menu_items
, i
))))
496 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
498 free_menubar_widget_value_tree (first_wv
);
499 discard_menu_items ();
500 unbind_to (specpdl_count
, Qnil
);
504 f
->menu_bar_vector
= menu_items
;
505 f
->menu_bar_items_used
= menu_items_used
;
507 /* This undoes save_menu_items. */
508 unbind_to (specpdl_count
, Qnil
);
510 /* Now GC cannot happen during the lifetime of the widget_value,
511 so it's safe to store data from a Lisp_String, as long as
512 local copies are made when the actual menu is created.
513 Windows takes care of this for normal string items, but
514 not for owner-drawn items or additional item-info. */
515 wv
= first_wv
->contents
;
516 for (i
= 0; i
< ASIZE (items
); i
+= 4)
519 string
= AREF (items
, i
+ 1);
522 wv
->name
= SSDATA (string
);
523 update_submenu_strings (wv
->contents
);
529 /* Make a widget-value tree containing
530 just the top level menu bar strings. */
532 wv
= xmalloc_widget_value ();
533 wv
->name
= "menubar";
536 wv
->button_type
= BUTTON_TYPE_NONE
;
540 items
= FRAME_MENU_BAR_ITEMS (f
);
541 for (i
= 0; i
< ASIZE (items
); i
+= 4)
545 string
= AREF (items
, i
+ 1);
549 wv
= xmalloc_widget_value ();
550 wv
->name
= SSDATA (string
);
553 wv
->button_type
= BUTTON_TYPE_NONE
;
555 /* This prevents lwlib from assuming this
556 menu item is really supposed to be empty. */
557 /* The EMACS_INT cast avoids a warning.
558 This value just has to be different from small integers. */
559 wv
->call_data
= (void *) (EMACS_INT
) (-1);
564 first_wv
->contents
= wv
;
568 /* Forget what we thought we knew about what is in the
569 detailed contents of the menu bar menus.
570 Changing the top level always destroys the contents. */
571 f
->menu_bar_items_used
= 0;
574 /* Create or update the menu bar widget. */
580 /* Empty current menubar, rather than creating a fresh one. */
581 while (DeleteMenu (menubar_widget
, 0, MF_BYPOSITION
))
586 menubar_widget
= CreateMenu ();
588 fill_in_menu (menubar_widget
, first_wv
->contents
);
590 free_menubar_widget_value_tree (first_wv
);
593 HMENU old_widget
= f
->output_data
.w32
->menubar_widget
;
595 f
->output_data
.w32
->menubar_widget
= menubar_widget
;
596 SetMenu (FRAME_W32_WINDOW (f
), f
->output_data
.w32
->menubar_widget
);
597 /* Causes flicker when menu bar is updated
598 DrawMenuBar (FRAME_W32_WINDOW (f)); */
600 /* Force the window size to be recomputed so that the frame's text
601 area remains the same, if menubar has just been created. */
602 if (old_widget
== NULL
)
603 x_set_window_size (f
, 0, FRAME_COLS (f
), FRAME_LINES (f
));
609 /* Called from Fx_create_frame to create the initial menubar of a frame
610 before it is mapped, so that the window is mapped with the menubar already
611 there instead of us tacking it on later and thrashing the window after it
615 initialize_frame_menubar (FRAME_PTR f
)
617 /* This function is called before the first chance to redisplay
618 the frame. It has to be, so the frame will have the right size. */
619 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
620 set_frame_menubar (f
, 1, 1);
623 /* Get rid of the menu bar of frame F, and free its storage.
624 This is used when deleting a frame, and when turning off the menu bar. */
627 free_frame_menubar (FRAME_PTR f
)
632 HMENU old
= GetMenu (FRAME_W32_WINDOW (f
));
633 SetMenu (FRAME_W32_WINDOW (f
), NULL
);
634 f
->output_data
.w32
->menubar_widget
= NULL
;
642 /* w32_menu_show actually displays a menu using the panes and items in
643 menu_items and returns the value selected from it; we assume input
644 is blocked by the caller. */
646 /* F is the frame the menu is for.
647 X and Y are the frame-relative specified position,
648 relative to the inside upper left corner of the frame F.
649 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
650 KEYMAPS is 1 if this menu was specified with keymaps;
651 in that case, we return a list containing the chosen item's value
652 and perhaps also the pane's prefix.
653 TITLE is the specified menu title.
654 ERROR is a place to store an error message string in case of failure.
655 (We return nil on failure, but the value doesn't actually matter.) */
658 w32_menu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
659 Lisp_Object title
, const char **error
)
662 int menu_item_selection
;
665 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
666 widget_value
**submenu_stack
667 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
668 Lisp_Object
*subprefix_stack
669 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
670 int submenu_depth
= 0;
675 if (menu_items_n_panes
== 0)
678 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
680 *error
= "Empty menu";
684 /* Create a tree of widget_value objects
685 representing the panes and their items. */
686 wv
= xmalloc_widget_value ();
690 wv
->button_type
= BUTTON_TYPE_NONE
;
695 /* Loop over all panes and items, filling in the tree. */
697 while (i
< menu_items_used
)
699 if (EQ (AREF (menu_items
, i
), Qnil
))
701 submenu_stack
[submenu_depth
++] = save_wv
;
707 else if (EQ (AREF (menu_items
, i
), Qlambda
))
710 save_wv
= submenu_stack
[--submenu_depth
];
714 else if (EQ (AREF (menu_items
, i
), Qt
)
715 && submenu_depth
!= 0)
716 i
+= MENU_ITEMS_PANE_LENGTH
;
717 /* Ignore a nil in the item list.
718 It's meaningful only for dialog boxes. */
719 else if (EQ (AREF (menu_items
, i
), Qquote
))
721 else if (EQ (AREF (menu_items
, i
), Qt
))
723 /* Create a new pane. */
724 Lisp_Object pane_name
, prefix
;
726 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
727 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
729 if (STRINGP (pane_name
))
731 if (unicode_append_menu
)
732 pane_name
= ENCODE_UTF_8 (pane_name
);
733 else if (STRING_MULTIBYTE (pane_name
))
734 pane_name
= ENCODE_SYSTEM (pane_name
);
736 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
739 pane_string
= (NILP (pane_name
)
740 ? "" : SSDATA (pane_name
));
741 /* If there is just one top-level pane, put all its items directly
742 under the top-level menu. */
743 if (menu_items_n_panes
== 1)
746 /* If the pane has a meaningful name,
747 make the pane a top-level menu item
748 with its items as a submenu beneath it. */
749 if (!keymaps
&& strcmp (pane_string
, ""))
751 wv
= xmalloc_widget_value ();
755 first_wv
->contents
= wv
;
756 wv
->name
= pane_string
;
757 if (keymaps
&& !NILP (prefix
))
761 wv
->button_type
= BUTTON_TYPE_NONE
;
772 i
+= MENU_ITEMS_PANE_LENGTH
;
776 /* Create a new item within current pane. */
777 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
779 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
780 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
781 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
782 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
783 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
784 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
785 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
787 if (STRINGP (item_name
))
789 if (unicode_append_menu
)
790 item_name
= ENCODE_UTF_8 (item_name
);
791 else if (STRING_MULTIBYTE (item_name
))
792 item_name
= ENCODE_SYSTEM (item_name
);
794 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
797 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
799 descrip
= ENCODE_SYSTEM (descrip
);
800 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
803 wv
= xmalloc_widget_value ();
807 save_wv
->contents
= wv
;
808 wv
->name
= SSDATA (item_name
);
810 wv
->key
= SSDATA (descrip
);
812 /* Use the contents index as call_data, since we are
813 restricted to 16-bits. */
814 wv
->call_data
= !NILP (def
) ? (void *) (EMACS_INT
) i
: 0;
815 wv
->enabled
= !NILP (enable
);
818 wv
->button_type
= BUTTON_TYPE_NONE
;
819 else if (EQ (type
, QCtoggle
))
820 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
821 else if (EQ (type
, QCradio
))
822 wv
->button_type
= BUTTON_TYPE_RADIO
;
826 wv
->selected
= !NILP (selected
);
835 i
+= MENU_ITEMS_ITEM_LENGTH
;
839 /* Deal with the title, if it is non-nil. */
842 widget_value
*wv_title
= xmalloc_widget_value ();
843 widget_value
*wv_sep
= xmalloc_widget_value ();
845 /* Maybe replace this separator with a bitmap or owner-draw item
846 so that it looks better. Having two separators looks odd. */
848 wv_sep
->next
= first_wv
->contents
;
851 if (unicode_append_menu
)
852 title
= ENCODE_UTF_8 (title
);
853 else if (STRING_MULTIBYTE (title
))
854 title
= ENCODE_SYSTEM (title
);
856 wv_title
->name
= SSDATA (title
);
857 wv_title
->enabled
= TRUE
;
858 wv_title
->title
= TRUE
;
859 wv_title
->button_type
= BUTTON_TYPE_NONE
;
860 wv_title
->help
= Qnil
;
861 wv_title
->next
= wv_sep
;
862 first_wv
->contents
= wv_title
;
865 /* No selection has been chosen yet. */
866 menu_item_selection
= 0;
868 /* Actually create the menu. */
869 current_popup_menu
= menu
= CreatePopupMenu ();
870 fill_in_menu (menu
, first_wv
->contents
);
872 /* Adjust coordinates to be root-window-relative. */
875 ClientToScreen (FRAME_W32_WINDOW (f
), &pos
);
877 /* Display the menu. */
878 menu_item_selection
= SendMessage (FRAME_W32_WINDOW (f
),
879 WM_EMACS_TRACKPOPUPMENU
,
880 (WPARAM
)menu
, (LPARAM
)&pos
);
882 /* Clean up extraneous mouse events which might have been generated
884 discard_mouse_events ();
885 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
887 /* Free the widget_value objects we used to specify the contents. */
888 free_menubar_widget_value_tree (first_wv
);
892 /* Free the owner-drawn and help-echo menu strings. */
893 w32_free_menu_strings (FRAME_W32_WINDOW (f
));
894 f
->output_data
.w32
->menubar_active
= 0;
896 /* Find the selected item, and its pane, to return
898 if (menu_item_selection
!= 0)
900 Lisp_Object prefix
, entry
;
902 prefix
= entry
= Qnil
;
904 while (i
< menu_items_used
)
906 if (EQ (AREF (menu_items
, i
), Qnil
))
908 subprefix_stack
[submenu_depth
++] = prefix
;
912 else if (EQ (AREF (menu_items
, i
), Qlambda
))
914 prefix
= subprefix_stack
[--submenu_depth
];
917 else if (EQ (AREF (menu_items
, i
), Qt
))
919 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
920 i
+= MENU_ITEMS_PANE_LENGTH
;
922 /* Ignore a nil in the item list.
923 It's meaningful only for dialog boxes. */
924 else if (EQ (AREF (menu_items
, i
), Qquote
))
928 entry
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
929 if (menu_item_selection
== i
)
935 entry
= Fcons (entry
, Qnil
);
937 entry
= Fcons (prefix
, entry
);
938 for (j
= submenu_depth
- 1; j
>= 0; j
--)
939 if (!NILP (subprefix_stack
[j
]))
940 entry
= Fcons (subprefix_stack
[j
], entry
);
944 i
+= MENU_ITEMS_ITEM_LENGTH
;
949 /* Make "Cancel" equivalent to C-g. */
950 Fsignal (Qquit
, Qnil
);
957 /* TODO: On Windows, there are two ways of defining a dialog.
959 1. Create a predefined dialog resource and include it in nt/emacs.rc.
960 Using this method, we could then set the titles and make unneeded
961 buttons invisible before displaying the dialog. Everything would
962 be a fixed size though, so there is a risk that text does not
964 2. Create the dialog template in memory on the fly. This allows us
965 to size the dialog and buttons dynamically, probably giving more
966 natural looking results for dialogs with few buttons, and eliminating
967 the problem of text overflowing the buttons. But the API for this is
968 quite complex - structures have to be allocated in particular ways,
969 text content is tacked onto the end of structures in variable length
970 arrays with further structures tacked on after these, there are
971 certain alignment requirements for all this, and we have to
972 measure all the text and convert to "dialog coordinates" to figure
973 out how big to make everything.
975 For now, we'll just stick with menus for dialogs that are more
976 complicated than simple yes/no type questions for which we can use
977 the MessageBox function.
980 static char * button_names
[] = {
981 "button1", "button2", "button3", "button4", "button5",
982 "button6", "button7", "button8", "button9", "button10" };
985 w32_dialog_show (FRAME_PTR f
, int keymaps
,
986 Lisp_Object title
, Lisp_Object header
,
989 int i
, nb_buttons
= 0;
991 int menu_item_selection
;
993 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
995 /* Number of elements seen so far, before boundary. */
997 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
998 int boundary_seen
= 0;
1002 if (menu_items_n_panes
> 1)
1004 *error
= "Multiple panes in dialog box";
1008 /* Create a tree of widget_value objects
1009 representing the text label and buttons. */
1011 Lisp_Object pane_name
, prefix
;
1013 pane_name
= AREF (menu_items
, MENU_ITEMS_PANE_NAME
);
1014 prefix
= AREF (menu_items
, MENU_ITEMS_PANE_PREFIX
);
1015 pane_string
= (NILP (pane_name
)
1016 ? "" : SSDATA (pane_name
));
1017 prev_wv
= xmalloc_widget_value ();
1018 prev_wv
->value
= pane_string
;
1019 if (keymaps
&& !NILP (prefix
))
1021 prev_wv
->enabled
= 1;
1022 prev_wv
->name
= "message";
1023 prev_wv
->help
= Qnil
;
1026 /* Loop over all panes and items, filling in the tree. */
1027 i
= MENU_ITEMS_PANE_LENGTH
;
1028 while (i
< menu_items_used
)
1031 /* Create a new item within current pane. */
1032 Lisp_Object item_name
, enable
, descrip
, help
;
1034 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1035 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1036 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1037 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1039 if (NILP (item_name
))
1041 free_menubar_widget_value_tree (first_wv
);
1042 *error
= "Submenu in dialog items";
1045 if (EQ (item_name
, Qquote
))
1047 /* This is the boundary between left-side elts
1048 and right-side elts. Stop incrementing right_count. */
1053 if (nb_buttons
>= 9)
1055 free_menubar_widget_value_tree (first_wv
);
1056 *error
= "Too many dialog items";
1060 wv
= xmalloc_widget_value ();
1062 wv
->name
= (char *) button_names
[nb_buttons
];
1063 if (!NILP (descrip
))
1064 wv
->key
= SSDATA (descrip
);
1065 wv
->value
= SSDATA (item_name
);
1066 wv
->call_data
= (void *) &AREF (menu_items
, i
);
1067 wv
->enabled
= !NILP (enable
);
1071 if (! boundary_seen
)
1075 i
+= MENU_ITEMS_ITEM_LENGTH
;
1078 /* If the boundary was not specified,
1079 by default put half on the left and half on the right. */
1080 if (! boundary_seen
)
1081 left_count
= nb_buttons
- nb_buttons
/ 2;
1083 wv
= xmalloc_widget_value ();
1084 wv
->name
= dialog_name
;
1087 /* Frame title: 'Q' = Question, 'I' = Information.
1088 Can also have 'E' = Error if, one day, we want
1089 a popup for errors. */
1091 dialog_name
[0] = 'Q';
1093 dialog_name
[0] = 'I';
1095 /* Dialog boxes use a really stupid name encoding
1096 which specifies how many buttons to use
1097 and how many buttons are on the right. */
1098 dialog_name
[1] = '0' + nb_buttons
;
1099 dialog_name
[2] = 'B';
1100 dialog_name
[3] = 'R';
1101 /* Number of buttons to put on the right. */
1102 dialog_name
[4] = '0' + nb_buttons
- left_count
;
1104 wv
->contents
= first_wv
;
1108 /* Actually create the dialog. */
1109 dialog_id
= widget_id_tick
++;
1110 menu
= lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1111 f
->output_data
.w32
->widget
, 1, 0,
1112 dialog_selection_callback
, 0);
1113 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, TRUE
);
1115 /* Free the widget_value objects we used to specify the contents. */
1116 free_menubar_widget_value_tree (first_wv
);
1118 /* No selection has been chosen yet. */
1119 menu_item_selection
= 0;
1121 /* Display the menu. */
1122 lw_pop_up_all_widgets (dialog_id
);
1124 /* Process events that apply to the menu. */
1125 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), dialog_id
);
1127 lw_destroy_all_widgets (dialog_id
);
1129 /* Find the selected item, and its pane, to return
1130 the proper value. */
1131 if (menu_item_selection
!= 0)
1137 while (i
< menu_items_used
)
1141 if (EQ (AREF (menu_items
, i
), Qt
))
1143 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1144 i
+= MENU_ITEMS_PANE_LENGTH
;
1148 entry
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1149 if (menu_item_selection
== i
)
1153 entry
= Fcons (entry
, Qnil
);
1155 entry
= Fcons (prefix
, entry
);
1159 i
+= MENU_ITEMS_ITEM_LENGTH
;
1164 /* Make "Cancel" equivalent to C-g. */
1165 Fsignal (Qquit
, Qnil
);
1169 #else /* !HAVE_DIALOGS */
1171 /* Currently we only handle Yes No dialogs (y-or-n-p and yes-or-no-p) as
1172 simple dialogs. We could handle a few more, but I'm not aware of
1173 anywhere in Emacs that uses the other specific dialog choices that
1174 MessageBox provides. */
1177 is_simple_dialog (Lisp_Object contents
)
1179 Lisp_Object options
;
1180 Lisp_Object name
, yes
, no
, other
;
1182 if (!CONSP (contents
))
1184 options
= XCDR (contents
);
1186 yes
= build_string ("Yes");
1187 no
= build_string ("No");
1189 if (!CONSP (options
))
1192 name
= XCAR (options
);
1197 if (!NILP (Fstring_equal (name
, yes
)))
1199 else if (!NILP (Fstring_equal (name
, no
)))
1204 options
= XCDR (options
);
1205 if (!CONSP (options
))
1208 name
= XCAR (options
);
1212 if (NILP (Fstring_equal (name
, other
)))
1215 /* Check there are no more options. */
1216 options
= XCDR (options
);
1217 return !(CONSP (options
));
1221 simple_dialog_show (FRAME_PTR f
, Lisp_Object contents
, Lisp_Object header
)
1225 Lisp_Object lispy_answer
= Qnil
, temp
= XCAR (contents
);
1229 /* Since we only handle Yes/No dialogs, and we already checked
1230 is_simple_dialog, we don't need to worry about checking contents
1231 to see what type of dialog to use. */
1233 /* Use Unicode if possible, so any language can be displayed. */
1234 if (unicode_message_box
)
1236 WCHAR
*text
, *title
;
1241 char *utf8_text
= SDATA (ENCODE_UTF_8 (temp
));
1242 /* Be pessimistic about the number of characters needed.
1243 Remember characters outside the BMP will take more than
1244 one utf16 word, so we cannot simply use the character
1246 int utf8_len
= strlen (utf8_text
);
1247 SAFE_ALLOCA (text
, WCHAR
*, (utf8_len
+ 1) * sizeof (WCHAR
));
1248 utf8to16 (utf8_text
, utf8_len
, text
);
1257 title
= L
"Question";
1258 type
|= MB_ICONQUESTION
;
1262 title
= L
"Information";
1263 type
|= MB_ICONINFORMATION
;
1266 answer
= unicode_message_box (FRAME_W32_WINDOW (f
), text
, title
, type
);
1273 /* Fall back on ANSI message box, but at least use system
1274 encoding so questions representable by the system codepage
1275 are encoded properly. */
1277 text
= SDATA (ENCODE_SYSTEM (temp
));
1284 type
|= MB_ICONQUESTION
;
1288 title
= "Information";
1289 type
|= MB_ICONINFORMATION
;
1292 answer
= MessageBox (FRAME_W32_WINDOW (f
), text
, title
, type
);
1295 if (answer
== IDYES
)
1296 lispy_answer
= build_string ("Yes");
1297 else if (answer
== IDNO
)
1298 lispy_answer
= build_string ("No");
1300 Fsignal (Qquit
, Qnil
);
1302 for (temp
= XCDR (contents
); CONSP (temp
); temp
= XCDR (temp
))
1304 Lisp_Object item
, name
, value
;
1309 value
= XCDR (item
);
1317 if (!NILP (Fstring_equal (name
, lispy_answer
)))
1322 Fsignal (Qquit
, Qnil
);
1325 #endif /* !HAVE_DIALOGS */
1328 /* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
1330 utf8to16 (unsigned char * src
, int len
, WCHAR
* dest
)
1336 *dest
= (WCHAR
) *src
;
1337 dest
++; src
++; len
--;
1339 /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */
1340 else if (*src
< 0xC0)
1344 /* 2 char UTF-8 sequence. */
1345 else if (*src
< 0xE0)
1347 *dest
= (WCHAR
) (((*src
& 0x1f) << 6)
1348 | (*(src
+ 1) & 0x3f));
1349 src
+= 2; len
-= 2; dest
++;
1351 else if (*src
< 0xF0)
1353 *dest
= (WCHAR
) (((*src
& 0x0f) << 12)
1354 | ((*(src
+ 1) & 0x3f) << 6)
1355 | (*(src
+ 2) & 0x3f));
1356 src
+= 3; len
-= 3; dest
++;
1358 else /* Not encodable. Insert Unicode Substitution char. */
1360 *dest
= (WCHAR
) 0xfffd;
1361 src
++; len
--; dest
++;
1368 add_menu_item (HMENU menu
, widget_value
*wv
, HMENU item
)
1371 char *out_string
, *p
, *q
;
1373 size_t nlen
, orig_len
;
1376 if (menu_separator_name_p (wv
->name
))
1378 fuFlags
= MF_SEPARATOR
;
1384 fuFlags
= MF_STRING
;
1386 fuFlags
= MF_STRING
| MF_GRAYED
;
1388 if (wv
->key
!= NULL
)
1390 SAFE_ALLOCA (out_string
, char *,
1391 strlen (wv
->name
) + strlen (wv
->key
) + 2);
1392 strcpy (out_string
, wv
->name
);
1393 strcat (out_string
, "\t");
1394 strcat (out_string
, wv
->key
);
1397 out_string
= (char *)wv
->name
;
1399 /* Quote any special characters within the menu item's text and
1401 nlen
= orig_len
= strlen (out_string
);
1402 if (unicode_append_menu
)
1404 /* With UTF-8, & cannot be part of a multibyte character. */
1405 for (p
= out_string
; *p
; p
++)
1413 /* If encoded with the system codepage, use multibyte string
1414 functions in case of multibyte characters that contain '&'. */
1415 for (p
= out_string
; *p
; p
= _mbsinc (p
))
1417 if (_mbsnextc (p
) == '&')
1422 if (nlen
> orig_len
)
1425 SAFE_ALLOCA (out_string
, char *, nlen
+ 1);
1429 if (unicode_append_menu
)
1437 if (_mbsnextc (p
) == '&')
1452 else if (wv
->title
|| wv
->call_data
== 0)
1454 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
1455 we can't deallocate the memory otherwise. */
1456 if (get_menu_item_info
)
1458 out_string
= (char *) local_alloc (strlen (wv
->name
) + 1);
1459 strcpy (out_string
, wv
->name
);
1461 DebPrint ("Menu: allocating %ld for owner-draw", out_string
);
1463 fuFlags
= MF_OWNERDRAW
| MF_DISABLED
;
1466 fuFlags
= MF_DISABLED
;
1469 /* Draw radio buttons and tickboxes. */
1470 else if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
||
1471 wv
->button_type
== BUTTON_TYPE_RADIO
))
1472 fuFlags
|= MF_CHECKED
;
1474 fuFlags
|= MF_UNCHECKED
;
1477 if (unicode_append_menu
&& out_string
)
1479 /* Convert out_string from UTF-8 to UTF-16-LE. */
1480 int utf8_len
= strlen (out_string
);
1481 WCHAR
* utf16_string
;
1482 if (fuFlags
& MF_OWNERDRAW
)
1483 utf16_string
= local_alloc ((utf8_len
+ 1) * sizeof (WCHAR
));
1485 SAFE_ALLOCA (utf16_string
, WCHAR
*, (utf8_len
+ 1) * sizeof (WCHAR
));
1487 utf8to16 (out_string
, utf8_len
, utf16_string
);
1488 return_value
= unicode_append_menu (menu
, fuFlags
,
1489 item
!= NULL
? (UINT
) item
1490 : (UINT
) wv
->call_data
,
1494 /* On W9x/ME, Unicode menus are not supported, though AppendMenuW
1495 apparently does exist at least in some cases and appears to be
1496 stubbed out to do nothing. out_string is UTF-8, but since
1497 our standard menus are in English and this is only going to
1498 happen the first time a menu is used, the encoding is
1499 of minor importance compared with menus not working at all. */
1501 AppendMenu (menu
, fuFlags
,
1502 item
!= NULL
? (UINT
) item
: (UINT
) wv
->call_data
,
1504 /* Don't use Unicode menus in future, unless this is Windows
1505 NT or later, where a failure of AppendMenuW does NOT mean
1506 Unicode menus are unsupported. */
1507 if (osinfo_cache
.dwPlatformId
!= VER_PLATFORM_WIN32_NT
)
1508 unicode_append_menu
= NULL
;
1511 if (unicode_append_menu
&& (fuFlags
& MF_OWNERDRAW
))
1512 local_free (out_string
);
1519 item
!= NULL
? (UINT
) item
: (UINT
) wv
->call_data
,
1523 /* This must be done after the menu item is created. */
1524 if (!wv
->title
&& wv
->call_data
!= 0)
1526 if (set_menu_item_info
)
1529 memset (&info
, 0, sizeof (info
));
1530 info
.cbSize
= sizeof (info
);
1531 info
.fMask
= MIIM_DATA
;
1533 /* Set help string for menu item. Leave it as a Lisp_Object
1534 until it is ready to be displayed, since GC can happen while
1535 menus are active. */
1536 if (!NILP (wv
->help
))
1537 info
.dwItemData
= (DWORD
) XLI (wv
->help
);
1538 if (wv
->button_type
== BUTTON_TYPE_RADIO
)
1540 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
1541 RADIO items, but is not available on NT 3.51 and earlier. */
1542 info
.fMask
|= MIIM_TYPE
| MIIM_STATE
;
1543 info
.fType
= MFT_RADIOCHECK
| MFT_STRING
;
1544 info
.dwTypeData
= out_string
;
1545 info
.fState
= wv
->selected
? MFS_CHECKED
: MFS_UNCHECKED
;
1548 set_menu_item_info (menu
,
1549 item
!= NULL
? (UINT
) item
: (UINT
) wv
->call_data
,
1554 return return_value
;
1557 /* Construct native Windows menu(bar) based on widget_value tree. */
1559 fill_in_menu (HMENU menu
, widget_value
*wv
)
1561 for ( ; wv
!= NULL
; wv
= wv
->next
)
1565 HMENU sub_menu
= CreatePopupMenu ();
1567 if (sub_menu
== NULL
)
1570 if (!fill_in_menu (sub_menu
, wv
->contents
) ||
1571 !add_menu_item (menu
, wv
, sub_menu
))
1573 DestroyMenu (sub_menu
);
1579 if (!add_menu_item (menu
, wv
, NULL
))
1586 /* Display help string for currently pointed to menu item. Not
1587 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
1590 w32_menu_display_help (HWND owner
, HMENU menu
, UINT item
, UINT flags
)
1592 if (get_menu_item_info
)
1594 struct frame
*f
= x_window_to_frame (&one_w32_display_info
, owner
);
1595 Lisp_Object frame
, help
;
1597 /* No help echo on owner-draw menu items, or when the keyboard is used
1598 to navigate the menus, since tooltips are distracting if they pop
1600 if (flags
& MF_OWNERDRAW
|| flags
& MF_POPUP
1601 || !(flags
& MF_MOUSESELECT
))
1607 memset (&info
, 0, sizeof (info
));
1608 info
.cbSize
= sizeof (info
);
1609 info
.fMask
= MIIM_DATA
;
1610 get_menu_item_info (menu
, item
, FALSE
, &info
);
1612 help
= info
.dwItemData
? XIL (info
.dwItemData
) : Qnil
;
1615 /* Store the help echo in the keyboard buffer as the X toolkit
1616 version does, rather than directly showing it. This seems to
1617 solve the GC problems that were present when we based the
1618 Windows code on the non-toolkit version. */
1621 XSETFRAME (frame
, f
);
1622 kbd_buffer_store_help_event (frame
, help
);
1625 /* X version has a loop through frames here, which doesn't
1626 appear to do anything, unless it has some side effect. */
1627 show_help_echo (help
, Qnil
, Qnil
, Qnil
);
1631 /* Free memory used by owner-drawn strings. */
1633 w32_free_submenu_strings (HMENU menu
)
1635 int i
, num
= GetMenuItemCount (menu
);
1636 for (i
= 0; i
< num
; i
++)
1639 memset (&info
, 0, sizeof (info
));
1640 info
.cbSize
= sizeof (info
);
1641 info
.fMask
= MIIM_DATA
| MIIM_TYPE
| MIIM_SUBMENU
;
1643 get_menu_item_info (menu
, i
, TRUE
, &info
);
1645 /* Owner-drawn names are held in dwItemData. */
1646 if ((info
.fType
& MF_OWNERDRAW
) && info
.dwItemData
)
1649 DebPrint ("Menu: freeing %ld for owner-draw", info
.dwItemData
);
1651 local_free (info
.dwItemData
);
1654 /* Recurse down submenus. */
1656 w32_free_submenu_strings (info
.hSubMenu
);
1661 w32_free_menu_strings (HWND hwnd
)
1663 HMENU menu
= current_popup_menu
;
1665 if (get_menu_item_info
)
1667 /* If there is no popup menu active, free the strings from the frame's
1670 menu
= GetMenu (hwnd
);
1673 w32_free_submenu_strings (menu
);
1676 current_popup_menu
= NULL
;
1679 #endif /* HAVE_MENUS */
1681 /* The following is used by delayed window autoselection. */
1683 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
1684 doc
: /* Return t if a menu or popup dialog is active on selected frame. */)
1689 f
= SELECTED_FRAME ();
1690 return (f
->output_data
.w32
->menubar_active
> 0) ? Qt
: Qnil
;
1693 #endif /* HAVE_MENUS */
1697 syms_of_w32menu (void)
1699 globals_of_w32menu ();
1701 current_popup_menu
= NULL
;
1703 DEFSYM (Qdebug_on_next_call
, "debug-on-next-call");
1705 defsubr (&Smenu_or_popup_active_p
);
1707 defsubr (&Sx_popup_dialog
);
1712 globals_of_w32menu is used to initialize those global variables that
1713 must always be initialized on startup even when the global variable
1714 initialized is non zero (see the function main in emacs.c).
1715 globals_of_w32menu is called from syms_of_w32menu when the global
1716 variable initialized is 0 and directly from main when initialized
1720 globals_of_w32menu (void)
1722 /* See if Get/SetMenuItemInfo functions are available. */
1723 HMODULE user32
= GetModuleHandle ("user32.dll");
1724 get_menu_item_info
= (GetMenuItemInfoA_Proc
) GetProcAddress (user32
, "GetMenuItemInfoA");
1725 set_menu_item_info
= (SetMenuItemInfoA_Proc
) GetProcAddress (user32
, "SetMenuItemInfoA");
1726 unicode_append_menu
= (AppendMenuW_Proc
) GetProcAddress (user32
, "AppendMenuW");
1727 unicode_message_box
= (MessageBoxW_Proc
) GetProcAddress (user32
, "MessageBoxW");