]> code.delx.au - gnu-emacs/blobdiff - src/menu.c
* src/buffer.c (init_buffer_once): Initialize buffer_local_flags early.
[gnu-emacs] / src / menu.c
index b65401c6f4fbb600f13315c32543864cce8dbef7..5a8ea34242f2a65ea012ad56d1f741b576ae616f 100644 (file)
@@ -1,6 +1,6 @@
 /* Platform-independent code for terminal communications.
 
-Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2014 Free Software
+Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2015 Free Software
 Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -66,9 +66,6 @@ Lisp_Object menu_items;
 
 /* If non-nil, means that the global vars defined here are already in use.
    Used to detect cases where we try to re-enter this non-reentrant code.  */
-#if ! (defined USE_GTK || defined USE_MOTIF)
-static
-#endif
 Lisp_Object menu_items_inuse;
 
 /* Number of slots currently allocated in menu_items.  */
@@ -357,7 +354,7 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
      front of them.  */
   if (!have_boxes ())
     {
-      Lisp_Object prefix = Qnil;
+      char const *prefix = 0;
       Lisp_Object type = AREF (item_properties, ITEM_PROPERTY_TYPE);
       if (!NILP (type))
        {
@@ -392,8 +389,11 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
                    {
                      if (!submenu && SREF (tem, 0) != '\0'
                          && SREF (tem, 0) != '-')
-                       ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
-                             concat2 (build_string ("    "), tem));
+                       {
+                         AUTO_STRING (spaces, "    ");
+                         ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
+                               concat2 (spaces, tem));
+                       }
                      idx += MENU_ITEMS_ITEM_LENGTH;
                    }
                }
@@ -402,24 +402,30 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
 
          /* Calculate prefix, if any, for this item.  */
          if (EQ (type, QCtoggle))
-           prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
+           prefix = NILP (selected) ? "[ ] " : "[X] ";
          else if (EQ (type, QCradio))
-           prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
+           prefix = NILP (selected) ? "( ) " : "(*) ";
        }
       /* Not a button. If we have earlier buttons, then we need a prefix.  */
       else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
               && SREF (item_string, 0) != '-')
-       prefix = build_string ("    ");
+       prefix = "    ";
 
-      if (!NILP (prefix))
-       item_string = concat2 (prefix, item_string);
+      if (prefix)
+       {
+         AUTO_STRING (prefix_obj, prefix);
+         item_string = concat2 (prefix_obj, item_string);
+       }
   }
 
   if ((FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame))
        || FRAME_MSDOS_P (XFRAME (Vmenu_updating_frame)))
       && !NILP (map))
     /* Indicate visually that this is a submenu.  */
-    item_string = concat2 (item_string, build_string (" >"));
+    {
+      AUTO_STRING (space_gt, " >");
+      item_string = concat2 (item_string, space_gt);
+    }
 
   push_menu_item (item_string, enabled, key,
                  AREF (item_properties, ITEM_PROPERTY_DEF),
@@ -635,8 +641,9 @@ digest_single_submenu (int start, int end, bool top_level_items)
   widget_value **submenu_stack;
   bool panes_seen = 0;
   struct frame *f = XFRAME (Vmenu_updating_frame);
+  USE_SAFE_ALLOCA;
 
-  submenu_stack = alloca (menu_items_used * sizeof *submenu_stack);
+  SAFE_NALLOCA (submenu_stack, 1, menu_items_used);
   wv = make_widget_value ("menu", NULL, true, Qnil);
   wv->button_type = BUTTON_TYPE_NONE;
   first_wv = wv;
@@ -838,11 +845,12 @@ digest_single_submenu (int start, int end, bool top_level_items)
      that was originally a button, return it by itself.  */
   if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
     {
-      wv = first_wv->contents;
-      xfree (first_wv);
-      return wv;
+      wv = first_wv;
+      first_wv = first_wv->contents;
+      xfree (wv);
     }
 
+  SAFE_FREE ();
   return first_wv;
 }
 
@@ -893,9 +901,10 @@ find_and_call_menu_selection (struct frame *f, int menu_bar_items_used,
   Lisp_Object *subprefix_stack;
   int submenu_depth = 0;
   int i;
+  USE_SAFE_ALLOCA;
 
   entry = Qnil;
-  subprefix_stack = alloca (menu_bar_items_used * sizeof *subprefix_stack);
+  SAFE_NALLOCA (subprefix_stack, 1, menu_bar_items_used);
   prefix = Qnil;
   i = 0;
 
@@ -957,11 +966,13 @@ find_and_call_menu_selection (struct frame *f, int menu_bar_items_used,
              buf.arg = entry;
              kbd_buffer_store_event (&buf);
 
-             return;
+             break;
            }
          i += MENU_ITEMS_ITEM_LENGTH;
        }
     }
+
+  SAFE_FREE ();
 }
 
 #endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */
@@ -976,10 +987,11 @@ find_and_return_menu_selection (struct frame *f, bool keymaps, void *client_data
   int i;
   Lisp_Object *subprefix_stack;
   int submenu_depth = 0;
+  USE_SAFE_ALLOCA;
 
   prefix = entry = Qnil;
   i = 0;
-  subprefix_stack = alloca (menu_items_used * word_size);
+  SAFE_ALLOCA_LISP (subprefix_stack, menu_items_used);
 
   while (i < menu_items_used)
     {
@@ -1021,11 +1033,13 @@ find_and_return_menu_selection (struct frame *f, bool keymaps, void *client_data
                     if (!NILP (subprefix_stack[j]))
                       entry = Fcons (subprefix_stack[j], entry);
                 }
+             SAFE_FREE ();
               return entry;
             }
           i += MENU_ITEMS_ITEM_LENGTH;
         }
     }
+  SAFE_FREE ();
   return Qnil;
 }
 #endif  /* HAVE_NS */
@@ -1236,7 +1250,7 @@ no quit occurs and `x-popup-menu' returns nil.  */)
          {
            int cur_x, cur_y;
 
-           mouse_position_for_popup (new_f, &cur_x, &cur_y);
+           x_relative_mouse_position (new_f, &cur_x, &cur_y);
            /* cur_x/y may be negative, so use make_number.  */
            x = make_number (cur_x);
            y = make_number (cur_y);
@@ -1413,9 +1427,12 @@ no quit occurs and `x-popup-menu' returns nil.  */)
   record_unwind_protect_void (discard_menu_items);
 #endif
 
-  /* Display them in a menu.  */
-  selection = FRAME_TERMINAL (f)->menu_show_hook (f, xpos, ypos, menuflags,
-                                                 title, &error_name);
+  /* Display them in a menu, but not if F is the initial frame that
+     doesn't have its hooks set (e.g., in a batch session), because
+     such a frame cannot display menus.  */
+  if (!FRAME_INITIAL_P (f))
+    selection = FRAME_TERMINAL (f)->menu_show_hook (f, xpos, ypos, menuflags,
+                                                   title, &error_name);
 
 #ifdef HAVE_NS
   unbind_to (specpdl_count, Qnil);
@@ -1434,6 +1451,38 @@ no quit occurs and `x-popup-menu' returns nil.  */)
   return selection;
 }
 
+/* If F's terminal is not capable of displaying a popup dialog,
+   emulate it with a menu.  */
+
+static Lisp_Object
+emulate_dialog_with_menu (struct frame *f, Lisp_Object contents)
+{
+  Lisp_Object x, y, frame, newpos, prompt = Fcar (contents);
+  int x_coord, y_coord;
+
+  if (FRAME_WINDOW_P (f))
+    {
+      x_coord = FRAME_PIXEL_WIDTH (f);
+      y_coord = FRAME_PIXEL_HEIGHT (f);
+    }
+  else
+    {
+      x_coord = FRAME_COLS (f);
+      /* Center the title at frame middle.  (TTY menus have
+        their upper-left corner at the given position.)  */
+      if (STRINGP (prompt))
+       x_coord -= SCHARS (prompt);
+      y_coord = FRAME_TOTAL_LINES (f);
+    }
+
+  XSETFRAME (frame, f);
+  XSETINT (x, x_coord / 2);
+  XSETINT (y, y_coord / 2);
+  newpos = list2 (list2 (x, y), frame);
+
+  return Fx_popup_menu (newpos, list2 (prompt, contents));
+}
+
 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
        doc: /* Pop up a dialog box and return user's selection.
 POSITION specifies which frame to use.
@@ -1466,24 +1515,7 @@ for instance using the window manager, then this produces a quit and
   if (EQ (position, Qt)
       || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
                               || EQ (XCAR (position), Qtool_bar))))
-    {
-#if 0 /* Using the frame the mouse is on may not be right.  */
-      /* Use the mouse's current position.  */
-      struct frame *new_f = SELECTED_FRAME ();
-      Lisp_Object bar_window;
-      enum scroll_bar_part part;
-      Time time;
-      Lisp_Object x, y;
-
-      (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
-
-      if (new_f != 0)
-       XSETFRAME (window, new_f);
-      else
-       window = selected_window;
-#endif
-      window = selected_window;
-    }
+    window = selected_window;
   else if (CONSP (position))
     {
       Lisp_Object tem = XCAR (position);
@@ -1514,6 +1546,11 @@ for instance using the window manager, then this produces a quit and
        but I don't want to make one now.  */
     CHECK_WINDOW (window);
 
+  /* Note that xw_popup_dialog can call menu code, so
+     Vmenu_updating_frame should be set (Bug#17891).  */
+  eassert (f && FRAME_LIVE_P (f));
+  XSETFRAME (Vmenu_updating_frame, f);
+
   /* Force a redisplay before showing the dialog.  If a frame is created
      just before showing the dialog, its contents may not have been fully
      drawn, as this depends on timing of events from the X server.  Redisplay
@@ -1525,51 +1562,21 @@ for instance using the window manager, then this produces a quit and
      string contents, because Fredisplay may GC and relocate them.  */
   Fredisplay (Qt);
 
-#if defined USE_X_TOOLKIT || defined USE_GTK
-  if (FRAME_WINDOW_P (f))
-    return xw_popup_dialog (f, header, contents);
-#endif
-#ifdef HAVE_NTGUI
-  if (FRAME_W32_P (f))
+  /* Display the popup dialog by a terminal-specific hook ... */
+  if (FRAME_TERMINAL (f)->popup_dialog_hook)
     {
-      Lisp_Object selection = w32_popup_dialog (f, header, contents);
-
+      Lisp_Object selection
+       = FRAME_TERMINAL (f)->popup_dialog_hook (f, header, contents);
+#ifdef HAVE_NTGUI
+      /* NTGUI supports only simple dialogs with Yes/No choices.  For
+        other dialogs, it returns the symbol 'unsupported--w32-dialog',
+        as a signal for the caller to fall back to the emulation code.  */
       if (!EQ (selection, Qunsupported__w32_dialog))
+#endif
        return selection;
     }
-#endif
-#ifdef HAVE_NS
-  if (FRAME_NS_P (f))
-    return ns_popup_dialog (position, header, contents);
-#endif
-  /* Display a menu with these alternatives
-     in the middle of frame F.  */
-  {
-    Lisp_Object x, y, frame, newpos, prompt;
-    int x_coord, y_coord;
-
-    prompt = Fcar (contents);
-    if (FRAME_WINDOW_P (f))
-      {
-       x_coord = FRAME_PIXEL_WIDTH (f);
-       y_coord = FRAME_PIXEL_HEIGHT (f);
-      }
-    else
-      {
-       x_coord = FRAME_COLS (f);
-       /* Center the title at frame middle.  (TTY menus have their
-          upper-left corner at the given position.)  */
-       if (STRINGP (prompt))
-         x_coord -= SCHARS (prompt);
-       y_coord = FRAME_LINES (f);
-      }
-    XSETFRAME (frame, f);
-    XSETINT (x, x_coord / 2);
-    XSETINT (y, y_coord / 2);
-    newpos = list2 (list2 (x, y), frame);
-
-    return Fx_popup_menu (newpos, list2 (prompt, contents));
-  }
+  /* ... or emulate it with a menu.  */
+  return emulate_dialog_with_menu (f, contents);
 }
 
 void