* org.texi: Fix typo in previous change (2010-07-19T09:47:27Z!carsten.dominik@gmail...
[emacs.git] / src / w32menu.c
blobe96b70b59dc0469005553113028973e3a65e16f5
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/>. */
21 #include <config.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <mbstring.h>
26 #include <setjmp.h>
28 #include "lisp.h"
29 #include "keyboard.h"
30 #include "keymap.h"
31 #include "frame.h"
32 #include "termhooks.h"
33 #include "window.h"
34 #include "blockinput.h"
35 #include "buffer.h"
36 #include "charset.h"
37 #include "character.h"
38 #include "coding.h"
39 #include "menu.h"
41 /* This may include sys/types.h, and that somehow loses
42 if this is not done before the other system files. */
43 #include "w32term.h"
45 /* Load sys/types.h if not already loaded.
46 In some systems loading it twice is suicidal. */
47 #ifndef makedev
48 #include <sys/types.h>
49 #endif
51 #include "dispextern.h"
53 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
55 #ifndef TRUE
56 #define TRUE 1
57 #define FALSE 0
58 #endif /* no TRUE */
60 HMENU current_popup_menu;
62 void syms_of_w32menu (void);
63 void globals_of_w32menu (void);
65 typedef BOOL (WINAPI * GetMenuItemInfoA_Proc) (
66 IN HMENU,
67 IN UINT,
68 IN BOOL,
69 IN OUT LPMENUITEMINFOA);
70 typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) (
71 IN HMENU,
72 IN UINT,
73 IN BOOL,
74 IN LPCMENUITEMINFOA);
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 Voverriding_local_map;
87 extern Lisp_Object 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 (FRAME_PTR, int, int);
95 #ifdef HAVE_DIALOGS
96 static Lisp_Object w32_dialog_show (FRAME_PTR, int, Lisp_Object, char**);
97 #else
98 static int is_simple_dialog (Lisp_Object);
99 static Lisp_Object simple_dialog_show (FRAME_PTR, Lisp_Object, Lisp_Object);
100 #endif
102 void w32_free_menu_strings (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
116 ID, or 0 if none. */
118 static struct frame *
119 menubar_id_to_frame (HMENU id)
121 Lisp_Object tail, frame;
122 FRAME_PTR f;
124 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
126 frame = XCAR (tail);
127 if (!FRAMEP (frame))
128 continue;
129 f = XFRAME (frame);
130 if (!FRAME_WINDOW_P (f))
131 continue;
132 if (f->output_data.w32->menubar_widget == id)
133 return f;
135 return 0;
138 #ifdef HAVE_MENUS
140 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
141 doc: /* Pop up a dialog box and return user's selection.
142 POSITION specifies which frame to use.
143 This is normally a mouse button event or a window or frame.
144 If POSITION is t, it means to use the frame the mouse is on.
145 The dialog box appears in the middle of the specified frame.
147 CONTENTS specifies the alternatives to display in the dialog box.
148 It is a list of the form (TITLE ITEM1 ITEM2...).
149 Each ITEM is a cons cell (STRING . VALUE).
150 The return value is VALUE from the chosen item.
152 An ITEM may also be just a string--that makes a nonselectable item.
153 An ITEM may also be nil--that means to put all preceding items
154 on the left of the dialog box and all following items on the right.
155 \(By default, approximately half appear on each side.)
157 If HEADER is non-nil, the frame title for the box is "Information",
158 otherwise it is "Question". */)
159 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
161 FRAME_PTR f = NULL;
162 Lisp_Object window;
164 check_w32 ();
166 /* Decode the first argument: find the window or frame to use. */
167 if (EQ (position, Qt)
168 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
169 || EQ (XCAR (position), Qtool_bar))))
171 #if 0 /* Using the frame the mouse is on may not be right. */
172 /* Use the mouse's current position. */
173 FRAME_PTR new_f = SELECTED_FRAME ();
174 Lisp_Object bar_window;
175 enum scroll_bar_part part;
176 unsigned long time;
177 Lisp_Object x, y;
179 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
181 if (new_f != 0)
182 XSETFRAME (window, new_f);
183 else
184 window = selected_window;
185 #endif
186 window = selected_window;
188 else if (CONSP (position))
190 Lisp_Object tem;
191 tem = Fcar (position);
192 if (CONSP (tem))
193 window = Fcar (Fcdr (position));
194 else
196 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
197 window = Fcar (tem); /* POSN_WINDOW (tem) */
200 else if (WINDOWP (position) || FRAMEP (position))
201 window = position;
202 else
203 window = Qnil;
205 /* Decode where to put the menu. */
207 if (FRAMEP (window))
208 f = XFRAME (window);
209 else if (WINDOWP (window))
211 CHECK_LIVE_WINDOW (window);
212 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
214 else
215 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
216 but I don't want to make one now. */
217 CHECK_WINDOW (window);
219 #ifndef HAVE_DIALOGS
222 /* Handle simple Yes/No choices as MessageBox popups. */
223 if (is_simple_dialog (contents))
224 return simple_dialog_show (f, contents, header);
225 else
227 /* Display a menu with these alternatives
228 in the middle of frame F. */
229 Lisp_Object x, y, frame, newpos;
230 XSETFRAME (frame, f);
231 XSETINT (x, x_pixel_width (f) / 2);
232 XSETINT (y, x_pixel_height (f) / 2);
233 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
234 return Fx_popup_menu (newpos,
235 Fcons (Fcar (contents), Fcons (contents, Qnil)));
238 #else /* HAVE_DIALOGS */
240 Lisp_Object title;
241 char *error_name;
242 Lisp_Object selection;
244 /* Decode the dialog items from what was specified. */
245 title = Fcar (contents);
246 CHECK_STRING (title);
248 list_of_panes (Fcons (contents, Qnil));
250 /* Display them in a dialog box. */
251 BLOCK_INPUT;
252 selection = w32_dialog_show (f, 0, title, header, &error_name);
253 UNBLOCK_INPUT;
255 discard_menu_items ();
256 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
258 if (error_name) error (error_name);
259 return selection;
261 #endif /* HAVE_DIALOGS */
264 /* Activate the menu bar of frame F.
265 This is called from keyboard.c when it gets the
266 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
268 To activate the menu bar, we signal to the input thread that it can
269 return from the WM_INITMENU message, allowing the normal Windows
270 processing of the menus.
272 But first we recompute the menu bar contents (the whole tree).
274 This way we can safely execute Lisp code. */
276 void
277 x_activate_menubar (FRAME_PTR f)
279 set_frame_menubar (f, 0, 1);
281 /* Lock out further menubar changes while active. */
282 f->output_data.w32->menubar_active = 1;
284 /* Signal input thread to return from WM_INITMENU. */
285 complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
288 /* This callback is called from the menu bar pulldown menu
289 when the user makes a selection.
290 Figure out what the user chose
291 and put the appropriate events into the keyboard buffer. */
293 void
294 menubar_selection_callback (FRAME_PTR f, void * client_data)
296 Lisp_Object prefix, entry;
297 Lisp_Object vector;
298 Lisp_Object *subprefix_stack;
299 int submenu_depth = 0;
300 int i;
302 if (!f)
303 return;
304 entry = Qnil;
305 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
306 vector = f->menu_bar_vector;
307 prefix = Qnil;
308 i = 0;
309 while (i < f->menu_bar_items_used)
311 if (EQ (AREF (vector, i), Qnil))
313 subprefix_stack[submenu_depth++] = prefix;
314 prefix = entry;
315 i++;
317 else if (EQ (AREF (vector, i), Qlambda))
319 prefix = subprefix_stack[--submenu_depth];
320 i++;
322 else if (EQ (AREF (vector, i), Qt))
324 prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
325 i += MENU_ITEMS_PANE_LENGTH;
327 else
329 entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
330 /* The EMACS_INT cast avoids a warning. There's no problem
331 as long as pointers have enough bits to hold small integers. */
332 if ((int) (EMACS_INT) client_data == i)
334 int j;
335 struct input_event buf;
336 Lisp_Object frame;
337 EVENT_INIT (buf);
339 XSETFRAME (frame, f);
340 buf.kind = MENU_BAR_EVENT;
341 buf.frame_or_window = frame;
342 buf.arg = frame;
343 kbd_buffer_store_event (&buf);
345 for (j = 0; j < submenu_depth; j++)
346 if (!NILP (subprefix_stack[j]))
348 buf.kind = MENU_BAR_EVENT;
349 buf.frame_or_window = frame;
350 buf.arg = subprefix_stack[j];
351 kbd_buffer_store_event (&buf);
354 if (!NILP (prefix))
356 buf.kind = MENU_BAR_EVENT;
357 buf.frame_or_window = frame;
358 buf.arg = prefix;
359 kbd_buffer_store_event (&buf);
362 buf.kind = MENU_BAR_EVENT;
363 buf.frame_or_window = frame;
364 buf.arg = entry;
365 /* Free memory used by owner-drawn and help-echo strings. */
366 w32_free_menu_strings (FRAME_W32_WINDOW (f));
367 kbd_buffer_store_event (&buf);
369 f->output_data.w32->menubar_active = 0;
370 return;
372 i += MENU_ITEMS_ITEM_LENGTH;
375 /* Free memory used by owner-drawn and help-echo strings. */
376 w32_free_menu_strings (FRAME_W32_WINDOW (f));
377 f->output_data.w32->menubar_active = 0;
381 /* Set the contents of the menubar widgets of frame F.
382 The argument FIRST_TIME is currently ignored;
383 it is set the first time this is called, from initialize_frame_menubar. */
385 void
386 set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
388 HMENU menubar_widget = f->output_data.w32->menubar_widget;
389 Lisp_Object items;
390 widget_value *wv, *first_wv, *prev_wv = 0;
391 int i, last_i;
392 int *submenu_start, *submenu_end;
393 int *submenu_top_level_items, *submenu_n_panes;
395 /* We must not change the menubar when actually in use. */
396 if (f->output_data.w32->menubar_active)
397 return;
399 XSETFRAME (Vmenu_updating_frame, f);
401 if (! menubar_widget)
402 deep_p = 1;
403 else if (pending_menu_activation && !deep_p)
404 deep_p = 1;
406 if (deep_p)
408 /* Make a widget-value tree representing the entire menu trees. */
410 struct buffer *prev = current_buffer;
411 Lisp_Object buffer;
412 int specpdl_count = SPECPDL_INDEX ();
413 int previous_menu_items_used = f->menu_bar_items_used;
414 Lisp_Object *previous_items
415 = (Lisp_Object *) alloca (previous_menu_items_used
416 * sizeof (Lisp_Object));
418 /* If we are making a new widget, its contents are empty,
419 do always reinitialize them. */
420 if (! menubar_widget)
421 previous_menu_items_used = 0;
423 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
424 specbind (Qinhibit_quit, Qt);
425 /* Don't let the debugger step into this code
426 because it is not reentrant. */
427 specbind (Qdebug_on_next_call, Qnil);
429 record_unwind_save_match_data ();
431 if (NILP (Voverriding_local_map_menu_flag))
433 specbind (Qoverriding_terminal_local_map, Qnil);
434 specbind (Qoverriding_local_map, Qnil);
437 set_buffer_internal_1 (XBUFFER (buffer));
439 /* Run the Lucid hook. */
440 safe_run_hooks (Qactivate_menubar_hook);
441 /* If it has changed current-menubar from previous value,
442 really recompute the menubar from the value. */
443 if (! NILP (Vlucid_menu_bar_dirty_flag))
444 call0 (Qrecompute_lucid_menubar);
445 safe_run_hooks (Qmenu_bar_update_hook);
446 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
448 items = FRAME_MENU_BAR_ITEMS (f);
450 /* Save the frame's previous menu bar contents data. */
451 if (previous_menu_items_used)
452 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
453 previous_menu_items_used * sizeof (Lisp_Object));
455 /* Fill in menu_items with the current menu bar contents.
456 This can evaluate Lisp code. */
457 save_menu_items ();
459 menu_items = f->menu_bar_vector;
460 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
461 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
462 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
463 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
464 submenu_top_level_items
465 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
466 init_menu_items ();
467 for (i = 0; i < ASIZE (items); i += 4)
469 Lisp_Object key, string, maps;
471 last_i = i;
473 key = AREF (items, i);
474 string = AREF (items, i + 1);
475 maps = AREF (items, i + 2);
476 if (NILP (string))
477 break;
479 submenu_start[i] = menu_items_used;
481 menu_items_n_panes = 0;
482 submenu_top_level_items[i]
483 = parse_single_submenu (key, string, maps);
484 submenu_n_panes[i] = menu_items_n_panes;
486 submenu_end[i] = menu_items_used;
489 finish_menu_items ();
491 /* Convert menu_items into widget_value trees
492 to display the menu. This cannot evaluate Lisp code. */
494 wv = xmalloc_widget_value ();
495 wv->name = "menubar";
496 wv->value = 0;
497 wv->enabled = 1;
498 wv->button_type = BUTTON_TYPE_NONE;
499 wv->help = Qnil;
500 first_wv = wv;
502 for (i = 0; i < last_i; i += 4)
504 menu_items_n_panes = submenu_n_panes[i];
505 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
506 submenu_top_level_items[i]);
507 if (prev_wv)
508 prev_wv->next = wv;
509 else
510 first_wv->contents = wv;
511 /* Don't set wv->name here; GC during the loop might relocate it. */
512 wv->enabled = 1;
513 wv->button_type = BUTTON_TYPE_NONE;
514 prev_wv = wv;
517 set_buffer_internal_1 (prev);
519 /* If there has been no change in the Lisp-level contents
520 of the menu bar, skip redisplaying it. Just exit. */
522 for (i = 0; i < previous_menu_items_used; i++)
523 if (menu_items_used == i
524 || (!EQ (previous_items[i], AREF (menu_items, i))))
525 break;
526 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
528 free_menubar_widget_value_tree (first_wv);
529 discard_menu_items ();
530 unbind_to (specpdl_count, Qnil);
531 return;
534 f->menu_bar_vector = menu_items;
535 f->menu_bar_items_used = menu_items_used;
537 /* This undoes save_menu_items. */
538 unbind_to (specpdl_count, Qnil);
540 /* Now GC cannot happen during the lifetime of the widget_value,
541 so it's safe to store data from a Lisp_String, as long as
542 local copies are made when the actual menu is created.
543 Windows takes care of this for normal string items, but
544 not for owner-drawn items or additional item-info. */
545 wv = first_wv->contents;
546 for (i = 0; i < ASIZE (items); i += 4)
548 Lisp_Object string;
549 string = AREF (items, i + 1);
550 if (NILP (string))
551 break;
552 wv->name = (char *) SDATA (string);
553 update_submenu_strings (wv->contents);
554 wv = wv->next;
557 else
559 /* Make a widget-value tree containing
560 just the top level menu bar strings. */
562 wv = xmalloc_widget_value ();
563 wv->name = "menubar";
564 wv->value = 0;
565 wv->enabled = 1;
566 wv->button_type = BUTTON_TYPE_NONE;
567 wv->help = Qnil;
568 first_wv = wv;
570 items = FRAME_MENU_BAR_ITEMS (f);
571 for (i = 0; i < ASIZE (items); i += 4)
573 Lisp_Object string;
575 string = AREF (items, i + 1);
576 if (NILP (string))
577 break;
579 wv = xmalloc_widget_value ();
580 wv->name = (char *) SDATA (string);
581 wv->value = 0;
582 wv->enabled = 1;
583 wv->button_type = BUTTON_TYPE_NONE;
584 wv->help = Qnil;
585 /* This prevents lwlib from assuming this
586 menu item is really supposed to be empty. */
587 /* The EMACS_INT cast avoids a warning.
588 This value just has to be different from small integers. */
589 wv->call_data = (void *) (EMACS_INT) (-1);
591 if (prev_wv)
592 prev_wv->next = wv;
593 else
594 first_wv->contents = wv;
595 prev_wv = wv;
598 /* Forget what we thought we knew about what is in the
599 detailed contents of the menu bar menus.
600 Changing the top level always destroys the contents. */
601 f->menu_bar_items_used = 0;
604 /* Create or update the menu bar widget. */
606 BLOCK_INPUT;
608 if (menubar_widget)
610 /* Empty current menubar, rather than creating a fresh one. */
611 while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
614 else
616 menubar_widget = CreateMenu ();
618 fill_in_menu (menubar_widget, first_wv->contents);
620 free_menubar_widget_value_tree (first_wv);
623 HMENU old_widget = f->output_data.w32->menubar_widget;
625 f->output_data.w32->menubar_widget = menubar_widget;
626 SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
627 /* Causes flicker when menu bar is updated
628 DrawMenuBar (FRAME_W32_WINDOW (f)); */
630 /* Force the window size to be recomputed so that the frame's text
631 area remains the same, if menubar has just been created. */
632 if (old_widget == NULL)
633 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
636 UNBLOCK_INPUT;
639 /* Called from Fx_create_frame to create the initial menubar of a frame
640 before it is mapped, so that the window is mapped with the menubar already
641 there instead of us tacking it on later and thrashing the window after it
642 is visible. */
644 void
645 initialize_frame_menubar (FRAME_PTR f)
647 /* This function is called before the first chance to redisplay
648 the frame. It has to be, so the frame will have the right size. */
649 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
650 set_frame_menubar (f, 1, 1);
653 /* Get rid of the menu bar of frame F, and free its storage.
654 This is used when deleting a frame, and when turning off the menu bar. */
656 void
657 free_frame_menubar (FRAME_PTR f)
659 BLOCK_INPUT;
662 HMENU old = GetMenu (FRAME_W32_WINDOW (f));
663 SetMenu (FRAME_W32_WINDOW (f), NULL);
664 f->output_data.w32->menubar_widget = NULL;
665 DestroyMenu (old);
668 UNBLOCK_INPUT;
672 /* w32_menu_show actually displays a menu using the panes and items in
673 menu_items and returns the value selected from it; we assume input
674 is blocked by the caller. */
676 /* F is the frame the menu is for.
677 X and Y are the frame-relative specified position,
678 relative to the inside upper left corner of the frame F.
679 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
680 KEYMAPS is 1 if this menu was specified with keymaps;
681 in that case, we return a list containing the chosen item's value
682 and perhaps also the pane's prefix.
683 TITLE is the specified menu title.
684 ERROR is a place to store an error message string in case of failure.
685 (We return nil on failure, but the value doesn't actually matter.) */
687 Lisp_Object
688 w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
689 Lisp_Object title, char **error)
691 int i;
692 int menu_item_selection;
693 HMENU menu;
694 POINT pos;
695 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
696 widget_value **submenu_stack
697 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
698 Lisp_Object *subprefix_stack
699 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
700 int submenu_depth = 0;
701 int first_pane;
703 *error = NULL;
705 if (menu_items_n_panes == 0)
706 return Qnil;
708 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
710 *error = "Empty menu";
711 return Qnil;
714 /* Create a tree of widget_value objects
715 representing the panes and their items. */
716 wv = xmalloc_widget_value ();
717 wv->name = "menu";
718 wv->value = 0;
719 wv->enabled = 1;
720 wv->button_type = BUTTON_TYPE_NONE;
721 wv->help = Qnil;
722 first_wv = wv;
723 first_pane = 1;
725 /* Loop over all panes and items, filling in the tree. */
726 i = 0;
727 while (i < menu_items_used)
729 if (EQ (AREF (menu_items, i), Qnil))
731 submenu_stack[submenu_depth++] = save_wv;
732 save_wv = prev_wv;
733 prev_wv = 0;
734 first_pane = 1;
735 i++;
737 else if (EQ (AREF (menu_items, i), Qlambda))
739 prev_wv = save_wv;
740 save_wv = submenu_stack[--submenu_depth];
741 first_pane = 0;
742 i++;
744 else if (EQ (AREF (menu_items, i), Qt)
745 && submenu_depth != 0)
746 i += MENU_ITEMS_PANE_LENGTH;
747 /* Ignore a nil in the item list.
748 It's meaningful only for dialog boxes. */
749 else if (EQ (AREF (menu_items, i), Qquote))
750 i += 1;
751 else if (EQ (AREF (menu_items, i), Qt))
753 /* Create a new pane. */
754 Lisp_Object pane_name, prefix;
755 char *pane_string;
756 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
757 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
759 if (STRINGP (pane_name))
761 if (unicode_append_menu)
762 pane_name = ENCODE_UTF_8 (pane_name);
763 else if (STRING_MULTIBYTE (pane_name))
764 pane_name = ENCODE_SYSTEM (pane_name);
766 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
769 pane_string = (NILP (pane_name)
770 ? "" : (char *) SDATA (pane_name));
771 /* If there is just one top-level pane, put all its items directly
772 under the top-level menu. */
773 if (menu_items_n_panes == 1)
774 pane_string = "";
776 /* If the pane has a meaningful name,
777 make the pane a top-level menu item
778 with its items as a submenu beneath it. */
779 if (!keymaps && strcmp (pane_string, ""))
781 wv = xmalloc_widget_value ();
782 if (save_wv)
783 save_wv->next = wv;
784 else
785 first_wv->contents = wv;
786 wv->name = pane_string;
787 if (keymaps && !NILP (prefix))
788 wv->name++;
789 wv->value = 0;
790 wv->enabled = 1;
791 wv->button_type = BUTTON_TYPE_NONE;
792 wv->help = Qnil;
793 save_wv = wv;
794 prev_wv = 0;
796 else if (first_pane)
798 save_wv = wv;
799 prev_wv = 0;
801 first_pane = 0;
802 i += MENU_ITEMS_PANE_LENGTH;
804 else
806 /* Create a new item within current pane. */
807 Lisp_Object item_name, enable, descrip, def, type, selected, help;
809 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
810 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
811 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
812 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
813 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
814 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
815 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
817 if (STRINGP (item_name))
819 if (unicode_append_menu)
820 item_name = ENCODE_UTF_8 (item_name);
821 else if (STRING_MULTIBYTE (item_name))
822 item_name = ENCODE_SYSTEM (item_name);
824 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
827 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
829 descrip = ENCODE_SYSTEM (descrip);
830 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
833 wv = xmalloc_widget_value ();
834 if (prev_wv)
835 prev_wv->next = wv;
836 else
837 save_wv->contents = wv;
838 wv->name = (char *) SDATA (item_name);
839 if (!NILP (descrip))
840 wv->key = (char *) SDATA (descrip);
841 wv->value = 0;
842 /* Use the contents index as call_data, since we are
843 restricted to 16-bits. */
844 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
845 wv->enabled = !NILP (enable);
847 if (NILP (type))
848 wv->button_type = BUTTON_TYPE_NONE;
849 else if (EQ (type, QCtoggle))
850 wv->button_type = BUTTON_TYPE_TOGGLE;
851 else if (EQ (type, QCradio))
852 wv->button_type = BUTTON_TYPE_RADIO;
853 else
854 abort ();
856 wv->selected = !NILP (selected);
858 if (!STRINGP (help))
859 help = Qnil;
861 wv->help = help;
863 prev_wv = wv;
865 i += MENU_ITEMS_ITEM_LENGTH;
869 /* Deal with the title, if it is non-nil. */
870 if (!NILP (title))
872 widget_value *wv_title = xmalloc_widget_value ();
873 widget_value *wv_sep = xmalloc_widget_value ();
875 /* Maybe replace this separator with a bitmap or owner-draw item
876 so that it looks better. Having two separators looks odd. */
877 wv_sep->name = "--";
878 wv_sep->next = first_wv->contents;
879 wv_sep->help = Qnil;
881 if (unicode_append_menu)
882 title = ENCODE_UTF_8 (title);
883 else if (STRING_MULTIBYTE (title))
884 title = ENCODE_SYSTEM (title);
886 wv_title->name = (char *) SDATA (title);
887 wv_title->enabled = TRUE;
888 wv_title->title = TRUE;
889 wv_title->button_type = BUTTON_TYPE_NONE;
890 wv_title->help = Qnil;
891 wv_title->next = wv_sep;
892 first_wv->contents = wv_title;
895 /* No selection has been chosen yet. */
896 menu_item_selection = 0;
898 /* Actually create the menu. */
899 current_popup_menu = menu = CreatePopupMenu ();
900 fill_in_menu (menu, first_wv->contents);
902 /* Adjust coordinates to be root-window-relative. */
903 pos.x = x;
904 pos.y = y;
905 ClientToScreen (FRAME_W32_WINDOW (f), &pos);
907 /* Display the menu. */
908 menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
909 WM_EMACS_TRACKPOPUPMENU,
910 (WPARAM)menu, (LPARAM)&pos);
912 /* Clean up extraneous mouse events which might have been generated
913 during the call. */
914 discard_mouse_events ();
915 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
917 /* Free the widget_value objects we used to specify the contents. */
918 free_menubar_widget_value_tree (first_wv);
920 DestroyMenu (menu);
922 /* Free the owner-drawn and help-echo menu strings. */
923 w32_free_menu_strings (FRAME_W32_WINDOW (f));
924 f->output_data.w32->menubar_active = 0;
926 /* Find the selected item, and its pane, to return
927 the proper value. */
928 if (menu_item_selection != 0)
930 Lisp_Object prefix, entry;
932 prefix = entry = Qnil;
933 i = 0;
934 while (i < menu_items_used)
936 if (EQ (AREF (menu_items, i), Qnil))
938 subprefix_stack[submenu_depth++] = prefix;
939 prefix = entry;
940 i++;
942 else if (EQ (AREF (menu_items, i), Qlambda))
944 prefix = subprefix_stack[--submenu_depth];
945 i++;
947 else if (EQ (AREF (menu_items, i), Qt))
949 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
950 i += MENU_ITEMS_PANE_LENGTH;
952 /* Ignore a nil in the item list.
953 It's meaningful only for dialog boxes. */
954 else if (EQ (AREF (menu_items, i), Qquote))
955 i += 1;
956 else
958 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
959 if (menu_item_selection == i)
961 if (keymaps != 0)
963 int j;
965 entry = Fcons (entry, Qnil);
966 if (!NILP (prefix))
967 entry = Fcons (prefix, entry);
968 for (j = submenu_depth - 1; j >= 0; j--)
969 if (!NILP (subprefix_stack[j]))
970 entry = Fcons (subprefix_stack[j], entry);
972 return entry;
974 i += MENU_ITEMS_ITEM_LENGTH;
978 else if (!for_click)
979 /* Make "Cancel" equivalent to C-g. */
980 Fsignal (Qquit, Qnil);
982 return Qnil;
986 #ifdef HAVE_DIALOGS
987 /* TODO: On Windows, there are two ways of defining a dialog.
989 1. Create a predefined dialog resource and include it in nt/emacs.rc.
990 Using this method, we could then set the titles and make unneeded
991 buttons invisible before displaying the dialog. Everything would
992 be a fixed size though, so there is a risk that text does not
993 fit on a button.
994 2. Create the dialog template in memory on the fly. This allows us
995 to size the dialog and buttons dynamically, probably giving more
996 natural looking results for dialogs with few buttons, and eliminating
997 the problem of text overflowing the buttons. But the API for this is
998 quite complex - structures have to be allocated in particular ways,
999 text content is tacked onto the end of structures in variable length
1000 arrays with further structures tacked on after these, there are
1001 certain alignment requirements for all this, and we have to
1002 measure all the text and convert to "dialog coordinates" to figure
1003 out how big to make everything.
1005 For now, we'll just stick with menus for dialogs that are more
1006 complicated than simple yes/no type questions for which we can use
1007 the MessageBox function.
1010 static char * button_names [] = {
1011 "button1", "button2", "button3", "button4", "button5",
1012 "button6", "button7", "button8", "button9", "button10" };
1014 static Lisp_Object
1015 w32_dialog_show (FRAME_PTR f, int keymaps,
1016 Lisp_Object title, Lisp_Object header,
1017 char **error)
1019 int i, nb_buttons=0;
1020 char dialog_name[6];
1021 int menu_item_selection;
1023 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1025 /* Number of elements seen so far, before boundary. */
1026 int left_count = 0;
1027 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1028 int boundary_seen = 0;
1030 *error = NULL;
1032 if (menu_items_n_panes > 1)
1034 *error = "Multiple panes in dialog box";
1035 return Qnil;
1038 /* Create a tree of widget_value objects
1039 representing the text label and buttons. */
1041 Lisp_Object pane_name, prefix;
1042 char *pane_string;
1043 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1044 prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX);
1045 pane_string = (NILP (pane_name)
1046 ? "" : (char *) SDATA (pane_name));
1047 prev_wv = xmalloc_widget_value ();
1048 prev_wv->value = pane_string;
1049 if (keymaps && !NILP (prefix))
1050 prev_wv->name++;
1051 prev_wv->enabled = 1;
1052 prev_wv->name = "message";
1053 prev_wv->help = Qnil;
1054 first_wv = prev_wv;
1056 /* Loop over all panes and items, filling in the tree. */
1057 i = MENU_ITEMS_PANE_LENGTH;
1058 while (i < menu_items_used)
1061 /* Create a new item within current pane. */
1062 Lisp_Object item_name, enable, descrip, help;
1064 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1065 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1066 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1067 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1069 if (NILP (item_name))
1071 free_menubar_widget_value_tree (first_wv);
1072 *error = "Submenu in dialog items";
1073 return Qnil;
1075 if (EQ (item_name, Qquote))
1077 /* This is the boundary between left-side elts
1078 and right-side elts. Stop incrementing right_count. */
1079 boundary_seen = 1;
1080 i++;
1081 continue;
1083 if (nb_buttons >= 9)
1085 free_menubar_widget_value_tree (first_wv);
1086 *error = "Too many dialog items";
1087 return Qnil;
1090 wv = xmalloc_widget_value ();
1091 prev_wv->next = wv;
1092 wv->name = (char *) button_names[nb_buttons];
1093 if (!NILP (descrip))
1094 wv->key = (char *) SDATA (descrip);
1095 wv->value = (char *) SDATA (item_name);
1096 wv->call_data = (void *) &AREF (menu_items, i);
1097 wv->enabled = !NILP (enable);
1098 wv->help = Qnil;
1099 prev_wv = wv;
1101 if (! boundary_seen)
1102 left_count++;
1104 nb_buttons++;
1105 i += MENU_ITEMS_ITEM_LENGTH;
1108 /* If the boundary was not specified,
1109 by default put half on the left and half on the right. */
1110 if (! boundary_seen)
1111 left_count = nb_buttons - nb_buttons / 2;
1113 wv = xmalloc_widget_value ();
1114 wv->name = dialog_name;
1115 wv->help = Qnil;
1117 /* Frame title: 'Q' = Question, 'I' = Information.
1118 Can also have 'E' = Error if, one day, we want
1119 a popup for errors. */
1120 if (NILP (header))
1121 dialog_name[0] = 'Q';
1122 else
1123 dialog_name[0] = 'I';
1125 /* Dialog boxes use a really stupid name encoding
1126 which specifies how many buttons to use
1127 and how many buttons are on the right. */
1128 dialog_name[1] = '0' + nb_buttons;
1129 dialog_name[2] = 'B';
1130 dialog_name[3] = 'R';
1131 /* Number of buttons to put on the right. */
1132 dialog_name[4] = '0' + nb_buttons - left_count;
1133 dialog_name[5] = 0;
1134 wv->contents = first_wv;
1135 first_wv = wv;
1138 /* Actually create the dialog. */
1139 dialog_id = widget_id_tick++;
1140 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1141 f->output_data.w32->widget, 1, 0,
1142 dialog_selection_callback, 0);
1143 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
1145 /* Free the widget_value objects we used to specify the contents. */
1146 free_menubar_widget_value_tree (first_wv);
1148 /* No selection has been chosen yet. */
1149 menu_item_selection = 0;
1151 /* Display the menu. */
1152 lw_pop_up_all_widgets (dialog_id);
1154 /* Process events that apply to the menu. */
1155 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
1157 lw_destroy_all_widgets (dialog_id);
1159 /* Find the selected item, and its pane, to return
1160 the proper value. */
1161 if (menu_item_selection != 0)
1163 Lisp_Object prefix;
1165 prefix = Qnil;
1166 i = 0;
1167 while (i < menu_items_used)
1169 Lisp_Object entry;
1171 if (EQ (AREF (menu_items, i), Qt))
1173 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1174 i += MENU_ITEMS_PANE_LENGTH;
1176 else
1178 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1179 if (menu_item_selection == i)
1181 if (keymaps != 0)
1183 entry = Fcons (entry, Qnil);
1184 if (!NILP (prefix))
1185 entry = Fcons (prefix, entry);
1187 return entry;
1189 i += MENU_ITEMS_ITEM_LENGTH;
1193 else
1194 /* Make "Cancel" equivalent to C-g. */
1195 Fsignal (Qquit, Qnil);
1197 return Qnil;
1199 #else /* !HAVE_DIALOGS */
1201 /* Currently we only handle Yes No dialogs (y-or-n-p and yes-or-no-p) as
1202 simple dialogs. We could handle a few more, but I'm not aware of
1203 anywhere in Emacs that uses the other specific dialog choices that
1204 MessageBox provides. */
1206 static int
1207 is_simple_dialog (Lisp_Object contents)
1209 Lisp_Object options = XCDR (contents);
1210 Lisp_Object name, yes, no, other;
1212 yes = build_string ("Yes");
1213 no = build_string ("No");
1215 if (!CONSP (options))
1216 return 0;
1218 name = XCAR (XCAR (options));
1219 if (!CONSP (options))
1220 return 0;
1222 if (!NILP (Fstring_equal (name, yes)))
1223 other = no;
1224 else if (!NILP (Fstring_equal (name, no)))
1225 other = yes;
1226 else
1227 return 0;
1229 options = XCDR (options);
1230 if (!CONSP (options))
1231 return 0;
1233 name = XCAR (XCAR (options));
1234 if (NILP (Fstring_equal (name, other)))
1235 return 0;
1237 /* Check there are no more options. */
1238 options = XCDR (options);
1239 return !(CONSP (options));
1242 static Lisp_Object
1243 simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header)
1245 int answer;
1246 UINT type;
1247 char *text, *title;
1248 Lisp_Object lispy_answer = Qnil, temp = XCAR (contents);
1250 if (STRINGP (temp))
1251 text = SDATA (temp);
1252 else
1253 text = "";
1255 if (NILP (header))
1257 title = "Question";
1258 type = MB_ICONQUESTION;
1260 else
1262 title = "Information";
1263 type = MB_ICONINFORMATION;
1265 type |= MB_YESNO;
1267 /* Since we only handle Yes/No dialogs, and we already checked
1268 is_simple_dialog, we don't need to worry about checking contents
1269 to see what type of dialog to use. */
1270 answer = MessageBox (FRAME_W32_WINDOW (f), text, title, type);
1272 if (answer == IDYES)
1273 lispy_answer = build_string ("Yes");
1274 else if (answer == IDNO)
1275 lispy_answer = build_string ("No");
1276 else
1277 Fsignal (Qquit, Qnil);
1279 for (temp = XCDR (contents); CONSP (temp); temp = XCDR (temp))
1281 Lisp_Object item, name, value;
1282 item = XCAR (temp);
1283 if (CONSP (item))
1285 name = XCAR (item);
1286 value = XCDR (item);
1288 else
1290 name = item;
1291 value = Qnil;
1294 if (!NILP (Fstring_equal (name, lispy_answer)))
1296 return value;
1299 Fsignal (Qquit, Qnil);
1300 return Qnil;
1302 #endif /* !HAVE_DIALOGS */
1305 /* Is this item a separator? */
1306 static int
1307 name_is_separator (char *name)
1309 char *start = name;
1311 /* Check if name string consists of only dashes ('-'). */
1312 while (*name == '-') name++;
1313 /* Separators can also be of the form "--:TripleSuperMegaEtched"
1314 or "--deep-shadow". We don't implement them yet, se we just treat
1315 them like normal separators. */
1316 return (*name == '\0' || start + 2 == name);
1320 /* Indicate boundary between left and right. */
1321 static int
1322 add_left_right_boundary (HMENU menu)
1324 return AppendMenu (menu, MF_MENUBARBREAK, 0, NULL);
1327 /* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
1328 static void
1329 utf8to16 (unsigned char * src, int len, WCHAR * dest)
1331 while (len > 0)
1333 int utf16;
1334 if (*src < 0x80)
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)
1342 src++; len--;
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++;
1364 *dest = 0;
1367 static int
1368 add_menu_item (HMENU menu, widget_value *wv, HMENU item)
1370 UINT fuFlags;
1371 char *out_string, *p, *q;
1372 int return_value;
1373 size_t nlen, orig_len;
1375 if (name_is_separator (wv->name))
1377 fuFlags = MF_SEPARATOR;
1378 out_string = NULL;
1380 else
1382 if (wv->enabled)
1383 fuFlags = MF_STRING;
1384 else
1385 fuFlags = MF_STRING | MF_GRAYED;
1387 if (wv->key != NULL)
1389 out_string = alloca (strlen (wv->name) + strlen (wv->key) + 2);
1390 strcpy (out_string, wv->name);
1391 strcat (out_string, "\t");
1392 strcat (out_string, wv->key);
1394 else
1395 out_string = wv->name;
1397 /* Quote any special characters within the menu item's text and
1398 key binding. */
1399 nlen = orig_len = strlen (out_string);
1400 if (unicode_append_menu)
1402 /* With UTF-8, & cannot be part of a multibyte character. */
1403 for (p = out_string; *p; p++)
1405 if (*p == '&')
1406 nlen++;
1409 else
1411 /* If encoded with the system codepage, use multibyte string
1412 functions in case of multibyte characters that contain '&'. */
1413 for (p = out_string; *p; p = _mbsinc (p))
1415 if (_mbsnextc (p) == '&')
1416 nlen++;
1420 if (nlen > orig_len)
1422 p = out_string;
1423 out_string = alloca (nlen + 1);
1424 q = out_string;
1425 while (*p)
1427 if (unicode_append_menu)
1429 if (*p == '&')
1430 *q++ = *p;
1431 *q++ = *p++;
1433 else
1435 if (_mbsnextc (p) == '&')
1437 _mbsncpy (q, p, 1);
1438 q = _mbsinc (q);
1440 _mbsncpy (q, p, 1);
1441 p = _mbsinc (p);
1442 q = _mbsinc (q);
1445 *q = '\0';
1448 if (item != NULL)
1449 fuFlags = MF_POPUP;
1450 else if (wv->title || wv->call_data == 0)
1452 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
1453 we can't deallocate the memory otherwise. */
1454 if (get_menu_item_info)
1456 out_string = (char *) local_alloc (strlen (wv->name) + 1);
1457 strcpy (out_string, wv->name);
1458 #ifdef MENU_DEBUG
1459 DebPrint ("Menu: allocing %ld for owner-draw", out_string);
1460 #endif
1461 fuFlags = MF_OWNERDRAW | MF_DISABLED;
1463 else
1464 fuFlags = MF_DISABLED;
1467 /* Draw radio buttons and tickboxes. */
1468 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
1469 wv->button_type == BUTTON_TYPE_RADIO))
1470 fuFlags |= MF_CHECKED;
1471 else
1472 fuFlags |= MF_UNCHECKED;
1475 if (unicode_append_menu && out_string)
1477 /* Convert out_string from UTF-8 to UTF-16-LE. */
1478 int utf8_len = strlen (out_string);
1479 WCHAR * utf16_string;
1480 if (fuFlags & MF_OWNERDRAW)
1481 utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
1482 else
1483 utf16_string = alloca ((utf8_len + 1) * sizeof (WCHAR));
1485 utf8to16 (out_string, utf8_len, utf16_string);
1486 return_value = unicode_append_menu (menu, fuFlags,
1487 item != NULL ? (UINT) item
1488 : (UINT) wv->call_data,
1489 utf16_string);
1490 if (!return_value)
1492 /* On W9x/ME, unicode menus are not supported, though AppendMenuW
1493 apparently does exist at least in some cases and appears to be
1494 stubbed out to do nothing. out_string is UTF-8, but since
1495 our standard menus are in English and this is only going to
1496 happen the first time a menu is used, the encoding is
1497 of minor importance compared with menus not working at all. */
1498 return_value =
1499 AppendMenu (menu, fuFlags,
1500 item != NULL ? (UINT) item: (UINT) wv->call_data,
1501 out_string);
1502 /* Don't use unicode menus in future. */
1503 unicode_append_menu = NULL;
1506 if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
1507 local_free (out_string);
1509 else
1511 return_value =
1512 AppendMenu (menu,
1513 fuFlags,
1514 item != NULL ? (UINT) item : (UINT) wv->call_data,
1515 out_string );
1518 /* This must be done after the menu item is created. */
1519 if (!wv->title && wv->call_data != 0)
1521 if (set_menu_item_info)
1523 MENUITEMINFO info;
1524 memset (&info, 0, sizeof (info));
1525 info.cbSize = sizeof (info);
1526 info.fMask = MIIM_DATA;
1528 /* Set help string for menu item. Leave it as a Lisp_Object
1529 until it is ready to be displayed, since GC can happen while
1530 menus are active. */
1531 if (!NILP (wv->help))
1532 #ifdef USE_LISP_UNION_TYPE
1533 info.dwItemData = (DWORD) (wv->help).i;
1534 #else
1535 info.dwItemData = (DWORD) (wv->help);
1536 #endif
1537 if (wv->button_type == BUTTON_TYPE_RADIO)
1539 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
1540 RADIO items, but is not available on NT 3.51 and earlier. */
1541 info.fMask |= MIIM_TYPE | MIIM_STATE;
1542 info.fType = MFT_RADIOCHECK | MFT_STRING;
1543 info.dwTypeData = out_string;
1544 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
1547 set_menu_item_info (menu,
1548 item != NULL ? (UINT) item : (UINT) wv->call_data,
1549 FALSE, &info);
1552 return return_value;
1555 /* Construct native Windows menu(bar) based on widget_value tree. */
1557 fill_in_menu (HMENU menu, widget_value *wv)
1559 int items_added = 0;
1561 for ( ; wv != NULL; wv = wv->next)
1563 if (wv->contents)
1565 HMENU sub_menu = CreatePopupMenu ();
1567 if (sub_menu == NULL)
1568 return 0;
1570 if (!fill_in_menu (sub_menu, wv->contents) ||
1571 !add_menu_item (menu, wv, sub_menu))
1573 DestroyMenu (sub_menu);
1574 return 0;
1577 else
1579 if (!add_menu_item (menu, wv, NULL))
1580 return 0;
1583 return 1;
1586 /* Display help string for currently pointed to menu item. Not
1587 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
1588 available. */
1589 void
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
1599 up elsewhere. */
1600 if (flags & MF_OWNERDRAW || flags & MF_POPUP
1601 || !(flags & MF_MOUSESELECT))
1602 help = Qnil;
1603 else
1605 MENUITEMINFO info;
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 #ifdef USE_LISP_UNION_TYPE
1613 help = info.dwItemData ? (Lisp_Object) ((EMACS_INT) info.dwItemData)
1614 : Qnil;
1615 #else
1616 help = info.dwItemData ? (Lisp_Object) info.dwItemData : Qnil;
1617 #endif
1620 /* Store the help echo in the keyboard buffer as the X toolkit
1621 version does, rather than directly showing it. This seems to
1622 solve the GC problems that were present when we based the
1623 Windows code on the non-toolkit version. */
1624 if (f)
1626 XSETFRAME (frame, f);
1627 kbd_buffer_store_help_event (frame, help);
1629 else
1630 /* X version has a loop through frames here, which doesn't
1631 appear to do anything, unless it has some side effect. */
1632 show_help_echo (help, Qnil, Qnil, Qnil, 1);
1636 /* Free memory used by owner-drawn strings. */
1637 static void
1638 w32_free_submenu_strings (HMENU menu)
1640 int i, num = GetMenuItemCount (menu);
1641 for (i = 0; i < num; i++)
1643 MENUITEMINFO info;
1644 memset (&info, 0, sizeof (info));
1645 info.cbSize = sizeof (info);
1646 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
1648 get_menu_item_info (menu, i, TRUE, &info);
1650 /* Owner-drawn names are held in dwItemData. */
1651 if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
1653 #ifdef MENU_DEBUG
1654 DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
1655 #endif
1656 local_free (info.dwItemData);
1659 /* Recurse down submenus. */
1660 if (info.hSubMenu)
1661 w32_free_submenu_strings (info.hSubMenu);
1665 void
1666 w32_free_menu_strings (HWND hwnd)
1668 HMENU menu = current_popup_menu;
1670 if (get_menu_item_info)
1672 /* If there is no popup menu active, free the strings from the frame's
1673 menubar. */
1674 if (!menu)
1675 menu = GetMenu (hwnd);
1677 if (menu)
1678 w32_free_submenu_strings (menu);
1681 current_popup_menu = NULL;
1684 #endif /* HAVE_MENUS */
1686 /* The following is used by delayed window autoselection. */
1688 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1689 doc: /* Return t if a menu or popup dialog is active on selected frame. */)
1690 (void)
1692 #ifdef HAVE_MENUS
1693 FRAME_PTR f;
1694 f = SELECTED_FRAME ();
1695 return (f->output_data.w32->menubar_active > 0) ? Qt : Qnil;
1696 #else
1697 return Qnil;
1698 #endif /* HAVE_MENUS */
1701 void
1702 syms_of_w32menu (void)
1704 globals_of_w32menu ();
1706 current_popup_menu = NULL;
1708 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
1710 defsubr (&Smenu_or_popup_active_p);
1711 #ifdef HAVE_MENUS
1712 defsubr (&Sx_popup_dialog);
1713 #endif
1717 globals_of_w32menu is used to initialize those global variables that
1718 must always be initialized on startup even when the global variable
1719 initialized is non zero (see the function main in emacs.c).
1720 globals_of_w32menu is called from syms_of_w32menu when the global
1721 variable initialized is 0 and directly from main when initialized
1722 is non zero.
1724 void
1725 globals_of_w32menu (void)
1727 /* See if Get/SetMenuItemInfo functions are available. */
1728 HMODULE user32 = GetModuleHandle ("user32.dll");
1729 get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA");
1730 set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA");
1731 unicode_append_menu = (AppendMenuW_Proc) GetProcAddress (user32, "AppendMenuW");
1734 /* arch-tag: 0eaed431-bb4e-4aac-a527-95a1b4f1fed0
1735 (do not change this comment) */