This source file includes following definitions.
- menubar_id_to_frame
- x_menu_set_in_use
- x_menu_wait_for_event
- x_menu_translate_generic_event
- x_menu_dispatch_event
- popup_get_selection
- DEFUN
- DEFUN
- popup_widget_loop
- x_activate_menubar
- popup_activate_callback
- popup_deactivate_callback
- show_help_event
- menu_highlight_callback
- menu_highlight_callback
- menubar_selection_callback
- menubar_selection_callback
- update_frame_menubar
- apply_systemfont_to_dialog
- apply_systemfont_to_menu
- set_frame_menubar
- initialize_frame_menubar
- free_frame_menubar
- menu_position_func
- popup_selection_callback
- pop_down_menu
- create_and_show_popup_menu
- popup_selection_callback
- prepare_for_entry_into_toolkit_menu
- leave_toolkit_menu
- pop_down_menu
- server_timestamp_predicate
- create_and_show_popup_menu
- cleanup_widget_value_tree
- x_menu_show
- dialog_selection_callback
- create_and_show_dialog
- dialog_selection_callback
- create_and_show_dialog
- x_dialog_show
- xw_popup_dialog
- menu_help_callback
- pop_down_menu
- x_menu_show
- popup_activated
- DEFUN
- syms_of_xmenu
- syms_of_xmenu_for_pdumper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include <config.h>
35
36 #include <stdio.h>
37
38 #include "lisp.h"
39 #include "keyboard.h"
40 #include "frame.h"
41 #include "systime.h"
42 #include "termhooks.h"
43 #include "window.h"
44 #include "blockinput.h"
45 #include "buffer.h"
46 #include "coding.h"
47 #include "sysselect.h"
48 #include "pdumper.h"
49
50 #ifdef MSDOS
51 #include "msdos.h"
52 #endif
53
54 #ifdef HAVE_XINPUT2
55 #include <math.h>
56 #include <X11/extensions/XInput2.h>
57 #endif
58
59 #ifdef HAVE_X_WINDOWS
60
61
62 #include "xterm.h"
63 #endif
64
65
66
67 #ifndef makedev
68 #include <sys/types.h>
69 #endif
70
71 #ifdef HAVE_X_WINDOWS
72
73
74 #undef HAVE_MULTILINGUAL_MENU
75 #ifdef USE_X_TOOLKIT
76 #include "widget.h"
77 #include <X11/Xlib.h>
78 #include <X11/IntrinsicP.h>
79 #include <X11/CoreP.h>
80 #include <X11/StringDefs.h>
81 #include <X11/Shell.h>
82 #ifdef USE_LUCID
83 #include "xsettings.h"
84 #include "../lwlib/xlwmenu.h"
85 #ifdef HAVE_XAW3D
86 #include <X11/Xaw3d/Paned.h>
87 #else
88 #include <X11/Xaw/Paned.h>
89 #endif
90 #endif
91 #ifdef USE_MOTIF
92 #include "../lwlib/lwlib.h"
93 #endif
94 #else
95 #ifndef USE_GTK
96 #include "../oldXMenu/XMenu.h"
97 #endif
98 #endif
99 #endif
100
101 #ifdef USE_GTK
102 #include "gtkutil.h"
103 #ifdef HAVE_GTK3
104 #include "xgselect.h"
105 #endif
106 #endif
107
108 #include "menu.h"
109
110
111
112
113 #ifndef HAVE_XINPUT2
114 static int popup_activated_flag;
115 #else
116 int popup_activated_flag;
117 #endif
118
119
120 #ifdef USE_X_TOOLKIT
121
122 static LWLIB_ID next_menubar_widget_id;
123
124
125
126 static struct frame *
127 menubar_id_to_frame (LWLIB_ID id)
128 {
129 Lisp_Object tail, frame;
130 struct frame *f;
131
132 FOR_EACH_FRAME (tail, frame)
133 {
134 f = XFRAME (frame);
135 if (!FRAME_WINDOW_P (f))
136 continue;
137 if (f->output_data.x->id == id)
138 return f;
139 }
140 return 0;
141 }
142
143 #endif
144
145 #ifndef MSDOS
146
147 #if defined USE_GTK || defined USE_MOTIF
148
149
150
151 void
152 x_menu_set_in_use (bool in_use)
153 {
154 Lisp_Object frames, frame;
155
156 menu_items_inuse = in_use;
157 popup_activated_flag = in_use;
158 #ifdef USE_X_TOOLKIT
159 if (popup_activated_flag)
160 x_activate_timeout_atimer ();
161 #endif
162
163
164 FOR_EACH_FRAME (frames, frame)
165 {
166 struct frame *f = XFRAME (frame);
167
168 if (in_use && FRAME_Z_GROUP_ABOVE (f))
169 x_set_z_group (f, Qabove_suspended, Qabove);
170 else if (!in_use && FRAME_Z_GROUP_ABOVE_SUSPENDED (f))
171 x_set_z_group (f, Qabove, Qabove_suspended);
172 }
173 }
174 #endif
175
176
177
178 void
179 x_menu_wait_for_event (void *data)
180 {
181
182
183
184
185
186 while (
187 #if defined USE_X_TOOLKIT
188 ! (data ? XPending (data) : XtAppPending (Xt_app_con))
189 #elif defined USE_GTK
190 ! gtk_events_pending ()
191 #else
192 ! XPending (data)
193 #endif
194 )
195 {
196 struct timespec next_time = timer_check (), *ntp;
197 fd_set read_fds;
198 struct x_display_info *dpyinfo;
199 int n = 0;
200
201
202
203 x_handle_pending_selection_requests ();
204
205 FD_ZERO (&read_fds);
206 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
207 {
208 int fd = ConnectionNumber (dpyinfo->display);
209 FD_SET (fd, &read_fds);
210 if (fd > n) n = fd;
211 XFlush (dpyinfo->display);
212 }
213
214 if (! timespec_valid_p (next_time))
215 ntp = 0;
216 else
217 ntp = &next_time;
218
219 #if defined USE_GTK && defined HAVE_GTK3
220
221
222
223 xg_select (n + 1, &read_fds, NULL, NULL, ntp, NULL);
224 #else
225 pselect (n + 1, &read_fds, NULL, NULL, ntp, NULL);
226 #endif
227 }
228 }
229
230 #if !defined USE_GTK && !defined USE_X_TOOLKIT && defined HAVE_XINPUT2
231 static void
232 x_menu_translate_generic_event (XEvent *event)
233 {
234 struct x_display_info *dpyinfo;
235 struct xi_device_t *device;
236 XEvent copy;
237 XIDeviceEvent *xev;
238
239 dpyinfo = x_display_info_for_display (event->xgeneric.display);
240
241 if (event->xgeneric.extension == dpyinfo->xi2_opcode)
242 {
243 eassert (!event->xcookie.data);
244
245 switch (event->xcookie.evtype)
246 {
247 case XI_ButtonPress:
248 case XI_ButtonRelease:
249
250 if (!XGetEventData (dpyinfo->display, &event->xcookie))
251 break;
252
253 xev = (XIDeviceEvent *) event->xcookie.data;
254 copy.xbutton.type = (event->xcookie.evtype == XI_ButtonPress
255 ? ButtonPress : ButtonRelease);
256 copy.xbutton.serial = xev->serial;
257 copy.xbutton.send_event = xev->send_event;
258 copy.xbutton.display = dpyinfo->display;
259 copy.xbutton.window = xev->event;
260 copy.xbutton.root = xev->root;
261 copy.xbutton.subwindow = xev->child;
262 copy.xbutton.time = xev->time;
263 copy.xbutton.x = lrint (xev->event_x);
264 copy.xbutton.y = lrint (xev->event_y);
265 copy.xbutton.x_root = lrint (xev->root_x);
266 copy.xbutton.y_root = lrint (xev->root_y);
267 copy.xbutton.state = xi_convert_event_state (xev);
268 copy.xbutton.button = xev->detail;
269 copy.xbutton.same_screen = True;
270
271 device = xi_device_from_id (dpyinfo, xev->deviceid);
272
273
274
275
276
277
278 if (device && xev->evtype == XI_ButtonRelease)
279 device->grab &= ~(1 << xev->detail);
280
281 XPutBackEvent (dpyinfo->display, ©);
282 XFreeEventData (dpyinfo->display, &event->xcookie);
283
284 break;
285
286 case XI_HierarchyChanged:
287 case XI_DeviceChanged:
288
289 x_dispatch_event (event, dpyinfo->display);
290 break;
291 }
292 }
293 }
294 #endif
295
296 #if !defined USE_X_TOOLKIT && !defined USE_GTK
297 static int
298 x_menu_dispatch_event (XEvent *event)
299 {
300 x_dispatch_event (event, event->xexpose.display);
301
302
303 return 0;
304 }
305 #endif
306 #endif
307
308
309 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
310
311 #ifdef USE_X_TOOLKIT
312
313
314
315
316
317
318
319
320 static void
321 popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo,
322 LWLIB_ID id, bool do_timers)
323 {
324 XEvent event;
325 XEvent copy;
326 #ifdef HAVE_XINPUT2
327 bool cookie_claimed_p = false;
328 XIDeviceEvent *xev;
329 struct xi_device_t *device;
330 #endif
331
332 while (popup_activated_flag)
333 {
334 if (initial_event)
335 {
336 copy = event = *initial_event;
337 initial_event = 0;
338 }
339 else
340 {
341 if (do_timers) x_menu_wait_for_event (0);
342 XtAppNextEvent (Xt_app_con, &event);
343 copy = event;
344 }
345
346
347
348
349 if (event.type == ButtonRelease
350 && dpyinfo->display == event.xbutton.display)
351 {
352 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
353 #ifdef USE_MOTIF
354
355
356
357 event.xbutton.button = 1;
358
359
360
361 event.xbutton.state = 0;
362 #endif
363 copy = event;
364 }
365
366 else if (event.type == KeyPress
367 && dpyinfo->display == event.xbutton.display)
368 {
369 KeySym keysym = XLookupKeysym (&event.xkey, 0);
370
371 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
372 || keysym == XK_Escape)
373 popup_activated_flag = 0;
374
375 copy = event;
376 }
377 #ifdef HAVE_XINPUT2
378 else if (event.type == GenericEvent
379 && dpyinfo->supports_xi2
380 && event.xgeneric.display == dpyinfo->display
381 && event.xgeneric.extension == dpyinfo->xi2_opcode)
382 {
383 if (!event.xcookie.data
384 && XGetEventData (dpyinfo->display, &event.xcookie))
385 cookie_claimed_p = true;
386
387 if (event.xcookie.data)
388 {
389 switch (event.xgeneric.evtype)
390 {
391 case XI_ButtonRelease:
392 {
393 xev = (XIDeviceEvent *) event.xcookie.data;
394 device = xi_device_from_id (dpyinfo, xev->deviceid);
395
396 dpyinfo->grabbed &= ~(1 << xev->detail);
397 device->grab &= ~(1 << xev->detail);
398
399 copy.xbutton.type = ButtonRelease;
400 copy.xbutton.serial = xev->serial;
401 copy.xbutton.send_event = xev->send_event;
402 copy.xbutton.display = dpyinfo->display;
403 copy.xbutton.window = xev->event;
404 copy.xbutton.root = xev->root;
405 copy.xbutton.subwindow = xev->child;
406 copy.xbutton.time = xev->time;
407 copy.xbutton.x = lrint (xev->event_x);
408 copy.xbutton.y = lrint (xev->event_y);
409 copy.xbutton.x_root = lrint (xev->root_x);
410 copy.xbutton.y_root = lrint (xev->root_y);
411 copy.xbutton.state = xi_convert_event_state (xev);
412 copy.xbutton.button = xev->detail;
413 copy.xbutton.same_screen = True;
414
415 #ifdef USE_MOTIF
416
417
418
419 copy.xbutton.button = 1;
420
421
422
423 copy.xbutton.state = 0;
424 #endif
425
426 break;
427 }
428 case XI_KeyPress:
429 {
430 KeySym keysym;
431
432 xev = (XIDeviceEvent *) event.xcookie.data;
433
434 copy.xkey.type = KeyPress;
435 copy.xkey.serial = xev->serial;
436 copy.xkey.send_event = xev->send_event;
437 copy.xkey.display = dpyinfo->display;
438 copy.xkey.window = xev->event;
439 copy.xkey.root = xev->root;
440 copy.xkey.subwindow = xev->child;
441 copy.xkey.time = xev->time;
442 copy.xkey.x = lrint (xev->event_x);
443 copy.xkey.y = lrint (xev->event_y);
444 copy.xkey.x_root = lrint (xev->root_x);
445 copy.xkey.y_root = lrint (xev->root_y);
446 copy.xkey.state = xi_convert_event_state (xev);
447 copy.xkey.keycode = xev->detail;
448 copy.xkey.same_screen = True;
449
450 keysym = XLookupKeysym (©.xkey, 0);
451
452 if ((keysym == XK_g
453 && (copy.xkey.state & ControlMask) != 0)
454 || keysym == XK_Escape)
455 popup_activated_flag = 0;
456
457 break;
458 }
459 }
460 }
461 }
462
463 if (cookie_claimed_p)
464 XFreeEventData (dpyinfo->display, &event.xcookie);
465 #endif
466
467 x_dispatch_event (©, copy.xany.display);
468 }
469 }
470
471 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
472 doc: )
473 (Lisp_Object frame)
474 {
475 XEvent ev;
476 struct frame *f = decode_window_system_frame (frame);
477 #if defined USE_X_TOOLKIT && defined HAVE_XINPUT2
478 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
479 #endif
480 Widget menubar;
481 block_input ();
482
483 if (FRAME_EXTERNAL_MENU_BAR (f))
484 set_frame_menubar (f, true);
485
486 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
487 if (menubar)
488 {
489 Window child;
490 bool error_p = false;
491
492 #if defined USE_X_TOOLKIT && defined HAVE_XINPUT2
493
494
495
496
497 if (dpyinfo->supports_xi2
498 && xi_frame_selected_for (f, XI_ButtonPress))
499 {
500 for (int i = 0; i < dpyinfo->num_devices; ++i)
501 {
502
503
504 #ifndef USE_LUCID
505 if (dpyinfo->devices[i].grab)
506 #endif
507 {
508 XIUngrabDevice (dpyinfo->display,
509 dpyinfo->devices[i].device_id,
510 CurrentTime);
511 dpyinfo->devices[i].grab = 0;
512 }
513 }
514 }
515 #endif
516
517 x_catch_errors (FRAME_X_DISPLAY (f));
518 memset (&ev, 0, sizeof ev);
519 ev.xbutton.display = FRAME_X_DISPLAY (f);
520 ev.xbutton.window = XtWindow (menubar);
521 ev.xbutton.root = FRAME_DISPLAY_INFO (f)->root_window;
522 #ifndef HAVE_XINPUT2
523 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
524 #else
525 ev.xbutton.time = ((dpyinfo->supports_xi2
526 && xi_frame_selected_for (f, XI_KeyPress))
527 ? dpyinfo->last_user_time
528 : XtLastTimestampProcessed (dpyinfo->display));
529 #endif
530 ev.xbutton.button = Button1;
531 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
532 ev.xbutton.same_screen = True;
533
534 #ifdef USE_MOTIF
535 {
536 Arg al[2];
537 WidgetList list;
538 Cardinal nr;
539 XtSetArg (al[0], XtNchildren, &list);
540 XtSetArg (al[1], XtNnumChildren, &nr);
541 XtGetValues (menubar, al, 2);
542 ev.xbutton.window = XtWindow (list[0]);
543 }
544 #endif
545
546 XTranslateCoordinates (FRAME_X_DISPLAY (f),
547
548 ev.xbutton.window, ev.xbutton.root,
549
550
551 ev.xbutton.x, ev.xbutton.y,
552 &ev.xbutton.x_root, &ev.xbutton.y_root,
553
554
555 &child);
556 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
557 x_uncatch_errors_after_check ();
558
559 if (! error_p)
560 {
561 ev.type = ButtonPress;
562 ev.xbutton.state = 0;
563
564 XtDispatchEvent (&ev);
565 ev.xbutton.type = ButtonRelease;
566 ev.xbutton.state = Button1Mask;
567 XtDispatchEvent (&ev);
568 }
569 }
570
571 unblock_input ();
572
573 return Qnil;
574 }
575 #endif
576
577
578 #ifdef USE_GTK
579 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
580 doc:
581
582
583
584
585 )
586 (Lisp_Object frame)
587 {
588 GtkWidget *menubar;
589 struct frame *f;
590
591 block_input ();
592 f = decode_window_system_frame (frame);
593
594 if (FRAME_EXTERNAL_MENU_BAR (f))
595 set_frame_menubar (f, true);
596
597 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
598 if (menubar)
599 {
600
601 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
602
603 if (children)
604 {
605 g_signal_emit_by_name (children->data, "activate_item");
606 popup_activated_flag = 1;
607 g_list_free (children);
608 }
609 }
610 unblock_input ();
611
612 return Qnil;
613 }
614
615
616
617
618 static void
619 popup_widget_loop (bool do_timers, GtkWidget *widget)
620 {
621 ++popup_activated_flag;
622
623
624 while (popup_activated_flag)
625 {
626 if (do_timers) x_menu_wait_for_event (0);
627 gtk_main_iteration ();
628 }
629 }
630 #endif
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646 void
647 x_activate_menubar (struct frame *f)
648 {
649 eassert (FRAME_X_P (f));
650
651 if (!f->output_data.x->saved_menu_event->type)
652 return;
653
654 #ifdef USE_GTK
655 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
656 f->output_data.x->saved_menu_event->xany.window))
657 return;
658 #endif
659
660 set_frame_menubar (f, true);
661 block_input ();
662 popup_activated_flag = 1;
663 #ifdef USE_GTK
664 XPutBackEvent (f->output_data.x->display_info->display,
665 f->output_data.x->saved_menu_event);
666 #else
667 #if defined USE_X_TOOLKIT && defined HAVE_XINPUT2
668 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
669
670
671
672
673 if (dpyinfo->supports_xi2
674 && xi_frame_selected_for (f, XI_ButtonPress))
675 {
676 for (int i = 0; i < dpyinfo->num_devices; ++i)
677 {
678 if (dpyinfo->devices[i].grab)
679 XIUngrabDevice (dpyinfo->display,
680 dpyinfo->devices[i].device_id,
681 CurrentTime);
682 }
683 }
684 #endif
685
686
687 popup_activated_flag
688 = XtDispatchEvent (f->output_data.x->saved_menu_event);
689 #endif
690 unblock_input ();
691
692
693 f->output_data.x->saved_menu_event->type = 0;
694 }
695
696
697
698
699 #ifndef USE_GTK
700 static void
701 popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
702 {
703 popup_activated_flag = 1;
704 x_activate_timeout_atimer ();
705 }
706 #endif
707
708
709
710
711 static void
712 popup_deactivate_callback (
713 #ifdef USE_GTK
714 GtkWidget *widget, gpointer client_data
715 #else
716 Widget widget, LWLIB_ID id, XtPointer client_data
717 #endif
718 )
719 {
720 popup_activated_flag = 0;
721 }
722
723
724
725
726
727 static void
728 show_help_event (struct frame *f, xt_or_gtk_widget widget, Lisp_Object help)
729 {
730 Lisp_Object frame;
731
732 if (f)
733 {
734 XSETFRAME (frame, f);
735 kbd_buffer_store_help_event (frame, help);
736 }
737 else
738 show_help_echo (help, Qnil, Qnil, Qnil);
739 }
740
741
742
743
744
745
746
747 #ifdef USE_GTK
748 static void
749 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
750 {
751 xg_menu_item_cb_data *cb_data;
752 Lisp_Object help;
753
754 cb_data = g_object_get_data (G_OBJECT (widget), XG_ITEM_DATA);
755 if (! cb_data) return;
756
757 help = call_data ? cb_data->help : Qnil;
758
759
760
761
762
763
764
765 show_help_event (popup_activated_flag <= 1 ? cb_data->cl_data->f : NULL,
766 widget, help);
767 }
768 #else
769 static void
770 menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
771 {
772 widget_value *wv = call_data;
773 Lisp_Object help = wv ? wv->help : Qnil;
774
775
776 struct frame *f = menubar_id_to_frame (id);
777
778 show_help_event (f, widget, help);
779 }
780 #endif
781
782 #ifdef USE_GTK
783
784
785
786
787 static bool xg_crazy_callback_abort;
788
789
790
791
792
793 static void
794 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
795 {
796 xg_menu_item_cb_data *cb_data = client_data;
797
798 if (xg_crazy_callback_abort)
799 return;
800
801 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
802 return;
803
804
805
806
807
808
809 if (GTK_IS_RADIO_MENU_ITEM (widget)
810 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
811 return;
812
813
814
815
816
817
818
819 block_input ();
820 while (gtk_events_pending ())
821 gtk_main_iteration ();
822 unblock_input ();
823
824 find_and_call_menu_selection (cb_data->cl_data->f,
825 cb_data->cl_data->menu_bar_items_used,
826 cb_data->cl_data->menu_bar_vector,
827 cb_data->call_data);
828 }
829
830 #else
831
832
833
834
835
836 static void
837 menubar_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
838 {
839 struct frame *f;
840
841 f = menubar_id_to_frame (id);
842 if (!f)
843 return;
844 find_and_call_menu_selection (f, f->menu_bar_items_used,
845 f->menu_bar_vector, client_data);
846 }
847 #endif
848
849
850
851
852 static void
853 update_frame_menubar (struct frame *f)
854 {
855 #ifdef USE_GTK
856 xg_update_frame_menubar (f);
857 #else
858 struct x_output *x;
859
860 eassert (FRAME_X_P (f));
861
862 x = f->output_data.x;
863
864 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
865 return;
866
867 block_input ();
868
869
870
871 lw_refigure_widget (x->column_widget, False);
872
873
874
875
876 XtUnmanageChild (x->edit_widget);
877
878
879
880 XtManageChild (x->menubar_widget);
881 XtMapWidget (x->menubar_widget);
882 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
883
884
885 XtManageChild (x->edit_widget);
886 lw_refigure_widget (x->column_widget, True);
887
888
889 adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
890 unblock_input ();
891 #endif
892 }
893
894 #ifdef USE_LUCID
895 static void
896 apply_systemfont_to_dialog (Widget w)
897 {
898 const char *fn = xsettings_get_system_normal_font ();
899 if (fn)
900 {
901 XrmDatabase db = XtDatabase (XtDisplay (w));
902 if (db)
903 XrmPutStringResource (&db, "*dialog.font", fn);
904 }
905 }
906
907 static void
908 apply_systemfont_to_menu (struct frame *f, Widget w)
909 {
910 const char *fn = xsettings_get_system_normal_font ();
911
912 if (fn)
913 {
914 XrmDatabase db = XtDatabase (XtDisplay (w));
915 if (db)
916 {
917 XrmPutStringResource (&db, "*menubar*font", fn);
918 XrmPutStringResource (&db, "*popup*font", fn);
919 }
920 }
921 }
922
923 #endif
924
925
926
927 void
928 set_frame_menubar (struct frame *f, bool deep_p)
929 {
930 xt_or_gtk_widget menubar_widget, old_widget;
931 #ifdef USE_X_TOOLKIT
932 LWLIB_ID id;
933 #endif
934 Lisp_Object items;
935 widget_value *wv, *first_wv, *prev_wv = 0;
936 int i;
937 int *submenu_start, *submenu_end;
938 bool *submenu_top_level_items;
939 int *submenu_n_panes;
940
941 eassert (FRAME_X_P (f));
942
943 menubar_widget = old_widget = f->output_data.x->menubar_widget;
944
945 XSETFRAME (Vmenu_updating_frame, f);
946
947 #ifdef USE_X_TOOLKIT
948 if (f->output_data.x->id == 0)
949 f->output_data.x->id = next_menubar_widget_id++;
950 id = f->output_data.x->id;
951 #endif
952
953 if (! menubar_widget)
954 deep_p = true;
955
956 else if (!f->output_data.x->saved_menu_event && !deep_p)
957 {
958 deep_p = true;
959 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
960 f->output_data.x->saved_menu_event->type = 0;
961 }
962
963 if (deep_p)
964 {
965
966
967 struct buffer *prev = current_buffer;
968 Lisp_Object buffer;
969 specpdl_ref specpdl_count = SPECPDL_INDEX ();
970 int previous_menu_items_used = f->menu_bar_items_used;
971 Lisp_Object *previous_items
972 = alloca (previous_menu_items_used * sizeof *previous_items);
973 int subitems;
974
975
976
977 if (! menubar_widget)
978 previous_menu_items_used = 0;
979
980 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
981 specbind (Qinhibit_quit, Qt);
982
983
984 specbind (Qdebug_on_next_call, Qnil);
985
986 record_unwind_save_match_data ();
987 if (NILP (Voverriding_local_map_menu_flag))
988 {
989 specbind (Qoverriding_terminal_local_map, Qnil);
990 specbind (Qoverriding_local_map, Qnil);
991 }
992
993 set_buffer_internal_1 (XBUFFER (buffer));
994
995
996 safe_run_hooks (Qactivate_menubar_hook);
997
998
999
1000 safe_run_hooks (Qmenu_bar_update_hook);
1001 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1002
1003 items = FRAME_MENU_BAR_ITEMS (f);
1004
1005
1006 if (previous_menu_items_used)
1007 memcpy (previous_items, xvector_contents (f->menu_bar_vector),
1008 previous_menu_items_used * word_size);
1009
1010
1011
1012 save_menu_items ();
1013
1014 menu_items = f->menu_bar_vector;
1015 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1016 subitems = ASIZE (items) / 4;
1017 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
1018 submenu_end = alloca (subitems * sizeof *submenu_end);
1019 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
1020 submenu_top_level_items = alloca (subitems
1021 * sizeof *submenu_top_level_items);
1022 init_menu_items ();
1023 for (i = 0; i < subitems; i++)
1024 {
1025 Lisp_Object key, string, maps;
1026
1027 key = AREF (items, 4 * i);
1028 string = AREF (items, 4 * i + 1);
1029 maps = AREF (items, 4 * i + 2);
1030 if (NILP (string))
1031 break;
1032
1033 submenu_start[i] = menu_items_used;
1034
1035 menu_items_n_panes = 0;
1036 submenu_top_level_items[i]
1037 = parse_single_submenu (key, string, maps);
1038 submenu_n_panes[i] = menu_items_n_panes;
1039
1040 submenu_end[i] = menu_items_used;
1041 }
1042
1043 submenu_start[i] = -1;
1044 finish_menu_items ();
1045
1046
1047
1048
1049 wv = make_widget_value ("menubar", NULL, true, Qnil);
1050 wv->button_type = BUTTON_TYPE_NONE;
1051 first_wv = wv;
1052
1053 for (i = 0; submenu_start[i] >= 0; i++)
1054 {
1055 menu_items_n_panes = submenu_n_panes[i];
1056 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1057 submenu_top_level_items[i]);
1058 if (prev_wv)
1059 prev_wv->next = wv;
1060 else
1061 first_wv->contents = wv;
1062
1063 wv->enabled = true;
1064 wv->button_type = BUTTON_TYPE_NONE;
1065 prev_wv = wv;
1066 }
1067
1068 set_buffer_internal_1 (prev);
1069
1070
1071
1072
1073
1074 for (i = 0; i < previous_menu_items_used; i++)
1075 if (menu_items_used == i
1076 || (!EQ (previous_items[i], AREF (menu_items, i))))
1077 break;
1078 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1079 {
1080
1081
1082 free_menubar_widget_value_tree (first_wv);
1083 discard_menu_items ();
1084 unbind_to (specpdl_count, Qnil);
1085 return;
1086 }
1087
1088
1089 fset_menu_bar_vector (f, menu_items);
1090 f->menu_bar_items_used = menu_items_used;
1091
1092
1093 unbind_to (specpdl_count, Qnil);
1094
1095
1096
1097 wv = first_wv->contents;
1098 for (i = 0; i < ASIZE (items); i += 4)
1099 {
1100 Lisp_Object string;
1101 string = AREF (items, i + 1);
1102 if (NILP (string))
1103 break;
1104 wv->name = SSDATA (string);
1105 update_submenu_strings (wv->contents);
1106 wv = wv->next;
1107 }
1108
1109 }
1110 else
1111 {
1112
1113
1114
1115 wv = make_widget_value ("menubar", NULL, true, Qnil);
1116 wv->button_type = BUTTON_TYPE_NONE;
1117 first_wv = wv;
1118
1119 items = FRAME_MENU_BAR_ITEMS (f);
1120 for (i = 0; i < ASIZE (items); i += 4)
1121 {
1122 Lisp_Object string;
1123
1124 string = AREF (items, i + 1);
1125 if (NILP (string))
1126 break;
1127
1128 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
1129 wv->button_type = BUTTON_TYPE_NONE;
1130
1131
1132
1133
1134 wv->call_data = (void *) (intptr_t) (-1);
1135
1136 if (prev_wv)
1137 prev_wv->next = wv;
1138 else
1139 first_wv->contents = wv;
1140 prev_wv = wv;
1141 }
1142
1143
1144
1145
1146 f->menu_bar_items_used = 0;
1147 }
1148
1149
1150
1151 block_input ();
1152
1153 #ifdef USE_GTK
1154 xg_crazy_callback_abort = true;
1155 if (menubar_widget)
1156 {
1157
1158
1159 xg_modify_menubar_widgets (menubar_widget,
1160 f,
1161 first_wv,
1162 deep_p,
1163 G_CALLBACK (menubar_selection_callback),
1164 G_CALLBACK (popup_deactivate_callback),
1165 G_CALLBACK (menu_highlight_callback));
1166 }
1167 else
1168 {
1169 menubar_widget
1170 = xg_create_widget ("menubar", "menubar", f, first_wv,
1171 G_CALLBACK (menubar_selection_callback),
1172 G_CALLBACK (popup_deactivate_callback),
1173 G_CALLBACK (menu_highlight_callback));
1174
1175 f->output_data.x->menubar_widget = menubar_widget;
1176 }
1177
1178
1179 #else
1180 if (menubar_widget)
1181 {
1182
1183 lw_allow_resizing (f->output_data.x->widget, False);
1184
1185
1186
1187 lw_modify_all_widgets (id, first_wv, deep_p);
1188
1189
1190 lw_allow_resizing (f->output_data.x->widget, True);
1191 }
1192 else
1193 {
1194 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1195 XtTranslations override = XtParseTranslationTable (menuOverride);
1196
1197 #ifdef USE_LUCID
1198 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
1199 #endif
1200 menubar_widget = lw_create_widget ("menubar", "menubar", id,
1201 first_wv,
1202 f->output_data.x->column_widget,
1203 false,
1204 popup_activate_callback,
1205 menubar_selection_callback,
1206 popup_deactivate_callback,
1207 menu_highlight_callback);
1208 f->output_data.x->menubar_widget = menubar_widget;
1209
1210
1211 XtOverrideTranslations (menubar_widget, override);
1212 }
1213
1214 {
1215 int menubar_size;
1216 if (f->output_data.x->menubar_widget)
1217 XtRealizeWidget (f->output_data.x->menubar_widget);
1218
1219 menubar_size
1220 = (f->output_data.x->menubar_widget
1221 ? (f->output_data.x->menubar_widget->core.height
1222 #ifndef USE_LUCID
1223
1224
1225
1226
1227
1228 + f->output_data.x->menubar_widget->core.border_width
1229 #endif
1230 )
1231 : 0);
1232
1233 #ifdef USE_LUCID
1234
1235
1236
1237
1238 if (FRAME_EXTERNAL_MENU_BAR (f))
1239 {
1240 Dimension ibw = 0;
1241
1242 XtVaGetValues (f->output_data.x->column_widget,
1243 XtNinternalBorderWidth, &ibw, NULL);
1244 menubar_size += ibw;
1245 }
1246 #endif
1247
1248 FRAME_MENUBAR_HEIGHT (f) = menubar_size;
1249 }
1250 #endif
1251
1252 free_menubar_widget_value_tree (first_wv);
1253 update_frame_menubar (f);
1254
1255 #ifdef USE_GTK
1256 xg_crazy_callback_abort = false;
1257 #endif
1258
1259 unblock_input ();
1260 }
1261
1262
1263
1264
1265
1266
1267 void
1268 initialize_frame_menubar (struct frame *f)
1269 {
1270
1271
1272 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1273 set_frame_menubar (f, true);
1274 }
1275
1276
1277
1278
1279
1280
1281 #ifndef USE_GTK
1282 void
1283 free_frame_menubar (struct frame *f)
1284 {
1285 Widget menubar_widget;
1286 #ifdef USE_MOTIF
1287
1288
1289
1290 int old_width = FRAME_TEXT_WIDTH (f);
1291 int old_height = FRAME_TEXT_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
1292 #endif
1293
1294 eassert (FRAME_X_P (f));
1295
1296 menubar_widget = f->output_data.x->menubar_widget;
1297
1298 FRAME_MENUBAR_HEIGHT (f) = 0;
1299
1300 if (menubar_widget)
1301 {
1302 #ifdef USE_MOTIF
1303
1304
1305
1306
1307
1308
1309
1310
1311 Position x0, y0, x1, y1;
1312 #endif
1313
1314 block_input ();
1315
1316 #ifdef USE_MOTIF
1317 if (f->output_data.x->widget)
1318 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1319 #endif
1320
1321 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1322 f->output_data.x->menubar_widget = NULL;
1323
1324
1325
1326
1327
1328
1329
1330 if (f->output_data.x->widget)
1331 {
1332 #ifdef USE_MOTIF
1333 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1334 if (x1 == 0 && y1 == 0)
1335 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1336
1337
1338
1339
1340
1341
1342 if (frame_inhibit_resize (f, false, Qmenu_bar_lines)
1343 && !EQ (get_frame_param (f, Qfullscreen), Qfullheight))
1344 adjust_frame_size (f, old_width, old_height, 1, false,
1345 Qmenu_bar_lines);
1346 else
1347 adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
1348 #else
1349 adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
1350 #endif
1351 }
1352 else
1353 {
1354 #ifdef USE_MOTIF
1355 if (WINDOWP (FRAME_ROOT_WINDOW (f))
1356
1357 && frame_inhibit_resize (f, false, Qmenu_bar_lines)
1358 && !EQ (get_frame_param (f, Qfullscreen), Qfullheight))
1359 adjust_frame_size (f, old_width, old_height, 1, false,
1360 Qmenu_bar_lines);
1361 #endif
1362 }
1363
1364 unblock_input ();
1365 }
1366 }
1367 #endif
1368
1369 #endif
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1389
1390
1391 static Lisp_Object *volatile menu_item_selection;
1392
1393 #ifdef USE_GTK
1394
1395
1396
1397 struct next_popup_x_y
1398 {
1399 struct frame *f;
1400 int x;
1401 int y;
1402 };
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414 static void
1415 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1416 {
1417 struct next_popup_x_y *data = user_data;
1418 GtkRequisition req;
1419 int max_x = -1;
1420 int max_y = -1;
1421 #ifdef HAVE_GTK3
1422 int scale;
1423 #endif
1424
1425 Lisp_Object frame, workarea;
1426
1427 XSETFRAME (frame, data->f);
1428
1429 #ifdef HAVE_GTK3
1430 scale = xg_get_scale (data->f);
1431 #endif
1432
1433
1434 workarea = call3 (Qframe_monitor_workarea,
1435 Qnil,
1436 make_fixnum (data->x),
1437 make_fixnum (data->y));
1438
1439 if (CONSP (workarea))
1440 {
1441 int min_x, min_y;
1442
1443 min_x = XFIXNUM (XCAR (workarea));
1444 min_y = XFIXNUM (Fnth (make_fixnum (1), workarea));
1445 max_x = min_x + XFIXNUM (Fnth (make_fixnum (2), workarea));
1446 max_y = min_y + XFIXNUM (Fnth (make_fixnum (3), workarea));
1447 }
1448
1449 if (max_x < 0 || max_y < 0)
1450 {
1451 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1452
1453 max_x = x_display_pixel_width (dpyinfo);
1454 max_y = x_display_pixel_height (dpyinfo);
1455 }
1456
1457
1458
1459
1460 #ifdef HAVE_GTK3
1461 max_x /= scale;
1462 max_y /= scale;
1463 #endif
1464 *x = data->x;
1465 *y = data->y;
1466
1467
1468
1469
1470
1471 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1472 if (data->x + req.width > max_x)
1473 *x -= data->x + req.width - max_x;
1474 if (data->y + req.height > max_y)
1475 *y -= data->y + req.height - max_y;
1476 }
1477
1478 static void
1479 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1480 {
1481 xg_menu_item_cb_data *cb_data = client_data;
1482
1483 if (xg_crazy_callback_abort) return;
1484 if (cb_data) menu_item_selection = cb_data->call_data;
1485 }
1486
1487 static void
1488 pop_down_menu (void *arg)
1489 {
1490 popup_activated_flag = 0;
1491 block_input ();
1492 gtk_widget_destroy (GTK_WIDGET (arg));
1493 unblock_input ();
1494 }
1495
1496
1497
1498
1499 static void
1500 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1501 int x, int y, bool for_click)
1502 {
1503 int i;
1504 GtkWidget *menu;
1505 GtkMenuPositionFunc pos_func = 0;
1506 struct next_popup_x_y popup_x_y;
1507 specpdl_ref specpdl_count = SPECPDL_INDEX ();
1508 bool use_pos_func = ! for_click;
1509
1510 #ifdef HAVE_GTK3
1511
1512
1513 use_pos_func = true;
1514 #endif
1515
1516 eassert (FRAME_X_P (f));
1517
1518 xg_crazy_callback_abort = true;
1519 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1520 G_CALLBACK (popup_selection_callback),
1521 G_CALLBACK (popup_deactivate_callback),
1522 G_CALLBACK (menu_highlight_callback));
1523 xg_crazy_callback_abort = false;
1524
1525 if (use_pos_func)
1526 {
1527
1528 pos_func = menu_position_func;
1529
1530
1531 block_input ();
1532 x_translate_coordinates_to_root (f, x, y, &x, &y);
1533 #ifdef HAVE_GTK3
1534
1535
1536 x /= xg_get_scale (f);
1537 y /= xg_get_scale (f);
1538 #endif
1539 unblock_input ();
1540 popup_x_y.x = x;
1541 popup_x_y.y = y;
1542 popup_x_y.f = f;
1543
1544 i = 0;
1545 }
1546
1547 if (for_click)
1548 {
1549 for (i = 0; i < 5; i++)
1550 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1551 break;
1552
1553 if (i == 5) i = 0;
1554 }
1555
1556 #if !defined HAVE_GTK3 && defined HAVE_XINPUT2
1557 if (FRAME_DISPLAY_INFO (f)->supports_xi2
1558 && xi_frame_selected_for (f, XI_ButtonPress))
1559 {
1560 for (int i = 0; i < FRAME_DISPLAY_INFO (f)->num_devices; ++i)
1561 {
1562 if (FRAME_DISPLAY_INFO (f)->devices[i].grab)
1563 {
1564 FRAME_DISPLAY_INFO (f)->devices[i].grab = 0;
1565
1566 XIUngrabDevice (FRAME_X_DISPLAY (f),
1567 FRAME_DISPLAY_INFO (f)->devices[i].device_id,
1568 CurrentTime);
1569 }
1570 }
1571 }
1572 #endif
1573
1574 DEFER_SELECTIONS;
1575
1576
1577 gtk_widget_show_all (menu);
1578
1579 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1580 FRAME_DISPLAY_INFO (f)->last_user_time);
1581
1582 record_unwind_protect_ptr (pop_down_menu, menu);
1583
1584 if (gtk_widget_get_mapped (menu))
1585 {
1586
1587
1588 popup_activated_flag = 1;
1589
1590 popup_widget_loop (true, menu);
1591 }
1592
1593 unbind_to (specpdl_count, Qnil);
1594
1595
1596
1597 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1598 }
1599
1600 #else
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610 LWLIB_ID widget_id_tick;
1611
1612 static void
1613 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1614 {
1615 menu_item_selection = client_data;
1616 }
1617
1618
1619 #ifdef HAVE_XINPUT2
1620
1621 static void
1622 prepare_for_entry_into_toolkit_menu (struct frame *f)
1623 {
1624 XIEventMask mask;
1625 ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
1626 unsigned char *m;
1627 Lisp_Object tail, frame;
1628 struct x_display_info *dpyinfo;
1629
1630 dpyinfo = FRAME_DISPLAY_INFO (f);
1631
1632 if (!dpyinfo->supports_xi2)
1633 return;
1634
1635 mask.mask = m = alloca (l);
1636 memset (m, 0, l);
1637 mask.mask_len = l;
1638
1639 mask.deviceid = XIAllMasterDevices;
1640
1641 XISetMask (m, XI_Motion);
1642 XISetMask (m, XI_Enter);
1643 XISetMask (m, XI_Leave);
1644
1645 FOR_EACH_FRAME (tail, frame)
1646 {
1647 f = XFRAME (frame);
1648
1649 if (FRAME_X_P (f)
1650 && FRAME_DISPLAY_INFO (f) == dpyinfo
1651 && !FRAME_TOOLTIP_P (f))
1652 XISelectEvents (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1653 &mask, 1);
1654 }
1655 }
1656
1657 static void
1658 leave_toolkit_menu (void *data)
1659 {
1660 XIEventMask mask;
1661 ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
1662 unsigned char *m;
1663 Lisp_Object tail, frame;
1664 struct x_display_info *dpyinfo;
1665 struct frame *f;
1666
1667 dpyinfo = FRAME_DISPLAY_INFO ((struct frame *) data);
1668
1669 if (!dpyinfo->supports_xi2)
1670 return;
1671
1672 mask.mask = m = alloca (l);
1673 memset (m, 0, l);
1674 mask.mask_len = l;
1675
1676 mask.deviceid = XIAllMasterDevices;
1677
1678 XISetMask (m, XI_ButtonPress);
1679 XISetMask (m, XI_ButtonRelease);
1680 XISetMask (m, XI_Motion);
1681 XISetMask (m, XI_Enter);
1682 XISetMask (m, XI_Leave);
1683
1684 #ifdef HAVE_XINPUT2_4
1685
1686
1687
1688
1689 if (dpyinfo->xi2_version >= 4)
1690 {
1691 XISetMask (m, XI_GesturePinchBegin);
1692 XISetMask (m, XI_GesturePinchUpdate);
1693 XISetMask (m, XI_GesturePinchEnd);
1694 }
1695 #endif
1696
1697 FOR_EACH_FRAME (tail, frame)
1698 {
1699 f = XFRAME (frame);
1700
1701 if (FRAME_X_P (f)
1702 && FRAME_DISPLAY_INFO (f) == dpyinfo
1703 && !FRAME_TOOLTIP_P (f))
1704 XISelectEvents (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1705 &mask, 1);
1706 }
1707 }
1708
1709 #endif
1710
1711
1712
1713 static void
1714 pop_down_menu (int id)
1715 {
1716 block_input ();
1717 lw_destroy_all_widgets ((LWLIB_ID) id);
1718 unblock_input ();
1719 popup_activated_flag = 0;
1720 }
1721
1722 #if defined HAVE_XINPUT2 && defined USE_MOTIF
1723 static Bool
1724 server_timestamp_predicate (Display *display,
1725 XEvent *xevent,
1726 XPointer arg)
1727 {
1728 XID *args = (XID *) arg;
1729
1730 if (xevent->type == PropertyNotify
1731 && xevent->xproperty.window == args[0]
1732 && xevent->xproperty.atom == args[1])
1733 return True;
1734
1735 return False;
1736 }
1737 #endif
1738
1739
1740
1741
1742 static void
1743 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1744 int x, int y, bool for_click)
1745 {
1746 int i;
1747 Arg av[2];
1748 int ac = 0;
1749 XEvent dummy;
1750 XButtonPressedEvent *event = &(dummy.xbutton);
1751 LWLIB_ID menu_id;
1752 Widget menu;
1753 #if defined HAVE_XINPUT2 && defined USE_MOTIF
1754 XEvent property_dummy;
1755 Atom property_atom;
1756 #endif
1757
1758 eassert (FRAME_X_P (f));
1759
1760 #ifdef USE_LUCID
1761 apply_systemfont_to_menu (f, f->output_data.x->widget);
1762 #endif
1763
1764 menu_id = widget_id_tick++;
1765 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1766 f->output_data.x->widget, true, 0,
1767 popup_selection_callback,
1768 popup_deactivate_callback,
1769 menu_highlight_callback);
1770
1771 event->type = ButtonPress;
1772 event->serial = 0;
1773 event->send_event = false;
1774 event->display = FRAME_X_DISPLAY (f);
1775 event->time = CurrentTime;
1776 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1777 event->window = event->subwindow = event->root;
1778 event->x = x;
1779 event->y = y;
1780
1781
1782 block_input ();
1783 x += FRAME_LEFT_SCROLL_BAR_AREA_WIDTH (f);
1784 x_translate_coordinates_to_root (f, x, y, &x, &y);
1785 unblock_input ();
1786
1787 event->x_root = x;
1788 event->y_root = y;
1789
1790 event->state = 0;
1791 event->button = 0;
1792 for (i = 0; i < 5; i++)
1793 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1794 event->button = i;
1795
1796
1797 XtSetArg (av[ac], (char *) XtNgeometry, 0); ac++;
1798 XtSetValues (menu, av, ac);
1799
1800 #ifdef HAVE_XINPUT2
1801 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1802
1803
1804
1805 if (dpyinfo->supports_xi2)
1806 XGrabServer (dpyinfo->display);
1807
1808 if (dpyinfo->supports_xi2
1809 && xi_frame_selected_for (f, XI_ButtonPress))
1810 {
1811 for (int i = 0; i < dpyinfo->num_devices; ++i)
1812 {
1813 if (dpyinfo->devices[i].grab)
1814 {
1815 dpyinfo->devices[i].grab = 0;
1816
1817 XIUngrabDevice (dpyinfo->display,
1818 dpyinfo->devices[i].device_id,
1819 CurrentTime);
1820 }
1821 }
1822 }
1823
1824 #ifdef USE_MOTIF
1825 if (dpyinfo->supports_xi2)
1826 {
1827
1828
1829
1830
1831
1832 property_atom = dpyinfo->Xatom_EMACS_SERVER_TIME_PROP;
1833
1834 XChangeProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
1835 property_atom, XA_ATOM, 32,
1836 PropModeReplace, (unsigned char *) &property_atom, 1);
1837
1838 XIfEvent (dpyinfo->display, &property_dummy, server_timestamp_predicate,
1839 (XPointer) &(XID[]) {FRAME_OUTER_WINDOW (f), property_atom});
1840
1841 XtDispatchEvent (&property_dummy);
1842 }
1843 #endif
1844 #endif
1845
1846 #ifdef HAVE_XINPUT2
1847 prepare_for_entry_into_toolkit_menu (f);
1848
1849 #ifdef USE_LUCID
1850 if (dpyinfo->supports_xi2)
1851 x_mouse_leave (dpyinfo);
1852 #endif
1853 #endif
1854
1855 lw_popup_menu (menu, &dummy);
1856
1857 #ifdef HAVE_XINPUT2
1858 if (dpyinfo->supports_xi2)
1859 XUngrabServer (dpyinfo->display);
1860 #endif
1861
1862 popup_activated_flag = 1;
1863
1864 x_activate_timeout_atimer ();
1865
1866 {
1867 specpdl_ref specpdl_count = SPECPDL_INDEX ();
1868
1869 DEFER_SELECTIONS;
1870
1871 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1872 #ifdef HAVE_XINPUT2
1873 record_unwind_protect_ptr (leave_toolkit_menu, f);
1874 #endif
1875
1876
1877 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, true);
1878
1879 unbind_to (specpdl_count, Qnil);
1880 }
1881 }
1882
1883 #endif
1884
1885 static void
1886 cleanup_widget_value_tree (void *arg)
1887 {
1888 free_menubar_widget_value_tree (arg);
1889 }
1890
1891 Lisp_Object
1892 x_menu_show (struct frame *f, int x, int y, int menuflags,
1893 Lisp_Object title, const char **error_name)
1894 {
1895 int i;
1896 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1897 widget_value **submenu_stack;
1898 Lisp_Object *subprefix_stack;
1899 int submenu_depth = 0;
1900 specpdl_ref specpdl_count;
1901
1902 USE_SAFE_ALLOCA;
1903
1904 submenu_stack = SAFE_ALLOCA (menu_items_used
1905 * sizeof *submenu_stack);
1906 subprefix_stack = SAFE_ALLOCA (menu_items_used
1907 * sizeof *subprefix_stack);
1908
1909 specpdl_count = SPECPDL_INDEX ();
1910
1911 eassert (FRAME_X_P (f));
1912
1913 *error_name = NULL;
1914
1915 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1916 {
1917 *error_name = "Empty menu";
1918 SAFE_FREE ();
1919 return Qnil;
1920 }
1921
1922 block_input ();
1923
1924
1925
1926 wv = make_widget_value ("menu", NULL, true, Qnil);
1927 wv->button_type = BUTTON_TYPE_NONE;
1928 first_wv = wv;
1929 bool first_pane = true;
1930
1931
1932 i = 0;
1933 while (i < menu_items_used)
1934 {
1935 if (NILP (AREF (menu_items, i)))
1936 {
1937 submenu_stack[submenu_depth++] = save_wv;
1938 save_wv = prev_wv;
1939 prev_wv = 0;
1940 first_pane = true;
1941 i++;
1942 }
1943 else if (EQ (AREF (menu_items, i), Qlambda))
1944 {
1945 prev_wv = save_wv;
1946 save_wv = submenu_stack[--submenu_depth];
1947 first_pane = false;
1948 i++;
1949 }
1950 else if (EQ (AREF (menu_items, i), Qt)
1951 && submenu_depth != 0)
1952 i += MENU_ITEMS_PANE_LENGTH;
1953
1954
1955 else if (EQ (AREF (menu_items, i), Qquote))
1956 i += 1;
1957 else if (EQ (AREF (menu_items, i), Qt))
1958 {
1959
1960 Lisp_Object pane_name, prefix;
1961 const char *pane_string;
1962
1963 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1964 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1965
1966 #ifndef HAVE_MULTILINGUAL_MENU
1967 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1968 {
1969 pane_name = ENCODE_MENU_STRING (pane_name);
1970 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1971 }
1972 #endif
1973 pane_string = (NILP (pane_name)
1974 ? "" : SSDATA (pane_name));
1975
1976
1977 if (menu_items_n_panes == 1)
1978 pane_string = "";
1979
1980
1981
1982
1983 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1984 {
1985 wv = make_widget_value (pane_string, NULL, true, Qnil);
1986 if (save_wv)
1987 save_wv->next = wv;
1988 else
1989 first_wv->contents = wv;
1990 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1991 wv->name++;
1992 wv->button_type = BUTTON_TYPE_NONE;
1993 save_wv = wv;
1994 prev_wv = 0;
1995 }
1996 else if (first_pane)
1997 {
1998 save_wv = wv;
1999 prev_wv = 0;
2000 }
2001 first_pane = false;
2002 i += MENU_ITEMS_PANE_LENGTH;
2003 }
2004 else
2005 {
2006
2007 Lisp_Object item_name, enable, descrip, def, type, selected, help;
2008 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2009 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2010 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2011 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
2012 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
2013 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
2014 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2015
2016 #ifndef HAVE_MULTILINGUAL_MENU
2017 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
2018 {
2019 item_name = ENCODE_MENU_STRING (item_name);
2020 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
2021 }
2022
2023 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
2024 {
2025 descrip = ENCODE_MENU_STRING (descrip);
2026 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
2027 }
2028 #endif
2029
2030 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
2031 STRINGP (help) ? help : Qnil);
2032 if (prev_wv)
2033 prev_wv->next = wv;
2034 else if (!save_wv)
2035 {
2036
2037
2038
2039
2040 emacs_abort ();
2041 }
2042 else
2043 save_wv->contents = wv;
2044 if (!NILP (descrip))
2045 wv->key = SSDATA (descrip);
2046
2047
2048
2049 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
2050
2051 if (NILP (type))
2052 wv->button_type = BUTTON_TYPE_NONE;
2053 else if (EQ (type, QCtoggle))
2054 wv->button_type = BUTTON_TYPE_TOGGLE;
2055 else if (EQ (type, QCradio))
2056 wv->button_type = BUTTON_TYPE_RADIO;
2057 else
2058 emacs_abort ();
2059
2060 wv->selected = !NILP (selected);
2061
2062 prev_wv = wv;
2063
2064 i += MENU_ITEMS_ITEM_LENGTH;
2065 }
2066 }
2067
2068
2069 if (!NILP (title))
2070 {
2071 widget_value *wv_title;
2072 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
2073 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
2074
2075 wv_sep2->next = first_wv->contents;
2076 wv_sep1->next = wv_sep2;
2077
2078 #ifndef HAVE_MULTILINGUAL_MENU
2079 if (STRING_MULTIBYTE (title))
2080 title = ENCODE_MENU_STRING (title);
2081 #endif
2082
2083 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
2084 wv_title->button_type = BUTTON_TYPE_NONE;
2085 wv_title->next = wv_sep1;
2086 first_wv->contents = wv_title;
2087 }
2088
2089
2090 menu_item_selection = 0;
2091
2092
2093
2094 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
2095
2096
2097 create_and_show_popup_menu (f, first_wv, x, y,
2098 menuflags & MENU_FOR_CLICK);
2099
2100 unbind_to (specpdl_count, Qnil);
2101
2102
2103
2104 if (menu_item_selection != 0)
2105 {
2106 Lisp_Object prefix, entry;
2107
2108 prefix = entry = Qnil;
2109 i = 0;
2110 while (i < menu_items_used)
2111 {
2112 if (NILP (AREF (menu_items, i)))
2113 {
2114 subprefix_stack[submenu_depth++] = prefix;
2115 prefix = entry;
2116 i++;
2117 }
2118 else if (EQ (AREF (menu_items, i), Qlambda))
2119 {
2120 prefix = subprefix_stack[--submenu_depth];
2121 i++;
2122 }
2123 else if (EQ (AREF (menu_items, i), Qt))
2124 {
2125 prefix
2126 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2127 i += MENU_ITEMS_PANE_LENGTH;
2128 }
2129
2130
2131 else if (EQ (AREF (menu_items, i), Qquote))
2132 i += 1;
2133 else
2134 {
2135 entry
2136 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2137 if (menu_item_selection == aref_addr (menu_items, i))
2138 {
2139 if (menuflags & MENU_KEYMAPS)
2140 {
2141 int j;
2142
2143 entry = list1 (entry);
2144 if (!NILP (prefix))
2145 entry = Fcons (prefix, entry);
2146 for (j = submenu_depth - 1; j >= 0; j--)
2147 if (!NILP (subprefix_stack[j]))
2148 entry = Fcons (subprefix_stack[j], entry);
2149 }
2150 unblock_input ();
2151
2152 SAFE_FREE ();
2153 return entry;
2154 }
2155 i += MENU_ITEMS_ITEM_LENGTH;
2156 }
2157 }
2158 }
2159 else if (!(menuflags & MENU_FOR_CLICK))
2160 {
2161 unblock_input ();
2162
2163 quit ();
2164 }
2165
2166 unblock_input ();
2167
2168 SAFE_FREE ();
2169 return Qnil;
2170 }
2171
2172 #ifdef USE_GTK
2173 static void
2174 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
2175 {
2176
2177
2178 if ((intptr_t) client_data != -1)
2179 menu_item_selection = client_data;
2180
2181 popup_activated_flag = 0;
2182 }
2183
2184
2185
2186
2187 static void
2188 create_and_show_dialog (struct frame *f, widget_value *first_wv)
2189 {
2190 GtkWidget *menu;
2191
2192 eassert (FRAME_X_P (f));
2193
2194 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
2195 G_CALLBACK (dialog_selection_callback),
2196 G_CALLBACK (popup_deactivate_callback),
2197 0);
2198
2199 if (menu)
2200 {
2201 specpdl_ref specpdl_count = SPECPDL_INDEX ();
2202
2203 DEFER_SELECTIONS;
2204 record_unwind_protect_ptr (pop_down_menu, menu);
2205
2206
2207 gtk_widget_show_all (menu);
2208
2209
2210 popup_widget_loop (true, menu);
2211
2212 unbind_to (specpdl_count, Qnil);
2213 }
2214 }
2215
2216 #else
2217 static void
2218 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
2219 {
2220
2221
2222 if ((intptr_t) client_data != -1)
2223 menu_item_selection = client_data;
2224
2225 block_input ();
2226 lw_destroy_all_widgets (id);
2227 unblock_input ();
2228 popup_activated_flag = 0;
2229 }
2230
2231
2232
2233
2234
2235 static void
2236 create_and_show_dialog (struct frame *f, widget_value *first_wv)
2237 {
2238 LWLIB_ID dialog_id;
2239
2240 eassert (FRAME_X_P (f));
2241
2242 dialog_id = widget_id_tick++;
2243 #ifdef USE_LUCID
2244 apply_systemfont_to_dialog (f->output_data.x->widget);
2245 #endif
2246 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2247 f->output_data.x->widget, true, 0,
2248 dialog_selection_callback, 0, 0);
2249 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
2250
2251 lw_pop_up_all_widgets (dialog_id);
2252 popup_activated_flag = 1;
2253 x_activate_timeout_atimer ();
2254
2255
2256
2257 {
2258 specpdl_ref count = SPECPDL_INDEX ();
2259
2260 DEFER_SELECTIONS;
2261
2262
2263
2264 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
2265
2266 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, true);
2267
2268 unbind_to (count, Qnil);
2269 }
2270 }
2271
2272 #endif
2273
2274 static const char * button_names [] = {
2275 "button1", "button2", "button3", "button4", "button5",
2276 "button6", "button7", "button8", "button9", "button10" };
2277
2278 static Lisp_Object
2279 x_dialog_show (struct frame *f, Lisp_Object title,
2280 Lisp_Object header, const char **error_name)
2281 {
2282 int i, nb_buttons=0;
2283 char dialog_name[6];
2284
2285 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2286
2287
2288 int left_count = 0;
2289
2290 bool boundary_seen = false;
2291
2292 specpdl_ref specpdl_count = SPECPDL_INDEX ();
2293
2294 eassert (FRAME_X_P (f));
2295
2296 *error_name = NULL;
2297
2298 if (menu_items_n_panes > 1)
2299 {
2300 *error_name = "Multiple panes in dialog box";
2301 return Qnil;
2302 }
2303
2304
2305
2306 {
2307 Lisp_Object pane_name;
2308 const char *pane_string;
2309 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
2310 pane_string = (NILP (pane_name)
2311 ? "" : SSDATA (pane_name));
2312 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
2313 first_wv = prev_wv;
2314
2315
2316 i = MENU_ITEMS_PANE_LENGTH;
2317 while (i < menu_items_used)
2318 {
2319
2320
2321 Lisp_Object item_name, enable, descrip;
2322 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2323 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2324 descrip
2325 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2326
2327 if (NILP (item_name))
2328 {
2329 free_menubar_widget_value_tree (first_wv);
2330 *error_name = "Submenu in dialog items";
2331 return Qnil;
2332 }
2333 if (EQ (item_name, Qquote))
2334 {
2335
2336
2337 boundary_seen = true;
2338 i++;
2339 continue;
2340 }
2341 if (nb_buttons >= 9)
2342 {
2343 free_menubar_widget_value_tree (first_wv);
2344 *error_name = "Too many dialog items";
2345 return Qnil;
2346 }
2347
2348 wv = make_widget_value (button_names[nb_buttons],
2349 SSDATA (item_name),
2350 !NILP (enable), Qnil);
2351 prev_wv->next = wv;
2352 if (!NILP (descrip))
2353 wv->key = SSDATA (descrip);
2354 wv->call_data = aref_addr (menu_items, i);
2355 prev_wv = wv;
2356
2357 if (! boundary_seen)
2358 left_count++;
2359
2360 nb_buttons++;
2361 i += MENU_ITEMS_ITEM_LENGTH;
2362 }
2363
2364
2365
2366 if (! boundary_seen)
2367 left_count = nb_buttons - nb_buttons / 2;
2368
2369 wv = make_widget_value (dialog_name, NULL, false, Qnil);
2370
2371
2372
2373
2374 if (NILP (header))
2375 dialog_name[0] = 'Q';
2376 else
2377 dialog_name[0] = 'I';
2378
2379
2380
2381
2382 dialog_name[1] = '0' + nb_buttons;
2383 dialog_name[2] = 'B';
2384 dialog_name[3] = 'R';
2385
2386 dialog_name[4] = '0' + nb_buttons - left_count;
2387 dialog_name[5] = 0;
2388 wv->contents = first_wv;
2389 first_wv = wv;
2390 }
2391
2392
2393 menu_item_selection = 0;
2394
2395
2396
2397 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
2398
2399
2400 create_and_show_dialog (f, first_wv);
2401
2402 unbind_to (specpdl_count, Qnil);
2403
2404
2405
2406 if (menu_item_selection != 0)
2407 {
2408 i = 0;
2409 while (i < menu_items_used)
2410 {
2411 Lisp_Object entry;
2412
2413 if (EQ (AREF (menu_items, i), Qt))
2414 i += MENU_ITEMS_PANE_LENGTH;
2415 else if (EQ (AREF (menu_items, i), Qquote))
2416 {
2417
2418
2419 ++i;
2420 }
2421 else
2422 {
2423 entry
2424 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2425 if (menu_item_selection == aref_addr (menu_items, i))
2426 return entry;
2427 i += MENU_ITEMS_ITEM_LENGTH;
2428 }
2429 }
2430 }
2431 else
2432
2433 quit ();
2434
2435 return Qnil;
2436 }
2437
2438 Lisp_Object
2439 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
2440 {
2441 Lisp_Object title;
2442 const char *error_name;
2443 Lisp_Object selection;
2444 specpdl_ref specpdl_count = SPECPDL_INDEX ();
2445
2446 check_window_system (f);
2447
2448
2449 title = Fcar (contents);
2450 CHECK_STRING (title);
2451 record_unwind_protect_void (unuse_menu_items);
2452
2453 if (NILP (Fcar (Fcdr (contents))))
2454
2455
2456
2457 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
2458
2459 list_of_panes (list1 (contents));
2460
2461
2462 block_input ();
2463 selection = x_dialog_show (f, title, header, &error_name);
2464 unblock_input ();
2465
2466 unbind_to (specpdl_count, Qnil);
2467 discard_menu_items ();
2468
2469 if (error_name) error ("%s", error_name);
2470 return selection;
2471 }
2472
2473 #else
2474
2475
2476
2477
2478 static struct frame *menu_help_frame;
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490 static void
2491 menu_help_callback (char const *help_string, int pane, int item)
2492 {
2493 Lisp_Object *first_item;
2494 Lisp_Object pane_name;
2495 Lisp_Object menu_object;
2496
2497 first_item = XVECTOR (menu_items)->contents;
2498 if (EQ (first_item[0], Qt))
2499 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2500 else if (EQ (first_item[0], Qquote))
2501
2502 pane_name = empty_unibyte_string;
2503 else
2504 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2505
2506
2507 menu_object = list3 (Qmenu_item, pane_name, make_fixnum (pane));
2508 show_help_echo (help_string ? build_string (help_string) : Qnil,
2509 Qnil, menu_object, make_fixnum (item));
2510 }
2511
2512 struct pop_down_menu
2513 {
2514 struct frame *frame;
2515 XMenu *menu;
2516 };
2517
2518 static void
2519 pop_down_menu (void *arg)
2520 {
2521 struct pop_down_menu *data = arg;
2522 struct frame *f = data->frame;
2523 XMenu *menu = data->menu;
2524 #ifdef HAVE_XINPUT2
2525 int i;
2526 struct xi_device_t *device;
2527 #endif
2528
2529 block_input ();
2530 #ifndef MSDOS
2531 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2532 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2533 #endif
2534 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2535
2536 #ifdef HAVE_X_WINDOWS
2537
2538
2539 x_mouse_leave (FRAME_DISPLAY_INFO (f));
2540
2541
2542
2543
2544
2545 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2546
2547 #ifdef HAVE_XINPUT2
2548
2549
2550
2551 for (i = 0; i < FRAME_DISPLAY_INFO (f)->num_devices; ++i)
2552 {
2553 device = &FRAME_DISPLAY_INFO (f)->devices[i];
2554 device->grab = 0;
2555 }
2556 #endif
2557
2558
2559 popup_activated_flag = 0;
2560 #endif
2561
2562 unblock_input ();
2563 }
2564
2565
2566 Lisp_Object
2567 x_menu_show (struct frame *f, int x, int y, int menuflags,
2568 Lisp_Object title, const char **error_name)
2569 {
2570 Window root;
2571 XMenu *menu;
2572 int pane, selidx, lpane, status;
2573 Lisp_Object entry = Qnil;
2574 Lisp_Object pane_prefix;
2575 char *datap;
2576 int ulx, uly, width, height;
2577 int dispwidth, dispheight;
2578 int i, j, lines, maxlines;
2579 int maxwidth;
2580 int dummy_int;
2581 unsigned int dummy_uint;
2582 specpdl_ref specpdl_count = SPECPDL_INDEX ();
2583
2584 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2585
2586 *error_name = 0;
2587 if (menu_items_n_panes == 0)
2588 return Qnil;
2589
2590 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2591 {
2592 *error_name = "Empty menu";
2593 return Qnil;
2594 }
2595
2596 USE_SAFE_ALLOCA;
2597 block_input ();
2598
2599
2600 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2601 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2602 &dummy_uint, &dummy_uint);
2603
2604
2605 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2606 if (menu == NULL)
2607 {
2608 *error_name = "Can't create menu";
2609 goto return_entry;
2610 }
2611
2612
2613
2614
2615 inhibit_garbage_collection ();
2616
2617 #ifdef HAVE_X_WINDOWS
2618 x_translate_coordinates_to_root (f, x, y, &x, &y);
2619 #else
2620
2621 x += f->left_pos;
2622 y += f->top_pos;
2623 #endif
2624
2625
2626 maxwidth = maxlines = lines = i = 0;
2627 lpane = XM_FAILURE;
2628 while (i < menu_items_used)
2629 {
2630 if (EQ (AREF (menu_items, i), Qt))
2631 {
2632
2633 Lisp_Object pane_name, prefix;
2634 const char *pane_string;
2635
2636 maxlines = max (maxlines, lines);
2637 lines = 0;
2638 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2639 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2640 pane_string = (NILP (pane_name)
2641 ? "" : SSDATA (pane_name));
2642 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2643 pane_string++;
2644
2645 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, true);
2646 if (lpane == XM_FAILURE)
2647 {
2648 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2649 *error_name = "Can't create pane";
2650 goto return_entry;
2651 }
2652 i += MENU_ITEMS_PANE_LENGTH;
2653
2654
2655 j = i;
2656 while (j < menu_items_used)
2657 {
2658 Lisp_Object item;
2659 item = AREF (menu_items, j);
2660 if (EQ (item, Qt))
2661 break;
2662 if (NILP (item))
2663 {
2664 j++;
2665 continue;
2666 }
2667 width = SBYTES (item);
2668 if (width > maxwidth)
2669 maxwidth = width;
2670
2671 j += MENU_ITEMS_ITEM_LENGTH;
2672 }
2673 }
2674
2675
2676 else if (EQ (AREF (menu_items, i), Qquote))
2677 i += 1;
2678 else
2679 {
2680
2681 Lisp_Object item_name, enable, descrip, help;
2682 char *item_data;
2683 char const *help_string;
2684
2685 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2686 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2687 descrip
2688 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2689 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2690 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2691
2692 if (!NILP (descrip))
2693 {
2694 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
2695 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2696 for (j = SCHARS (item_name); j < maxwidth; j++)
2697 item_data[j] = ' ';
2698 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2699 item_data[j + SBYTES (descrip)] = 0;
2700 }
2701 else
2702 item_data = SSDATA (item_name);
2703
2704 if (lpane == XM_FAILURE
2705 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2706 menu, lpane, 0, item_data,
2707 !NILP (enable), help_string)
2708 == XM_FAILURE))
2709 {
2710 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2711 *error_name = "Can't add selection to menu";
2712 goto return_entry;
2713 }
2714 i += MENU_ITEMS_ITEM_LENGTH;
2715 lines++;
2716 }
2717 }
2718
2719 maxlines = max (maxlines, lines);
2720
2721
2722 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2723 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2724 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2725 x = min (x, dispwidth);
2726 y = min (y, dispheight);
2727 x = max (x, 1);
2728 y = max (y, 1);
2729 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2730 &ulx, &uly, &width, &height);
2731 if (ulx + width > dispwidth)
2732 {
2733 x -= (ulx + width) - dispwidth;
2734 ulx = dispwidth - width;
2735 }
2736 if (uly + height > dispheight)
2737 {
2738 y -= (uly + height) - dispheight;
2739 uly = dispheight - height;
2740 }
2741 #ifndef HAVE_X_WINDOWS
2742 if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 1)
2743 {
2744
2745
2746 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2747 {
2748 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2749 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2750 }
2751 else
2752 {
2753 y--;
2754 uly--;
2755 }
2756 }
2757 #endif
2758 if (ulx < 0) x -= ulx;
2759 if (uly < 0) y -= uly;
2760
2761 if (!(menuflags & MENU_FOR_CLICK))
2762 {
2763
2764
2765
2766 x += width / 2;
2767 y += 1.5 * height/ (maxlines + 2);
2768 }
2769
2770 XMenuSetFreeze (menu, true);
2771 pane = selidx = 0;
2772
2773 #ifndef MSDOS
2774 DEFER_SELECTIONS;
2775
2776 XMenuActivateSetWaitFunction (x_menu_wait_for_event,
2777 FRAME_X_DISPLAY (f));
2778 XMenuEventHandler (x_menu_dispatch_event);
2779
2780
2781
2782
2783 #ifdef HAVE_XINPUT2
2784 XMenuActivateSetTranslateFunction (x_menu_translate_generic_event);
2785 #endif
2786 #endif
2787
2788 record_unwind_protect_ptr (pop_down_menu,
2789 &(struct pop_down_menu) {f, menu});
2790
2791
2792
2793 menu_help_frame = f;
2794
2795 #ifdef HAVE_XINPUT2
2796 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2797
2798
2799 if (dpyinfo->supports_xi2
2800 && xi_frame_selected_for (f, XI_ButtonPress))
2801 {
2802 for (int i = 0; i < dpyinfo->num_devices; ++i)
2803 {
2804 if (dpyinfo->devices[i].grab)
2805 XIUngrabDevice (dpyinfo->display, dpyinfo->devices[i].device_id,
2806 CurrentTime);
2807 }
2808 }
2809 #endif
2810
2811 #ifdef HAVE_X_WINDOWS
2812
2813
2814
2815 popup_activated_flag = 1;
2816 #endif
2817 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2818 x, y, ButtonReleaseMask, &datap,
2819 menu_help_callback);
2820 pane_prefix = Qnil;
2821
2822 switch (status)
2823 {
2824 case XM_SUCCESS:
2825 #ifdef XDEBUG
2826 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2827 #endif
2828
2829
2830 i = 0;
2831 while (i < menu_items_used)
2832 {
2833 if (EQ (AREF (menu_items, i), Qt))
2834 {
2835 if (pane == 0)
2836 pane_prefix
2837 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2838 pane--;
2839 i += MENU_ITEMS_PANE_LENGTH;
2840 }
2841 else
2842 {
2843 if (pane == -1)
2844 {
2845 if (selidx == 0)
2846 {
2847 entry
2848 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2849 if (menuflags & MENU_KEYMAPS)
2850 {
2851 entry = list1 (entry);
2852 if (!NILP (pane_prefix))
2853 entry = Fcons (pane_prefix, entry);
2854 }
2855 break;
2856 }
2857 selidx--;
2858 }
2859 i += MENU_ITEMS_ITEM_LENGTH;
2860 }
2861 }
2862 break;
2863
2864 case XM_FAILURE:
2865 *error_name = "Can't activate menu";
2866 case XM_IA_SELECT:
2867 break;
2868 case XM_NO_SELECT:
2869
2870
2871 if (!(menuflags & MENU_FOR_CLICK))
2872 {
2873 unblock_input ();
2874 quit ();
2875 }
2876 break;
2877 }
2878
2879 return_entry:
2880 unblock_input ();
2881 return SAFE_FREE_UNBIND_TO (specpdl_count, entry);
2882 }
2883
2884 #endif
2885
2886 #ifndef MSDOS
2887
2888
2889
2890 int
2891 popup_activated (void)
2892 {
2893 return popup_activated_flag;
2894 }
2895 #endif
2896
2897
2898
2899 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2900 doc:
2901 )
2902 (void)
2903 {
2904 return (popup_activated ()) ? Qt : Qnil;
2905 }
2906
2907
2908 static void syms_of_xmenu_for_pdumper (void);
2909
2910 void
2911 syms_of_xmenu (void)
2912 {
2913 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2914 defsubr (&Smenu_or_popup_active_p);
2915
2916 #ifdef USE_GTK
2917 DEFSYM (Qframe_monitor_workarea, "frame-monitor-workarea");
2918 #endif
2919
2920 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2921 defsubr (&Sx_menu_bar_open_internal);
2922 Ffset (intern_c_string ("accelerate-menu"),
2923 intern_c_string (Sx_menu_bar_open_internal.s.symbol_name));
2924 #endif
2925
2926 pdumper_do_now_and_after_load (syms_of_xmenu_for_pdumper);
2927 }
2928
2929 static void
2930 syms_of_xmenu_for_pdumper (void)
2931 {
2932 #ifdef USE_X_TOOLKIT
2933 enum { WIDGET_ID_TICK_START = 1 << 16 };
2934 widget_id_tick = WIDGET_ID_TICK_START;
2935 next_menubar_widget_id = 1;
2936 #endif
2937 }