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