]> code.delx.au - gnu-emacs/blob - src/w32menu.c
f29ca9e2ef1fde41e1cb9195e6f8e30c63e449eb
[gnu-emacs] / src / w32menu.c
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, 2011
4 Free Software Foundation, Inc.
5
6 This file is part of GNU Emacs.
7
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.
12
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.
17
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/>. */
20
21 #include <config.h>
22
23 #include <signal.h>
24 #include <stdio.h>
25 #include <mbstring.h>
26 #include <setjmp.h>
27
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"
40
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"
44
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
50
51 #include "dispextern.h"
52
53 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
54
55 #ifndef TRUE
56 #define TRUE 1
57 #define FALSE 0
58 #endif /* no TRUE */
59
60 HMENU current_popup_menu;
61
62 void syms_of_w32menu ();
63 void globals_of_w32menu ();
64
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);
75
76 GetMenuItemInfoA_Proc get_menu_item_info = NULL;
77 SetMenuItemInfoA_Proc set_menu_item_info = NULL;
78 AppendMenuW_Proc unicode_append_menu = NULL;
79
80 Lisp_Object Qdebug_on_next_call;
81
82 extern Lisp_Object Qmenu_bar;
83
84 extern Lisp_Object QCtoggle, QCradio;
85
86 extern Lisp_Object Voverriding_local_map;
87 extern Lisp_Object Voverriding_local_map_menu_flag;
88
89 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
90
91 extern Lisp_Object Qmenu_bar_update_hook;
92
93 void set_frame_menubar P_ ((FRAME_PTR, int, int));
94
95 #ifdef HAVE_DIALOGS
96 static Lisp_Object w32_dialog_show P_ ((FRAME_PTR, int, Lisp_Object, char**));
97 #else
98 static int is_simple_dialog P_ ((Lisp_Object));
99 static Lisp_Object simple_dialog_show P_ ((FRAME_PTR, Lisp_Object, Lisp_Object));
100 #endif
101
102 void w32_free_menu_strings P_ ((HWND));
103 \f
104
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.
108
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>. */
111
112 int pending_menu_activation;
113 \f
114
115 /* Return the frame whose ->output_data.w32->menubar_widget equals
116 ID, or 0 if none. */
117
118 static struct frame *
119 menubar_id_to_frame (id)
120 HMENU id;
121 {
122 Lisp_Object tail, frame;
123 FRAME_PTR f;
124
125 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
126 {
127 frame = XCAR (tail);
128 if (!FRAMEP (frame))
129 continue;
130 f = XFRAME (frame);
131 if (!FRAME_WINDOW_P (f))
132 continue;
133 if (f->output_data.w32->menubar_widget == id)
134 return f;
135 }
136 return 0;
137 }
138 \f
139 #ifdef HAVE_MENUS
140
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.
147
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.
152
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.)
157
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;
162 {
163 FRAME_PTR f = NULL;
164 Lisp_Object window;
165
166 check_w32 ();
167
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))))
172 {
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;
178 unsigned long time;
179 Lisp_Object x, y;
180
181 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
182
183 if (new_f != 0)
184 XSETFRAME (window, new_f);
185 else
186 window = selected_window;
187 #endif
188 window = selected_window;
189 }
190 else if (CONSP (position))
191 {
192 Lisp_Object tem;
193 tem = Fcar (position);
194 if (CONSP (tem))
195 window = Fcar (Fcdr (position));
196 else
197 {
198 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
199 window = Fcar (tem); /* POSN_WINDOW (tem) */
200 }
201 }
202 else if (WINDOWP (position) || FRAMEP (position))
203 window = position;
204 else
205 window = Qnil;
206
207 /* Decode where to put the menu. */
208
209 if (FRAMEP (window))
210 f = XFRAME (window);
211 else if (WINDOWP (window))
212 {
213 CHECK_LIVE_WINDOW (window);
214 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
215 }
216 else
217 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
218 but I don't want to make one now. */
219 CHECK_WINDOW (window);
220
221 #ifndef HAVE_DIALOGS
222
223 {
224 /* Handle simple Yes/No choices as MessageBox popups. */
225 if (is_simple_dialog (contents))
226 return simple_dialog_show (f, contents, header);
227 else
228 {
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)));
238 }
239 }
240 #else /* HAVE_DIALOGS */
241 {
242 Lisp_Object title;
243 char *error_name;
244 Lisp_Object selection;
245
246 /* Decode the dialog items from what was specified. */
247 title = Fcar (contents);
248 CHECK_STRING (title);
249
250 list_of_panes (Fcons (contents, Qnil));
251
252 /* Display them in a dialog box. */
253 BLOCK_INPUT;
254 selection = w32_dialog_show (f, 0, title, header, &error_name);
255 UNBLOCK_INPUT;
256
257 discard_menu_items ();
258 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
259
260 if (error_name) error (error_name);
261 return selection;
262 }
263 #endif /* HAVE_DIALOGS */
264 }
265
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.
269
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.
273
274 But first we recompute the menu bar contents (the whole tree).
275
276 This way we can safely execute Lisp code. */
277
278 void
279 x_activate_menubar (f)
280 FRAME_PTR f;
281 {
282 set_frame_menubar (f, 0, 1);
283
284 /* Lock out further menubar changes while active. */
285 f->output_data.w32->menubar_active = 1;
286
287 /* Signal input thread to return from WM_INITMENU. */
288 complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
289 }
290
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. */
295
296 void
297 menubar_selection_callback (FRAME_PTR f, void * client_data)
298 {
299 Lisp_Object prefix, entry;
300 Lisp_Object vector;
301 Lisp_Object *subprefix_stack;
302 int submenu_depth = 0;
303 int i;
304
305 if (!f)
306 return;
307 entry = Qnil;
308 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
309 vector = f->menu_bar_vector;
310 prefix = Qnil;
311 i = 0;
312 while (i < f->menu_bar_items_used)
313 {
314 if (EQ (AREF (vector, i), Qnil))
315 {
316 subprefix_stack[submenu_depth++] = prefix;
317 prefix = entry;
318 i++;
319 }
320 else if (EQ (AREF (vector, i), Qlambda))
321 {
322 prefix = subprefix_stack[--submenu_depth];
323 i++;
324 }
325 else if (EQ (AREF (vector, i), Qt))
326 {
327 prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
328 i += MENU_ITEMS_PANE_LENGTH;
329 }
330 else
331 {
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)
336 {
337 int j;
338 struct input_event buf;
339 Lisp_Object frame;
340 EVENT_INIT (buf);
341
342 XSETFRAME (frame, f);
343 buf.kind = MENU_BAR_EVENT;
344 buf.frame_or_window = frame;
345 buf.arg = frame;
346 kbd_buffer_store_event (&buf);
347
348 for (j = 0; j < submenu_depth; j++)
349 if (!NILP (subprefix_stack[j]))
350 {
351 buf.kind = MENU_BAR_EVENT;
352 buf.frame_or_window = frame;
353 buf.arg = subprefix_stack[j];
354 kbd_buffer_store_event (&buf);
355 }
356
357 if (!NILP (prefix))
358 {
359 buf.kind = MENU_BAR_EVENT;
360 buf.frame_or_window = frame;
361 buf.arg = prefix;
362 kbd_buffer_store_event (&buf);
363 }
364
365 buf.kind = MENU_BAR_EVENT;
366 buf.frame_or_window = frame;
367 buf.arg = entry;
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);
371
372 f->output_data.w32->menubar_active = 0;
373 return;
374 }
375 i += MENU_ITEMS_ITEM_LENGTH;
376 }
377 }
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;
381 }
382
383 \f
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. */
387
388 void
389 set_frame_menubar (f, first_time, deep_p)
390 FRAME_PTR f;
391 int first_time;
392 int deep_p;
393 {
394 HMENU menubar_widget = f->output_data.w32->menubar_widget;
395 Lisp_Object items;
396 widget_value *wv, *first_wv, *prev_wv = 0;
397 int i, last_i;
398 int *submenu_start, *submenu_end;
399 int *submenu_top_level_items, *submenu_n_panes;
400
401 /* We must not change the menubar when actually in use. */
402 if (f->output_data.w32->menubar_active)
403 return;
404
405 XSETFRAME (Vmenu_updating_frame, f);
406
407 if (! menubar_widget)
408 deep_p = 1;
409 else if (pending_menu_activation && !deep_p)
410 deep_p = 1;
411
412 if (deep_p)
413 {
414 /* Make a widget-value tree representing the entire menu trees. */
415
416 struct buffer *prev = current_buffer;
417 Lisp_Object 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));
423
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;
428
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);
434
435 record_unwind_save_match_data ();
436
437 if (NILP (Voverriding_local_map_menu_flag))
438 {
439 specbind (Qoverriding_terminal_local_map, Qnil);
440 specbind (Qoverriding_local_map, Qnil);
441 }
442
443 set_buffer_internal_1 (XBUFFER (buffer));
444
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));
453
454 items = FRAME_MENU_BAR_ITEMS (f);
455
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));
460
461 /* Fill in menu_items with the current menu bar contents.
462 This can evaluate Lisp code. */
463 save_menu_items ();
464
465 menu_items = f->menu_bar_vector;
466 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
467 submenu_start = (int *) alloca (XVECTOR_SIZE (items) * sizeof (int *));
468 submenu_end = (int *) alloca (XVECTOR_SIZE (items) * sizeof (int *));
469 submenu_n_panes = (int *) alloca (XVECTOR_SIZE (items) * sizeof (int));
470 submenu_top_level_items
471 = (int *) alloca (XVECTOR_SIZE (items) * sizeof (int *));
472 init_menu_items ();
473 for (i = 0; i < ASIZE (items); i += 4)
474 {
475 Lisp_Object key, string, maps;
476
477 last_i = i;
478
479 key = AREF (items, i);
480 string = AREF (items, i + 1);
481 maps = AREF (items, i + 2);
482 if (NILP (string))
483 break;
484
485 submenu_start[i] = menu_items_used;
486
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;
491
492 submenu_end[i] = menu_items_used;
493 }
494
495 finish_menu_items ();
496
497 /* Convert menu_items into widget_value trees
498 to display the menu. This cannot evaluate Lisp code. */
499
500 wv = xmalloc_widget_value ();
501 wv->name = "menubar";
502 wv->value = 0;
503 wv->enabled = 1;
504 wv->button_type = BUTTON_TYPE_NONE;
505 wv->help = Qnil;
506 first_wv = wv;
507
508 for (i = 0; i < last_i; i += 4)
509 {
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]);
513 if (prev_wv)
514 prev_wv->next = wv;
515 else
516 first_wv->contents = wv;
517 /* Don't set wv->name here; GC during the loop might relocate it. */
518 wv->enabled = 1;
519 wv->button_type = BUTTON_TYPE_NONE;
520 prev_wv = wv;
521 }
522
523 set_buffer_internal_1 (prev);
524
525 /* If there has been no change in the Lisp-level contents
526 of the menu bar, skip redisplaying it. Just exit. */
527
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))))
531 break;
532 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
533 {
534 free_menubar_widget_value_tree (first_wv);
535 discard_menu_items ();
536 unbind_to (specpdl_count, Qnil);
537 return;
538 }
539
540 f->menu_bar_vector = menu_items;
541 f->menu_bar_items_used = menu_items_used;
542
543 /* This undoes save_menu_items. */
544 unbind_to (specpdl_count, Qnil);
545
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)
553 {
554 Lisp_Object string;
555 string = AREF (items, i + 1);
556 if (NILP (string))
557 break;
558 wv->name = (char *) SDATA (string);
559 update_submenu_strings (wv->contents);
560 wv = wv->next;
561 }
562 }
563 else
564 {
565 /* Make a widget-value tree containing
566 just the top level menu bar strings. */
567
568 wv = xmalloc_widget_value ();
569 wv->name = "menubar";
570 wv->value = 0;
571 wv->enabled = 1;
572 wv->button_type = BUTTON_TYPE_NONE;
573 wv->help = Qnil;
574 first_wv = wv;
575
576 items = FRAME_MENU_BAR_ITEMS (f);
577 for (i = 0; i < ASIZE (items); i += 4)
578 {
579 Lisp_Object string;
580
581 string = AREF (items, i + 1);
582 if (NILP (string))
583 break;
584
585 wv = xmalloc_widget_value ();
586 wv->name = (char *) SDATA (string);
587 wv->value = 0;
588 wv->enabled = 1;
589 wv->button_type = BUTTON_TYPE_NONE;
590 wv->help = Qnil;
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);
596
597 if (prev_wv)
598 prev_wv->next = wv;
599 else
600 first_wv->contents = wv;
601 prev_wv = wv;
602 }
603
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;
608 }
609
610 /* Create or update the menu bar widget. */
611
612 BLOCK_INPUT;
613
614 if (menubar_widget)
615 {
616 /* Empty current menubar, rather than creating a fresh one. */
617 while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
618 ;
619 }
620 else
621 {
622 menubar_widget = CreateMenu ();
623 }
624 fill_in_menu (menubar_widget, first_wv->contents);
625
626 free_menubar_widget_value_tree (first_wv);
627
628 {
629 HMENU old_widget = f->output_data.w32->menubar_widget;
630
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)); */
635
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));
640 }
641
642 UNBLOCK_INPUT;
643 }
644
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
648 is visible. */
649
650 void
651 initialize_frame_menubar (f)
652 FRAME_PTR f;
653 {
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);
658 }
659
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. */
662
663 void
664 free_frame_menubar (f)
665 FRAME_PTR f;
666 {
667 BLOCK_INPUT;
668
669 {
670 HMENU old = GetMenu (FRAME_W32_WINDOW (f));
671 SetMenu (FRAME_W32_WINDOW (f), NULL);
672 f->output_data.w32->menubar_widget = NULL;
673 DestroyMenu (old);
674 }
675
676 UNBLOCK_INPUT;
677 }
678
679 \f
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. */
683
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.) */
694
695 Lisp_Object
696 w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
697 Lisp_Object title, char **error)
698 {
699 int i;
700 int menu_item_selection;
701 HMENU menu;
702 POINT pos;
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;
709 int first_pane;
710
711 *error = NULL;
712
713 if (menu_items_n_panes == 0)
714 return Qnil;
715
716 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
717 {
718 *error = "Empty menu";
719 return Qnil;
720 }
721
722 /* Create a tree of widget_value objects
723 representing the panes and their items. */
724 wv = xmalloc_widget_value ();
725 wv->name = "menu";
726 wv->value = 0;
727 wv->enabled = 1;
728 wv->button_type = BUTTON_TYPE_NONE;
729 wv->help = Qnil;
730 first_wv = wv;
731 first_pane = 1;
732
733 /* Loop over all panes and items, filling in the tree. */
734 i = 0;
735 while (i < menu_items_used)
736 {
737 if (EQ (AREF (menu_items, i), Qnil))
738 {
739 submenu_stack[submenu_depth++] = save_wv;
740 save_wv = prev_wv;
741 prev_wv = 0;
742 first_pane = 1;
743 i++;
744 }
745 else if (EQ (AREF (menu_items, i), Qlambda))
746 {
747 prev_wv = save_wv;
748 save_wv = submenu_stack[--submenu_depth];
749 first_pane = 0;
750 i++;
751 }
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))
758 i += 1;
759 else if (EQ (AREF (menu_items, i), Qt))
760 {
761 /* Create a new pane. */
762 Lisp_Object pane_name, prefix;
763 char *pane_string;
764 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
765 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
766
767 if (STRINGP (pane_name))
768 {
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);
773
774 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
775 }
776
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)
782 pane_string = "";
783
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, ""))
788 {
789 wv = xmalloc_widget_value ();
790 if (save_wv)
791 save_wv->next = wv;
792 else
793 first_wv->contents = wv;
794 wv->name = pane_string;
795 if (keymaps && !NILP (prefix))
796 wv->name++;
797 wv->value = 0;
798 wv->enabled = 1;
799 wv->button_type = BUTTON_TYPE_NONE;
800 wv->help = Qnil;
801 save_wv = wv;
802 prev_wv = 0;
803 }
804 else if (first_pane)
805 {
806 save_wv = wv;
807 prev_wv = 0;
808 }
809 first_pane = 0;
810 i += MENU_ITEMS_PANE_LENGTH;
811 }
812 else
813 {
814 /* Create a new item within current pane. */
815 Lisp_Object item_name, enable, descrip, def, type, selected, help;
816
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);
824
825 if (STRINGP (item_name))
826 {
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);
831
832 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
833 }
834
835 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
836 {
837 descrip = ENCODE_SYSTEM (descrip);
838 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
839 }
840
841 wv = xmalloc_widget_value ();
842 if (prev_wv)
843 prev_wv->next = wv;
844 else
845 save_wv->contents = wv;
846 wv->name = (char *) SDATA (item_name);
847 if (!NILP (descrip))
848 wv->key = (char *) SDATA (descrip);
849 wv->value = 0;
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);
854
855 if (NILP (type))
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;
861 else
862 abort ();
863
864 wv->selected = !NILP (selected);
865
866 if (!STRINGP (help))
867 help = Qnil;
868
869 wv->help = help;
870
871 prev_wv = wv;
872
873 i += MENU_ITEMS_ITEM_LENGTH;
874 }
875 }
876
877 /* Deal with the title, if it is non-nil. */
878 if (!NILP (title))
879 {
880 widget_value *wv_title = xmalloc_widget_value ();
881 widget_value *wv_sep = xmalloc_widget_value ();
882
883 /* Maybe replace this separator with a bitmap or owner-draw item
884 so that it looks better. Having two separators looks odd. */
885 wv_sep->name = "--";
886 wv_sep->next = first_wv->contents;
887 wv_sep->help = Qnil;
888
889 if (unicode_append_menu)
890 title = ENCODE_UTF_8 (title);
891 else if (STRING_MULTIBYTE (title))
892 title = ENCODE_SYSTEM (title);
893
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;
901 }
902
903 /* No selection has been chosen yet. */
904 menu_item_selection = 0;
905
906 /* Actually create the menu. */
907 current_popup_menu = menu = CreatePopupMenu ();
908 fill_in_menu (menu, first_wv->contents);
909
910 /* Adjust coordinates to be root-window-relative. */
911 pos.x = x;
912 pos.y = y;
913 ClientToScreen (FRAME_W32_WINDOW (f), &pos);
914
915 /* Display the menu. */
916 menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
917 WM_EMACS_TRACKPOPUPMENU,
918 (WPARAM)menu, (LPARAM)&pos);
919
920 /* Clean up extraneous mouse events which might have been generated
921 during the call. */
922 discard_mouse_events ();
923 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
924
925 /* Free the widget_value objects we used to specify the contents. */
926 free_menubar_widget_value_tree (first_wv);
927
928 DestroyMenu (menu);
929
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;
933
934 /* Find the selected item, and its pane, to return
935 the proper value. */
936 if (menu_item_selection != 0)
937 {
938 Lisp_Object prefix, entry;
939
940 prefix = entry = Qnil;
941 i = 0;
942 while (i < menu_items_used)
943 {
944 if (EQ (AREF (menu_items, i), Qnil))
945 {
946 subprefix_stack[submenu_depth++] = prefix;
947 prefix = entry;
948 i++;
949 }
950 else if (EQ (AREF (menu_items, i), Qlambda))
951 {
952 prefix = subprefix_stack[--submenu_depth];
953 i++;
954 }
955 else if (EQ (AREF (menu_items, i), Qt))
956 {
957 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
958 i += MENU_ITEMS_PANE_LENGTH;
959 }
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))
963 i += 1;
964 else
965 {
966 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
967 if (menu_item_selection == i)
968 {
969 if (keymaps != 0)
970 {
971 int j;
972
973 entry = Fcons (entry, Qnil);
974 if (!NILP (prefix))
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);
979 }
980 return entry;
981 }
982 i += MENU_ITEMS_ITEM_LENGTH;
983 }
984 }
985 }
986 else if (!for_click)
987 /* Make "Cancel" equivalent to C-g. */
988 Fsignal (Qquit, Qnil);
989
990 return Qnil;
991 }
992 \f
993
994 #ifdef HAVE_DIALOGS
995 /* TODO: On Windows, there are two ways of defining a dialog.
996
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
1001 fit on a button.
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.
1012
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.
1016 */
1017
1018 static char * button_names [] = {
1019 "button1", "button2", "button3", "button4", "button5",
1020 "button6", "button7", "button8", "button9", "button10" };
1021
1022 static Lisp_Object
1023 w32_dialog_show (f, keymaps, title, header, error)
1024 FRAME_PTR f;
1025 int keymaps;
1026 Lisp_Object title, header;
1027 char **error;
1028 {
1029 int i, nb_buttons = 0;
1030 char dialog_name[6];
1031 int menu_item_selection;
1032
1033 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1034
1035 /* Number of elements seen so far, before boundary. */
1036 int left_count = 0;
1037 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1038 int boundary_seen = 0;
1039
1040 *error = NULL;
1041
1042 if (menu_items_n_panes > 1)
1043 {
1044 *error = "Multiple panes in dialog box";
1045 return Qnil;
1046 }
1047
1048 /* Create a tree of widget_value objects
1049 representing the text label and buttons. */
1050 {
1051 Lisp_Object pane_name, prefix;
1052 char *pane_string;
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))
1060 prev_wv->name++;
1061 prev_wv->enabled = 1;
1062 prev_wv->name = "message";
1063 prev_wv->help = Qnil;
1064 first_wv = prev_wv;
1065
1066 /* Loop over all panes and items, filling in the tree. */
1067 i = MENU_ITEMS_PANE_LENGTH;
1068 while (i < menu_items_used)
1069 {
1070
1071 /* Create a new item within current pane. */
1072 Lisp_Object item_name, enable, descrip, help;
1073
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);
1078
1079 if (NILP (item_name))
1080 {
1081 free_menubar_widget_value_tree (first_wv);
1082 *error = "Submenu in dialog items";
1083 return Qnil;
1084 }
1085 if (EQ (item_name, Qquote))
1086 {
1087 /* This is the boundary between left-side elts
1088 and right-side elts. Stop incrementing right_count. */
1089 boundary_seen = 1;
1090 i++;
1091 continue;
1092 }
1093 if (nb_buttons >= 9)
1094 {
1095 free_menubar_widget_value_tree (first_wv);
1096 *error = "Too many dialog items";
1097 return Qnil;
1098 }
1099
1100 wv = xmalloc_widget_value ();
1101 prev_wv->next = wv;
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);
1108 wv->help = Qnil;
1109 prev_wv = wv;
1110
1111 if (! boundary_seen)
1112 left_count++;
1113
1114 nb_buttons++;
1115 i += MENU_ITEMS_ITEM_LENGTH;
1116 }
1117
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;
1122
1123 wv = xmalloc_widget_value ();
1124 wv->name = dialog_name;
1125 wv->help = Qnil;
1126
1127 /* Frame title: 'Q' = Question, 'I' = Information.
1128 Can also have 'E' = Error if, one day, we want
1129 a popup for errors. */
1130 if (NILP (header))
1131 dialog_name[0] = 'Q';
1132 else
1133 dialog_name[0] = 'I';
1134
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;
1143 dialog_name[5] = 0;
1144 wv->contents = first_wv;
1145 first_wv = wv;
1146 }
1147
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);
1154
1155 /* Free the widget_value objects we used to specify the contents. */
1156 free_menubar_widget_value_tree (first_wv);
1157
1158 /* No selection has been chosen yet. */
1159 menu_item_selection = 0;
1160
1161 /* Display the menu. */
1162 lw_pop_up_all_widgets (dialog_id);
1163
1164 /* Process events that apply to the menu. */
1165 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
1166
1167 lw_destroy_all_widgets (dialog_id);
1168
1169 /* Find the selected item, and its pane, to return
1170 the proper value. */
1171 if (menu_item_selection != 0)
1172 {
1173 Lisp_Object prefix;
1174
1175 prefix = Qnil;
1176 i = 0;
1177 while (i < menu_items_used)
1178 {
1179 Lisp_Object entry;
1180
1181 if (EQ (AREF (menu_items, i), Qt))
1182 {
1183 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1184 i += MENU_ITEMS_PANE_LENGTH;
1185 }
1186 else
1187 {
1188 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1189 if (menu_item_selection == i)
1190 {
1191 if (keymaps != 0)
1192 {
1193 entry = Fcons (entry, Qnil);
1194 if (!NILP (prefix))
1195 entry = Fcons (prefix, entry);
1196 }
1197 return entry;
1198 }
1199 i += MENU_ITEMS_ITEM_LENGTH;
1200 }
1201 }
1202 }
1203 else
1204 /* Make "Cancel" equivalent to C-g. */
1205 Fsignal (Qquit, Qnil);
1206
1207 return Qnil;
1208 }
1209 #else /* !HAVE_DIALOGS */
1210
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. */
1215
1216 static int
1217 is_simple_dialog (contents)
1218 Lisp_Object contents;
1219 {
1220 Lisp_Object options = XCDR (contents);
1221 Lisp_Object name, yes, no, other;
1222
1223 yes = build_string ("Yes");
1224 no = build_string ("No");
1225
1226 if (!CONSP (options))
1227 return 0;
1228
1229 name = XCAR (XCAR (options));
1230 if (!CONSP (options))
1231 return 0;
1232
1233 if (!NILP (Fstring_equal (name, yes)))
1234 other = no;
1235 else if (!NILP (Fstring_equal (name, no)))
1236 other = yes;
1237 else
1238 return 0;
1239
1240 options = XCDR (options);
1241 if (!CONSP (options))
1242 return 0;
1243
1244 name = XCAR (XCAR (options));
1245 if (NILP (Fstring_equal (name, other)))
1246 return 0;
1247
1248 /* Check there are no more options. */
1249 options = XCDR (options);
1250 return !(CONSP (options));
1251 }
1252
1253 static Lisp_Object
1254 simple_dialog_show (f, contents, header)
1255 FRAME_PTR f;
1256 Lisp_Object contents, header;
1257 {
1258 int answer;
1259 UINT type;
1260 char *text, *title;
1261 Lisp_Object lispy_answer = Qnil, temp = XCAR (contents);
1262
1263 if (STRINGP (temp))
1264 text = SDATA (temp);
1265 else
1266 text = "";
1267
1268 if (NILP (header))
1269 {
1270 title = "Question";
1271 type = MB_ICONQUESTION;
1272 }
1273 else
1274 {
1275 title = "Information";
1276 type = MB_ICONINFORMATION;
1277 }
1278 type |= MB_YESNO;
1279
1280 /* Since we only handle Yes/No dialogs, and we already checked
1281 is_simple_dialog, we don't need to worry about checking contents
1282 to see what type of dialog to use. */
1283 answer = MessageBox (FRAME_W32_WINDOW (f), text, title, type);
1284
1285 if (answer == IDYES)
1286 lispy_answer = build_string ("Yes");
1287 else if (answer == IDNO)
1288 lispy_answer = build_string ("No");
1289 else
1290 Fsignal (Qquit, Qnil);
1291
1292 for (temp = XCDR (contents); CONSP (temp); temp = XCDR (temp))
1293 {
1294 Lisp_Object item, name, value;
1295 item = XCAR (temp);
1296 if (CONSP (item))
1297 {
1298 name = XCAR (item);
1299 value = XCDR (item);
1300 }
1301 else
1302 {
1303 name = item;
1304 value = Qnil;
1305 }
1306
1307 if (!NILP (Fstring_equal (name, lispy_answer)))
1308 {
1309 return value;
1310 }
1311 }
1312 Fsignal (Qquit, Qnil);
1313 return Qnil;
1314 }
1315 #endif /* !HAVE_DIALOGS */
1316 \f
1317
1318 /* Is this item a separator? */
1319 static int
1320 name_is_separator (name)
1321 char *name;
1322 {
1323 char *start = name;
1324
1325 /* Check if name string consists of only dashes ('-'). */
1326 while (*name == '-') name++;
1327 /* Separators can also be of the form "--:TripleSuperMegaEtched"
1328 or "--deep-shadow". We don't implement them yet, se we just treat
1329 them like normal separators. */
1330 return (*name == '\0' || start + 2 == name);
1331 }
1332
1333 /* Indicate boundary between left and right. */
1334 static int
1335 add_left_right_boundary (HMENU menu)
1336 {
1337 return AppendMenu (menu, MF_MENUBARBREAK, 0, NULL);
1338 }
1339
1340 /* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
1341 static void
1342 utf8to16 (unsigned char * src, int len, WCHAR * dest)
1343 {
1344 while (len > 0)
1345 {
1346 int utf16;
1347 if (*src < 0x80)
1348 {
1349 *dest = (WCHAR) *src;
1350 dest++; src++; len--;
1351 }
1352 /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */
1353 else if (*src < 0xC0)
1354 {
1355 src++; len--;
1356 }
1357 /* 2 char UTF-8 sequence. */
1358 else if (*src < 0xE0)
1359 {
1360 *dest = (WCHAR) (((*src & 0x1f) << 6)
1361 | (*(src + 1) & 0x3f));
1362 src += 2; len -= 2; dest++;
1363 }
1364 else if (*src < 0xF0)
1365 {
1366 *dest = (WCHAR) (((*src & 0x0f) << 12)
1367 | ((*(src + 1) & 0x3f) << 6)
1368 | (*(src + 2) & 0x3f));
1369 src += 3; len -= 3; dest++;
1370 }
1371 else /* Not encodable. Insert Unicode Substitution char. */
1372 {
1373 *dest = (WCHAR) 0xfffd;
1374 src++; len--; dest++;
1375 }
1376 }
1377 *dest = 0;
1378 }
1379
1380 static int
1381 add_menu_item (HMENU menu, widget_value *wv, HMENU item)
1382 {
1383 UINT fuFlags;
1384 char *out_string, *p, *q;
1385 int return_value;
1386 size_t nlen, orig_len;
1387
1388 if (name_is_separator (wv->name))
1389 {
1390 fuFlags = MF_SEPARATOR;
1391 out_string = NULL;
1392 }
1393 else
1394 {
1395 if (wv->enabled)
1396 fuFlags = MF_STRING;
1397 else
1398 fuFlags = MF_STRING | MF_GRAYED;
1399
1400 if (wv->key != NULL)
1401 {
1402 out_string = alloca (strlen (wv->name) + strlen (wv->key) + 2);
1403 strcpy (out_string, wv->name);
1404 strcat (out_string, "\t");
1405 strcat (out_string, wv->key);
1406 }
1407 else
1408 out_string = wv->name;
1409
1410 /* Quote any special characters within the menu item's text and
1411 key binding. */
1412 nlen = orig_len = strlen (out_string);
1413 if (unicode_append_menu)
1414 {
1415 /* With UTF-8, & cannot be part of a multibyte character. */
1416 for (p = out_string; *p; p++)
1417 {
1418 if (*p == '&')
1419 nlen++;
1420 }
1421 }
1422 else
1423 {
1424 /* If encoded with the system codepage, use multibyte string
1425 functions in case of multibyte characters that contain '&'. */
1426 for (p = out_string; *p; p = _mbsinc (p))
1427 {
1428 if (_mbsnextc (p) == '&')
1429 nlen++;
1430 }
1431 }
1432
1433 if (nlen > orig_len)
1434 {
1435 p = out_string;
1436 out_string = alloca (nlen + 1);
1437 q = out_string;
1438 while (*p)
1439 {
1440 if (unicode_append_menu)
1441 {
1442 if (*p == '&')
1443 *q++ = *p;
1444 *q++ = *p++;
1445 }
1446 else
1447 {
1448 if (_mbsnextc (p) == '&')
1449 {
1450 _mbsncpy (q, p, 1);
1451 q = _mbsinc (q);
1452 }
1453 _mbsncpy (q, p, 1);
1454 p = _mbsinc (p);
1455 q = _mbsinc (q);
1456 }
1457 }
1458 *q = '\0';
1459 }
1460
1461 if (item != NULL)
1462 fuFlags = MF_POPUP;
1463 else if (wv->title || wv->call_data == 0)
1464 {
1465 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
1466 we can't deallocate the memory otherwise. */
1467 if (get_menu_item_info)
1468 {
1469 out_string = (char *) local_alloc (strlen (wv->name) + 1);
1470 strcpy (out_string, wv->name);
1471 #ifdef MENU_DEBUG
1472 DebPrint ("Menu: allocing %ld for owner-draw", out_string);
1473 #endif
1474 fuFlags = MF_OWNERDRAW | MF_DISABLED;
1475 }
1476 else
1477 fuFlags = MF_DISABLED;
1478 }
1479
1480 /* Draw radio buttons and tickboxes. */
1481 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
1482 wv->button_type == BUTTON_TYPE_RADIO))
1483 fuFlags |= MF_CHECKED;
1484 else
1485 fuFlags |= MF_UNCHECKED;
1486 }
1487
1488 if (unicode_append_menu && out_string)
1489 {
1490 /* Convert out_string from UTF-8 to UTF-16-LE. */
1491 int utf8_len = strlen (out_string);
1492 WCHAR * utf16_string;
1493 if (fuFlags & MF_OWNERDRAW)
1494 utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
1495 else
1496 utf16_string = alloca ((utf8_len + 1) * sizeof (WCHAR));
1497
1498 utf8to16 (out_string, utf8_len, utf16_string);
1499 return_value = unicode_append_menu (menu, fuFlags,
1500 item != NULL ? (UINT) item
1501 : (UINT) wv->call_data,
1502 utf16_string);
1503 if (!return_value)
1504 {
1505 /* On W9x/ME, unicode menus are not supported, though AppendMenuW
1506 apparently does exist at least in some cases and appears to be
1507 stubbed out to do nothing. out_string is UTF-8, but since
1508 our standard menus are in English and this is only going to
1509 happen the first time a menu is used, the encoding is
1510 of minor importance compared with menus not working at all. */
1511 return_value =
1512 AppendMenu (menu, fuFlags,
1513 item != NULL ? (UINT) item: (UINT) wv->call_data,
1514 out_string);
1515 /* Don't use unicode menus in future. */
1516 unicode_append_menu = NULL;
1517 }
1518
1519 if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
1520 local_free (out_string);
1521 }
1522 else
1523 {
1524 return_value =
1525 AppendMenu (menu,
1526 fuFlags,
1527 item != NULL ? (UINT) item : (UINT) wv->call_data,
1528 out_string );
1529 }
1530
1531 /* This must be done after the menu item is created. */
1532 if (!wv->title && wv->call_data != 0)
1533 {
1534 if (set_menu_item_info)
1535 {
1536 MENUITEMINFO info;
1537 bzero (&info, sizeof (info));
1538 info.cbSize = sizeof (info);
1539 info.fMask = MIIM_DATA;
1540
1541 /* Set help string for menu item. Leave it as a Lisp_Object
1542 until it is ready to be displayed, since GC can happen while
1543 menus are active. */
1544 if (!NILP (wv->help))
1545 #ifdef USE_LISP_UNION_TYPE
1546 info.dwItemData = (DWORD) (wv->help).i;
1547 #else
1548 info.dwItemData = (DWORD) (wv->help);
1549 #endif
1550 if (wv->button_type == BUTTON_TYPE_RADIO)
1551 {
1552 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
1553 RADIO items, but is not available on NT 3.51 and earlier. */
1554 info.fMask |= MIIM_TYPE | MIIM_STATE;
1555 info.fType = MFT_RADIOCHECK | MFT_STRING;
1556 info.dwTypeData = out_string;
1557 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
1558 }
1559
1560 set_menu_item_info (menu,
1561 item != NULL ? (UINT) item : (UINT) wv->call_data,
1562 FALSE, &info);
1563 }
1564 }
1565 return return_value;
1566 }
1567
1568 /* Construct native Windows menu(bar) based on widget_value tree. */
1569 int
1570 fill_in_menu (HMENU menu, widget_value *wv)
1571 {
1572 int items_added = 0;
1573
1574 for ( ; wv != NULL; wv = wv->next)
1575 {
1576 if (wv->contents)
1577 {
1578 HMENU sub_menu = CreatePopupMenu ();
1579
1580 if (sub_menu == NULL)
1581 return 0;
1582
1583 if (!fill_in_menu (sub_menu, wv->contents) ||
1584 !add_menu_item (menu, wv, sub_menu))
1585 {
1586 DestroyMenu (sub_menu);
1587 return 0;
1588 }
1589 }
1590 else
1591 {
1592 if (!add_menu_item (menu, wv, NULL))
1593 return 0;
1594 }
1595 }
1596 return 1;
1597 }
1598
1599 /* Display help string for currently pointed to menu item. Not
1600 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
1601 available. */
1602 void
1603 w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
1604 {
1605 if (get_menu_item_info)
1606 {
1607 struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
1608 Lisp_Object frame, help;
1609
1610 /* No help echo on owner-draw menu items, or when the keyboard is used
1611 to navigate the menus, since tooltips are distracting if they pop
1612 up elsewhere. */
1613 if (flags & MF_OWNERDRAW || flags & MF_POPUP
1614 || !(flags & MF_MOUSESELECT))
1615 help = Qnil;
1616 else
1617 {
1618 MENUITEMINFO info;
1619
1620 bzero (&info, sizeof (info));
1621 info.cbSize = sizeof (info);
1622 info.fMask = MIIM_DATA;
1623 get_menu_item_info (menu, item, FALSE, &info);
1624
1625 #ifdef USE_LISP_UNION_TYPE
1626 help = info.dwItemData ? (Lisp_Object) ((EMACS_INT) info.dwItemData)
1627 : Qnil;
1628 #else
1629 help = info.dwItemData ? (Lisp_Object) info.dwItemData : Qnil;
1630 #endif
1631 }
1632
1633 /* Store the help echo in the keyboard buffer as the X toolkit
1634 version does, rather than directly showing it. This seems to
1635 solve the GC problems that were present when we based the
1636 Windows code on the non-toolkit version. */
1637 if (f)
1638 {
1639 XSETFRAME (frame, f);
1640 kbd_buffer_store_help_event (frame, help);
1641 }
1642 else
1643 /* X version has a loop through frames here, which doesn't
1644 appear to do anything, unless it has some side effect. */
1645 show_help_echo (help, Qnil, Qnil, Qnil, 1);
1646 }
1647 }
1648
1649 /* Free memory used by owner-drawn strings. */
1650 static void
1651 w32_free_submenu_strings (menu)
1652 HMENU menu;
1653 {
1654 int i, num = GetMenuItemCount (menu);
1655 for (i = 0; i < num; i++)
1656 {
1657 MENUITEMINFO info;
1658 bzero (&info, sizeof (info));
1659 info.cbSize = sizeof (info);
1660 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
1661
1662 get_menu_item_info (menu, i, TRUE, &info);
1663
1664 /* Owner-drawn names are held in dwItemData. */
1665 if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
1666 {
1667 #ifdef MENU_DEBUG
1668 DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
1669 #endif
1670 local_free (info.dwItemData);
1671 }
1672
1673 /* Recurse down submenus. */
1674 if (info.hSubMenu)
1675 w32_free_submenu_strings (info.hSubMenu);
1676 }
1677 }
1678
1679 void
1680 w32_free_menu_strings (hwnd)
1681 HWND hwnd;
1682 {
1683 HMENU menu = current_popup_menu;
1684
1685 if (get_menu_item_info)
1686 {
1687 /* If there is no popup menu active, free the strings from the frame's
1688 menubar. */
1689 if (!menu)
1690 menu = GetMenu (hwnd);
1691
1692 if (menu)
1693 w32_free_submenu_strings (menu);
1694 }
1695
1696 current_popup_menu = NULL;
1697 }
1698
1699 #endif /* HAVE_MENUS */
1700
1701 /* The following is used by delayed window autoselection. */
1702
1703 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1704 doc: /* Return t if a menu or popup dialog is active on selected frame. */)
1705 ()
1706 {
1707 #ifdef HAVE_MENUS
1708 FRAME_PTR f;
1709 f = SELECTED_FRAME ();
1710 return (f->output_data.w32->menubar_active > 0) ? Qt : Qnil;
1711 #else
1712 return Qnil;
1713 #endif /* HAVE_MENUS */
1714 }
1715
1716 void
1717 syms_of_w32menu ()
1718 {
1719 globals_of_w32menu ();
1720
1721 current_popup_menu = NULL;
1722
1723 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
1724
1725 defsubr (&Smenu_or_popup_active_p);
1726 #ifdef HAVE_MENUS
1727 defsubr (&Sx_popup_dialog);
1728 #endif
1729 }
1730
1731 /*
1732 globals_of_w32menu is used to initialize those global variables that
1733 must always be initialized on startup even when the global variable
1734 initialized is non zero (see the function main in emacs.c).
1735 globals_of_w32menu is called from syms_of_w32menu when the global
1736 variable initialized is 0 and directly from main when initialized
1737 is non zero.
1738 */
1739 void
1740 globals_of_w32menu ()
1741 {
1742 /* See if Get/SetMenuItemInfo functions are available. */
1743 HMODULE user32 = GetModuleHandle ("user32.dll");
1744 get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA");
1745 set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA");
1746 unicode_append_menu = (AppendMenuW_Proc) GetProcAddress (user32, "AppendMenuW");
1747 }
1748
1749 /* arch-tag: 0eaed431-bb4e-4aac-a527-95a1b4f1fed0
1750 (do not change this comment) */