root/src/xmenu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. menubar_id_to_frame
  2. x_menu_set_in_use
  3. x_menu_wait_for_event
  4. x_menu_translate_generic_event
  5. x_menu_dispatch_event
  6. popup_get_selection
  7. DEFUN
  8. DEFUN
  9. popup_widget_loop
  10. x_activate_menubar
  11. popup_activate_callback
  12. popup_deactivate_callback
  13. show_help_event
  14. menu_highlight_callback
  15. menu_highlight_callback
  16. menubar_selection_callback
  17. menubar_selection_callback
  18. update_frame_menubar
  19. apply_systemfont_to_dialog
  20. apply_systemfont_to_menu
  21. set_frame_menubar
  22. initialize_frame_menubar
  23. free_frame_menubar
  24. menu_position_func
  25. popup_selection_callback
  26. pop_down_menu
  27. create_and_show_popup_menu
  28. popup_selection_callback
  29. prepare_for_entry_into_toolkit_menu
  30. leave_toolkit_menu
  31. pop_down_menu
  32. server_timestamp_predicate
  33. create_and_show_popup_menu
  34. cleanup_widget_value_tree
  35. x_menu_show
  36. dialog_selection_callback
  37. create_and_show_dialog
  38. dialog_selection_callback
  39. create_and_show_dialog
  40. x_dialog_show
  41. xw_popup_dialog
  42. menu_help_callback
  43. pop_down_menu
  44. x_menu_show
  45. popup_activated
  46. DEFUN
  47. syms_of_xmenu
  48. syms_of_xmenu_for_pdumper

     1 /* X Communication module for terminals which understand the X protocol.
     2 
     3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2023 Free Software
     4 Foundation, Inc.
     5 
     6 Author: Jon Arnold
     7         Roman Budzianowski
     8         Robert Krawitz
     9 
    10 This file is part of GNU Emacs.
    11 
    12 GNU Emacs is free software: you can redistribute it and/or modify
    13 it under the terms of the GNU General Public License as published by
    14 the Free Software Foundation, either version 3 of the License, or (at
    15 your option) any later version.
    16 
    17 GNU Emacs is distributed in the hope that it will be useful,
    18 but WITHOUT ANY WARRANTY; without even the implied warranty of
    19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    20 GNU General Public License for more details.
    21 
    22 You should have received a copy of the GNU General Public License
    23 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    24 
    25 /* X pop-up deck-of-cards menu facility for GNU Emacs.
    26  *
    27  */
    28 
    29 /* Modified by Fred Pierresteguy on December 93
    30    to make the popup menus and menubar use the Xt.  */
    31 
    32 /* Rewritten for clarity and GC protection by rms in Feb 94.  */
    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 /* This may include sys/types.h, and that somehow loses
    61    if this is not done before the other system files.  */
    62 #include "xterm.h"
    63 #endif
    64 
    65 /* Load sys/types.h if not already loaded.
    66    In some systems loading it twice is suicidal.  */
    67 #ifndef makedev
    68 #include <sys/types.h>
    69 #endif
    70 
    71 #ifdef HAVE_X_WINDOWS
    72 /*  Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
    73     code accepts the Emacs internal encoding.  */
    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 /* !HAVE_XAW3D */
    88 #include <X11/Xaw/Paned.h>
    89 #endif /* HAVE_XAW3D */
    90 #endif /* USE_LUCID */
    91 #ifdef USE_MOTIF
    92 #include "../lwlib/lwlib.h"
    93 #endif
    94 #else /* not USE_X_TOOLKIT */
    95 #ifndef USE_GTK
    96 #include "../oldXMenu/XMenu.h"
    97 #endif
    98 #endif /* not USE_X_TOOLKIT */
    99 #endif /* HAVE_X_WINDOWS */
   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 /* Flag which when set indicates a dialog or menu has been posted by
   112    Xt on behalf of one of the widget sets.  */
   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 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none.  */
   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 /* Set menu_items_inuse so no other popup menu or dialog is created.  */
   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   /* Don't let frames in `above' z-group obscure popups.  */
   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 /* Wait for an X event to arrive or for a timer to expire.  */
   177 
   178 void
   179 x_menu_wait_for_event (void *data)
   180 {
   181   /* Another way to do this is to register a timer callback, that can be
   182      done in GTK and Xt.  But we have to do it like this when using only X
   183      anyway, and with callbacks we would have three variants for timer handling
   184      instead of the small ifdefs below.  */
   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       /* ISTM that if timer_check is okay, this should be too, since
   202          both can run random Lisp.  */
   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       /* Gtk3 have arrows on menus when they don't fit.  When the
   221          pointer is over an arrow, a timeout scrolls it a bit.  Use
   222          xg_select so that timeout gets triggered.  */
   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           /* I don't know the repercussions of changing
   274              device->grab on XI_ButtonPress events, so be safe and
   275              only do what is necessary to prevent the grab from
   276              being left invalid as XMenuActivate swallows
   277              events.  */
   278           if (device && xev->evtype == XI_ButtonRelease)
   279             device->grab &= ~(1 << xev->detail);
   280 
   281           XPutBackEvent (dpyinfo->display, &copy);
   282           XFreeEventData (dpyinfo->display, &event->xcookie);
   283 
   284           break;
   285 
   286         case XI_HierarchyChanged:
   287         case XI_DeviceChanged:
   288           /* These events must always be handled.  */
   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   /* The return doesn't really matter.  */
   303   return 0;
   304 }
   305 #endif
   306 #endif /* ! MSDOS */
   307 
   308 
   309 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
   310 
   311 #ifdef USE_X_TOOLKIT
   312 
   313 /* Loop in Xt until the menu pulldown or dialog popup has been
   314    popped down (deactivated).  This is used for x-popup-menu
   315    and x-popup-dialog; it is not used for the menu bar.
   316 
   317    NOTE: All calls to popup_get_selection should be protected
   318    with BLOCK_INPUT, UNBLOCK_INPUT wrappers.  */
   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       /* Make sure we don't consider buttons grabbed after menu goes.
   347          And make sure to deactivate for any ButtonRelease,
   348          even if XtDispatchEvent doesn't do that.  */
   349       if (event.type == ButtonRelease
   350           && dpyinfo->display == event.xbutton.display)
   351         {
   352           dpyinfo->grabbed &= ~(1 << event.xbutton.button);
   353 #ifdef USE_MOTIF /* Pretending that the event came from a
   354                     Btn1Down seems the only way to convince Motif to
   355                     activate its callbacks; setting the XmNmenuPost
   356                     isn't working. --marcus@sysc.pdx.edu.  */
   357           event.xbutton.button = 1;
   358           /*  Motif only pops down menus when no Ctrl, Alt or Mod
   359               key is pressed and the button is released.  So reset key state
   360               so Motif thinks this is the case.  */
   361           event.xbutton.state = 0;
   362 #endif
   363           copy = event;
   364         }
   365       /* Pop down on C-g and Escape.  */
   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) /* Any escape, ignore modifiers.  */
   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 /* Pretending that the event came from a
   416                     Btn1Down seems the only way to convince Motif to
   417                     activate its callbacks; setting the XmNmenuPost
   418                     isn't working. --marcus@sysc.pdx.edu.  */
   419                     copy.xbutton.button = 1;
   420                     /*  Motif only pops down menus when no Ctrl, Alt or Mod
   421                         key is pressed and the button is released.  So reset key state
   422                         so Motif thinks this is the case.  */
   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 (&copy.xkey, 0);
   451 
   452                     if ((keysym == XK_g
   453                          && (copy.xkey.state & ControlMask) != 0)
   454                         || keysym == XK_Escape) /* Any escape, ignore modifiers.  */
   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, 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: /* SKIP: real doc in USE_GTK definition in xmenu.c.  */)
   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       /* Clear the XI2 grab so Motif or lwlib can set a core grab.
   494          Otherwise some versions of Motif will emit a warning and hang,
   495          and lwlib will fail to destroy the menu window.  */
   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               /* The keyboard grab matters too, in this specific
   503                  case.  */
   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                              /* From-window, to-window.  */
   548                              ev.xbutton.window, ev.xbutton.root,
   549 
   550                              /* From-position, to-position.  */
   551                              ev.xbutton.x, ev.xbutton.y,
   552                              &ev.xbutton.x_root, &ev.xbutton.y_root,
   553 
   554                              /* Child of win.  */
   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 /* USE_X_TOOLKIT */
   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: /* Start key navigation of the menu bar in FRAME.
   581 This initially opens the first menu bar item and you can then navigate with the
   582 arrow keys, select a menu entry with the return key or cancel with the
   583 escape key.  If FRAME has no menu bar this function does nothing.
   584 
   585 If FRAME is nil or not given, use the selected frame.  */)
   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       /* Activate the first menu.  */
   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 /* Loop util popup_activated_flag is set to zero in a callback.
   616    Used for popup menus and dialogs. */
   617 
   618 static void
   619 popup_widget_loop (bool do_timers, GtkWidget *widget)
   620 {
   621   ++popup_activated_flag;
   622 
   623   /* Process events in the Gtk event loop until done.  */
   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 /* Activate the menu bar of frame F.
   633    This is called from keyboard.c when it gets the
   634    MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
   635 
   636    To activate the menu bar, we use the X button-press event
   637    that was saved in saved_menu_event.
   638    That makes the toolkit do its thing.
   639 
   640    But first we recompute the menu bar contents (the whole tree).
   641 
   642    The reason for saving the button event until here, instead of
   643    passing it to the toolkit right away, is that we can safely
   644    execute Lisp code.  */
   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   /* Clear the XI2 grab so Motif or lwlib can set a core grab.
   670      Otherwise some versions of Motif will emit a warning and hang,
   671      and lwlib will fail to destroy the menu window.  */
   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   /* The cascade button might have been deleted, so don't activate the
   686      popup if it no widget was found to dispatch to.  */
   687   popup_activated_flag
   688     = XtDispatchEvent (f->output_data.x->saved_menu_event);
   689 #endif
   690   unblock_input ();
   691 
   692   /* Ignore this if we get it a second time.  */
   693   f->output_data.x->saved_menu_event->type = 0;
   694 }
   695 
   696 /* This callback is invoked when the user selects a menubar cascade
   697    pushbutton, but before the pulldown menu is posted.  */
   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 /* This callback is invoked when a dialog or menu is finished being
   709    used and has been unposted.  */
   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 /* Function that finds the frame for WIDGET and shows the HELP text
   725    for that widget.
   726    F is the frame if known, or NULL if not known.  */
   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 /* Callback called when menu items are highlighted/unhighlighted
   742    while moving the mouse over them.  WIDGET is the menu bar or menu
   743    popup widget.  ID is its LWLIB_ID.  CALL_DATA contains a pointer to
   744    the data structure for the menu item, or null in case of
   745    unhighlighting.  */
   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   /* If popup_activated_flag is greater than 1 we are in a popup menu.
   760      Don't pass the frame to show_help_event for those.
   761      Passing frame creates an Emacs event.  As we are looping in
   762      popup_widget_loop, it won't be handled.  Passing NULL shows the tip
   763      directly without using an Emacs event.  This is what the Lucid code
   764      does below.  */
   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   /* Determine the frame for the help event.  */
   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 /* Gtk calls callbacks just because we tell it what item should be
   784    selected in a radio group.  If this variable is set to a non-zero
   785    value, we are creating menus and don't want callbacks right now.
   786 */
   787 static bool xg_crazy_callback_abort;
   788 
   789 /* This callback is called from the menu bar pulldown menu
   790    when the user makes a selection.
   791    Figure out what the user chose
   792    and put the appropriate events into the keyboard buffer.  */
   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   /* For a group of radio buttons, GTK calls the selection callback first
   805      for the item that was active before the selection and then for the one that
   806      is active after the selection.  For C-h k this means we get the help on
   807      the deselected item and then the selected item is executed.  Prevent that
   808      by ignoring the non-active item.  */
   809   if (GTK_IS_RADIO_MENU_ITEM (widget)
   810       && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
   811     return;
   812 
   813   /* When a menu is popped down, X generates a focus event (i.e. focus
   814      goes back to the frame below the menu).  Since GTK buffers events,
   815      we force it out here before the menu selection event.  Otherwise
   816      sit-for will exit at once if the focus event follows the menu selection
   817      event.  */
   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 /* not USE_GTK */
   831 
   832 /* This callback is called from the menu bar pulldown menu
   833    when the user makes a selection.
   834    Figure out what the user chose
   835    and put the appropriate events into the keyboard buffer.  */
   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 /* not USE_GTK */
   848 
   849 /* Recompute all the widgets of frame F, when the menu bar has been
   850    changed.  */
   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   /* Do the voodoo which means "I'm changing lots of things, don't try
   870      to refigure sizes until I'm done."  */
   871   lw_refigure_widget (x->column_widget, False);
   872 
   873   /* The order in which children are managed is the top to bottom
   874      order in which they are displayed in the paned window.  First,
   875      remove the text-area widget.  */
   876   XtUnmanageChild (x->edit_widget);
   877 
   878   /* Remove the menubar that is there now, and put up the menubar that
   879      should be there.  */
   880   XtManageChild (x->menubar_widget);
   881   XtMapWidget (x->menubar_widget);
   882   XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
   883 
   884   /* Re-manage the text-area widget, and then thrash the sizes.  */
   885   XtManageChild (x->edit_widget);
   886   lw_refigure_widget (x->column_widget, True);
   887 
   888   /* Force the pane widget to resize itself.  */
   889   adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
   890   unblock_input ();
   891 #endif /* USE_GTK */
   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 /* Set the contents of the menubar widgets of frame F.  */
   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   /* Make the first call for any given frame always go deep.  */
   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       /* Make a widget-value tree representing the entire menu trees.  */
   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       /* If we are making a new widget, its contents are empty,
   976          do always reinitialize them.  */
   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       /* Don't let the debugger step into this code
   983          because it is not reentrant.  */
   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       /* Run the Lucid hook.  */
   996       safe_run_hooks (Qactivate_menubar_hook);
   997 
   998       /* If it has changed current-menubar from previous value,
   999          really recompute the menubar from the value.  */
  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       /* Save the frame's previous menu bar contents data.  */
  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       /* Fill in menu_items with the current menu bar contents.
  1011          This can evaluate Lisp code.  */
  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       /* Convert menu_items into widget_value trees
  1047          to display the menu.  This cannot evaluate Lisp code.  */
  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           /* Don't set wv->name here; GC during the loop might relocate it.  */
  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       /* If there has been no change in the Lisp-level contents
  1071          of the menu bar, skip redisplaying it.  Just exit.  */
  1072 
  1073       /* Compare the new menu items with the ones computed last time.  */
  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           /* The menu items have not changed.  Don't bother updating
  1081              the menus in any form, since it would be a no-op.  */
  1082           free_menubar_widget_value_tree (first_wv);
  1083           discard_menu_items ();
  1084           unbind_to (specpdl_count, Qnil);
  1085           return;
  1086         }
  1087 
  1088       /* The menu items are different, so store them in the frame.  */
  1089       fset_menu_bar_vector (f, menu_items);
  1090       f->menu_bar_items_used = menu_items_used;
  1091 
  1092       /* This undoes save_menu_items.  */
  1093       unbind_to (specpdl_count, Qnil);
  1094 
  1095       /* Now GC cannot happen during the lifetime of the widget_value,
  1096          so it's safe to store data from a Lisp_String.  */
  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       /* Make a widget-value tree containing
  1113          just the top level menu bar strings.  */
  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           /* This prevents lwlib from assuming this
  1131              menu item is really supposed to be empty.  */
  1132           /* The intptr_t cast avoids a warning.
  1133              This value just has to be different from small integers.  */
  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       /* Forget what we thought we knew about what is in the
  1144          detailed contents of the menu bar menus.
  1145          Changing the top level always destroys the contents.  */
  1146       f->menu_bar_items_used = 0;
  1147     }
  1148 
  1149   /* Create or update the menu bar widget.  */
  1150 
  1151   block_input ();
  1152 
  1153 #ifdef USE_GTK
  1154   xg_crazy_callback_abort = true;
  1155   if (menubar_widget)
  1156     {
  1157       /* The fourth arg is DEEP_P, which says to consider the entire
  1158          menu trees we supply, rather than just the menu bar item names.  */
  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 /* not USE_GTK */
  1180   if (menubar_widget)
  1181     {
  1182       /* Disable resizing (done for Motif!) */
  1183       lw_allow_resizing (f->output_data.x->widget, False);
  1184 
  1185       /* The third arg is DEEP_P, which says to consider the entire
  1186          menu trees we supply, rather than just the menu bar item names.  */
  1187       lw_modify_all_widgets (id, first_wv, deep_p);
  1188 
  1189       /* Re-enable the edit widget to resize.  */
  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       /* Make menu pop down on C-g.  */
  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             /* Damn me...  With Lucid I get a core.border_width of 1
  1224                only the first time this is called and an ibw of 1 every
  1225                time this is called.  So the first time this is called I
  1226                was off by one.  Fix that here by never adding
  1227                core.border_width for Lucid.  */
  1228             + f->output_data.x->menubar_widget->core.border_width
  1229 #endif /* USE_LUCID */
  1230             )
  1231          : 0);
  1232 
  1233 #ifdef USE_LUCID
  1234       /* Experimentally, we now get the right results
  1235          for -geometry -0-0 without this.  24 Aug 96, rms.
  1236          Maybe so, but the menu bar size is missing the pixels so the
  1237          WM size hints are off by these pixels.  Jan D, oct 2009.  */
  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 /* USE_LUCID */
  1247 
  1248     FRAME_MENUBAR_HEIGHT (f) = menubar_size;
  1249   }
  1250 #endif /* not USE_GTK */
  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 /* Called from Fx_create_frame to create the initial menubar of a frame
  1263    before it is mapped, so that the window is mapped with the menubar already
  1264    there instead of us tacking it on later and thrashing the window after it
  1265    is visible.  */
  1266 
  1267 void
  1268 initialize_frame_menubar (struct frame *f)
  1269 {
  1270   /* This function is called before the first chance to redisplay
  1271      the frame.  It has to be, so the frame will have the right size.  */
  1272   fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
  1273   set_frame_menubar (f, true);
  1274 }
  1275 
  1276 
  1277 /* Get rid of the menu bar of frame F, and free its storage.
  1278    This is used when deleting a frame, and when turning off the menu bar.
  1279    For GTK this function is in gtkutil.c.  */
  1280 
  1281 #ifndef USE_GTK
  1282 void
  1283 free_frame_menubar (struct frame *f)
  1284 {
  1285   Widget menubar_widget;
  1286 #ifdef USE_MOTIF
  1287   /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
  1288      If we want to preserve the old height, calculate it now so we can
  1289      restore it below.  */
  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       /* Removing the menu bar magically changes the shell widget's x
  1304          and y position of (0, 0) which, when the menu bar is turned
  1305          on again, leads to pull-down menus appearing in strange
  1306          positions near the upper-left corner of the display.  This
  1307          happens only with some window managers like twm and ctwm,
  1308          but not with other like Motif's mwm or kwm, because the
  1309          latter generate ConfigureNotify events when the menu bar
  1310          is switched off, which fixes the shell position.  */
  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       /* When double-buffering is enabled and the frame shall not be
  1325          resized either because resizing is inhibited or the frame is
  1326          fullheight, some (usually harmless) display artifacts like a
  1327          doubled mode line may show up.  Sometimes the configuration
  1328          gets messed up in a more serious fashion though and you may
  1329          have to resize the frame to get it back in a normal state.  */
  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           /* When resizing is inhibited and a normal Motif frame is not
  1337              fullheight, we have to explicitly request its old sizes
  1338              here since otherwise turning off the menu bar will shrink
  1339              the frame but turning them on again will not resize it
  1340              back.  For a fullheight frame we let the window manager
  1341              deal with this problem.  */
  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 /* USE_MOTIF */
  1351         }
  1352       else
  1353         {
  1354 #ifdef USE_MOTIF
  1355           if (WINDOWP (FRAME_ROOT_WINDOW (f))
  1356               /* See comment above.  */
  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 /* not USE_GTK */
  1368 
  1369 #endif /* USE_X_TOOLKIT || USE_GTK */
  1370 
  1371 /* x_menu_show actually displays a menu using the panes and items in menu_items
  1372    and returns the value selected from it.
  1373    There are two versions of x_menu_show, one for Xt and one for Xlib.
  1374    Both assume input is blocked by the caller.  */
  1375 
  1376 /* F is the frame the menu is for.
  1377    X and Y are the frame-relative specified position,
  1378    relative to the inside upper left corner of the frame F.
  1379    Bitfield MENUFLAGS bits are:
  1380    MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
  1381    MENU_KEYMAPS is set if this menu was specified with keymaps;
  1382     in that case, we return a list containing the chosen item's value
  1383     and perhaps also the pane's prefix.
  1384    TITLE is the specified menu title.
  1385    ERROR is a place to store an error message string in case of failure.
  1386    (We return nil on failure, but the value doesn't actually matter.)  */
  1387 
  1388 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
  1389 
  1390 /* The item selected in the popup menu.  */
  1391 static Lisp_Object *volatile menu_item_selection;
  1392 
  1393 #ifdef USE_GTK
  1394 
  1395 /* Used when position a popup menu.  See menu_position_func and
  1396    create_and_show_popup_menu below.  */
  1397 struct next_popup_x_y
  1398 {
  1399   struct frame *f;
  1400   int x;
  1401   int y;
  1402 };
  1403 
  1404 /* The menu position function to use if we are not putting a popup
  1405    menu where the pointer is.
  1406    MENU is the menu to pop up.
  1407    X and Y shall on exit contain x/y where the menu shall pop up.
  1408    PUSH_IN is not documented in the GTK manual.
  1409    USER_DATA is any data passed in when calling gtk_menu_popup.
  1410    Here it points to a struct next_popup_x_y where the coordinates
  1411    to store in *X and *Y are as well as the frame for the popup.
  1412 
  1413    Here only X and Y are used.  */
  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   /* TODO: Get the monitor workarea directly without calculating other
  1433      items in x-display-monitor-attributes-list. */
  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   /* frame-monitor-workarea and {x,y}_display_pixel_width/height all
  1458      return device pixels, but GTK wants scaled pixels.  The positions
  1459      passed in via data were already scaled for us.  */
  1460 #ifdef HAVE_GTK3
  1461   max_x /= scale;
  1462   max_y /= scale;
  1463 #endif
  1464   *x = data->x;
  1465   *y = data->y;
  1466 
  1467   /* Check if there is room for the menu.  If not, adjust x/y so that
  1468      the menu is fully visible.  gtk_widget_get_preferred_size returns
  1469      scaled pixels, so there is no need to apply the scaling
  1470      factor.  */
  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 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
  1497    menu pops down.
  1498    menu_item_selection will be set to the selection.  */
  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;  /* Pop up at pointer.  */
  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   /* Always use position function for Gtk3.  Otherwise menus may become
  1512      too small to show anything.  */
  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       /* Not invoked by a click.  pop up at x/y.  */
  1528       pos_func = menu_position_func;
  1529 
  1530       /* Adjust coordinates to be root-window-relative.  */
  1531       block_input ();
  1532       x_translate_coordinates_to_root (f, x, y, &x, &y);
  1533 #ifdef HAVE_GTK3
  1534       /* Use window scaling factor to adjust position for scaled
  1535          outputs.  */
  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;  /* gtk_menu_popup needs this to be 0 for a non-button popup.  */
  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       /* If keys aren't grabbed (i.e., a mouse up event), use 0.  */
  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   /* Display the menu.  */
  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       /* Set this to one.  popup_widget_loop increases it by one, so it becomes
  1587          two.  show_help_echo uses this to detect popup menus.  */
  1588       popup_activated_flag = 1;
  1589       /* Process events that apply to the menu.  */
  1590       popup_widget_loop (true, menu);
  1591     }
  1592 
  1593   unbind_to (specpdl_count, Qnil);
  1594 
  1595   /* Must reset this manually because the button release event is not passed
  1596      to Emacs event loop. */
  1597   FRAME_DISPLAY_INFO (f)->grabbed = 0;
  1598 }
  1599 
  1600 #else /* not USE_GTK */
  1601 
  1602 /* We need a unique id for each widget handled by the Lucid Widget
  1603    library.
  1604 
  1605    For the main windows, and popup menus, we use this counter, which we
  1606    increment each time after use.  This starts from WIDGET_ID_TICK_START.
  1607 
  1608    For menu bars, we use numbers starting at 0, counted in
  1609    next_menubar_widget_id.  */
  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   /* Select for gesture events.  Emacs selects for gesture events from
  1686      all master devices on non-GTK3 builds, so that event mask is also
  1687      clobbered by prepare_for_entry_into_toolkit_menu.  (bug#65129) */
  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 /* HAVE_XINPUT2_4 */
  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 /* HAVE_XINPUT2 */
  1710 
  1711 /* ID is the LWLIB ID of the dialog box.  */
  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 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
  1740    menu pops down.
  1741    menu_item_selection will be set to the selection.  */
  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   /* Adjust coordinates to be root-window-relative.  */
  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   /* Don't allow any geometry request from the user.  */
  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   /* Clear the XI2 grab, and if any XI2 grab was set, place a core
  1804      grab on the frame's edit widget.  */
  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       /* Dispatch a PropertyNotify to Xt with the current server time.
  1828          Motif tries to set a grab with the timestamp of the last event
  1829          processed by Xt, but Xt doesn't consider GenericEvents, so the
  1830          timestamp is always less than the last grab time.  */
  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   /* Display the menu.  */
  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     /* Process events that apply to the menu.  */
  1877     popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, true);
  1878 
  1879     unbind_to (specpdl_count, Qnil);
  1880   }
  1881 }
  1882 
  1883 #endif /* not USE_GTK */
  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   /* Create a tree of widget_value objects
  1925      representing the panes and their items.  */
  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   /* Loop over all panes and items, filling in the tree.  */
  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       /* Ignore a nil in the item list.
  1954          It's meaningful only for dialog boxes.  */
  1955       else if (EQ (AREF (menu_items, i), Qquote))
  1956         i += 1;
  1957       else if (EQ (AREF (menu_items, i), Qt))
  1958         {
  1959           /* Create a new pane.  */
  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           /* If there is just one top-level pane, put all its items directly
  1976              under the top-level menu.  */
  1977           if (menu_items_n_panes == 1)
  1978             pane_string = "";
  1979 
  1980           /* If the pane has a meaningful name,
  1981              make the pane a top-level menu item
  1982              with its items as a submenu beneath it.  */
  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           /* Create a new item within current pane.  */
  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 /* not HAVE_MULTILINGUAL_MENU */
  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               /* This emacs_abort call pacifies gcc 11.2.1 when Emacs
  2037                  is configured with --enable-gcc-warnings.  FIXME: If
  2038                  save_wv can be null, do something better; otherwise,
  2039                  explain why save_wv cannot be null.  */
  2040               emacs_abort ();
  2041             }
  2042           else
  2043             save_wv->contents = wv;
  2044           if (!NILP (descrip))
  2045             wv->key = SSDATA (descrip);
  2046           /* If this item has a null value,
  2047              make the call_data null so that it won't display a box
  2048              when the mouse is on it.  */
  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   /* Deal with the title, if it is non-nil.  */
  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   /* No selection has been chosen yet.  */
  2090   menu_item_selection = 0;
  2091 
  2092   /* Make sure to free the widget_value objects we used to specify the
  2093      contents even with longjmp.  */
  2094   record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
  2095 
  2096   /* Actually create and show the menu until popped down.  */
  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   /* Find the selected item, and its pane, to return
  2103      the proper value.  */
  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           /* Ignore a nil in the item list.
  2130              It's meaningful only for dialog boxes.  */
  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       /* Make "Cancel" equivalent to C-g.  */
  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   /* Treat the pointer as an integer.  There's no problem
  2177      as long as pointers have enough bits to hold small integers.  */
  2178   if ((intptr_t) client_data != -1)
  2179     menu_item_selection = client_data;
  2180 
  2181   popup_activated_flag = 0;
  2182 }
  2183 
  2184 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
  2185    dialog pops down.
  2186    menu_item_selection will be set to the selection.  */
  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       /* Display the menu.  */
  2207       gtk_widget_show_all (menu);
  2208 
  2209       /* Process events that apply to the menu.  */
  2210       popup_widget_loop (true, menu);
  2211 
  2212       unbind_to (specpdl_count, Qnil);
  2213     }
  2214 }
  2215 
  2216 #else /* not USE_GTK */
  2217 static void
  2218 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
  2219 {
  2220   /* Treat the pointer as an integer.  There's no problem
  2221      as long as pointers have enough bits to hold small integers.  */
  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 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
  2233    dialog pops down.
  2234    menu_item_selection will be set to the selection.  */
  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   /* Display the dialog box.  */
  2251   lw_pop_up_all_widgets (dialog_id);
  2252   popup_activated_flag = 1;
  2253   x_activate_timeout_atimer ();
  2254 
  2255   /* Process events that apply to the dialog box.
  2256      Also handle timers.  */
  2257   {
  2258     specpdl_ref count = SPECPDL_INDEX ();
  2259 
  2260     DEFER_SELECTIONS;
  2261 
  2262     /* xdialog_show_unwind is responsible for popping the dialog box down.  */
  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 /* not USE_GTK */
  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   /* Number of elements seen so far, before boundary.  */
  2288   int left_count = 0;
  2289   /* Whether we've seen the boundary between left-hand elts and right-hand.  */
  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   /* Create a tree of widget_value objects
  2305      representing the text label and buttons.  */
  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     /* Loop over all panes and items, filling in the tree.  */
  2316     i = MENU_ITEMS_PANE_LENGTH;
  2317     while (i < menu_items_used)
  2318       {
  2319 
  2320         /* Create a new item within current pane.  */
  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             /* This is the boundary between left-side elts
  2336                and right-side elts.  Stop incrementing right_count.  */
  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     /* If the boundary was not specified,
  2365        by default put half on the left and half on the right.  */
  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     /*  Frame title: 'Q' = Question, 'I' = Information.
  2372         Can also have 'E' = Error if, one day, we want
  2373         a popup for errors. */
  2374     if (NILP (header))
  2375       dialog_name[0] = 'Q';
  2376     else
  2377       dialog_name[0] = 'I';
  2378 
  2379     /* Dialog boxes use a really stupid name encoding
  2380        which specifies how many buttons to use
  2381        and how many buttons are on the right. */
  2382     dialog_name[1] = '0' + nb_buttons;
  2383     dialog_name[2] = 'B';
  2384     dialog_name[3] = 'R';
  2385     /* Number of buttons to put on the right.  */
  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   /* No selection has been chosen yet.  */
  2393   menu_item_selection = 0;
  2394 
  2395   /* Make sure to free the widget_value objects we used to specify the
  2396      contents even with longjmp.  */
  2397   record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
  2398 
  2399   /* Actually create and show the dialog.  */
  2400   create_and_show_dialog (f, first_wv);
  2401 
  2402   unbind_to (specpdl_count, Qnil);
  2403 
  2404   /* Find the selected item, and its pane, to return
  2405      the proper value.  */
  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               /* This is the boundary between left-side elts and
  2418                  right-side elts.  */
  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     /* Make "Cancel" equivalent to C-g.  */
  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   /* Decode the dialog items from what was specified.  */
  2449   title = Fcar (contents);
  2450   CHECK_STRING (title);
  2451   record_unwind_protect_void (unuse_menu_items);
  2452 
  2453   if (NILP (Fcar (Fcdr (contents))))
  2454     /* No buttons specified, add an "Ok" button so users can pop down
  2455        the dialog.  Also, the lesstif/motif version crashes if there are
  2456        no buttons.  */
  2457     contents = list2 (title, Fcons (build_string ("Ok"), Qt));
  2458 
  2459   list_of_panes (list1 (contents));
  2460 
  2461   /* Display them in a dialog box.  */
  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 /* not USE_X_TOOLKIT && not USE_GTK */
  2474 
  2475 /* The frame of the last activated non-toolkit menu bar.
  2476    Used to generate menu help events.  */
  2477 
  2478 static struct frame *menu_help_frame;
  2479 
  2480 
  2481 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
  2482 
  2483    PANE is the pane number, and ITEM is the menu item number in
  2484    the menu (currently not used).
  2485 
  2486    This cannot be done with generating a HELP_EVENT because
  2487    XMenuActivate contains a loop that doesn't let Emacs process
  2488    keyboard events.  */
  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     /* This shouldn't happen, see x_menu_show.  */
  2502     pane_name = empty_unibyte_string;
  2503   else
  2504     pane_name = first_item[MENU_ITEMS_ITEM_NAME];
  2505 
  2506   /* (menu-item MENU-NAME PANE-NUMBER)  */
  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   /* Assume the mouse has moved out of the X window.
  2538      If it has actually moved in, we will get an EnterNotify.  */
  2539   x_mouse_leave (FRAME_DISPLAY_INFO (f));
  2540 
  2541   /* State that no mouse buttons are now held.
  2542      (The oldXMenu code doesn't track this info for us.)
  2543      That is not necessarily true, but the fiction leads to reasonable
  2544      results, and it is a pain to ask which are actually held now.  */
  2545   FRAME_DISPLAY_INFO (f)->grabbed = 0;
  2546 
  2547 #ifdef HAVE_XINPUT2
  2548   /* Likewise for XI grabs when the mouse is released on top of the
  2549      menu itself.  */
  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   /* Decrement the popup_activated_flag.  */
  2559   popup_activated_flag = 0;
  2560 #endif /* HAVE_X_WINDOWS */
  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   /* Figure out which root window F is on.  */
  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   /* Make the menu on that window.  */
  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   /* Don't GC while we prepare and show the menu,
  2613      because we give the oldxmenu library pointers to the
  2614      contents of strings.  */
  2615   inhibit_garbage_collection ();
  2616 
  2617 #ifdef HAVE_X_WINDOWS
  2618   x_translate_coordinates_to_root (f, x, y, &x, &y);
  2619 #else
  2620   /* MSDOS without X support.  */
  2621   x += f->left_pos;
  2622   y += f->top_pos;
  2623 #endif
  2624 
  2625   /* Create all the necessary panes and their items.  */
  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           /* Create a new pane.  */
  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           /* Find the width of the widest item in this pane.  */
  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       /* Ignore a nil in the item list.
  2675          It's meaningful only for dialog boxes.  */
  2676       else if (EQ (AREF (menu_items, i), Qquote))
  2677         i += 1;
  2678       else
  2679         {
  2680           /* Create a new item within current pane.  */
  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   /* All set and ready to fly.  */
  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       /* Move the menu away of the echo area, to avoid overwriting the
  2745          menu with help echo messages or vice versa.  */
  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       /* If position was not given by a mouse click, adjust so upper left
  2764          corner of the menu as a whole ends up at given coordinates.  This
  2765          is what x-popup-menu says in its documentation.  */
  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   /* When the input extension is in use, the owner_events grab will
  2781      report extension events on frames, which the XMenu library does
  2782      not normally understand.  */
  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   /* Help display under X won't work because XMenuActivate contains
  2792      a loop that doesn't give Emacs a chance to process it.  */
  2793   menu_help_frame = f;
  2794 
  2795 #ifdef HAVE_XINPUT2
  2796   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
  2797   /* Clear the XI2 grab so a core grab can be set.  */
  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   /* Increment the popup flag; this prevents nested popups from being
  2813      displayed by user Lisp code in help-echo callbacks, and also
  2814      prevents mouse face from being displayed.  */
  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       /* Find the item number SELIDX in pane number PANE.  */
  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       /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
  2870          the menu was invoked with a mouse event as POSITION).  */
  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 /* not USE_X_TOOLKIT */
  2885 
  2886 #ifndef MSDOS
  2887 /* Detect if a dialog or menu has been posted.  MSDOS has its own
  2888    implementation on msdos.c.  */
  2889 
  2890 int
  2891 popup_activated (void)
  2892 {
  2893   return popup_activated_flag;
  2894 }
  2895 #endif  /* not MSDOS */
  2896 
  2897 /* The following is used by delayed window autoselection.  */
  2898 
  2899 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
  2900        doc: /* Return t if a menu or popup dialog is active.
  2901 \(On MS Windows, this refers to the selected frame.)  */)
  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 }

/* [<][>][^][v][top][bottom][index][help] */