Simplify and avoid signal-handling races.
[bpt/emacs.git] / src / xmenu.c
index eab25d7..06d6cb0 100644 (file)
@@ -1,6 +1,6 @@
 /* X Communication module for terminals which understand the X protocol.
 
-Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2011
+Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2012
   Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -32,13 +32,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
-#if 0  /* Why was this included?  And without syssignal.h?  */
-/* On 4.3 this loses if it comes after xterm.h.  */
-#include <signal.h>
-#endif
-
 #include <stdio.h>
-#include <setjmp.h>
 
 #include "lisp.h"
 #include "keyboard.h"
@@ -47,6 +41,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "termhooks.h"
 #include "window.h"
 #include "blockinput.h"
+#include "character.h"
 #include "buffer.h"
 #include "charset.h"
 #include "coding.h"
@@ -102,6 +97,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #ifdef USE_GTK
 #include "gtkutil.h"
+#ifdef HAVE_GTK3
+#include "xgselect.h"
+#endif
 #endif
 
 #include "menu.h"
@@ -165,9 +163,9 @@ mouse_position_for_popup (FRAME_PTR f, int *x, int *y)
   int dummy;
 
   if (! FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
-  BLOCK_INPUT;
+  block_input ();
 
   XQueryPointer (FRAME_X_DISPLAY (f),
                  DefaultRootWindow (FRAME_X_DISPLAY (f)),
@@ -188,7 +186,7 @@ mouse_position_for_popup (FRAME_PTR f, int *x, int *y)
                     we don't care.  */
                  (unsigned int *) &dummy);
 
-  UNBLOCK_INPUT;
+  unblock_input ();
 
   /* xmenu_show expects window coordinates, not root window
      coordinates.  Translate.  */
@@ -254,13 +252,12 @@ for instance using the window manager, then this produces a quit and
     }
   else if (CONSP (position))
     {
-      Lisp_Object tem;
-      tem = Fcar (position);
+      Lisp_Object tem = XCAR (position);
       if (CONSP (tem))
-       window = Fcar (Fcdr (position));
+       window = Fcar (XCDR (position));
       else
        {
-         tem = Fcar (Fcdr (position));  /* EVENT_START (position) */
+         tem = Fcar (XCDR (position));  /* EVENT_START (position) */
          window = Fcar (tem);       /* POSN_WINDOW (tem) */
        }
     }
@@ -331,9 +328,9 @@ for instance using the window manager, then this produces a quit and
     list_of_panes (Fcons (contents, Qnil));
 
     /* Display them in a dialog box.  */
-    BLOCK_INPUT;
+    block_input ();
     selection = xdialog_show (f, 0, title, header, &error_name);
-    UNBLOCK_INPUT;
+    unblock_input ();
 
     unbind_to (specpdl_count, Qnil);
     discard_menu_items ();
@@ -388,8 +385,6 @@ x_menu_wait_for_event (void *data)
          )
     {
       EMACS_TIME next_time = timer_check (), *ntp;
-      long secs = EMACS_SECS (next_time);
-      long usecs = EMACS_USECS (next_time);
       SELECT_TYPE read_fds;
       struct x_display_info *dpyinfo;
       int n = 0;
@@ -403,12 +398,19 @@ x_menu_wait_for_event (void *data)
           XFlush (dpyinfo->display);
         }
 
-      if (secs < 0 && usecs < 0)
+      if (! EMACS_TIME_VALID_P (next_time))
         ntp = 0;
       else
         ntp = &next_time;
 
-      select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
+#ifdef HAVE_GTK3
+      /* Gtk3 have arrows on menus when they don't fit.  When the
+        pointer is over an arrow, a timeout scrolls it a bit.  Use
+        xg_select so that timeout gets triggered.  */
+      xg_select (n + 1, &read_fds, NULL, NULL, ntp, NULL);
+#else
+      pselect (n + 1, &read_fds, NULL, NULL, ntp, NULL);
+#endif
     }
 }
 #endif /* ! MSDOS */
@@ -488,7 +490,7 @@ If FRAME is nil or not given, use the selected frame.  */)
   XEvent ev;
   FRAME_PTR f = check_x_frame (frame);
   Widget menubar;
-  BLOCK_INPUT;
+  block_input ();
 
   if (FRAME_EXTERNAL_MENU_BAR (f))
     set_frame_menubar (f, 0, 1);
@@ -546,7 +548,7 @@ If FRAME is nil or not given, use the selected frame.  */)
         }
     }
 
-  UNBLOCK_INPUT;
+  unblock_input ();
 
   return Qnil;
 }
@@ -567,9 +569,9 @@ If FRAME is nil or not given, use the selected frame.  */)
   FRAME_PTR f;
 
   /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
-     BLOCK_INPUT.  */
+     block_input ().  */
 
-  BLOCK_INPUT;
+  block_input ();
   f = check_x_frame (frame);
 
   if (FRAME_EXTERNAL_MENU_BAR (f))
@@ -588,7 +590,7 @@ If FRAME is nil or not given, use the selected frame.  */)
           g_list_free (children);
         }
     }
-  UNBLOCK_INPUT;
+  unblock_input ();
 
   return Qnil;
 }
@@ -628,7 +630,7 @@ void
 x_activate_menubar (FRAME_PTR f)
 {
   if (! FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
   if (!f->output_data.x->saved_menu_event->type)
     return;
@@ -640,7 +642,7 @@ x_activate_menubar (FRAME_PTR f)
 #endif
 
   set_frame_menubar (f, 0, 1);
-  BLOCK_INPUT;
+  block_input ();
   popup_activated_flag = 1;
 #ifdef USE_GTK
   XPutBackEvent (f->output_data.x->display_info->display,
@@ -648,7 +650,7 @@ x_activate_menubar (FRAME_PTR f)
 #else
   XtDispatchEvent (f->output_data.x->saved_menu_event);
 #endif
-  UNBLOCK_INPUT;
+  unblock_input ();
 
   /* Ignore this if we get it a second time.  */
   f->output_data.x->saved_menu_event->type = 0;
@@ -671,19 +673,17 @@ popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
 /* This callback is invoked when a dialog or menu is finished being
    used and has been unposted.  */
 
-#ifdef USE_GTK
 static void
-popup_deactivate_callback (GtkWidget *widget, gpointer client_data)
-{
-  popup_activated_flag = 0;
-}
+popup_deactivate_callback (
+#ifdef USE_GTK
+                          GtkWidget *widget, gpointer client_data
 #else
-static void
-popup_deactivate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
+                          Widget widget, LWLIB_ID id, XtPointer client_data
+#endif
+                          )
 {
   popup_activated_flag = 0;
 }
-#endif
 
 
 /* Function that finds the frame for WIDGET and shows the HELP text
@@ -803,10 +803,10 @@ menubar_selection_callback (GtkWidget *widget, gpointer client_data)
      sit-for will exit at once if the focus event follows the menu selection
      event.  */
 
-  BLOCK_INPUT;
+  block_input ();
   while (gtk_events_pending ())
     gtk_main_iteration ();
-  UNBLOCK_INPUT;
+  unblock_input ();
 
   find_and_call_menu_selection (cb_data->cl_data->f,
                                 cb_data->cl_data->menu_bar_items_used,
@@ -846,14 +846,14 @@ update_frame_menubar (FRAME_PTR f)
   int columns, rows;
 
   if (! FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
   x = f->output_data.x;
 
   if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
     return 0;
 
-  BLOCK_INPUT;
+  block_input ();
   /* Save the size of the frame because the pane widget doesn't accept
      to resize itself. So force it.  */
   columns = FRAME_COLS (f);
@@ -880,7 +880,7 @@ update_frame_menubar (FRAME_PTR f)
 
   /* Force the pane widget to resize itself with the right values.  */
   EmacsFrameSetCharSize (x->edit_widget, columns, rows);
-  UNBLOCK_INPUT;
+  unblock_input ();
 #endif
   return 1;
 }
@@ -934,7 +934,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
   int *submenu_top_level_items, *submenu_n_panes;
 
   if (! FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
   menubar_widget = f->output_data.x->menubar_widget;
 
@@ -952,7 +952,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
   else if (!f->output_data.x->saved_menu_event && !deep_p)
     {
       deep_p = 1;
-      f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
+      f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
       f->output_data.x->saved_menu_event->type = 0;
     }
 
@@ -971,8 +971,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
       ptrdiff_t specpdl_count = SPECPDL_INDEX ();
       int previous_menu_items_used = f->menu_bar_items_used;
       Lisp_Object *previous_items
-       = (Lisp_Object *) alloca (previous_menu_items_used
-                                 * sizeof (Lisp_Object));
+       = alloca (previous_menu_items_used * sizeof *previous_items);
       int subitems;
 
       /* If we are making a new widget, its contents are empty,
@@ -1003,14 +1002,14 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
       if (! NILP (Vlucid_menu_bar_dirty_flag))
        call0 (Qrecompute_lucid_menubar);
       safe_run_hooks (Qmenu_bar_update_hook);
-      FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
+      fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
 
       items = FRAME_MENU_BAR_ITEMS (f);
 
       /* Save the frame's previous menu bar contents data.  */
       if (previous_menu_items_used)
        memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
-               previous_menu_items_used * sizeof (Lisp_Object));
+               previous_menu_items_used * word_size);
 
       /* Fill in menu_items with the current menu bar contents.
         This can evaluate Lisp code.  */
@@ -1019,18 +1018,19 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
       menu_items = f->menu_bar_vector;
       menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
       subitems = ASIZE (items) / 4;
-      submenu_start = (int *) alloca ((subitems + 1) * sizeof (int));
-      submenu_end = (int *) alloca (subitems * sizeof (int));
-      submenu_n_panes = (int *) alloca (subitems * sizeof (int));
-      submenu_top_level_items = (int *) alloca (subitems * sizeof (int));
+      submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
+      submenu_end = alloca (subitems * sizeof *submenu_end);
+      submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
+      submenu_top_level_items = alloca (subitems
+                                       * sizeof *submenu_top_level_items);
       init_menu_items ();
       for (i = 0; i < subitems; i++)
        {
          Lisp_Object key, string, maps;
 
-         key = XVECTOR (items)->contents[4 * i];
-         string = XVECTOR (items)->contents[4 * i + 1];
-         maps = XVECTOR (items)->contents[4 * i + 2];
+         key = AREF (items, 4 * i);
+         string = AREF (items, 4 * i + 1);
+         maps = AREF (items, 4 * i + 2);
          if (NILP (string))
            break;
 
@@ -1081,7 +1081,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
       /* Compare the new menu items with the ones computed last time.  */
       for (i = 0; i < previous_menu_items_used; i++)
        if (menu_items_used == i
-           || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
+           || (!EQ (previous_items[i], AREF (menu_items, i))))
          break;
       if (i == menu_items_used && i == previous_menu_items_used && i != 0)
        {
@@ -1094,7 +1094,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
        }
 
       /* The menu items are different, so store them in the frame.  */
-      f->menu_bar_vector = menu_items;
+      fset_menu_bar_vector (f, menu_items);
       f->menu_bar_items_used = menu_items_used;
 
       /* This undoes save_menu_items.  */
@@ -1106,7 +1106,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
       for (i = 0; i < ASIZE (items); i += 4)
        {
          Lisp_Object string;
-         string = XVECTOR (items)->contents[i + 1];
+         string = AREF (items, i + 1);
          if (NILP (string))
             break;
           wv->name = SSDATA (string);
@@ -1133,7 +1133,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
        {
          Lisp_Object string;
 
-         string = XVECTOR (items)->contents[i + 1];
+         string = AREF (items, i + 1);
          if (NILP (string))
            break;
 
@@ -1164,7 +1164,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
 
   /* Create or update the menu bar widget.  */
 
-  BLOCK_INPUT;
+  block_input ();
 
 #ifdef USE_GTK
   xg_crazy_callback_abort = 1;
@@ -1264,7 +1264,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
   xg_crazy_callback_abort = 0;
 #endif
 
-  UNBLOCK_INPUT;
+  unblock_input ();
 }
 
 /* Called from Fx_create_frame to create the initial menubar of a frame
@@ -1277,7 +1277,7 @@ initialize_frame_menubar (FRAME_PTR f)
 {
   /* This function is called before the first chance to redisplay
      the frame.  It has to be, so the frame will have the right size.  */
-  FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
+  fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
   set_frame_menubar (f, 1, 1);
 }
 
@@ -1293,7 +1293,7 @@ free_frame_menubar (FRAME_PTR f)
   Widget menubar_widget;
 
   if (! FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
   menubar_widget = f->output_data.x->menubar_widget;
 
@@ -1304,7 +1304,7 @@ free_frame_menubar (FRAME_PTR f)
 #ifdef USE_MOTIF
       /* Removing the menu bar magically changes the shell widget's x
         and y position of (0, 0) which, when the menu bar is turned
-        on again, leads to pull-down menuss appearing in strange
+        on again, leads to pull-down menus appearing in strange
         positions near the upper-left corner of the display.  This
         happens only with some window managers like twm and ctwm,
         but not with other like Motif's mwm or kwm, because the
@@ -1313,7 +1313,7 @@ free_frame_menubar (FRAME_PTR f)
       Position x0, y0, x1, y1;
 #endif
 
-      BLOCK_INPUT;
+      block_input ();
 
 #ifdef USE_MOTIF
       if (f->output_data.x->widget)
@@ -1332,7 +1332,7 @@ free_frame_menubar (FRAME_PTR f)
 #endif
           x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
        }
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
 }
 #endif /* not USE_GTK */
@@ -1417,9 +1417,9 @@ pop_down_menu (Lisp_Object arg)
   struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
 
   popup_activated_flag = 0;
-  BLOCK_INPUT;
+  block_input ();
   gtk_widget_destroy (GTK_WIDGET (p->pointer));
-  UNBLOCK_INPUT;
+  unblock_input ();
   return Qnil;
 }
 
@@ -1435,9 +1435,16 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y,
   GtkMenuPositionFunc pos_func = 0;  /* Pop up at pointer.  */
   struct next_popup_x_y popup_x_y;
   ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+  int use_pos_func = ! for_click;
+
+#ifdef HAVE_GTK3
+  /* Always use position function for Gtk3.  Otherwise menus may become
+     too small to show anything.  */
+  use_pos_func = 1;
+#endif
 
   if (! FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
   xg_crazy_callback_abort = 1;
   menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
@@ -1446,7 +1453,7 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y,
                            G_CALLBACK (menu_highlight_callback));
   xg_crazy_callback_abort = 0;
 
-  if (! for_click)
+  if (use_pos_func)
     {
       /* Not invoked by a click.  pop up at x/y.  */
       pos_func = menu_position_func;
@@ -1461,7 +1468,8 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y,
 
       i = 0;  /* gtk_menu_popup needs this to be 0 for a non-button popup.  */
     }
-  else
+
+  if (for_click)
     {
       for (i = 0; i < 5; i++)
         if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
@@ -1519,9 +1527,9 @@ pop_down_menu (Lisp_Object arg)
   LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
                  | XINT (XCDR (arg)));
 
-  BLOCK_INPUT;
+  block_input ();
   lw_destroy_all_widgets (id);
-  UNBLOCK_INPUT;
+  unblock_input ();
   popup_activated_flag = 0;
 
   return Qnil;
@@ -1543,7 +1551,7 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv,
   Widget menu;
 
   if (! FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
 #ifdef USE_LUCID
   apply_systemfont_to_menu (f, f->output_data.x->widget);
@@ -1604,6 +1612,17 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv,
 
 #endif /* not USE_GTK */
 
+static Lisp_Object
+cleanup_widget_value_tree (Lisp_Object arg)
+{
+  struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
+  widget_value *wv = p->pointer;
+
+  free_menubar_widget_value_tree (wv);
+
+  return Qnil;
+}
+
 Lisp_Object
 xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
            Lisp_Object title, const char **error_name, Time timestamp)
@@ -1611,15 +1630,17 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
   int i;
   widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
   widget_value **submenu_stack
-    = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
+    = alloca (menu_items_used * sizeof *submenu_stack);
   Lisp_Object *subprefix_stack
-    = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
+    = alloca (menu_items_used * sizeof *subprefix_stack);
   int submenu_depth = 0;
 
   int first_pane;
 
+  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+
   if (! FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
   *error_name = NULL;
 
@@ -1644,7 +1665,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
   i = 0;
   while (i < menu_items_used)
     {
-      if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
+      if (EQ (AREF (menu_items, i), Qnil))
        {
          submenu_stack[submenu_depth++] = save_wv;
          save_wv = prev_wv;
@@ -1652,21 +1673,21 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
          first_pane = 1;
          i++;
        }
-      else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
+      else if (EQ (AREF (menu_items, i), Qlambda))
        {
          prev_wv = save_wv;
          save_wv = submenu_stack[--submenu_depth];
          first_pane = 0;
          i++;
        }
-      else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
+      else if (EQ (AREF (menu_items, i), Qt)
               && submenu_depth != 0)
        i += MENU_ITEMS_PANE_LENGTH;
       /* Ignore a nil in the item list.
         It's meaningful only for dialog boxes.  */
-      else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
+      else if (EQ (AREF (menu_items, i), Qquote))
        i += 1;
-      else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+      else if (EQ (AREF (menu_items, i), Qt))
        {
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
@@ -1699,7 +1720,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
                save_wv->next = wv;
              else
                first_wv->contents = wv;
-             wv->name = pane_string;
+             wv->name = (char *) pane_string;
              if (keymaps && !NILP (prefix))
                wv->name++;
              wv->value = 0;
@@ -1755,8 +1776,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
          /* If this item has a null value,
             make the call_data null so that it won't display a box
             when the mouse is on it.  */
-         wv->call_data
-           = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
+         wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
          wv->enabled = !NILP (enable);
 
          if (NILP (type))
@@ -1766,7 +1786,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
          else if (EQ (type, QCradio))
            wv->button_type = BUTTON_TYPE_RADIO;
          else
-           abort ();
+           emacs_abort ();
 
          wv->selected = !NILP (selected);
 
@@ -1812,11 +1832,15 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
   /* No selection has been chosen yet.  */
   menu_item_selection = 0;
 
+  /* Make sure to free the widget_value objects we used to specify the
+     contents even with longjmp.  */
+  record_unwind_protect (cleanup_widget_value_tree,
+                        make_save_value (first_wv, 0));
+
   /* Actually create and show the menu until popped down.  */
   create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp);
 
-  /* Free the widget_value objects we used to specify the contents.  */
-  free_menubar_widget_value_tree (first_wv);
+  unbind_to (specpdl_count, Qnil);
 
   /* Find the selected item, and its pane, to return
      the proper value.  */
@@ -1828,32 +1852,32 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
       i = 0;
       while (i < menu_items_used)
        {
-         if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
+         if (EQ (AREF (menu_items, i), Qnil))
            {
              subprefix_stack[submenu_depth++] = prefix;
              prefix = entry;
              i++;
            }
-         else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
+         else if (EQ (AREF (menu_items, i), Qlambda))
            {
              prefix = subprefix_stack[--submenu_depth];
              i++;
            }
-         else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+         else if (EQ (AREF (menu_items, i), Qt))
            {
              prefix
-               = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+               = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
              i += MENU_ITEMS_PANE_LENGTH;
            }
          /* Ignore a nil in the item list.
             It's meaningful only for dialog boxes.  */
-         else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
+         else if (EQ (AREF (menu_items, i), Qquote))
            i += 1;
          else
            {
              entry
-               = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
-             if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
+               = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
+             if (menu_item_selection == aref_addr (menu_items, i))
                {
                  if (keymaps != 0)
                    {
@@ -1900,7 +1924,7 @@ create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
   GtkWidget *menu;
 
   if (! FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
   menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
                            G_CALLBACK (dialog_selection_callback),
@@ -1931,9 +1955,9 @@ dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
   if ((intptr_t) client_data != -1)
     menu_item_selection = (Lisp_Object *) client_data;
 
-  BLOCK_INPUT;
+  block_input ();
   lw_destroy_all_widgets (id);
-  UNBLOCK_INPUT;
+  unblock_input ();
   popup_activated_flag = 0;
 }
 
@@ -1947,7 +1971,7 @@ create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
   LWLIB_ID dialog_id;
 
   if (!FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
   dialog_id = widget_id_tick++;
 #ifdef USE_LUCID
@@ -2003,8 +2027,10 @@ xdialog_show (FRAME_PTR f,
   /* 1 means we've seen the boundary between left-hand elts and right-hand.  */
   int boundary_seen = 0;
 
+  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+
   if (! FRAME_X_P (f))
-    abort ();
+    emacs_abort ();
 
   *error_name = NULL;
 
@@ -2019,12 +2045,12 @@ xdialog_show (FRAME_PTR f,
   {
     Lisp_Object pane_name, prefix;
     const char *pane_string;
-    pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
-    prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
+    pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
+    prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX);
     pane_string = (NILP (pane_name)
                   ? "" : SSDATA (pane_name));
     prev_wv = xmalloc_widget_value ();
-    prev_wv->value = pane_string;
+    prev_wv->value = (char *) pane_string;
     if (keymaps && !NILP (prefix))
       prev_wv->name++;
     prev_wv->enabled = 1;
@@ -2039,10 +2065,10 @@ xdialog_show (FRAME_PTR f,
 
        /* Create a new item within current pane.  */
        Lisp_Object item_name, enable, descrip;
-       item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
-       enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
+       item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
+       enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
        descrip
-         = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
+         = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
 
        if (NILP (item_name))
          {
@@ -2071,7 +2097,7 @@ xdialog_show (FRAME_PTR f,
        if (!NILP (descrip))
          wv->key = SSDATA (descrip);
        wv->value = SSDATA (item_name);
-       wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
+       wv->call_data = aref_addr (menu_items, i);
        wv->enabled = !NILP (enable);
        wv->help = Qnil;
        prev_wv = wv;
@@ -2116,11 +2142,15 @@ xdialog_show (FRAME_PTR f,
   /* No selection has been chosen yet.  */
   menu_item_selection = 0;
 
+  /* Make sure to free the widget_value objects we used to specify the
+     contents even with longjmp.  */
+  record_unwind_protect (cleanup_widget_value_tree,
+                        make_save_value (first_wv, 0));
+
   /* Actually create and show the dialog.  */
   create_and_show_dialog (f, first_wv);
 
-  /* Free the widget_value objects we used to specify the contents.  */
-  free_menubar_widget_value_tree (first_wv);
+  unbind_to (specpdl_count, Qnil);
 
   /* Find the selected item, and its pane, to return
      the proper value.  */
@@ -2134,13 +2164,13 @@ xdialog_show (FRAME_PTR f,
        {
          Lisp_Object entry;
 
-         if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+         if (EQ (AREF (menu_items, i), Qt))
            {
              prefix
-               = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+               = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
              i += MENU_ITEMS_PANE_LENGTH;
            }
-         else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
+         else if (EQ (AREF (menu_items, i), Qquote))
            {
              /* This is the boundary between left-side elts and
                 right-side elts.  */
@@ -2149,8 +2179,8 @@ xdialog_show (FRAME_PTR f,
          else
            {
              entry
-               = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
-             if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
+               = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
+             if (menu_item_selection == aref_addr (menu_items, i))
                {
                  if (keymaps != 0)
                    {
@@ -2221,7 +2251,7 @@ pop_down_menu (Lisp_Object arg)
   FRAME_PTR f = p1->pointer;
   XMenu *menu = p2->pointer;
 
-  BLOCK_INPUT;
+  block_input ();
 #ifndef MSDOS
   XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
   XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
@@ -2241,7 +2271,7 @@ pop_down_menu (Lisp_Object arg)
 
 #endif /* HAVE_X_WINDOWS */
 
-  UNBLOCK_INPUT;
+  unblock_input ();
 
   return Qnil;
 }
@@ -2265,7 +2295,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
   ptrdiff_t specpdl_count = SPECPDL_INDEX ();
 
   if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
-    abort ();
+    emacs_abort ();
 
   *error_name = 0;
   if (menu_items_n_panes == 0)
@@ -2310,7 +2340,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
   lpane = XM_FAILURE;
   while (i < menu_items_used)
     {
-      if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+      if (EQ (AREF (menu_items, i), Qt))
        {
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
@@ -2318,8 +2348,8 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
 
           maxlines = max (maxlines, lines);
           lines = 0;
-         pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
-         prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+         pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
+         prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
          pane_string = (NILP (pane_name)
                         ? "" : SSDATA (pane_name));
          if (keymaps && !NILP (prefix))
@@ -2339,7 +2369,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
          while (j < menu_items_used)
            {
              Lisp_Object item;
-             item = XVECTOR (menu_items)->contents[j];
+             item = AREF (menu_items, j);
              if (EQ (item, Qt))
                break;
              if (NILP (item))
@@ -2356,7 +2386,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
        }
       /* Ignore a nil in the item list.
         It's meaningful only for dialog boxes.  */
-      else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
+      else if (EQ (AREF (menu_items, i), Qquote))
        i += 1;
       else
        {
@@ -2365,18 +2395,18 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
          char *item_data;
          char const *help_string;
 
-         item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
-         enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
+         item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
+         enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
          descrip
-           = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
-         help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
+           = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
+         help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
          help_string = STRINGP (help) ? SSDATA (help) : NULL;
 
          if (!NILP (descrip))
            {
              /* if alloca is fast, use that to make the space,
                 to reduce gc needs.  */
-             item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1);
+             item_data = alloca (maxwidth + SBYTES (descrip) + 1);
              memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
              for (j = SCHARS (item_name); j < maxwidth; j++)
                item_data[j] = ' ';
@@ -2483,11 +2513,11 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
       i = 0;
       while (i < menu_items_used)
        {
-         if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+         if (EQ (AREF (menu_items, i), Qt))
            {
              if (pane == 0)
                pane_prefix
-                 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+                 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
              pane--;
              i += MENU_ITEMS_PANE_LENGTH;
            }
@@ -2498,7 +2528,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
                  if (selidx == 0)
                    {
                      entry
-                       = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
+                       = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
                      if (keymaps != 0)
                        {
                          entry = Fcons (entry, Qnil);
@@ -2539,7 +2569,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
 /* Detect if a dialog or menu has been posted.  MSDOS has its own
    implementation on msdos.c.  */
 
-int
+int ATTRIBUTE_CONST
 popup_activated (void)
 {
   return popup_activated_flag;