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 static void
1621 prepare_for_entry_into_toolkit_menu (struct frame *f)
1622 {
1623 XIEventMask mask;
1624 ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
1625 unsigned char *m;
1626 Lisp_Object tail, frame;
1627 struct x_display_info *dpyinfo;
1628
1629 dpyinfo = FRAME_DISPLAY_INFO (f);
1630
1631 if (!dpyinfo->supports_xi2)
1632 return;
1633
1634 mask.mask = m = alloca (l);
1635 memset (m, 0, l);
1636 mask.mask_len = l;
1637
1638 mask.deviceid = XIAllMasterDevices;
1639
1640 XISetMask (m, XI_Motion);
1641 XISetMask (m, XI_Enter);
1642 XISetMask (m, XI_Leave);
1643
1644 FOR_EACH_FRAME (tail, frame)
1645 {
1646 f = XFRAME (frame);
1647
1648 if (FRAME_X_P (f)
1649 && FRAME_DISPLAY_INFO (f) == dpyinfo
1650 && !FRAME_TOOLTIP_P (f))
1651 XISelectEvents (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1652 &mask, 1);
1653 }
1654 }
1655
1656 static void
1657 leave_toolkit_menu (void *data)
1658 {
1659 XIEventMask mask;
1660 ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
1661 unsigned char *m;
1662 Lisp_Object tail, frame;
1663 struct x_display_info *dpyinfo;
1664 struct frame *f;
1665
1666 dpyinfo = FRAME_DISPLAY_INFO ((struct frame *) data);
1667
1668 if (!dpyinfo->supports_xi2)
1669 return;
1670
1671 mask.mask = m = alloca (l);
1672 memset (m, 0, l);
1673 mask.mask_len = l;
1674
1675 mask.deviceid = XIAllMasterDevices;
1676
1677 XISetMask (m, XI_ButtonPress);
1678 XISetMask (m, XI_ButtonRelease);
1679 XISetMask (m, XI_Motion);
1680 XISetMask (m, XI_Enter);
1681 XISetMask (m, XI_Leave);
1682
1683 FOR_EACH_FRAME (tail, frame)
1684 {
1685 f = XFRAME (frame);
1686
1687 if (FRAME_X_P (f)
1688 && FRAME_DISPLAY_INFO (f) == dpyinfo
1689 && !FRAME_TOOLTIP_P (f))
1690 XISelectEvents (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1691 &mask, 1);
1692 }
1693 }
1694 #endif
1695
1696
1697
1698 static void
1699 pop_down_menu (int id)
1700 {
1701 block_input ();
1702 lw_destroy_all_widgets ((LWLIB_ID) id);
1703 unblock_input ();
1704 popup_activated_flag = 0;
1705 }
1706
1707 #if defined HAVE_XINPUT2 && defined USE_MOTIF
1708 static Bool
1709 server_timestamp_predicate (Display *display,
1710 XEvent *xevent,
1711 XPointer arg)
1712 {
1713 XID *args = (XID *) arg;
1714
1715 if (xevent->type == PropertyNotify
1716 && xevent->xproperty.window == args[0]
1717 && xevent->xproperty.atom == args[1])
1718 return True;
1719
1720 return False;
1721 }
1722 #endif
1723
1724
1725
1726
1727 static void
1728 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1729 int x, int y, bool for_click)
1730 {
1731 int i;
1732 Arg av[2];
1733 int ac = 0;
1734 XEvent dummy;
1735 XButtonPressedEvent *event = &(dummy.xbutton);
1736 LWLIB_ID menu_id;
1737 Widget menu;
1738 #if defined HAVE_XINPUT2 && defined USE_MOTIF
1739 XEvent property_dummy;
1740 Atom property_atom;
1741 #endif
1742
1743 eassert (FRAME_X_P (f));
1744
1745 #ifdef USE_LUCID
1746 apply_systemfont_to_menu (f, f->output_data.x->widget);
1747 #endif
1748
1749 menu_id = widget_id_tick++;
1750 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1751 f->output_data.x->widget, true, 0,
1752 popup_selection_callback,
1753 popup_deactivate_callback,
1754 menu_highlight_callback);
1755
1756 event->type = ButtonPress;
1757 event->serial = 0;
1758 event->send_event = false;
1759 event->display = FRAME_X_DISPLAY (f);
1760 event->time = CurrentTime;
1761 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1762 event->window = event->subwindow = event->root;
1763 event->x = x;
1764 event->y = y;
1765
1766
1767 block_input ();
1768 x += FRAME_LEFT_SCROLL_BAR_AREA_WIDTH (f);
1769 x_translate_coordinates_to_root (f, x, y, &x, &y);
1770 unblock_input ();
1771
1772 event->x_root = x;
1773 event->y_root = y;
1774
1775 event->state = 0;
1776 event->button = 0;
1777 for (i = 0; i < 5; i++)
1778 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1779 event->button = i;
1780
1781
1782 XtSetArg (av[ac], (char *) XtNgeometry, 0); ac++;
1783 XtSetValues (menu, av, ac);
1784
1785 #ifdef HAVE_XINPUT2
1786 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1787
1788
1789
1790 if (dpyinfo->supports_xi2)
1791 XGrabServer (dpyinfo->display);
1792
1793 if (dpyinfo->supports_xi2
1794 && xi_frame_selected_for (f, XI_ButtonPress))
1795 {
1796 for (int i = 0; i < dpyinfo->num_devices; ++i)
1797 {
1798 if (dpyinfo->devices[i].grab)
1799 {
1800 dpyinfo->devices[i].grab = 0;
1801
1802 XIUngrabDevice (dpyinfo->display,
1803 dpyinfo->devices[i].device_id,
1804 CurrentTime);
1805 }
1806 }
1807 }
1808
1809 #ifdef USE_MOTIF
1810 if (dpyinfo->supports_xi2)
1811 {
1812
1813
1814
1815
1816
1817 property_atom = dpyinfo->Xatom_EMACS_SERVER_TIME_PROP;
1818
1819 XChangeProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
1820 property_atom, XA_ATOM, 32,
1821 PropModeReplace, (unsigned char *) &property_atom, 1);
1822
1823 XIfEvent (dpyinfo->display, &property_dummy, server_timestamp_predicate,
1824 (XPointer) &(XID[]) {FRAME_OUTER_WINDOW (f), property_atom});
1825
1826 XtDispatchEvent (&property_dummy);
1827 }
1828 #endif
1829 #endif
1830
1831 #ifdef HAVE_XINPUT2
1832 prepare_for_entry_into_toolkit_menu (f);
1833
1834 #ifdef USE_LUCID
1835 if (dpyinfo->supports_xi2)
1836 x_mouse_leave (dpyinfo);
1837 #endif
1838 #endif
1839
1840 lw_popup_menu (menu, &dummy);
1841
1842 #ifdef HAVE_XINPUT2
1843 if (dpyinfo->supports_xi2)
1844 XUngrabServer (dpyinfo->display);
1845 #endif
1846
1847 popup_activated_flag = 1;
1848
1849 x_activate_timeout_atimer ();
1850
1851 {
1852 specpdl_ref specpdl_count = SPECPDL_INDEX ();
1853
1854 DEFER_SELECTIONS;
1855
1856 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1857 #ifdef HAVE_XINPUT2
1858 record_unwind_protect_ptr (leave_toolkit_menu, f);
1859 #endif
1860
1861
1862 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, true);
1863
1864 unbind_to (specpdl_count, Qnil);
1865 }
1866 }
1867
1868 #endif
1869
1870 static void
1871 cleanup_widget_value_tree (void *arg)
1872 {
1873 free_menubar_widget_value_tree (arg);
1874 }
1875
1876 Lisp_Object
1877 x_menu_show (struct frame *f, int x, int y, int menuflags,
1878 Lisp_Object title, const char **error_name)
1879 {
1880 int i;
1881 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1882 widget_value **submenu_stack;
1883 Lisp_Object *subprefix_stack;
1884 int submenu_depth = 0;
1885 specpdl_ref specpdl_count;
1886
1887 USE_SAFE_ALLOCA;
1888
1889 submenu_stack = SAFE_ALLOCA (menu_items_used
1890 * sizeof *submenu_stack);
1891 subprefix_stack = SAFE_ALLOCA (menu_items_used
1892 * sizeof *subprefix_stack);
1893
1894 specpdl_count = SPECPDL_INDEX ();
1895
1896 eassert (FRAME_X_P (f));
1897
1898 *error_name = NULL;
1899
1900 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1901 {
1902 *error_name = "Empty menu";
1903 SAFE_FREE ();
1904 return Qnil;
1905 }
1906
1907 block_input ();
1908
1909
1910
1911 wv = make_widget_value ("menu", NULL, true, Qnil);
1912 wv->button_type = BUTTON_TYPE_NONE;
1913 first_wv = wv;
1914 bool first_pane = true;
1915
1916
1917 i = 0;
1918 while (i < menu_items_used)
1919 {
1920 if (NILP (AREF (menu_items, i)))
1921 {
1922 submenu_stack[submenu_depth++] = save_wv;
1923 save_wv = prev_wv;
1924 prev_wv = 0;
1925 first_pane = true;
1926 i++;
1927 }
1928 else if (EQ (AREF (menu_items, i), Qlambda))
1929 {
1930 prev_wv = save_wv;
1931 save_wv = submenu_stack[--submenu_depth];
1932 first_pane = false;
1933 i++;
1934 }
1935 else if (EQ (AREF (menu_items, i), Qt)
1936 && submenu_depth != 0)
1937 i += MENU_ITEMS_PANE_LENGTH;
1938
1939
1940 else if (EQ (AREF (menu_items, i), Qquote))
1941 i += 1;
1942 else if (EQ (AREF (menu_items, i), Qt))
1943 {
1944
1945 Lisp_Object pane_name, prefix;
1946 const char *pane_string;
1947
1948 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1949 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1950
1951 #ifndef HAVE_MULTILINGUAL_MENU
1952 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1953 {
1954 pane_name = ENCODE_MENU_STRING (pane_name);
1955 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1956 }
1957 #endif
1958 pane_string = (NILP (pane_name)
1959 ? "" : SSDATA (pane_name));
1960
1961
1962 if (menu_items_n_panes == 1)
1963 pane_string = "";
1964
1965
1966
1967
1968 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1969 {
1970 wv = make_widget_value (pane_string, NULL, true, Qnil);
1971 if (save_wv)
1972 save_wv->next = wv;
1973 else
1974 first_wv->contents = wv;
1975 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1976 wv->name++;
1977 wv->button_type = BUTTON_TYPE_NONE;
1978 save_wv = wv;
1979 prev_wv = 0;
1980 }
1981 else if (first_pane)
1982 {
1983 save_wv = wv;
1984 prev_wv = 0;
1985 }
1986 first_pane = false;
1987 i += MENU_ITEMS_PANE_LENGTH;
1988 }
1989 else
1990 {
1991
1992 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1993 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1994 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1995 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1996 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1997 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1998 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1999 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2000
2001 #ifndef HAVE_MULTILINGUAL_MENU
2002 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
2003 {
2004 item_name = ENCODE_MENU_STRING (item_name);
2005 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
2006 }
2007
2008 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
2009 {
2010 descrip = ENCODE_MENU_STRING (descrip);
2011 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
2012 }
2013 #endif
2014
2015 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
2016 STRINGP (help) ? help : Qnil);
2017 if (prev_wv)
2018 prev_wv->next = wv;
2019 else if (!save_wv)
2020 {
2021
2022
2023
2024
2025 emacs_abort ();
2026 }
2027 else
2028 save_wv->contents = wv;
2029 if (!NILP (descrip))
2030 wv->key = SSDATA (descrip);
2031
2032
2033
2034 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
2035
2036 if (NILP (type))
2037 wv->button_type = BUTTON_TYPE_NONE;
2038 else if (EQ (type, QCtoggle))
2039 wv->button_type = BUTTON_TYPE_TOGGLE;
2040 else if (EQ (type, QCradio))
2041 wv->button_type = BUTTON_TYPE_RADIO;
2042 else
2043 emacs_abort ();
2044
2045 wv->selected = !NILP (selected);
2046
2047 prev_wv = wv;
2048
2049 i += MENU_ITEMS_ITEM_LENGTH;
2050 }
2051 }
2052
2053
2054 if (!NILP (title))
2055 {
2056 widget_value *wv_title;
2057 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
2058 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
2059
2060 wv_sep2->next = first_wv->contents;
2061 wv_sep1->next = wv_sep2;
2062
2063 #ifndef HAVE_MULTILINGUAL_MENU
2064 if (STRING_MULTIBYTE (title))
2065 title = ENCODE_MENU_STRING (title);
2066 #endif
2067
2068 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
2069 wv_title->button_type = BUTTON_TYPE_NONE;
2070 wv_title->next = wv_sep1;
2071 first_wv->contents = wv_title;
2072 }
2073
2074
2075 menu_item_selection = 0;
2076
2077
2078
2079 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
2080
2081
2082 create_and_show_popup_menu (f, first_wv, x, y,
2083 menuflags & MENU_FOR_CLICK);
2084
2085 unbind_to (specpdl_count, Qnil);
2086
2087
2088
2089 if (menu_item_selection != 0)
2090 {
2091 Lisp_Object prefix, entry;
2092
2093 prefix = entry = Qnil;
2094 i = 0;
2095 while (i < menu_items_used)
2096 {
2097 if (NILP (AREF (menu_items, i)))
2098 {
2099 subprefix_stack[submenu_depth++] = prefix;
2100 prefix = entry;
2101 i++;
2102 }
2103 else if (EQ (AREF (menu_items, i), Qlambda))
2104 {
2105 prefix = subprefix_stack[--submenu_depth];
2106 i++;
2107 }
2108 else if (EQ (AREF (menu_items, i), Qt))
2109 {
2110 prefix
2111 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2112 i += MENU_ITEMS_PANE_LENGTH;
2113 }
2114
2115
2116 else if (EQ (AREF (menu_items, i), Qquote))
2117 i += 1;
2118 else
2119 {
2120 entry
2121 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2122 if (menu_item_selection == aref_addr (menu_items, i))
2123 {
2124 if (menuflags & MENU_KEYMAPS)
2125 {
2126 int j;
2127
2128 entry = list1 (entry);
2129 if (!NILP (prefix))
2130 entry = Fcons (prefix, entry);
2131 for (j = submenu_depth - 1; j >= 0; j--)
2132 if (!NILP (subprefix_stack[j]))
2133 entry = Fcons (subprefix_stack[j], entry);
2134 }
2135 unblock_input ();
2136
2137 SAFE_FREE ();
2138 return entry;
2139 }
2140 i += MENU_ITEMS_ITEM_LENGTH;
2141 }
2142 }
2143 }
2144 else if (!(menuflags & MENU_FOR_CLICK))
2145 {
2146 unblock_input ();
2147
2148 quit ();
2149 }
2150
2151 unblock_input ();
2152
2153 SAFE_FREE ();
2154 return Qnil;
2155 }
2156
2157 #ifdef USE_GTK
2158 static void
2159 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
2160 {
2161
2162
2163 if ((intptr_t) client_data != -1)
2164 menu_item_selection = client_data;
2165
2166 popup_activated_flag = 0;
2167 }
2168
2169
2170
2171
2172 static void
2173 create_and_show_dialog (struct frame *f, widget_value *first_wv)
2174 {
2175 GtkWidget *menu;
2176
2177 eassert (FRAME_X_P (f));
2178
2179 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
2180 G_CALLBACK (dialog_selection_callback),
2181 G_CALLBACK (popup_deactivate_callback),
2182 0);
2183
2184 if (menu)
2185 {
2186 specpdl_ref specpdl_count = SPECPDL_INDEX ();
2187
2188 DEFER_SELECTIONS;
2189 record_unwind_protect_ptr (pop_down_menu, menu);
2190
2191
2192 gtk_widget_show_all (menu);
2193
2194
2195 popup_widget_loop (true, menu);
2196
2197 unbind_to (specpdl_count, Qnil);
2198 }
2199 }
2200
2201 #else
2202 static void
2203 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
2204 {
2205
2206
2207 if ((intptr_t) client_data != -1)
2208 menu_item_selection = client_data;
2209
2210 block_input ();
2211 lw_destroy_all_widgets (id);
2212 unblock_input ();
2213 popup_activated_flag = 0;
2214 }
2215
2216
2217
2218
2219
2220 static void
2221 create_and_show_dialog (struct frame *f, widget_value *first_wv)
2222 {
2223 LWLIB_ID dialog_id;
2224
2225 eassert (FRAME_X_P (f));
2226
2227 dialog_id = widget_id_tick++;
2228 #ifdef USE_LUCID
2229 apply_systemfont_to_dialog (f->output_data.x->widget);
2230 #endif
2231 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2232 f->output_data.x->widget, true, 0,
2233 dialog_selection_callback, 0, 0);
2234 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
2235
2236 lw_pop_up_all_widgets (dialog_id);
2237 popup_activated_flag = 1;
2238 x_activate_timeout_atimer ();
2239
2240
2241
2242 {
2243 specpdl_ref count = SPECPDL_INDEX ();
2244
2245 DEFER_SELECTIONS;
2246
2247
2248
2249 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
2250
2251 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, true);
2252
2253 unbind_to (count, Qnil);
2254 }
2255 }
2256
2257 #endif
2258
2259 static const char * button_names [] = {
2260 "button1", "button2", "button3", "button4", "button5",
2261 "button6", "button7", "button8", "button9", "button10" };
2262
2263 static Lisp_Object
2264 x_dialog_show (struct frame *f, Lisp_Object title,
2265 Lisp_Object header, const char **error_name)
2266 {
2267 int i, nb_buttons=0;
2268 char dialog_name[6];
2269
2270 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2271
2272
2273 int left_count = 0;
2274
2275 bool boundary_seen = false;
2276
2277 specpdl_ref specpdl_count = SPECPDL_INDEX ();
2278
2279 eassert (FRAME_X_P (f));
2280
2281 *error_name = NULL;
2282
2283 if (menu_items_n_panes > 1)
2284 {
2285 *error_name = "Multiple panes in dialog box";
2286 return Qnil;
2287 }
2288
2289
2290
2291 {
2292 Lisp_Object pane_name;
2293 const char *pane_string;
2294 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
2295 pane_string = (NILP (pane_name)
2296 ? "" : SSDATA (pane_name));
2297 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
2298 first_wv = prev_wv;
2299
2300
2301 i = MENU_ITEMS_PANE_LENGTH;
2302 while (i < menu_items_used)
2303 {
2304
2305
2306 Lisp_Object item_name, enable, descrip;
2307 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2308 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2309 descrip
2310 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2311
2312 if (NILP (item_name))
2313 {
2314 free_menubar_widget_value_tree (first_wv);
2315 *error_name = "Submenu in dialog items";
2316 return Qnil;
2317 }
2318 if (EQ (item_name, Qquote))
2319 {
2320
2321
2322 boundary_seen = true;
2323 i++;
2324 continue;
2325 }
2326 if (nb_buttons >= 9)
2327 {
2328 free_menubar_widget_value_tree (first_wv);
2329 *error_name = "Too many dialog items";
2330 return Qnil;
2331 }
2332
2333 wv = make_widget_value (button_names[nb_buttons],
2334 SSDATA (item_name),
2335 !NILP (enable), Qnil);
2336 prev_wv->next = wv;
2337 if (!NILP (descrip))
2338 wv->key = SSDATA (descrip);
2339 wv->call_data = aref_addr (menu_items, i);
2340 prev_wv = wv;
2341
2342 if (! boundary_seen)
2343 left_count++;
2344
2345 nb_buttons++;
2346 i += MENU_ITEMS_ITEM_LENGTH;
2347 }
2348
2349
2350
2351 if (! boundary_seen)
2352 left_count = nb_buttons - nb_buttons / 2;
2353
2354 wv = make_widget_value (dialog_name, NULL, false, Qnil);
2355
2356
2357
2358
2359 if (NILP (header))
2360 dialog_name[0] = 'Q';
2361 else
2362 dialog_name[0] = 'I';
2363
2364
2365
2366
2367 dialog_name[1] = '0' + nb_buttons;
2368 dialog_name[2] = 'B';
2369 dialog_name[3] = 'R';
2370
2371 dialog_name[4] = '0' + nb_buttons - left_count;
2372 dialog_name[5] = 0;
2373 wv->contents = first_wv;
2374 first_wv = wv;
2375 }
2376
2377
2378 menu_item_selection = 0;
2379
2380
2381
2382 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
2383
2384
2385 create_and_show_dialog (f, first_wv);
2386
2387 unbind_to (specpdl_count, Qnil);
2388
2389
2390
2391 if (menu_item_selection != 0)
2392 {
2393 i = 0;
2394 while (i < menu_items_used)
2395 {
2396 Lisp_Object entry;
2397
2398 if (EQ (AREF (menu_items, i), Qt))
2399 i += MENU_ITEMS_PANE_LENGTH;
2400 else if (EQ (AREF (menu_items, i), Qquote))
2401 {
2402
2403
2404 ++i;
2405 }
2406 else
2407 {
2408 entry
2409 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2410 if (menu_item_selection == aref_addr (menu_items, i))
2411 return entry;
2412 i += MENU_ITEMS_ITEM_LENGTH;
2413 }
2414 }
2415 }
2416 else
2417
2418 quit ();
2419
2420 return Qnil;
2421 }
2422
2423 Lisp_Object
2424 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
2425 {
2426 Lisp_Object title;
2427 const char *error_name;
2428 Lisp_Object selection;
2429 specpdl_ref specpdl_count = SPECPDL_INDEX ();
2430
2431 check_window_system (f);
2432
2433
2434 title = Fcar (contents);
2435 CHECK_STRING (title);
2436 record_unwind_protect_void (unuse_menu_items);
2437
2438 if (NILP (Fcar (Fcdr (contents))))
2439
2440
2441
2442 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
2443
2444 list_of_panes (list1 (contents));
2445
2446
2447 block_input ();
2448 selection = x_dialog_show (f, title, header, &error_name);
2449 unblock_input ();
2450
2451 unbind_to (specpdl_count, Qnil);
2452 discard_menu_items ();
2453
2454 if (error_name) error ("%s", error_name);
2455 return selection;
2456 }
2457
2458 #else
2459
2460
2461
2462
2463 static struct frame *menu_help_frame;
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475 static void
2476 menu_help_callback (char const *help_string, int pane, int item)
2477 {
2478 Lisp_Object *first_item;
2479 Lisp_Object pane_name;
2480 Lisp_Object menu_object;
2481
2482 first_item = XVECTOR (menu_items)->contents;
2483 if (EQ (first_item[0], Qt))
2484 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2485 else if (EQ (first_item[0], Qquote))
2486
2487 pane_name = empty_unibyte_string;
2488 else
2489 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2490
2491
2492 menu_object = list3 (Qmenu_item, pane_name, make_fixnum (pane));
2493 show_help_echo (help_string ? build_string (help_string) : Qnil,
2494 Qnil, menu_object, make_fixnum (item));
2495 }
2496
2497 struct pop_down_menu
2498 {
2499 struct frame *frame;
2500 XMenu *menu;
2501 };
2502
2503 static void
2504 pop_down_menu (void *arg)
2505 {
2506 struct pop_down_menu *data = arg;
2507 struct frame *f = data->frame;
2508 XMenu *menu = data->menu;
2509 #ifdef HAVE_XINPUT2
2510 int i;
2511 struct xi_device_t *device;
2512 #endif
2513
2514 block_input ();
2515 #ifndef MSDOS
2516 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2517 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2518 #endif
2519 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2520
2521 #ifdef HAVE_X_WINDOWS
2522
2523
2524 x_mouse_leave (FRAME_DISPLAY_INFO (f));
2525
2526
2527
2528
2529
2530 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2531
2532 #ifdef HAVE_XINPUT2
2533
2534
2535
2536 for (i = 0; i < FRAME_DISPLAY_INFO (f)->num_devices; ++i)
2537 {
2538 device = &FRAME_DISPLAY_INFO (f)->devices[i];
2539 device->grab = 0;
2540 }
2541 #endif
2542
2543
2544 popup_activated_flag = 0;
2545 #endif
2546
2547 unblock_input ();
2548 }
2549
2550
2551 Lisp_Object
2552 x_menu_show (struct frame *f, int x, int y, int menuflags,
2553 Lisp_Object title, const char **error_name)
2554 {
2555 Window root;
2556 XMenu *menu;
2557 int pane, selidx, lpane, status;
2558 Lisp_Object entry = Qnil;
2559 Lisp_Object pane_prefix;
2560 char *datap;
2561 int ulx, uly, width, height;
2562 int dispwidth, dispheight;
2563 int i, j, lines, maxlines;
2564 int maxwidth;
2565 int dummy_int;
2566 unsigned int dummy_uint;
2567 specpdl_ref specpdl_count = SPECPDL_INDEX ();
2568
2569 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2570
2571 *error_name = 0;
2572 if (menu_items_n_panes == 0)
2573 return Qnil;
2574
2575 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2576 {
2577 *error_name = "Empty menu";
2578 return Qnil;
2579 }
2580
2581 USE_SAFE_ALLOCA;
2582 block_input ();
2583
2584
2585 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2586 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2587 &dummy_uint, &dummy_uint);
2588
2589
2590 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2591 if (menu == NULL)
2592 {
2593 *error_name = "Can't create menu";
2594 goto return_entry;
2595 }
2596
2597
2598
2599
2600 inhibit_garbage_collection ();
2601
2602 #ifdef HAVE_X_WINDOWS
2603 x_translate_coordinates_to_root (f, x, y, &x, &y);
2604 #else
2605
2606 x += f->left_pos;
2607 y += f->top_pos;
2608 #endif
2609
2610
2611 maxwidth = maxlines = lines = i = 0;
2612 lpane = XM_FAILURE;
2613 while (i < menu_items_used)
2614 {
2615 if (EQ (AREF (menu_items, i), Qt))
2616 {
2617
2618 Lisp_Object pane_name, prefix;
2619 const char *pane_string;
2620
2621 maxlines = max (maxlines, lines);
2622 lines = 0;
2623 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2624 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2625 pane_string = (NILP (pane_name)
2626 ? "" : SSDATA (pane_name));
2627 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2628 pane_string++;
2629
2630 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, true);
2631 if (lpane == XM_FAILURE)
2632 {
2633 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2634 *error_name = "Can't create pane";
2635 goto return_entry;
2636 }
2637 i += MENU_ITEMS_PANE_LENGTH;
2638
2639
2640 j = i;
2641 while (j < menu_items_used)
2642 {
2643 Lisp_Object item;
2644 item = AREF (menu_items, j);
2645 if (EQ (item, Qt))
2646 break;
2647 if (NILP (item))
2648 {
2649 j++;
2650 continue;
2651 }
2652 width = SBYTES (item);
2653 if (width > maxwidth)
2654 maxwidth = width;
2655
2656 j += MENU_ITEMS_ITEM_LENGTH;
2657 }
2658 }
2659
2660
2661 else if (EQ (AREF (menu_items, i), Qquote))
2662 i += 1;
2663 else
2664 {
2665
2666 Lisp_Object item_name, enable, descrip, help;
2667 char *item_data;
2668 char const *help_string;
2669
2670 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2671 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2672 descrip
2673 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2674 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2675 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2676
2677 if (!NILP (descrip))
2678 {
2679 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
2680 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2681 for (j = SCHARS (item_name); j < maxwidth; j++)
2682 item_data[j] = ' ';
2683 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2684 item_data[j + SBYTES (descrip)] = 0;
2685 }
2686 else
2687 item_data = SSDATA (item_name);
2688
2689 if (lpane == XM_FAILURE
2690 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2691 menu, lpane, 0, item_data,
2692 !NILP (enable), help_string)
2693 == XM_FAILURE))
2694 {
2695 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2696 *error_name = "Can't add selection to menu";
2697 goto return_entry;
2698 }
2699 i += MENU_ITEMS_ITEM_LENGTH;
2700 lines++;
2701 }
2702 }
2703
2704 maxlines = max (maxlines, lines);
2705
2706
2707 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2708 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2709 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2710 x = min (x, dispwidth);
2711 y = min (y, dispheight);
2712 x = max (x, 1);
2713 y = max (y, 1);
2714 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2715 &ulx, &uly, &width, &height);
2716 if (ulx + width > dispwidth)
2717 {
2718 x -= (ulx + width) - dispwidth;
2719 ulx = dispwidth - width;
2720 }
2721 if (uly + height > dispheight)
2722 {
2723 y -= (uly + height) - dispheight;
2724 uly = dispheight - height;
2725 }
2726 #ifndef HAVE_X_WINDOWS
2727 if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 1)
2728 {
2729
2730
2731 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2732 {
2733 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2734 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2735 }
2736 else
2737 {
2738 y--;
2739 uly--;
2740 }
2741 }
2742 #endif
2743 if (ulx < 0) x -= ulx;
2744 if (uly < 0) y -= uly;
2745
2746 if (!(menuflags & MENU_FOR_CLICK))
2747 {
2748
2749
2750
2751 x += width / 2;
2752 y += 1.5 * height/ (maxlines + 2);
2753 }
2754
2755 XMenuSetFreeze (menu, true);
2756 pane = selidx = 0;
2757
2758 #ifndef MSDOS
2759 DEFER_SELECTIONS;
2760
2761 XMenuActivateSetWaitFunction (x_menu_wait_for_event,
2762 FRAME_X_DISPLAY (f));
2763 XMenuEventHandler (x_menu_dispatch_event);
2764
2765
2766
2767
2768 #ifdef HAVE_XINPUT2
2769 XMenuActivateSetTranslateFunction (x_menu_translate_generic_event);
2770 #endif
2771 #endif
2772
2773 record_unwind_protect_ptr (pop_down_menu,
2774 &(struct pop_down_menu) {f, menu});
2775
2776
2777
2778 menu_help_frame = f;
2779
2780 #ifdef HAVE_XINPUT2
2781 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2782
2783
2784 if (dpyinfo->supports_xi2
2785 && xi_frame_selected_for (f, XI_ButtonPress))
2786 {
2787 for (int i = 0; i < dpyinfo->num_devices; ++i)
2788 {
2789 if (dpyinfo->devices[i].grab)
2790 XIUngrabDevice (dpyinfo->display, dpyinfo->devices[i].device_id,
2791 CurrentTime);
2792 }
2793 }
2794 #endif
2795
2796 #ifdef HAVE_X_WINDOWS
2797
2798
2799
2800 popup_activated_flag = 1;
2801 #endif
2802 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2803 x, y, ButtonReleaseMask, &datap,
2804 menu_help_callback);
2805 pane_prefix = Qnil;
2806
2807 switch (status)
2808 {
2809 case XM_SUCCESS:
2810 #ifdef XDEBUG
2811 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2812 #endif
2813
2814
2815 i = 0;
2816 while (i < menu_items_used)
2817 {
2818 if (EQ (AREF (menu_items, i), Qt))
2819 {
2820 if (pane == 0)
2821 pane_prefix
2822 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2823 pane--;
2824 i += MENU_ITEMS_PANE_LENGTH;
2825 }
2826 else
2827 {
2828 if (pane == -1)
2829 {
2830 if (selidx == 0)
2831 {
2832 entry
2833 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2834 if (menuflags & MENU_KEYMAPS)
2835 {
2836 entry = list1 (entry);
2837 if (!NILP (pane_prefix))
2838 entry = Fcons (pane_prefix, entry);
2839 }
2840 break;
2841 }
2842 selidx--;
2843 }
2844 i += MENU_ITEMS_ITEM_LENGTH;
2845 }
2846 }
2847 break;
2848
2849 case XM_FAILURE:
2850 *error_name = "Can't activate menu";
2851 case XM_IA_SELECT:
2852 break;
2853 case XM_NO_SELECT:
2854
2855
2856 if (!(menuflags & MENU_FOR_CLICK))
2857 {
2858 unblock_input ();
2859 quit ();
2860 }
2861 break;
2862 }
2863
2864 return_entry:
2865 unblock_input ();
2866 return SAFE_FREE_UNBIND_TO (specpdl_count, entry);
2867 }
2868
2869 #endif
2870
2871 #ifndef MSDOS
2872
2873
2874
2875 int
2876 popup_activated (void)
2877 {
2878 return popup_activated_flag;
2879 }
2880 #endif
2881
2882
2883
2884 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2885 doc:
2886 )
2887 (void)
2888 {
2889 return (popup_activated ()) ? Qt : Qnil;
2890 }
2891
2892
2893 static void syms_of_xmenu_for_pdumper (void);
2894
2895 void
2896 syms_of_xmenu (void)
2897 {
2898 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2899 defsubr (&Smenu_or_popup_active_p);
2900
2901 #ifdef USE_GTK
2902 DEFSYM (Qframe_monitor_workarea, "frame-monitor-workarea");
2903 #endif
2904
2905 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2906 defsubr (&Sx_menu_bar_open_internal);
2907 Ffset (intern_c_string ("accelerate-menu"),
2908 intern_c_string (Sx_menu_bar_open_internal.s.symbol_name));
2909 #endif
2910
2911 pdumper_do_now_and_after_load (syms_of_xmenu_for_pdumper);
2912 }
2913
2914 static void
2915 syms_of_xmenu_for_pdumper (void)
2916 {
2917 #ifdef USE_X_TOOLKIT
2918 enum { WIDGET_ID_TICK_START = 1 << 16 };
2919 widget_id_tick = WIDGET_ID_TICK_START;
2920 next_menubar_widget_id = 1;
2921 #endif
2922 }