This source file includes following definitions.
- w32_popup_dialog
- w32_activate_menubar
- menubar_selection_callback
- set_frame_menubar
- initialize_frame_menubar
- free_frame_menubar
- w32_menu_show
- w32_dialog_show
- is_simple_dialog
- simple_dialog_show
- utf8to16
- add_menu_item
- fill_in_menu
- w32_menu_display_help
- w32_free_submenu_strings
- w32_free_menu_strings
- DEFUN
- syms_of_w32menu
- globals_of_w32menu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <config.h>
21
22 #include <signal.h>
23 #include <stdio.h>
24 #include <setjmp.h>
25
26 #include "lisp.h"
27 #include "keyboard.h"
28 #include "frame.h"
29 #include "blockinput.h"
30 #include "buffer.h"
31 #include "coding.h"
32 #include "menu.h"
33 #include "pdumper.h"
34
35
36
37 #include "w32term.h"
38
39
40
41
42
43 #ifndef NTGUI_UNICODE
44 #include <mbstring.h>
45 #endif
46
47
48
49 #ifndef makedev
50 #include <sys/types.h>
51 #endif
52
53 #include "w32common.h"
54
55 #undef HAVE_DIALOGS
56
57 #ifndef TRUE
58 #define TRUE 1
59 #define FALSE 0
60 #endif
61
62 HMENU current_popup_menu;
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 const WCHAR *text,
77 IN const WCHAR *caption,
78 IN UINT type);
79
80 #ifdef NTGUI_UNICODE
81 GetMenuItemInfoA_Proc get_menu_item_info = GetMenuItemInfoA;
82 SetMenuItemInfoA_Proc set_menu_item_info = SetMenuItemInfoA;
83 AppendMenuW_Proc unicode_append_menu = AppendMenuW;
84 MessageBoxW_Proc unicode_message_box = MessageBoxW;
85 #else
86 GetMenuItemInfoA_Proc get_menu_item_info = NULL;
87 SetMenuItemInfoA_Proc set_menu_item_info = NULL;
88 AppendMenuW_Proc unicode_append_menu = NULL;
89 MessageBoxW_Proc unicode_message_box = NULL;
90 #endif
91
92 #ifdef HAVE_DIALOGS
93 static Lisp_Object w32_dialog_show (struct frame *, Lisp_Object, Lisp_Object, char **);
94 #else
95 static bool is_simple_dialog (Lisp_Object);
96 static Lisp_Object simple_dialog_show (struct frame *, Lisp_Object, Lisp_Object);
97 #endif
98
99 static void utf8to16 (unsigned char *, int, WCHAR *);
100 static int fill_in_menu (HMENU, widget_value *);
101
102 void w32_free_menu_strings (HWND);
103
104 Lisp_Object
105 w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
106 {
107
108 check_window_system (f);
109
110 #ifndef HAVE_DIALOGS
111
112
113 if (is_simple_dialog (contents))
114 return simple_dialog_show (f, contents, header);
115 else
116 return Qunsupported__w32_dialog;
117 #else
118 {
119 Lisp_Object title;
120 char *error_name;
121 Lisp_Object selection;
122
123
124 title = Fcar (contents);
125 CHECK_STRING (title);
126
127 list_of_panes (Fcons (contents, Qnil));
128
129
130 block_input ();
131 selection = w32_dialog_show (f, title, header, &error_name);
132 unblock_input ();
133
134 discard_menu_items ();
135 FRAME_DISPLAY_INFO (f)->grabbed = 0;
136
137 if (error_name) error (error_name);
138 return selection;
139 }
140 #endif
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154
155 void
156 w32_activate_menubar (struct frame *f)
157 {
158 set_frame_menubar (f, true);
159
160
161 f->output_data.w32->menubar_active = 1;
162
163
164 complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
165 }
166
167
168
169
170
171 void menubar_selection_callback (struct frame *, void *);
172
173 void
174 menubar_selection_callback (struct frame *f, void * client_data)
175 {
176 Lisp_Object prefix, entry;
177 Lisp_Object vector;
178 Lisp_Object *subprefix_stack;
179 int submenu_depth = 0;
180 int i;
181
182 if (!f)
183 return;
184 entry = Qnil;
185 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * word_size);
186 vector = f->menu_bar_vector;
187 prefix = Qnil;
188 i = 0;
189 while (i < f->menu_bar_items_used)
190 {
191 if (NILP (AREF (vector, i)))
192 {
193 subprefix_stack[submenu_depth++] = prefix;
194 prefix = entry;
195 i++;
196 }
197 else if (EQ (AREF (vector, i), Qlambda))
198 {
199 prefix = subprefix_stack[--submenu_depth];
200 i++;
201 }
202 else if (EQ (AREF (vector, i), Qt))
203 {
204 prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
205 i += MENU_ITEMS_PANE_LENGTH;
206 }
207 else
208 {
209 entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
210
211
212 if ((int) (UINT_PTR) client_data == i)
213 {
214 int j;
215 struct input_event buf;
216 Lisp_Object frame;
217 EVENT_INIT (buf);
218
219 XSETFRAME (frame, f);
220 buf.kind = MENU_BAR_EVENT;
221 buf.frame_or_window = frame;
222 buf.arg = frame;
223 kbd_buffer_store_event (&buf);
224
225 for (j = 0; j < submenu_depth; j++)
226 if (!NILP (subprefix_stack[j]))
227 {
228 buf.kind = MENU_BAR_EVENT;
229 buf.frame_or_window = frame;
230 buf.arg = subprefix_stack[j];
231 kbd_buffer_store_event (&buf);
232 }
233
234 if (!NILP (prefix))
235 {
236 buf.kind = MENU_BAR_EVENT;
237 buf.frame_or_window = frame;
238 buf.arg = prefix;
239 kbd_buffer_store_event (&buf);
240 }
241
242 buf.kind = MENU_BAR_EVENT;
243 buf.frame_or_window = frame;
244 buf.arg = entry;
245
246 w32_free_menu_strings (FRAME_W32_WINDOW (f));
247 kbd_buffer_store_event (&buf);
248
249 f->output_data.w32->menubar_active = 0;
250 return;
251 }
252 i += MENU_ITEMS_ITEM_LENGTH;
253 }
254 }
255
256 w32_free_menu_strings (FRAME_W32_WINDOW (f));
257 f->output_data.w32->menubar_active = 0;
258 }
259
260
261
262
263 void
264 set_frame_menubar (struct frame *f, bool deep_p)
265 {
266 HMENU menubar_widget = f->output_data.w32->menubar_widget;
267 Lisp_Object items;
268 widget_value *wv, *first_wv, *prev_wv = 0;
269 int i, last_i = 0;
270 int *submenu_start, *submenu_end;
271 int *submenu_top_level_items, *submenu_n_panes;
272
273
274 if (f->output_data.w32->menubar_active)
275 return;
276
277 XSETFRAME (Vmenu_updating_frame, f);
278
279 if (! menubar_widget)
280 deep_p = true;
281
282 if (deep_p)
283 {
284
285
286 struct buffer *prev = current_buffer;
287 Lisp_Object buffer;
288 specpdl_ref specpdl_count = SPECPDL_INDEX ();
289 int previous_menu_items_used = f->menu_bar_items_used;
290 Lisp_Object *previous_items
291 = (Lisp_Object *) alloca (previous_menu_items_used
292 * word_size);
293
294
295
296 if (! menubar_widget)
297 previous_menu_items_used = 0;
298
299 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
300 specbind (Qinhibit_quit, Qt);
301
302
303 specbind (Qdebug_on_next_call, Qnil);
304
305 record_unwind_save_match_data ();
306
307 if (NILP (Voverriding_local_map_menu_flag))
308 {
309 specbind (Qoverriding_terminal_local_map, Qnil);
310 specbind (Qoverriding_local_map, Qnil);
311 }
312
313 set_buffer_internal_1 (XBUFFER (buffer));
314
315
316 safe_run_hooks (Qactivate_menubar_hook);
317 safe_run_hooks (Qmenu_bar_update_hook);
318 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
319
320 items = FRAME_MENU_BAR_ITEMS (f);
321
322
323 if (previous_menu_items_used)
324 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
325 previous_menu_items_used * word_size);
326
327
328
329 save_menu_items ();
330
331 menu_items = f->menu_bar_vector;
332 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
333 submenu_start = (int *) alloca (ASIZE (items) * sizeof (int));
334 submenu_end = (int *) alloca (ASIZE (items) * sizeof (int));
335 submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int));
336 submenu_top_level_items = (int *) alloca (ASIZE (items) * sizeof (int));
337 init_menu_items ();
338 for (i = 0; i < ASIZE (items); i += 4)
339 {
340 Lisp_Object key, string, maps;
341
342 last_i = i;
343
344 key = AREF (items, i);
345 string = AREF (items, i + 1);
346 maps = AREF (items, i + 2);
347 if (NILP (string))
348 break;
349
350 submenu_start[i] = menu_items_used;
351
352 menu_items_n_panes = 0;
353 submenu_top_level_items[i]
354 = parse_single_submenu (key, string, maps);
355 submenu_n_panes[i] = menu_items_n_panes;
356
357 submenu_end[i] = menu_items_used;
358 }
359
360 finish_menu_items ();
361
362
363
364
365 wv = make_widget_value ("menubar", NULL, true, Qnil);
366 wv->button_type = BUTTON_TYPE_NONE;
367 first_wv = wv;
368
369 for (i = 0; i < last_i; i += 4)
370 {
371 menu_items_n_panes = submenu_n_panes[i];
372 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
373 submenu_top_level_items[i]);
374 if (prev_wv)
375 prev_wv->next = wv;
376 else
377 first_wv->contents = wv;
378
379 wv->enabled = true;
380 wv->button_type = BUTTON_TYPE_NONE;
381 prev_wv = wv;
382 }
383
384 set_buffer_internal_1 (prev);
385
386
387
388
389 for (i = 0; i < previous_menu_items_used; i++)
390 if (menu_items_used == i
391 || (!EQ (previous_items[i], AREF (menu_items, i))))
392 break;
393 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
394 {
395 free_menubar_widget_value_tree (first_wv);
396 discard_menu_items ();
397 unbind_to (specpdl_count, Qnil);
398 return;
399 }
400
401 fset_menu_bar_vector (f, menu_items);
402 f->menu_bar_items_used = menu_items_used;
403
404
405 unbind_to (specpdl_count, Qnil);
406
407
408
409
410
411
412 wv = first_wv->contents;
413 for (i = 0; i < ASIZE (items); i += 4)
414 {
415 Lisp_Object string;
416 string = AREF (items, i + 1);
417 if (NILP (string))
418 break;
419 wv->name = SSDATA (string);
420 update_submenu_strings (wv->contents);
421 wv = wv->next;
422 }
423 }
424 else
425 {
426
427
428
429 wv = make_widget_value ("menubar", NULL, true, Qnil);
430 wv->button_type = BUTTON_TYPE_NONE;
431 first_wv = wv;
432
433 items = FRAME_MENU_BAR_ITEMS (f);
434 for (i = 0; i < ASIZE (items); i += 4)
435 {
436 Lisp_Object string;
437
438 string = AREF (items, i + 1);
439 if (NILP (string))
440 break;
441
442 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
443 wv->button_type = BUTTON_TYPE_NONE;
444
445
446
447
448 wv->call_data = (void *) (EMACS_INT) (-1);
449
450 if (prev_wv)
451 prev_wv->next = wv;
452 else
453 first_wv->contents = wv;
454 prev_wv = wv;
455 }
456
457
458
459
460 f->menu_bar_items_used = 0;
461 }
462
463
464
465 block_input ();
466
467 if (menubar_widget)
468 {
469
470 while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
471 ;
472 }
473 else
474 {
475 menubar_widget = CreateMenu ();
476 }
477 fill_in_menu (menubar_widget, first_wv->contents);
478
479 free_menubar_widget_value_tree (first_wv);
480
481 {
482 HMENU old_widget = f->output_data.w32->menubar_widget;
483
484 f->output_data.w32->menubar_widget = menubar_widget;
485 SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
486
487
488
489
490
491 if (old_widget == NULL)
492 {
493 windows_or_buffers_changed = 23;
494 adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
495 }
496 }
497
498 unblock_input ();
499 }
500
501
502
503
504
505
506 void
507 initialize_frame_menubar (struct frame *f)
508 {
509
510
511 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
512 set_frame_menubar (f, true);
513 }
514
515
516
517
518 void
519 free_frame_menubar (struct frame *f)
520 {
521 block_input ();
522
523 {
524 HMENU old = GetMenu (FRAME_W32_WINDOW (f));
525 SetMenu (FRAME_W32_WINDOW (f), NULL);
526 f->output_data.w32->menubar_widget = NULL;
527 DestroyMenu (old);
528 }
529
530 unblock_input ();
531 }
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550 Lisp_Object
551 w32_menu_show (struct frame *f, int x, int y, int menuflags,
552 Lisp_Object title, const char **error)
553 {
554 int i;
555 int menu_item_selection;
556 HMENU menu;
557 POINT pos;
558 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
559 widget_value **submenu_stack;
560 Lisp_Object *subprefix_stack;
561 int submenu_depth = 0;
562 bool first_pane;
563
564 *error = NULL;
565
566 if (menu_items_n_panes == 0)
567 return Qnil;
568
569 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
570 {
571 *error = "Empty menu";
572 return Qnil;
573 }
574
575 USE_SAFE_ALLOCA;
576
577 submenu_stack = SAFE_ALLOCA (menu_items_used * sizeof (widget_value *));
578 subprefix_stack = SAFE_ALLOCA (menu_items_used * word_size);
579
580 block_input ();
581
582
583
584 wv = make_widget_value ("menu", NULL, true, Qnil);
585 wv->button_type = BUTTON_TYPE_NONE;
586 first_wv = wv;
587 first_pane = true;
588
589
590 i = 0;
591 while (i < menu_items_used)
592 {
593 if (NILP (AREF (menu_items, i)))
594 {
595 submenu_stack[submenu_depth++] = save_wv;
596 save_wv = prev_wv;
597 prev_wv = 0;
598 first_pane = false;
599 i++;
600 }
601 else if (EQ (AREF (menu_items, i), Qlambda))
602 {
603 prev_wv = save_wv;
604 save_wv = submenu_stack[--submenu_depth];
605 first_pane = false;
606 i++;
607 }
608 else if (EQ (AREF (menu_items, i), Qt)
609 && submenu_depth != 0)
610 i += MENU_ITEMS_PANE_LENGTH;
611
612
613 else if (EQ (AREF (menu_items, i), Qquote))
614 i += 1;
615 else if (EQ (AREF (menu_items, i), Qt))
616 {
617
618 Lisp_Object pane_name, prefix;
619 const char *pane_string;
620 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
621 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
622
623 if (STRINGP (pane_name))
624 {
625 if (unicode_append_menu)
626 pane_name = ENCODE_UTF_8 (pane_name);
627 else if (STRING_MULTIBYTE (pane_name))
628 pane_name = ENCODE_SYSTEM (pane_name);
629
630 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
631 }
632
633 pane_string = (NILP (pane_name)
634 ? "" : SSDATA (pane_name));
635
636
637 if (menu_items_n_panes == 1)
638 pane_string = "";
639
640
641
642
643 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
644 {
645 wv = make_widget_value (pane_string, NULL, true, Qnil);
646 if (save_wv)
647 save_wv->next = wv;
648 else
649 first_wv->contents = wv;
650 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
651 wv->name++;
652 wv->button_type = BUTTON_TYPE_NONE;
653 save_wv = wv;
654 prev_wv = 0;
655 }
656 else if (first_pane)
657 {
658 save_wv = wv;
659 prev_wv = 0;
660 }
661 first_pane = false;
662 i += MENU_ITEMS_PANE_LENGTH;
663 }
664 else
665 {
666
667 Lisp_Object item_name, enable, descrip, def, type, selected, help;
668
669 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
670 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
671 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
672 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
673 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
674 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
675 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
676
677 if (STRINGP (item_name))
678 {
679 if (unicode_append_menu)
680 item_name = ENCODE_UTF_8 (item_name);
681 else if (STRING_MULTIBYTE (item_name))
682 item_name = ENCODE_SYSTEM (item_name);
683
684 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
685 }
686
687 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
688 {
689 descrip = ENCODE_SYSTEM (descrip);
690 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
691 }
692
693 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
694 STRINGP (help) ? help : Qnil);
695 if (prev_wv)
696 prev_wv->next = wv;
697 else
698 save_wv->contents = wv;
699 if (!NILP (descrip))
700 wv->key = SSDATA (descrip);
701
702
703 wv->call_data = !NILP (def) ? (void *) (UINT_PTR) i : 0;
704
705 if (NILP (type))
706 wv->button_type = BUTTON_TYPE_NONE;
707 else if (EQ (type, QCtoggle))
708 wv->button_type = BUTTON_TYPE_TOGGLE;
709 else if (EQ (type, QCradio))
710 wv->button_type = BUTTON_TYPE_RADIO;
711 else
712 emacs_abort ();
713
714 wv->selected = !NILP (selected);
715
716 prev_wv = wv;
717
718 i += MENU_ITEMS_ITEM_LENGTH;
719 }
720 }
721
722
723 if (!NILP (title))
724 {
725 widget_value *wv_title;
726 widget_value *wv_sep = make_widget_value ("--", NULL, false, Qnil);
727
728
729
730 wv_sep->next = first_wv->contents;
731
732 if (unicode_append_menu)
733 title = ENCODE_UTF_8 (title);
734 else if (STRING_MULTIBYTE (title))
735 title = ENCODE_SYSTEM (title);
736
737 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
738 wv_title->title = TRUE;
739 wv_title->button_type = BUTTON_TYPE_NONE;
740 wv_title->next = wv_sep;
741 first_wv->contents = wv_title;
742 }
743
744
745 menu_item_selection = 0;
746
747
748 current_popup_menu = menu = CreatePopupMenu ();
749 fill_in_menu (menu, first_wv->contents);
750
751
752 pos.x = x;
753 pos.y = y;
754 ClientToScreen (FRAME_W32_WINDOW (f), &pos);
755
756
757 menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
758 WM_EMACS_TRACKPOPUPMENU,
759 (WPARAM)menu, (LPARAM)&pos);
760
761
762
763 discard_mouse_events ();
764 FRAME_DISPLAY_INFO (f)->grabbed = 0;
765
766
767 free_menubar_widget_value_tree (first_wv);
768
769 DestroyMenu (menu);
770
771
772 w32_free_menu_strings (FRAME_W32_WINDOW (f));
773 f->output_data.w32->menubar_active = 0;
774
775
776
777 if (menu_item_selection != 0)
778 {
779 Lisp_Object prefix, entry;
780
781 prefix = entry = Qnil;
782 i = 0;
783 while (i < menu_items_used)
784 {
785 if (NILP (AREF (menu_items, i)))
786 {
787 subprefix_stack[submenu_depth++] = prefix;
788 prefix = entry;
789 i++;
790 }
791 else if (EQ (AREF (menu_items, i), Qlambda))
792 {
793 prefix = subprefix_stack[--submenu_depth];
794 i++;
795 }
796 else if (EQ (AREF (menu_items, i), Qt))
797 {
798 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
799 i += MENU_ITEMS_PANE_LENGTH;
800 }
801
802
803 else if (EQ (AREF (menu_items, i), Qquote))
804 i += 1;
805 else
806 {
807 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
808 if (menu_item_selection == i)
809 {
810 if (menuflags & MENU_KEYMAPS)
811 {
812 int j;
813
814 entry = Fcons (entry, Qnil);
815 if (!NILP (prefix))
816 entry = Fcons (prefix, entry);
817 for (j = submenu_depth - 1; j >= 0; j--)
818 if (!NILP (subprefix_stack[j]))
819 entry = Fcons (subprefix_stack[j], entry);
820 }
821 unblock_input ();
822 SAFE_FREE ();
823 return entry;
824 }
825 i += MENU_ITEMS_ITEM_LENGTH;
826 }
827 }
828 }
829 else if (!(menuflags & MENU_FOR_CLICK))
830 {
831 unblock_input ();
832
833 quit ();
834 }
835
836 unblock_input ();
837 SAFE_FREE ();
838 return Qnil;
839 }
840
841
842 #ifdef HAVE_DIALOGS
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866 static char * button_names [] = {
867 "button1", "button2", "button3", "button4", "button5",
868 "button6", "button7", "button8", "button9", "button10" };
869
870 static Lisp_Object
871 w32_dialog_show (struct frame *f, Lisp_Object title,
872 Lisp_Object header, char **error)
873 {
874 int i, nb_buttons = 0;
875 char dialog_name[6];
876 int menu_item_selection;
877
878 widget_value *wv, *first_wv = 0, *prev_wv = 0;
879
880
881 int left_count = 0;
882
883
884 bool boundary_seen = false;
885
886 *error = NULL;
887
888 if (menu_items_n_panes > 1)
889 {
890 *error = "Multiple panes in dialog box";
891 return Qnil;
892 }
893
894
895
896 {
897 Lisp_Object pane_name;
898 char *pane_string;
899 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
900 pane_string = (NILP (pane_name)
901 ? "" : SSDATA (pane_name));
902 prev_wv = make_widget_value ("message", pane_string, true, Qnil);
903 first_wv = prev_wv;
904
905
906 i = MENU_ITEMS_PANE_LENGTH;
907 while (i < menu_items_used)
908 {
909
910
911 Lisp_Object item_name, enable, descrip, help;
912
913 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
914 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
915 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
916 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
917
918 if (NILP (item_name))
919 {
920 free_menubar_widget_value_tree (first_wv);
921 *error = "Submenu in dialog items";
922 return Qnil;
923 }
924 if (EQ (item_name, Qquote))
925 {
926
927
928 boundary_seen = true;
929 i++;
930 continue;
931 }
932 if (nb_buttons >= 9)
933 {
934 free_menubar_widget_value_tree (first_wv);
935 *error = "Too many dialog items";
936 return Qnil;
937 }
938
939 wv = make_widget_value (button_names[nb_buttons],
940 SSDATA (item_name),
941 !NILP (enable), Qnil);
942 prev_wv->next = wv;
943 if (!NILP (descrip))
944 wv->key = SSDATA (descrip);
945 wv->call_data = aref_addr (menu_items, i);
946 prev_wv = wv;
947
948 if (! boundary_seen)
949 left_count++;
950
951 nb_buttons++;
952 i += MENU_ITEMS_ITEM_LENGTH;
953 }
954
955
956
957 if (! boundary_seen)
958 left_count = nb_buttons - nb_buttons / 2;
959
960 wv = make_widget_value (dialog_name, NULL, false, Qnil);
961
962
963
964
965 if (NILP (header))
966 dialog_name[0] = 'Q';
967 else
968 dialog_name[0] = 'I';
969
970
971
972
973 dialog_name[1] = '0' + nb_buttons;
974 dialog_name[2] = 'B';
975 dialog_name[3] = 'R';
976
977 dialog_name[4] = '0' + nb_buttons - left_count;
978 dialog_name[5] = 0;
979 wv->contents = first_wv;
980 first_wv = wv;
981 }
982
983
984 dialog_id = widget_id_tick++;
985 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
986 f->output_data.w32->widget, true, 0,
987 dialog_selection_callback, 0);
988 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
989
990
991 free_menubar_widget_value_tree (first_wv);
992
993
994 menu_item_selection = 0;
995
996
997 lw_pop_up_all_widgets (dialog_id);
998
999
1000 popup_get_selection ((XEvent *) 0, FRAME_DISPLAY_INFO (f), dialog_id);
1001
1002 lw_destroy_all_widgets (dialog_id);
1003
1004
1005
1006 if (menu_item_selection != 0)
1007 {
1008 i = 0;
1009 while (i < menu_items_used)
1010 {
1011 Lisp_Object entry;
1012
1013 if (EQ (AREF (menu_items, i), Qt))
1014 i += MENU_ITEMS_PANE_LENGTH;
1015 else
1016 {
1017 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1018 if (menu_item_selection == i)
1019 return entry;
1020 i += MENU_ITEMS_ITEM_LENGTH;
1021 }
1022 }
1023 }
1024 else
1025
1026 quit ();
1027
1028 return Qnil;
1029 }
1030 #else
1031
1032
1033
1034
1035
1036
1037 static bool
1038 is_simple_dialog (Lisp_Object contents)
1039 {
1040 Lisp_Object options;
1041 Lisp_Object name, yes, no, other;
1042
1043 if (!CONSP (contents))
1044 return false;
1045 options = XCDR (contents);
1046
1047 yes = build_string ("Yes");
1048 no = build_string ("No");
1049
1050 if (!CONSP (options))
1051 return false;
1052
1053 name = XCAR (options);
1054 if (!CONSP (name))
1055 return false;
1056 name = XCAR (name);
1057
1058 if (!NILP (Fstring_equal (name, yes)))
1059 other = no;
1060 else if (!NILP (Fstring_equal (name, no)))
1061 other = yes;
1062 else
1063 return false;
1064
1065 options = XCDR (options);
1066 if (!CONSP (options))
1067 return false;
1068
1069 name = XCAR (options);
1070 if (!CONSP (name))
1071 return false;
1072 name = XCAR (name);
1073 if (NILP (Fstring_equal (name, other)))
1074 return false;
1075
1076
1077
1078
1079
1080 options = XCDR (options);
1081 return !(CONSP (options));
1082 }
1083
1084 static Lisp_Object
1085 simple_dialog_show (struct frame *f, Lisp_Object contents, Lisp_Object header)
1086 {
1087 int answer;
1088 UINT type;
1089 Lisp_Object lispy_answer = Qnil, temp = XCAR (contents);
1090
1091
1092
1093
1094 if (w32_yes_no_dialog_show_cancel)
1095 type = MB_YESNOCANCEL;
1096 else
1097 type = MB_YESNO;
1098
1099
1100
1101
1102
1103
1104 if (unicode_message_box)
1105 {
1106 WCHAR *text;
1107 const WCHAR *title;
1108 USE_SAFE_ALLOCA;
1109
1110 if (STRINGP (temp))
1111 {
1112 char *utf8_text = SSDATA (ENCODE_UTF_8 (temp));
1113
1114
1115
1116
1117 int utf8_len = strlen (utf8_text);
1118 text = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
1119 utf8to16 ((unsigned char *)utf8_text, utf8_len, text);
1120 }
1121 else
1122 {
1123 text = (WCHAR *)L"";
1124 }
1125
1126 if (NILP (header))
1127 {
1128 title = L"Question";
1129 type |= MB_ICONQUESTION;
1130 }
1131 else
1132 {
1133 title = L"Information";
1134 type |= MB_ICONINFORMATION;
1135 }
1136
1137 answer = unicode_message_box (FRAME_W32_WINDOW (f), text, title, type);
1138 SAFE_FREE ();
1139 }
1140 else
1141 {
1142 const char *text, *title;
1143
1144
1145
1146
1147 if (STRINGP (temp))
1148 text = SSDATA (ENCODE_SYSTEM (temp));
1149 else
1150 text = "";
1151
1152 if (NILP (header))
1153 {
1154 title = "Question";
1155 type |= MB_ICONQUESTION;
1156 }
1157 else
1158 {
1159 title = "Information";
1160 type |= MB_ICONINFORMATION;
1161 }
1162
1163 answer = MessageBox (FRAME_W32_WINDOW (f), text, title, type);
1164 }
1165
1166 if (answer == IDYES)
1167 lispy_answer = build_string ("Yes");
1168 else if (answer == IDNO)
1169 lispy_answer = build_string ("No");
1170 else
1171 quit ();
1172
1173 for (temp = XCDR (contents); CONSP (temp); temp = XCDR (temp))
1174 {
1175 Lisp_Object item, name, value;
1176 item = XCAR (temp);
1177 if (CONSP (item))
1178 {
1179 name = XCAR (item);
1180 value = XCDR (item);
1181 }
1182 else
1183 {
1184 name = item;
1185 value = Qnil;
1186 }
1187
1188 if (!NILP (Fstring_equal (name, lispy_answer)))
1189 {
1190 return value;
1191 }
1192 }
1193 return quit ();
1194 }
1195 #endif
1196
1197
1198
1199 static void
1200 utf8to16 (unsigned char * src, int len, WCHAR * dest)
1201 {
1202 while (len > 0)
1203 {
1204 if (*src < 0x80)
1205 {
1206 *dest = (WCHAR) *src;
1207 dest++; src++; len--;
1208 }
1209
1210 else if (*src < 0xC0)
1211 {
1212 src++; len--;
1213 }
1214
1215 else if (*src < 0xE0)
1216 {
1217 *dest = (WCHAR) (((*src & 0x1f) << 6)
1218 | (*(src + 1) & 0x3f));
1219 src += 2; len -= 2; dest++;
1220 }
1221 else if (*src < 0xF0)
1222 {
1223 *dest = (WCHAR) (((*src & 0x0f) << 12)
1224 | ((*(src + 1) & 0x3f) << 6)
1225 | (*(src + 2) & 0x3f));
1226 src += 3; len -= 3; dest++;
1227 }
1228 else
1229 {
1230 *dest = (WCHAR) 0xfffd;
1231 src++; len--; dest++;
1232 }
1233 }
1234 *dest = 0;
1235 }
1236
1237 static int
1238 add_menu_item (HMENU menu, widget_value *wv, HMENU item)
1239 {
1240 UINT fuFlags;
1241 char *out_string, *p, *q;
1242 int return_value;
1243 size_t nlen, orig_len;
1244 USE_SAFE_ALLOCA;
1245
1246 if (menu_separator_name_p (wv->name))
1247 {
1248 fuFlags = MF_SEPARATOR;
1249 out_string = NULL;
1250 }
1251 else
1252 {
1253 if (wv->enabled)
1254 fuFlags = MF_STRING;
1255 else
1256 fuFlags = MF_STRING | MF_GRAYED;
1257
1258 if (wv->key != NULL)
1259 {
1260 out_string = SAFE_ALLOCA (strlen (wv->name) + strlen (wv->key) + 2);
1261 p = stpcpy (out_string, wv->name);
1262 p = stpcpy (p, "\t");
1263 strcpy (p, wv->key);
1264 }
1265 else
1266 out_string = (char *)wv->name;
1267
1268
1269
1270 nlen = orig_len = strlen (out_string);
1271 if (unicode_append_menu)
1272 {
1273
1274 for (p = out_string; *p; p++)
1275 {
1276 if (*p == '&')
1277 nlen++;
1278 }
1279 }
1280 #ifndef NTGUI_UNICODE
1281 else
1282 {
1283
1284
1285 for (p = out_string; *p; p = _mbsinc (p))
1286 {
1287 if (_mbsnextc (p) == '&')
1288 nlen++;
1289 }
1290 }
1291 #endif
1292
1293 if (nlen > orig_len)
1294 {
1295 p = out_string;
1296 out_string = SAFE_ALLOCA (nlen + 1);
1297 q = out_string;
1298 while (*p)
1299 {
1300 if (unicode_append_menu)
1301 {
1302 if (*p == '&')
1303 *q++ = *p;
1304 *q++ = *p++;
1305 }
1306 #ifndef NTGUI_UNICODE
1307 else
1308 {
1309 if (_mbsnextc (p) == '&')
1310 {
1311 _mbsncpy (q, p, 1);
1312 q = _mbsinc (q);
1313 }
1314 _mbsncpy (q, p, 1);
1315 p = _mbsinc (p);
1316 q = _mbsinc (q);
1317 }
1318 #endif
1319 }
1320 *q = '\0';
1321 }
1322
1323 if (item != NULL)
1324 fuFlags = MF_POPUP;
1325 else if (wv->title || wv->call_data == 0)
1326 {
1327
1328
1329 if (get_menu_item_info)
1330 {
1331 out_string = (char *) local_alloc (strlen (wv->name) + 1);
1332 strcpy (out_string, wv->name);
1333 #ifdef MENU_DEBUG
1334 DebPrint ("Menu: allocating %ld for owner-draw", out_string);
1335 #endif
1336 fuFlags = MF_OWNERDRAW | MF_DISABLED;
1337 }
1338 else
1339 fuFlags = MF_DISABLED;
1340 }
1341
1342
1343 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
1344 wv->button_type == BUTTON_TYPE_RADIO))
1345 fuFlags |= MF_CHECKED;
1346 else
1347 fuFlags |= MF_UNCHECKED;
1348 }
1349
1350 if (unicode_append_menu && out_string)
1351 {
1352
1353 int utf8_len = strlen (out_string);
1354 WCHAR * utf16_string;
1355 if (fuFlags & MF_OWNERDRAW)
1356 utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
1357 else
1358 utf16_string = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
1359
1360 utf8to16 ((unsigned char *)out_string, utf8_len, utf16_string);
1361 return_value = unicode_append_menu (menu, fuFlags,
1362 item != NULL ? (UINT_PTR) item
1363 : (UINT_PTR) wv->call_data,
1364 utf16_string);
1365
1366 #ifndef NTGUI_UNICODE
1367 if (!return_value)
1368 {
1369
1370
1371
1372
1373
1374
1375 return_value =
1376 AppendMenu (menu, fuFlags,
1377 item != NULL ? (UINT_PTR) item: (UINT_PTR) wv->call_data,
1378 out_string);
1379
1380
1381
1382 if (osinfo_cache.dwPlatformId != VER_PLATFORM_WIN32_NT)
1383 unicode_append_menu = NULL;
1384 }
1385 #endif
1386
1387 if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
1388 local_free (out_string);
1389 }
1390 else
1391 {
1392 return_value =
1393 AppendMenu (menu,
1394 fuFlags,
1395 item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data,
1396 out_string );
1397 }
1398
1399
1400 if (!wv->title && wv->call_data != 0)
1401 {
1402 if (set_menu_item_info)
1403 {
1404 MENUITEMINFO info;
1405 memset (&info, 0, sizeof (info));
1406 info.cbSize = sizeof (info);
1407 info.fMask = MIIM_DATA;
1408
1409
1410
1411
1412 if (!NILP (wv->help))
1413 {
1414
1415
1416
1417
1418
1419
1420
1421
1422 eassert (STRINGP (wv->help));
1423 info.dwItemData = (ULONG_PTR) XUNTAG (wv->help, Lisp_String,
1424 struct Lisp_String);
1425 }
1426 if (wv->button_type == BUTTON_TYPE_RADIO)
1427 {
1428
1429
1430 info.fMask |= MIIM_TYPE | MIIM_STATE;
1431 info.fType = MFT_RADIOCHECK | MFT_STRING;
1432 info.dwTypeData = out_string;
1433 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
1434 }
1435
1436 set_menu_item_info (menu,
1437 item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data,
1438 FALSE, &info);
1439 }
1440 }
1441 SAFE_FREE ();
1442 return return_value;
1443 }
1444
1445
1446 static int
1447 fill_in_menu (HMENU menu, widget_value *wv)
1448 {
1449 for ( ; wv != NULL; wv = wv->next)
1450 {
1451 if (wv->contents)
1452 {
1453 HMENU sub_menu = CreatePopupMenu ();
1454
1455 if (sub_menu == NULL)
1456 return 0;
1457
1458 if (!fill_in_menu (sub_menu, wv->contents) ||
1459 !add_menu_item (menu, wv, sub_menu))
1460 {
1461 DestroyMenu (sub_menu);
1462 return 0;
1463 }
1464 }
1465 else
1466 {
1467 if (!add_menu_item (menu, wv, NULL))
1468 return 0;
1469 }
1470 }
1471 return 1;
1472 }
1473
1474
1475
1476
1477 void w32_menu_display_help (HWND, HMENU, UINT, UINT);
1478
1479 void
1480 w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
1481 {
1482 if (get_menu_item_info)
1483 {
1484 struct frame *f = w32_window_to_frame (&one_w32_display_info, owner);
1485 Lisp_Object frame, help;
1486
1487
1488
1489
1490 if ((flags & MF_OWNERDRAW) || (flags & MF_POPUP)
1491 || !(flags & MF_MOUSESELECT)
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504 || !(flags & MF_HILITE))
1505 help = Qnil;
1506 else
1507 {
1508 MENUITEMINFO info;
1509
1510 memset (&info, 0, sizeof (info));
1511 info.cbSize = sizeof (info);
1512 info.fMask = MIIM_DATA;
1513 get_menu_item_info (menu, item, FALSE, &info);
1514
1515 help =
1516 info.dwItemData
1517 ? make_lisp_ptr ((void *) info.dwItemData, Lisp_String)
1518 : Qnil;
1519 }
1520
1521
1522
1523
1524
1525 if (f)
1526 {
1527 XSETFRAME (frame, f);
1528 kbd_buffer_store_help_event (frame, help);
1529 }
1530 else
1531
1532
1533 show_help_echo (help, Qnil, Qnil, Qnil);
1534 }
1535 }
1536
1537
1538 static void
1539 w32_free_submenu_strings (HMENU menu)
1540 {
1541 int i, num = GetMenuItemCount (menu);
1542 for (i = 0; i < num; i++)
1543 {
1544 MENUITEMINFO info;
1545 memset (&info, 0, sizeof (info));
1546 info.cbSize = sizeof (info);
1547 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
1548
1549 get_menu_item_info (menu, i, TRUE, &info);
1550
1551
1552 if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
1553 {
1554 #ifdef MENU_DEBUG
1555 DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
1556 #endif
1557 local_free (info.dwItemData);
1558 }
1559
1560
1561 if (info.hSubMenu)
1562 w32_free_submenu_strings (info.hSubMenu);
1563 }
1564 }
1565
1566 void
1567 w32_free_menu_strings (HWND hwnd)
1568 {
1569 HMENU menu = current_popup_menu;
1570
1571 if (get_menu_item_info)
1572 {
1573
1574
1575 if (!menu)
1576 menu = GetMenu (hwnd);
1577
1578 if (menu)
1579 w32_free_submenu_strings (menu);
1580 }
1581
1582 current_popup_menu = NULL;
1583 }
1584
1585
1586
1587 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1588 doc: )
1589 (void)
1590 {
1591 struct frame *f;
1592 f = SELECTED_FRAME ();
1593 return (f->output_data.w32->menubar_active > 0) ? Qt : Qnil;
1594 }
1595
1596 void
1597 syms_of_w32menu (void)
1598 {
1599 globals_of_w32menu ();
1600
1601 current_popup_menu = NULL;
1602 PDUMPER_IGNORE (current_popup_menu);
1603
1604 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
1605 DEFSYM (Qunsupported__w32_dialog, "unsupported--w32-dialog");
1606
1607 defsubr (&Smenu_or_popup_active_p);
1608 }
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618 void
1619 globals_of_w32menu (void)
1620 {
1621 #ifndef NTGUI_UNICODE
1622
1623 HMODULE user32 = GetModuleHandle ("user32.dll");
1624 get_menu_item_info = (GetMenuItemInfoA_Proc)
1625 get_proc_addr (user32, "GetMenuItemInfoA");
1626 set_menu_item_info = (SetMenuItemInfoA_Proc)
1627 get_proc_addr (user32, "SetMenuItemInfoA");
1628 unicode_append_menu = (AppendMenuW_Proc)
1629 get_proc_addr (user32, "AppendMenuW");
1630 unicode_message_box = (MessageBoxW_Proc)
1631 get_proc_addr (user32, "MessageBoxW");
1632 #endif
1633 }