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

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