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