1 /* Menu support for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1986, 1988, 1993, 1994, 1996, 1998, 1999, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
32 #include "termhooks.h"
34 #include "blockinput.h"
37 #include "character.h"
41 /* This may include sys/types.h, and that somehow loses
42 if this is not done before the other system files. */
45 /* Load sys/types.h if not already loaded.
46 In some systems loading it twice is suicidal. */
48 #include <sys/types.h>
51 #include "dispextern.h"
53 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
60 HMENU current_popup_menu
;
62 void syms_of_w32menu ();
63 void globals_of_w32menu ();
65 typedef BOOL (WINAPI
* GetMenuItemInfoA_Proc
) (
69 IN OUT LPMENUITEMINFOA
);
70 typedef BOOL (WINAPI
* SetMenuItemInfoA_Proc
) (
76 GetMenuItemInfoA_Proc get_menu_item_info
= NULL
;
77 SetMenuItemInfoA_Proc set_menu_item_info
= NULL
;
78 AppendMenuW_Proc unicode_append_menu
= NULL
;
80 Lisp_Object Qdebug_on_next_call
;
82 extern Lisp_Object Qmenu_bar
;
84 extern Lisp_Object QCtoggle
, QCradio
;
86 extern Lisp_Object impl_Voverriding_local_map
;
87 extern Lisp_Object impl_Voverriding_local_map_menu_flag
;
89 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
91 extern Lisp_Object Qmenu_bar_update_hook
;
93 void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
96 static Lisp_Object w32_dialog_show
P_ ((FRAME_PTR
, int, Lisp_Object
, char**));
98 static int is_simple_dialog
P_ ((Lisp_Object
));
99 static Lisp_Object simple_dialog_show
P_ ((FRAME_PTR
, Lisp_Object
, Lisp_Object
));
102 void w32_free_menu_strings
P_((HWND
));
105 /* This is set nonzero after the user activates the menu bar, and set
106 to zero again after the menu bars are redisplayed by prepare_menu_bar.
107 While it is nonzero, all calls to set_frame_menubar go deep.
109 I don't understand why this is needed, but it does seem to be
110 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
112 int pending_menu_activation
;
115 /* Return the frame whose ->output_data.w32->menubar_widget equals
118 static struct frame
*
119 menubar_id_to_frame (id
)
122 Lisp_Object tail
, frame
;
125 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
131 if (!FRAME_WINDOW_P (f
))
133 if (f
->output_data
.w32
->menubar_widget
== id
)
141 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
142 doc
: /* Pop up a dialog box and return user's selection.
143 POSITION specifies which frame to use.
144 This is normally a mouse button event or a window or frame.
145 If POSITION is t, it means to use the frame the mouse is on.
146 The dialog box appears in the middle of the specified frame.
148 CONTENTS specifies the alternatives to display in the dialog box.
149 It is a list of the form (TITLE ITEM1 ITEM2...).
150 Each ITEM is a cons cell (STRING . VALUE).
151 The return value is VALUE from the chosen item.
153 An ITEM may also be just a string--that makes a nonselectable item.
154 An ITEM may also be nil--that means to put all preceding items
155 on the left of the dialog box and all following items on the right.
156 \(By default, approximately half appear on each side.)
158 If HEADER is non-nil, the frame title for the box is "Information",
159 otherwise it is "Question". */)
160 (position
, contents
, header
)
161 Lisp_Object position
, contents
, header
;
168 /* Decode the first argument: find the window or frame to use. */
169 if (EQ (position
, Qt
)
170 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
171 || EQ (XCAR (position
), Qtool_bar
))))
173 #if 0 /* Using the frame the mouse is on may not be right. */
174 /* Use the mouse's current position. */
175 FRAME_PTR new_f
= SELECTED_FRAME ();
176 Lisp_Object bar_window
;
177 enum scroll_bar_part part
;
181 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
184 XSETFRAME (window
, new_f
);
186 window
= selected_window
;
188 window
= selected_window
;
190 else if (CONSP (position
))
193 tem
= Fcar (position
);
195 window
= Fcar (Fcdr (position
));
198 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
199 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
202 else if (WINDOWP (position
) || FRAMEP (position
))
207 /* Decode where to put the menu. */
211 else if (WINDOWP (window
))
213 CHECK_LIVE_WINDOW (window
);
214 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
217 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
218 but I don't want to make one now. */
219 CHECK_WINDOW (window
);
224 /* Handle simple Yes/No choices as MessageBox popups. */
225 if (is_simple_dialog (contents
))
226 return simple_dialog_show (f
, contents
, header
);
229 /* Display a menu with these alternatives
230 in the middle of frame F. */
231 Lisp_Object x
, y
, frame
, newpos
;
232 XSETFRAME (frame
, f
);
233 XSETINT (x
, x_pixel_width (f
) / 2);
234 XSETINT (y
, x_pixel_height (f
) / 2);
235 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
236 return Fx_popup_menu (newpos
,
237 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
240 #else /* HAVE_DIALOGS */
244 Lisp_Object selection
;
246 /* Decode the dialog items from what was specified. */
247 title
= Fcar (contents
);
248 CHECK_STRING (title
);
250 list_of_panes (Fcons (contents
, Qnil
));
252 /* Display them in a dialog box. */
254 selection
= w32_dialog_show (f
, 0, title
, header
, &error_name
);
257 discard_menu_items ();
258 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
260 if (error_name
) error (error_name
);
263 #endif /* HAVE_DIALOGS */
266 /* Activate the menu bar of frame F.
267 This is called from keyboard.c when it gets the
268 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
270 To activate the menu bar, we signal to the input thread that it can
271 return from the WM_INITMENU message, allowing the normal Windows
272 processing of the menus.
274 But first we recompute the menu bar contents (the whole tree).
276 This way we can safely execute Lisp code. */
279 x_activate_menubar (f
)
282 set_frame_menubar (f
, 0, 1);
284 /* Lock out further menubar changes while active. */
285 f
->output_data
.w32
->menubar_active
= 1;
287 /* Signal input thread to return from WM_INITMENU. */
288 complete_deferred_msg (FRAME_W32_WINDOW (f
), WM_INITMENU
, 0);
291 /* This callback is called from the menu bar pulldown menu
292 when the user makes a selection.
293 Figure out what the user chose
294 and put the appropriate events into the keyboard buffer. */
297 menubar_selection_callback (FRAME_PTR f
, void * client_data
)
299 Lisp_Object prefix
, entry
;
301 Lisp_Object
*subprefix_stack
;
302 int submenu_depth
= 0;
308 subprefix_stack
= (Lisp_Object
*) alloca (f
->menu_bar_items_used
* sizeof (Lisp_Object
));
309 vector
= f
->menu_bar_vector
;
312 while (i
< f
->menu_bar_items_used
)
314 if (EQ (AREF (vector
, i
), Qnil
))
316 subprefix_stack
[submenu_depth
++] = prefix
;
320 else if (EQ (AREF (vector
, i
), Qlambda
))
322 prefix
= subprefix_stack
[--submenu_depth
];
325 else if (EQ (AREF (vector
, i
), Qt
))
327 prefix
= AREF (vector
, i
+ MENU_ITEMS_PANE_PREFIX
);
328 i
+= MENU_ITEMS_PANE_LENGTH
;
332 entry
= AREF (vector
, i
+ MENU_ITEMS_ITEM_VALUE
);
333 /* The EMACS_INT cast avoids a warning. There's no problem
334 as long as pointers have enough bits to hold small integers. */
335 if ((int) (EMACS_INT
) client_data
== i
)
338 struct input_event buf
;
342 XSETFRAME (frame
, f
);
343 buf
.kind
= MENU_BAR_EVENT
;
344 buf
.frame_or_window
= frame
;
346 kbd_buffer_store_event (&buf
);
348 for (j
= 0; j
< submenu_depth
; j
++)
349 if (!NILP (subprefix_stack
[j
]))
351 buf
.kind
= MENU_BAR_EVENT
;
352 buf
.frame_or_window
= frame
;
353 buf
.arg
= subprefix_stack
[j
];
354 kbd_buffer_store_event (&buf
);
359 buf
.kind
= MENU_BAR_EVENT
;
360 buf
.frame_or_window
= frame
;
362 kbd_buffer_store_event (&buf
);
365 buf
.kind
= MENU_BAR_EVENT
;
366 buf
.frame_or_window
= frame
;
368 /* Free memory used by owner-drawn and help-echo strings. */
369 w32_free_menu_strings (FRAME_W32_WINDOW (f
));
370 kbd_buffer_store_event (&buf
);
372 f
->output_data
.w32
->menubar_active
= 0;
375 i
+= MENU_ITEMS_ITEM_LENGTH
;
378 /* Free memory used by owner-drawn and help-echo strings. */
379 w32_free_menu_strings (FRAME_W32_WINDOW (f
));
380 f
->output_data
.w32
->menubar_active
= 0;
384 /* Set the contents of the menubar widgets of frame F.
385 The argument FIRST_TIME is currently ignored;
386 it is set the first time this is called, from initialize_frame_menubar. */
389 set_frame_menubar (f
, first_time
, deep_p
)
394 HMENU menubar_widget
= f
->output_data
.w32
->menubar_widget
;
396 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
398 int *submenu_start
, *submenu_end
;
399 int *submenu_top_level_items
, *submenu_n_panes
;
401 /* We must not change the menubar when actually in use. */
402 if (f
->output_data
.w32
->menubar_active
)
405 XSETFRAME (Vmenu_updating_frame
, f
);
407 if (! menubar_widget
)
409 else if (pending_menu_activation
&& !deep_p
)
414 /* Make a widget-value tree representing the entire menu trees. */
416 struct buffer
*prev
= current_buffer
;
418 int specpdl_count
= SPECPDL_INDEX ();
419 int previous_menu_items_used
= f
->menu_bar_items_used
;
420 Lisp_Object
*previous_items
421 = (Lisp_Object
*) alloca (previous_menu_items_used
422 * sizeof (Lisp_Object
));
424 /* If we are making a new widget, its contents are empty,
425 do always reinitialize them. */
426 if (! menubar_widget
)
427 previous_menu_items_used
= 0;
429 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
430 specbind (Qinhibit_quit
, Qt
);
431 /* Don't let the debugger step into this code
432 because it is not reentrant. */
433 specbind (Qdebug_on_next_call
, Qnil
);
435 record_unwind_save_match_data ();
437 if (NILP (Voverriding_local_map_menu_flag
))
439 specbind (Qoverriding_terminal_local_map
, Qnil
);
440 specbind (Qoverriding_local_map
, Qnil
);
443 set_buffer_internal_1 (XBUFFER (buffer
));
445 /* Run the Lucid hook. */
446 safe_run_hooks (Qactivate_menubar_hook
);
447 /* If it has changed current-menubar from previous value,
448 really recompute the menubar from the value. */
449 if (! NILP (Vlucid_menu_bar_dirty_flag
))
450 call0 (Qrecompute_lucid_menubar
);
451 safe_run_hooks (Qmenu_bar_update_hook
);
452 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
454 items
= FRAME_MENU_BAR_ITEMS (f
);
456 /* Save the frame's previous menu bar contents data. */
457 if (previous_menu_items_used
)
458 bcopy (XVECTOR (f
->menu_bar_vector
)->contents
, previous_items
,
459 previous_menu_items_used
* sizeof (Lisp_Object
));
461 /* Fill in menu_items with the current menu bar contents.
462 This can evaluate Lisp code. */
465 menu_items
= f
->menu_bar_vector
;
466 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
467 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
468 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
469 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
470 submenu_top_level_items
471 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
473 for (i
= 0; i
< ASIZE (items
); i
+= 4)
475 Lisp_Object key
, string
, maps
;
479 key
= AREF (items
, i
);
480 string
= AREF (items
, i
+ 1);
481 maps
= AREF (items
, i
+ 2);
485 submenu_start
[i
] = menu_items_used
;
487 menu_items_n_panes
= 0;
488 submenu_top_level_items
[i
]
489 = parse_single_submenu (key
, string
, maps
);
490 submenu_n_panes
[i
] = menu_items_n_panes
;
492 submenu_end
[i
] = menu_items_used
;
495 finish_menu_items ();
497 /* Convert menu_items into widget_value trees
498 to display the menu. This cannot evaluate Lisp code. */
500 wv
= xmalloc_widget_value ();
501 wv
->name
= "menubar";
504 wv
->button_type
= BUTTON_TYPE_NONE
;
508 for (i
= 0; i
< last_i
; i
+= 4)
510 menu_items_n_panes
= submenu_n_panes
[i
];
511 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
512 submenu_top_level_items
[i
]);
516 first_wv
->contents
= wv
;
517 /* Don't set wv->name here; GC during the loop might relocate it. */
519 wv
->button_type
= BUTTON_TYPE_NONE
;
523 set_buffer_internal_1 (prev
);
525 /* If there has been no change in the Lisp-level contents
526 of the menu bar, skip redisplaying it. Just exit. */
528 for (i
= 0; i
< previous_menu_items_used
; i
++)
529 if (menu_items_used
== i
530 || (!EQ (previous_items
[i
], AREF (menu_items
, i
))))
532 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
534 free_menubar_widget_value_tree (first_wv
);
535 discard_menu_items ();
536 unbind_to (specpdl_count
, Qnil
);
540 f
->menu_bar_vector
= menu_items
;
541 f
->menu_bar_items_used
= menu_items_used
;
543 /* This undoes save_menu_items. */
544 unbind_to (specpdl_count
, Qnil
);
546 /* Now GC cannot happen during the lifetime of the widget_value,
547 so it's safe to store data from a Lisp_String, as long as
548 local copies are made when the actual menu is created.
549 Windows takes care of this for normal string items, but
550 not for owner-drawn items or additional item-info. */
551 wv
= first_wv
->contents
;
552 for (i
= 0; i
< ASIZE (items
); i
+= 4)
555 string
= AREF (items
, i
+ 1);
558 wv
->name
= (char *) SDATA (string
);
559 update_submenu_strings (wv
->contents
);
565 /* Make a widget-value tree containing
566 just the top level menu bar strings. */
568 wv
= xmalloc_widget_value ();
569 wv
->name
= "menubar";
572 wv
->button_type
= BUTTON_TYPE_NONE
;
576 items
= FRAME_MENU_BAR_ITEMS (f
);
577 for (i
= 0; i
< ASIZE (items
); i
+= 4)
581 string
= AREF (items
, i
+ 1);
585 wv
= xmalloc_widget_value ();
586 wv
->name
= (char *) SDATA (string
);
589 wv
->button_type
= BUTTON_TYPE_NONE
;
591 /* This prevents lwlib from assuming this
592 menu item is really supposed to be empty. */
593 /* The EMACS_INT cast avoids a warning.
594 This value just has to be different from small integers. */
595 wv
->call_data
= (void *) (EMACS_INT
) (-1);
600 first_wv
->contents
= wv
;
604 /* Forget what we thought we knew about what is in the
605 detailed contents of the menu bar menus.
606 Changing the top level always destroys the contents. */
607 f
->menu_bar_items_used
= 0;
610 /* Create or update the menu bar widget. */
616 /* Empty current menubar, rather than creating a fresh one. */
617 while (DeleteMenu (menubar_widget
, 0, MF_BYPOSITION
))
622 menubar_widget
= CreateMenu ();
624 fill_in_menu (menubar_widget
, first_wv
->contents
);
626 free_menubar_widget_value_tree (first_wv
);
629 HMENU old_widget
= f
->output_data
.w32
->menubar_widget
;
631 f
->output_data
.w32
->menubar_widget
= menubar_widget
;
632 SetMenu (FRAME_W32_WINDOW (f
), f
->output_data
.w32
->menubar_widget
);
633 /* Causes flicker when menu bar is updated
634 DrawMenuBar (FRAME_W32_WINDOW (f)); */
636 /* Force the window size to be recomputed so that the frame's text
637 area remains the same, if menubar has just been created. */
638 if (old_widget
== NULL
)
639 x_set_window_size (f
, 0, FRAME_COLS (f
), FRAME_LINES (f
));
645 /* Called from Fx_create_frame to create the initial menubar of a frame
646 before it is mapped, so that the window is mapped with the menubar already
647 there instead of us tacking it on later and thrashing the window after it
651 initialize_frame_menubar (f
)
654 /* This function is called before the first chance to redisplay
655 the frame. It has to be, so the frame will have the right size. */
656 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
657 set_frame_menubar (f
, 1, 1);
660 /* Get rid of the menu bar of frame F, and free its storage.
661 This is used when deleting a frame, and when turning off the menu bar. */
664 free_frame_menubar (f
)
670 HMENU old
= GetMenu (FRAME_W32_WINDOW (f
));
671 SetMenu (FRAME_W32_WINDOW (f
), NULL
);
672 f
->output_data
.w32
->menubar_widget
= NULL
;
680 /* w32_menu_show actually displays a menu using the panes and items in
681 menu_items and returns the value selected from it; we assume input
682 is blocked by the caller. */
684 /* F is the frame the menu is for.
685 X and Y are the frame-relative specified position,
686 relative to the inside upper left corner of the frame F.
687 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
688 KEYMAPS is 1 if this menu was specified with keymaps;
689 in that case, we return a list containing the chosen item's value
690 and perhaps also the pane's prefix.
691 TITLE is the specified menu title.
692 ERROR is a place to store an error message string in case of failure.
693 (We return nil on failure, but the value doesn't actually matter.) */
696 w32_menu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
697 Lisp_Object title
, char **error
)
700 int menu_item_selection
;
703 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
704 widget_value
**submenu_stack
705 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
706 Lisp_Object
*subprefix_stack
707 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
708 int submenu_depth
= 0;
713 if (menu_items_n_panes
== 0)
716 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
718 *error
= "Empty menu";
722 /* Create a tree of widget_value objects
723 representing the panes and their items. */
724 wv
= xmalloc_widget_value ();
728 wv
->button_type
= BUTTON_TYPE_NONE
;
733 /* Loop over all panes and items, filling in the tree. */
735 while (i
< menu_items_used
)
737 if (EQ (AREF (menu_items
, i
), Qnil
))
739 submenu_stack
[submenu_depth
++] = save_wv
;
745 else if (EQ (AREF (menu_items
, i
), Qlambda
))
748 save_wv
= submenu_stack
[--submenu_depth
];
752 else if (EQ (AREF (menu_items
, i
), Qt
)
753 && submenu_depth
!= 0)
754 i
+= MENU_ITEMS_PANE_LENGTH
;
755 /* Ignore a nil in the item list.
756 It's meaningful only for dialog boxes. */
757 else if (EQ (AREF (menu_items
, i
), Qquote
))
759 else if (EQ (AREF (menu_items
, i
), Qt
))
761 /* Create a new pane. */
762 Lisp_Object pane_name
, prefix
;
764 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
765 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
767 if (STRINGP (pane_name
))
769 if (unicode_append_menu
)
770 pane_name
= ENCODE_UTF_8 (pane_name
);
771 else if (STRING_MULTIBYTE (pane_name
))
772 pane_name
= ENCODE_SYSTEM (pane_name
);
774 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
777 pane_string
= (NILP (pane_name
)
778 ? "" : (char *) SDATA (pane_name
));
779 /* If there is just one top-level pane, put all its items directly
780 under the top-level menu. */
781 if (menu_items_n_panes
== 1)
784 /* If the pane has a meaningful name,
785 make the pane a top-level menu item
786 with its items as a submenu beneath it. */
787 if (!keymaps
&& strcmp (pane_string
, ""))
789 wv
= xmalloc_widget_value ();
793 first_wv
->contents
= wv
;
794 wv
->name
= pane_string
;
795 if (keymaps
&& !NILP (prefix
))
799 wv
->button_type
= BUTTON_TYPE_NONE
;
810 i
+= MENU_ITEMS_PANE_LENGTH
;
814 /* Create a new item within current pane. */
815 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
817 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
818 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
819 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
820 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
821 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
822 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
823 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
825 if (STRINGP (item_name
))
827 if (unicode_append_menu
)
828 item_name
= ENCODE_UTF_8 (item_name
);
829 else if (STRING_MULTIBYTE (item_name
))
830 item_name
= ENCODE_SYSTEM (item_name
);
832 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
835 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
837 descrip
= ENCODE_SYSTEM (descrip
);
838 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
841 wv
= xmalloc_widget_value ();
845 save_wv
->contents
= wv
;
846 wv
->name
= (char *) SDATA (item_name
);
848 wv
->key
= (char *) SDATA (descrip
);
850 /* Use the contents index as call_data, since we are
851 restricted to 16-bits. */
852 wv
->call_data
= !NILP (def
) ? (void *) (EMACS_INT
) i
: 0;
853 wv
->enabled
= !NILP (enable
);
856 wv
->button_type
= BUTTON_TYPE_NONE
;
857 else if (EQ (type
, QCtoggle
))
858 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
859 else if (EQ (type
, QCradio
))
860 wv
->button_type
= BUTTON_TYPE_RADIO
;
864 wv
->selected
= !NILP (selected
);
873 i
+= MENU_ITEMS_ITEM_LENGTH
;
877 /* Deal with the title, if it is non-nil. */
880 widget_value
*wv_title
= xmalloc_widget_value ();
881 widget_value
*wv_sep
= xmalloc_widget_value ();
883 /* Maybe replace this separator with a bitmap or owner-draw item
884 so that it looks better. Having two separators looks odd. */
886 wv_sep
->next
= first_wv
->contents
;
889 if (unicode_append_menu
)
890 title
= ENCODE_UTF_8 (title
);
891 else if (STRING_MULTIBYTE (title
))
892 title
= ENCODE_SYSTEM (title
);
894 wv_title
->name
= (char *) SDATA (title
);
895 wv_title
->enabled
= TRUE
;
896 wv_title
->title
= TRUE
;
897 wv_title
->button_type
= BUTTON_TYPE_NONE
;
898 wv_title
->help
= Qnil
;
899 wv_title
->next
= wv_sep
;
900 first_wv
->contents
= wv_title
;
903 /* No selection has been chosen yet. */
904 menu_item_selection
= 0;
906 /* Actually create the menu. */
907 current_popup_menu
= menu
= CreatePopupMenu ();
908 fill_in_menu (menu
, first_wv
->contents
);
910 /* Adjust coordinates to be root-window-relative. */
913 ClientToScreen (FRAME_W32_WINDOW (f
), &pos
);
915 /* Display the menu. */
916 menu_item_selection
= SendMessage (FRAME_W32_WINDOW (f
),
917 WM_EMACS_TRACKPOPUPMENU
,
918 (WPARAM
)menu
, (LPARAM
)&pos
);
920 /* Clean up extraneous mouse events which might have been generated
922 discard_mouse_events ();
923 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
925 /* Free the widget_value objects we used to specify the contents. */
926 free_menubar_widget_value_tree (first_wv
);
930 /* Free the owner-drawn and help-echo menu strings. */
931 w32_free_menu_strings (FRAME_W32_WINDOW (f
));
932 f
->output_data
.w32
->menubar_active
= 0;
934 /* Find the selected item, and its pane, to return
936 if (menu_item_selection
!= 0)
938 Lisp_Object prefix
, entry
;
940 prefix
= entry
= Qnil
;
942 while (i
< menu_items_used
)
944 if (EQ (AREF (menu_items
, i
), Qnil
))
946 subprefix_stack
[submenu_depth
++] = prefix
;
950 else if (EQ (AREF (menu_items
, i
), Qlambda
))
952 prefix
= subprefix_stack
[--submenu_depth
];
955 else if (EQ (AREF (menu_items
, i
), Qt
))
957 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
958 i
+= MENU_ITEMS_PANE_LENGTH
;
960 /* Ignore a nil in the item list.
961 It's meaningful only for dialog boxes. */
962 else if (EQ (AREF (menu_items
, i
), Qquote
))
966 entry
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
967 if (menu_item_selection
== i
)
973 entry
= Fcons (entry
, Qnil
);
975 entry
= Fcons (prefix
, entry
);
976 for (j
= submenu_depth
- 1; j
>= 0; j
--)
977 if (!NILP (subprefix_stack
[j
]))
978 entry
= Fcons (subprefix_stack
[j
], entry
);
982 i
+= MENU_ITEMS_ITEM_LENGTH
;
987 /* Make "Cancel" equivalent to C-g. */
988 Fsignal (Qquit
, Qnil
);
995 /* TODO: On Windows, there are two ways of defining a dialog.
997 1. Create a predefined dialog resource and include it in nt/emacs.rc.
998 Using this method, we could then set the titles and make unneeded
999 buttons invisible before displaying the dialog. Everything would
1000 be a fixed size though, so there is a risk that text does not
1002 2. Create the dialog template in memory on the fly. This allows us
1003 to size the dialog and buttons dynamically, probably giving more
1004 natural looking results for dialogs with few buttons, and eliminating
1005 the problem of text overflowing the buttons. But the API for this is
1006 quite complex - structures have to be allocated in particular ways,
1007 text content is tacked onto the end of structures in variable length
1008 arrays with further structures tacked on after these, there are
1009 certain alignment requirements for all this, and we have to
1010 measure all the text and convert to "dialog coordinates" to figure
1011 out how big to make everything.
1013 For now, we'll just stick with menus for dialogs that are more
1014 complicated than simple yes/no type questions for which we can use
1015 the MessageBox function.
1018 static char * button_names
[] = {
1019 "button1", "button2", "button3", "button4", "button5",
1020 "button6", "button7", "button8", "button9", "button10" };
1023 w32_dialog_show (f
, keymaps
, title
, header
, error
)
1026 Lisp_Object title
, header
;
1029 int i
, nb_buttons
=0;
1030 char dialog_name
[6];
1031 int menu_item_selection
;
1033 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
1035 /* Number of elements seen so far, before boundary. */
1037 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1038 int boundary_seen
= 0;
1042 if (menu_items_n_panes
> 1)
1044 *error
= "Multiple panes in dialog box";
1048 /* Create a tree of widget_value objects
1049 representing the text label and buttons. */
1051 Lisp_Object pane_name
, prefix
;
1053 pane_name
= AREF (menu_items
, MENU_ITEMS_PANE_NAME
);
1054 prefix
= AREF (menu_items
, MENU_ITEMS_PANE_PREFIX
);
1055 pane_string
= (NILP (pane_name
)
1056 ? "" : (char *) SDATA (pane_name
));
1057 prev_wv
= xmalloc_widget_value ();
1058 prev_wv
->value
= pane_string
;
1059 if (keymaps
&& !NILP (prefix
))
1061 prev_wv
->enabled
= 1;
1062 prev_wv
->name
= "message";
1063 prev_wv
->help
= Qnil
;
1066 /* Loop over all panes and items, filling in the tree. */
1067 i
= MENU_ITEMS_PANE_LENGTH
;
1068 while (i
< menu_items_used
)
1071 /* Create a new item within current pane. */
1072 Lisp_Object item_name
, enable
, descrip
, help
;
1074 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1075 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1076 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1077 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1079 if (NILP (item_name
))
1081 free_menubar_widget_value_tree (first_wv
);
1082 *error
= "Submenu in dialog items";
1085 if (EQ (item_name
, Qquote
))
1087 /* This is the boundary between left-side elts
1088 and right-side elts. Stop incrementing right_count. */
1093 if (nb_buttons
>= 9)
1095 free_menubar_widget_value_tree (first_wv
);
1096 *error
= "Too many dialog items";
1100 wv
= xmalloc_widget_value ();
1102 wv
->name
= (char *) button_names
[nb_buttons
];
1103 if (!NILP (descrip
))
1104 wv
->key
= (char *) SDATA (descrip
);
1105 wv
->value
= (char *) SDATA (item_name
);
1106 wv
->call_data
= (void *) &AREF (menu_items
, i
);
1107 wv
->enabled
= !NILP (enable
);
1111 if (! boundary_seen
)
1115 i
+= MENU_ITEMS_ITEM_LENGTH
;
1118 /* If the boundary was not specified,
1119 by default put half on the left and half on the right. */
1120 if (! boundary_seen
)
1121 left_count
= nb_buttons
- nb_buttons
/ 2;
1123 wv
= xmalloc_widget_value ();
1124 wv
->name
= dialog_name
;
1127 /* Frame title: 'Q' = Question, 'I' = Information.
1128 Can also have 'E' = Error if, one day, we want
1129 a popup for errors. */
1131 dialog_name
[0] = 'Q';
1133 dialog_name
[0] = 'I';
1135 /* Dialog boxes use a really stupid name encoding
1136 which specifies how many buttons to use
1137 and how many buttons are on the right. */
1138 dialog_name
[1] = '0' + nb_buttons
;
1139 dialog_name
[2] = 'B';
1140 dialog_name
[3] = 'R';
1141 /* Number of buttons to put on the right. */
1142 dialog_name
[4] = '0' + nb_buttons
- left_count
;
1144 wv
->contents
= first_wv
;
1148 /* Actually create the dialog. */
1149 dialog_id
= widget_id_tick
++;
1150 menu
= lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1151 f
->output_data
.w32
->widget
, 1, 0,
1152 dialog_selection_callback
, 0);
1153 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, TRUE
);
1155 /* Free the widget_value objects we used to specify the contents. */
1156 free_menubar_widget_value_tree (first_wv
);
1158 /* No selection has been chosen yet. */
1159 menu_item_selection
= 0;
1161 /* Display the menu. */
1162 lw_pop_up_all_widgets (dialog_id
);
1164 /* Process events that apply to the menu. */
1165 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), dialog_id
);
1167 lw_destroy_all_widgets (dialog_id
);
1169 /* Find the selected item, and its pane, to return
1170 the proper value. */
1171 if (menu_item_selection
!= 0)
1177 while (i
< menu_items_used
)
1181 if (EQ (AREF (menu_items
, i
), Qt
))
1183 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1184 i
+= MENU_ITEMS_PANE_LENGTH
;
1188 entry
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1189 if (menu_item_selection
== i
)
1193 entry
= Fcons (entry
, Qnil
);
1195 entry
= Fcons (prefix
, entry
);
1199 i
+= MENU_ITEMS_ITEM_LENGTH
;
1204 /* Make "Cancel" equivalent to C-g. */
1205 Fsignal (Qquit
, Qnil
);
1209 #else /* !HAVE_DIALOGS */
1211 /* Currently we only handle Yes No dialogs (y-or-n-p and yes-or-no-p) as
1212 simple dialogs. We could handle a few more, but I'm not aware of
1213 anywhere in Emacs that uses the other specific dialog choices that
1214 MessageBox provides. */
1216 static int is_simple_dialog (contents
)
1217 Lisp_Object contents
;
1219 Lisp_Object options
= XCDR (contents
);
1220 Lisp_Object name
, yes
, no
, other
;
1222 yes
= build_string ("Yes");
1223 no
= build_string ("No");
1225 if (!CONSP (options
))
1228 name
= XCAR (XCAR (options
));
1229 if (!CONSP (options
))
1232 if (!NILP (Fstring_equal (name
, yes
)))
1234 else if (!NILP (Fstring_equal (name
, no
)))
1239 options
= XCDR (options
);
1240 if (!CONSP (options
))
1243 name
= XCAR (XCAR (options
));
1244 if (NILP (Fstring_equal (name
, other
)))
1247 /* Check there are no more options. */
1248 options
= XCDR (options
);
1249 return !(CONSP (options
));
1252 static Lisp_Object
simple_dialog_show (f
, contents
, header
)
1254 Lisp_Object contents
, header
;
1259 Lisp_Object lispy_answer
= Qnil
, temp
= XCAR (contents
);
1262 text
= SDATA (temp
);
1269 type
= MB_ICONQUESTION
;
1273 title
= "Information";
1274 type
= MB_ICONINFORMATION
;
1278 /* Since we only handle Yes/No dialogs, and we already checked
1279 is_simple_dialog, we don't need to worry about checking contents
1280 to see what type of dialog to use. */
1281 answer
= MessageBox (FRAME_W32_WINDOW (f
), text
, title
, type
);
1283 if (answer
== IDYES
)
1284 lispy_answer
= build_string ("Yes");
1285 else if (answer
== IDNO
)
1286 lispy_answer
= build_string ("No");
1288 Fsignal (Qquit
, Qnil
);
1290 for (temp
= XCDR (contents
); CONSP (temp
); temp
= XCDR (temp
))
1292 Lisp_Object item
, name
, value
;
1297 value
= XCDR (item
);
1305 if (!NILP (Fstring_equal (name
, lispy_answer
)))
1310 Fsignal (Qquit
, Qnil
);
1313 #endif /* !HAVE_DIALOGS */
1316 /* Is this item a separator? */
1318 name_is_separator (name
)
1323 /* Check if name string consists of only dashes ('-'). */
1324 while (*name
== '-') name
++;
1325 /* Separators can also be of the form "--:TripleSuperMegaEtched"
1326 or "--deep-shadow". We don't implement them yet, se we just treat
1327 them like normal separators. */
1328 return (*name
== '\0' || start
+ 2 == name
);
1332 /* Indicate boundary between left and right. */
1334 add_left_right_boundary (HMENU menu
)
1336 return AppendMenu (menu
, MF_MENUBARBREAK
, 0, NULL
);
1339 /* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
1341 utf8to16 (unsigned char * src
, int len
, WCHAR
* dest
)
1348 *dest
= (WCHAR
) *src
;
1349 dest
++; src
++; len
--;
1351 /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */
1352 else if (*src
< 0xC0)
1356 /* 2 char UTF-8 sequence. */
1357 else if (*src
< 0xE0)
1359 *dest
= (WCHAR
) (((*src
& 0x1f) << 6)
1360 | (*(src
+ 1) & 0x3f));
1361 src
+= 2; len
-= 2; dest
++;
1363 else if (*src
< 0xF0)
1365 *dest
= (WCHAR
) (((*src
& 0x0f) << 12)
1366 | ((*(src
+ 1) & 0x3f) << 6)
1367 | (*(src
+ 2) & 0x3f));
1368 src
+= 3; len
-= 3; dest
++;
1370 else /* Not encodable. Insert Unicode Substitution char. */
1372 *dest
= (WCHAR
) 0xfffd;
1373 src
++; len
--; dest
++;
1380 add_menu_item (HMENU menu
, widget_value
*wv
, HMENU item
)
1383 char *out_string
, *p
, *q
;
1385 size_t nlen
, orig_len
;
1387 if (name_is_separator (wv
->name
))
1389 fuFlags
= MF_SEPARATOR
;
1395 fuFlags
= MF_STRING
;
1397 fuFlags
= MF_STRING
| MF_GRAYED
;
1399 if (wv
->key
!= NULL
)
1401 out_string
= alloca (strlen (wv
->name
) + strlen (wv
->key
) + 2);
1402 strcpy (out_string
, wv
->name
);
1403 strcat (out_string
, "\t");
1404 strcat (out_string
, wv
->key
);
1407 out_string
= wv
->name
;
1409 /* Quote any special characters within the menu item's text and
1411 nlen
= orig_len
= strlen (out_string
);
1412 if (unicode_append_menu
)
1414 /* With UTF-8, & cannot be part of a multibyte character. */
1415 for (p
= out_string
; *p
; p
++)
1423 /* If encoded with the system codepage, use multibyte string
1424 functions in case of multibyte characters that contain '&'. */
1425 for (p
= out_string
; *p
; p
= _mbsinc (p
))
1427 if (_mbsnextc (p
) == '&')
1432 if (nlen
> orig_len
)
1435 out_string
= alloca (nlen
+ 1);
1439 if (unicode_append_menu
)
1447 if (_mbsnextc (p
) == '&')
1462 else if (wv
->title
|| wv
->call_data
== 0)
1464 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
1465 we can't deallocate the memory otherwise. */
1466 if (get_menu_item_info
)
1468 out_string
= (char *) local_alloc (strlen (wv
->name
) + 1);
1469 strcpy (out_string
, wv
->name
);
1471 DebPrint ("Menu: allocing %ld for owner-draw", out_string
);
1473 fuFlags
= MF_OWNERDRAW
| MF_DISABLED
;
1476 fuFlags
= MF_DISABLED
;
1479 /* Draw radio buttons and tickboxes. */
1480 else if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
||
1481 wv
->button_type
== BUTTON_TYPE_RADIO
))
1482 fuFlags
|= MF_CHECKED
;
1484 fuFlags
|= MF_UNCHECKED
;
1487 if (unicode_append_menu
&& out_string
)
1489 /* Convert out_string from UTF-8 to UTF-16-LE. */
1490 int utf8_len
= strlen (out_string
);
1491 WCHAR
* utf16_string
;
1492 if (fuFlags
& MF_OWNERDRAW
)
1493 utf16_string
= local_alloc ((utf8_len
+ 1) * sizeof (WCHAR
));
1495 utf16_string
= alloca ((utf8_len
+ 1) * sizeof (WCHAR
));
1497 utf8to16 (out_string
, utf8_len
, utf16_string
);
1498 return_value
= unicode_append_menu (menu
, fuFlags
,
1499 item
!= NULL
? (UINT
) item
1500 : (UINT
) wv
->call_data
,
1504 /* On W9x/ME, unicode menus are not supported, though AppendMenuW
1505 apparently does exist at least in some cases and appears to be
1506 stubbed out to do nothing. out_string is UTF-8, but since
1507 our standard menus are in English and this is only going to
1508 happen the first time a menu is used, the encoding is
1509 of minor importance compared with menus not working at all. */
1511 AppendMenu (menu
, fuFlags
,
1512 item
!= NULL
? (UINT
) item
: (UINT
) wv
->call_data
,
1514 /* Don't use unicode menus in future. */
1515 unicode_append_menu
= NULL
;
1518 if (unicode_append_menu
&& (fuFlags
& MF_OWNERDRAW
))
1519 local_free (out_string
);
1526 item
!= NULL
? (UINT
) item
: (UINT
) wv
->call_data
,
1530 /* This must be done after the menu item is created. */
1531 if (!wv
->title
&& wv
->call_data
!= 0)
1533 if (set_menu_item_info
)
1536 bzero (&info
, sizeof (info
));
1537 info
.cbSize
= sizeof (info
);
1538 info
.fMask
= MIIM_DATA
;
1540 /* Set help string for menu item. Leave it as a Lisp_Object
1541 until it is ready to be displayed, since GC can happen while
1542 menus are active. */
1543 if (!NILP (wv
->help
))
1544 #ifdef USE_LISP_UNION_TYPE
1545 info
.dwItemData
= (DWORD
) (wv
->help
).i
;
1547 info
.dwItemData
= (DWORD
) (wv
->help
);
1549 if (wv
->button_type
== BUTTON_TYPE_RADIO
)
1551 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
1552 RADIO items, but is not available on NT 3.51 and earlier. */
1553 info
.fMask
|= MIIM_TYPE
| MIIM_STATE
;
1554 info
.fType
= MFT_RADIOCHECK
| MFT_STRING
;
1555 info
.dwTypeData
= out_string
;
1556 info
.fState
= wv
->selected
? MFS_CHECKED
: MFS_UNCHECKED
;
1559 set_menu_item_info (menu
,
1560 item
!= NULL
? (UINT
) item
: (UINT
) wv
->call_data
,
1564 return return_value
;
1567 /* Construct native Windows menu(bar) based on widget_value tree. */
1569 fill_in_menu (HMENU menu
, widget_value
*wv
)
1571 int items_added
= 0;
1573 for ( ; wv
!= NULL
; wv
= wv
->next
)
1577 HMENU sub_menu
= CreatePopupMenu ();
1579 if (sub_menu
== NULL
)
1582 if (!fill_in_menu (sub_menu
, wv
->contents
) ||
1583 !add_menu_item (menu
, wv
, sub_menu
))
1585 DestroyMenu (sub_menu
);
1591 if (!add_menu_item (menu
, wv
, NULL
))
1598 /* Display help string for currently pointed to menu item. Not
1599 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
1602 w32_menu_display_help (HWND owner
, HMENU menu
, UINT item
, UINT flags
)
1604 if (get_menu_item_info
)
1606 struct frame
*f
= x_window_to_frame (&one_w32_display_info
, owner
);
1607 Lisp_Object frame
, help
;
1609 /* No help echo on owner-draw menu items, or when the keyboard is used
1610 to navigate the menus, since tooltips are distracting if they pop
1612 if (flags
& MF_OWNERDRAW
|| flags
& MF_POPUP
1613 || !(flags
& MF_MOUSESELECT
))
1619 bzero (&info
, sizeof (info
));
1620 info
.cbSize
= sizeof (info
);
1621 info
.fMask
= MIIM_DATA
;
1622 get_menu_item_info (menu
, item
, FALSE
, &info
);
1624 #ifdef USE_LISP_UNION_TYPE
1625 help
= info
.dwItemData
? (Lisp_Object
) ((EMACS_INT
) info
.dwItemData
)
1628 help
= info
.dwItemData
? (Lisp_Object
) info
.dwItemData
: Qnil
;
1632 /* Store the help echo in the keyboard buffer as the X toolkit
1633 version does, rather than directly showing it. This seems to
1634 solve the GC problems that were present when we based the
1635 Windows code on the non-toolkit version. */
1638 XSETFRAME (frame
, f
);
1639 kbd_buffer_store_help_event (frame
, help
);
1642 /* X version has a loop through frames here, which doesn't
1643 appear to do anything, unless it has some side effect. */
1644 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
1648 /* Free memory used by owner-drawn strings. */
1650 w32_free_submenu_strings (menu
)
1653 int i
, num
= GetMenuItemCount (menu
);
1654 for (i
= 0; i
< num
; i
++)
1657 bzero (&info
, sizeof (info
));
1658 info
.cbSize
= sizeof (info
);
1659 info
.fMask
= MIIM_DATA
| MIIM_TYPE
| MIIM_SUBMENU
;
1661 get_menu_item_info (menu
, i
, TRUE
, &info
);
1663 /* Owner-drawn names are held in dwItemData. */
1664 if ((info
.fType
& MF_OWNERDRAW
) && info
.dwItemData
)
1667 DebPrint ("Menu: freeing %ld for owner-draw", info
.dwItemData
);
1669 local_free (info
.dwItemData
);
1672 /* Recurse down submenus. */
1674 w32_free_submenu_strings (info
.hSubMenu
);
1679 w32_free_menu_strings (hwnd
)
1682 HMENU menu
= current_popup_menu
;
1684 if (get_menu_item_info
)
1686 /* If there is no popup menu active, free the strings from the frame's
1689 menu
= GetMenu (hwnd
);
1692 w32_free_submenu_strings (menu
);
1695 current_popup_menu
= NULL
;
1698 #endif /* HAVE_MENUS */
1700 /* The following is used by delayed window autoselection. */
1702 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
1703 doc
: /* Return t if a menu or popup dialog is active on selected frame. */)
1708 f
= SELECTED_FRAME ();
1709 return (f
->output_data
.w32
->menubar_active
> 0) ? Qt
: Qnil
;
1712 #endif /* HAVE_MENUS */
1715 void syms_of_w32menu ()
1717 globals_of_w32menu ();
1719 current_popup_menu
= NULL
;
1721 DEFSYM (Qdebug_on_next_call
, "debug-on-next-call");
1723 defsubr (&Smenu_or_popup_active_p
);
1725 defsubr (&Sx_popup_dialog
);
1730 globals_of_w32menu is used to initialize those global variables that
1731 must always be initialized on startup even when the global variable
1732 initialized is non zero (see the function main in emacs.c).
1733 globals_of_w32menu is called from syms_of_w32menu when the global
1734 variable initialized is 0 and directly from main when initialized
1737 void globals_of_w32menu ()
1739 /* See if Get/SetMenuItemInfo functions are available. */
1740 HMODULE user32
= GetModuleHandle ("user32.dll");
1741 get_menu_item_info
= (GetMenuItemInfoA_Proc
) GetProcAddress (user32
, "GetMenuItemInfoA");
1742 set_menu_item_info
= (SetMenuItemInfoA_Proc
) GetProcAddress (user32
, "SetMenuItemInfoA");
1743 unicode_append_menu
= (AppendMenuW_Proc
) GetProcAddress (user32
, "AppendMenuW");
1746 /* arch-tag: 0eaed431-bb4e-4aac-a527-95a1b4f1fed0
1747 (do not change this comment) */