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