Merge from trunk.
[bpt/emacs.git] / src / menu.c
index 44bb5a5..5ca687f 100644 (file)
@@ -50,10 +50,16 @@ extern HMENU current_popup_menu;
 
 #include "menu.h"
 
-/* Define HAVE_BOXES if menus can handle radio and toggle buttons.  */
+/* Return non-zero if menus can handle radio and toggle buttons.  */
+static bool
+have_boxes (void)
+{
 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI)
-#define HAVE_BOXES 1
+  if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame)))
+    return 1;
 #endif
+  return 0;
+}
 
 Lisp_Object menu_items;
 
@@ -283,13 +289,14 @@ single_keymap_panes (Lisp_Object keymap, Lisp_Object pane_name,
 
   push_menu_pane (pane_name, prefix);
 
-#ifndef HAVE_BOXES
-  /* Remember index for first item in this pane so we can go back and
-     add a prefix when (if) we see the first button.  After that, notbuttons
-     is set to 0, to mark that we have seen a button and all non button
-     items need a prefix.  */
-  skp.notbuttons = menu_items_used;
-#endif
+  if (!have_boxes ())
+    {
+      /* Remember index for first item in this pane so we can go back
+        and add a prefix when (if) we see the first button.  After
+        that, notbuttons is set to 0, to mark that we have seen a
+        button and all non button items need a prefix.  */
+      skp.notbuttons = menu_items_used;
+    }
 
   GCPRO1 (skp.pending_maps);
   map_keymap_canonical (keymap, single_menu_item, Qnil, &skp);
@@ -345,77 +352,72 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
       return;
     }
 
-#if defined (HAVE_X_WINDOWS) || defined (MSDOS)
-#ifndef HAVE_BOXES
   /* Simulate radio buttons and toggle boxes by putting a prefix in
      front of them.  */
-  {
-    Lisp_Object prefix = Qnil;
-    Lisp_Object type = AREF (item_properties, ITEM_PROPERTY_TYPE);
-    if (!NILP (type))
-      {
-       Lisp_Object selected
-         = AREF (item_properties, ITEM_PROPERTY_SELECTED);
+  if (!have_boxes ())
+    {
+      Lisp_Object prefix = Qnil;
+      Lisp_Object type = AREF (item_properties, ITEM_PROPERTY_TYPE);
+      if (!NILP (type))
+       {
+         Lisp_Object selected
+           = AREF (item_properties, ITEM_PROPERTY_SELECTED);
 
-       if (skp->notbuttons)
-         /* The first button. Line up previous items in this menu.  */
-         {
-           int idx = skp->notbuttons; /* Index for first item this menu.  */
-           int submenu = 0;
-           Lisp_Object tem;
-           while (idx < menu_items_used)
-             {
-               tem
-                 = AREF (menu_items, idx + MENU_ITEMS_ITEM_NAME);
-               if (NILP (tem))
-                 {
-                   idx++;
-                   submenu++;          /* Skip sub menu.  */
-                 }
-               else if (EQ (tem, Qlambda))
-                 {
-                   idx++;
-                   submenu--;          /* End sub menu.  */
-                 }
-               else if (EQ (tem, Qt))
-                 idx += 3;             /* Skip new pane marker. */
-               else if (EQ (tem, Qquote))
-                 idx++;                /* Skip a left, right divider. */
-               else
-                 {
-                   if (!submenu && SREF (tem, 0) != '\0'
-                       && SREF (tem, 0) != '-')
-                     ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
-                           concat2 (build_string ("    "), tem));
-                   idx += MENU_ITEMS_ITEM_LENGTH;
-                 }
-             }
-           skp->notbuttons = 0;
-         }
+         if (skp->notbuttons)
+           /* The first button. Line up previous items in this menu.  */
+           {
+             int idx = skp->notbuttons; /* Index for first item this menu.  */
+             int submenu = 0;
+             Lisp_Object tem;
+             while (idx < menu_items_used)
+               {
+                 tem
+                   = AREF (menu_items, idx + MENU_ITEMS_ITEM_NAME);
+                 if (NILP (tem))
+                   {
+                     idx++;
+                     submenu++;                /* Skip sub menu.  */
+                   }
+                 else if (EQ (tem, Qlambda))
+                   {
+                     idx++;
+                     submenu--;                /* End sub menu.  */
+                   }
+                 else if (EQ (tem, Qt))
+                   idx += 3;           /* Skip new pane marker. */
+                 else if (EQ (tem, Qquote))
+                   idx++;              /* Skip a left, right divider. */
+                 else
+                   {
+                     if (!submenu && SREF (tem, 0) != '\0'
+                         && SREF (tem, 0) != '-')
+                       ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
+                             concat2 (build_string ("    "), tem));
+                     idx += MENU_ITEMS_ITEM_LENGTH;
+                   }
+               }
+             skp->notbuttons = 0;
+           }
 
-       /* Calculate prefix, if any, for this item.  */
-       if (EQ (type, QCtoggle))
-         prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
-       else if (EQ (type, QCradio))
-         prefix = build_string (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 ("    ");
+         /* Calculate prefix, if any, for this item.  */
+         if (EQ (type, QCtoggle))
+           prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
+         else if (EQ (type, QCradio))
+           prefix = build_string (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 ("    ");
 
-    if (!NILP (prefix))
-      item_string = concat2 (prefix, item_string);
+      if (!NILP (prefix))
+       item_string = concat2 (prefix, item_string);
   }
-#endif /* not HAVE_BOXES */
 
-#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
-  if (!NILP (map))
+  if (FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame))
+      && !NILP (map))
     /* Indicate visually that this is a submenu.  */
     item_string = concat2 (item_string, build_string (" >"));
-#endif
-
-#endif /* HAVE_X_WINDOWS || MSDOS */
 
   push_menu_item (item_string, enabled, key,
                  AREF (item_properties, ITEM_PROPERTY_DEF),
@@ -426,7 +428,8 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
 
 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI)
   /* Display a submenu using the toolkit.  */
-  if (! (NILP (map) || NILP (enabled)))
+  if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame))
+      && ! (NILP (map) || NILP (enabled)))
     {
       push_submenu_start ();
       single_keymap_panes (map, Qnil, key, skp->maxdepth - 1);
@@ -455,6 +458,16 @@ keymap_panes (Lisp_Object *keymaps, ptrdiff_t nmaps)
   finish_menu_items ();
 }
 
+/* Encode a menu string as appropriate for menu-updating-frame's type.  */
+static Lisp_Object
+encode_menu_string (Lisp_Object str)
+{
+  /* TTY menu strings are encoded by write_glyphs, when they are
+     delivered to the glass, so no need to encode them here.  */
+  if (FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame)))
+    return str;
+  return ENCODE_MENU_STRING (str);
+}
 
 /* Push the items in a single pane defined by the alist PANE.  */
 static void
@@ -466,13 +479,13 @@ list_of_items (Lisp_Object pane)
     {
       item = XCAR (tail);
       if (STRINGP (item))
-       push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
+       push_menu_item (encode_menu_string (item), Qnil, Qnil, Qt,
                        Qnil, Qnil, Qnil, Qnil);
       else if (CONSP (item))
        {
          item1 = XCAR (item);
          CHECK_STRING (item1);
-         push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
+         push_menu_item (encode_menu_string (item1), Qt, XCDR (item),
                          Qt, Qnil, Qnil, Qnil, Qnil);
        }
       else
@@ -497,7 +510,7 @@ list_of_panes (Lisp_Object menu)
       elt = XCAR (tail);
       pane_name = Fcar (elt);
       CHECK_STRING (pane_name);
-      push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
+      push_menu_pane (encode_menu_string (pane_name), Qnil);
       pane_data = Fcdr (elt);
       CHECK_CONS (pane_data);
       list_of_items (pane_data);
@@ -614,6 +627,7 @@ digest_single_submenu (int start, int end, bool top_level_items)
   int submenu_depth = 0;
   widget_value **submenu_stack;
   bool panes_seen = 0;
+  struct frame *f = XFRAME (Vmenu_updating_frame);
 
   submenu_stack = alloca (menu_items_used * sizeof *submenu_stack);
   wv = xmalloc_widget_value ();
@@ -663,30 +677,35 @@ digest_single_submenu (int start, int end, bool top_level_items)
 
          pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
 
-#ifdef HAVE_NTGUI
-         if (STRINGP (pane_name))
+         /* TTY menus display menu items via tty_write_glyphs, which
+            will encode the strings as appropriate.  */
+         if (!FRAME_TERMCAP_P (f))
            {
-             if (unicode_append_menu)
-               /* Encode as UTF-8 for now.  */
-               pane_name = ENCODE_UTF_8 (pane_name);
-             else if (STRING_MULTIBYTE (pane_name))
-               pane_name = ENCODE_SYSTEM (pane_name);
+#ifdef HAVE_NTGUI
+             if (STRINGP (pane_name))
+               {
+                 if (unicode_append_menu)
+                   /* Encode as UTF-8 for now.  */
+                   pane_name = ENCODE_UTF_8 (pane_name);
+                 else if (STRING_MULTIBYTE (pane_name))
+                   pane_name = ENCODE_SYSTEM (pane_name);
 
-             ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
-           }
+                 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
+               }
 #elif defined (USE_LUCID) && defined (HAVE_XFT)
-         if (STRINGP (pane_name))
-            {
-              pane_name = ENCODE_UTF_8 (pane_name);
-             ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
-            }
+             if (STRINGP (pane_name))
+               {
+                 pane_name = ENCODE_UTF_8 (pane_name);
+                 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
+               }
 #elif !defined (HAVE_MULTILINGUAL_MENU)
-         if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
-           {
-             pane_name = ENCODE_MENU_STRING (pane_name);
-             ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
-           }
+             if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
+               {
+                 pane_name = ENCODE_MENU_STRING (pane_name);
+                 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
+               }
 #endif
+           }
 
          pane_string = (NILP (pane_name)
                         ? "" : SSDATA (pane_name));
@@ -737,47 +756,52 @@ digest_single_submenu (int start, int end, bool top_level_items)
          selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
          help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
 
-#ifdef HAVE_NTGUI
-         if (STRINGP (item_name))
+         /* TTY menu items and their descriptions will be encoded by
+            tty_write_glyphs.  */
+         if (!FRAME_TERMCAP_P (f))
            {
-             if (unicode_append_menu)
-               item_name = ENCODE_UTF_8 (item_name);
-             else if (STRING_MULTIBYTE (item_name))
-               item_name = ENCODE_SYSTEM (item_name);
+#ifdef HAVE_NTGUI
+             if (STRINGP (item_name))
+               {
+                 if (unicode_append_menu)
+                   item_name = ENCODE_UTF_8 (item_name);
+                 else if (STRING_MULTIBYTE (item_name))
+                   item_name = ENCODE_SYSTEM (item_name);
 
-             ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
-           }
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
+               }
 
-         if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
-           {
-             descrip = ENCODE_SYSTEM (descrip);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
-           }
+             if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+               {
+                 descrip = ENCODE_SYSTEM (descrip);
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
+               }
 #elif USE_LUCID
-         if (STRINGP (item_name))
-           {
-              item_name = ENCODE_UTF_8 (item_name);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
-           }
+             if (STRINGP (item_name))
+               {
+                 item_name = ENCODE_UTF_8 (item_name);
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
+               }
 
-         if (STRINGP (descrip))
-           {
-             descrip = ENCODE_UTF_8 (descrip);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
-           }
+             if (STRINGP (descrip))
+               {
+                 descrip = ENCODE_UTF_8 (descrip);
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
+               }
 #elif !defined (HAVE_MULTILINGUAL_MENU)
-          if (STRING_MULTIBYTE (item_name))
-           {
-             item_name = ENCODE_MENU_STRING (item_name);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
-           }
+             if (STRING_MULTIBYTE (item_name))
+               {
+                 item_name = ENCODE_MENU_STRING (item_name);
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
+               }
 
-          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
-           {
-             descrip = ENCODE_MENU_STRING (descrip);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
-           }
+             if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+               {
+                 descrip = ENCODE_MENU_STRING (descrip);
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
+               }
 #endif
+           }
 
          wv = xmalloc_widget_value ();
          if (prev_wv)
@@ -1077,8 +1101,6 @@ no quit occurs and `x-popup-menu' returns nil.  */)
   {
     bool get_current_pos_p = 0;
 
-    check_window_system (SELECTED_FRAME ());
-
     /* Decode the first argument: find the window and the coordinates.  */
     if (EQ (position, Qt)
        || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
@@ -1194,11 +1216,6 @@ no quit occurs and `x-popup-menu' returns nil.  */)
     xpos += XINT (x);
     ypos += XINT (y);
 
-    /* FIXME: Find a more general check!  */
-    if (!(FRAME_X_P (f) || FRAME_MSDOS_P (f)
-         || FRAME_W32_P (f) || FRAME_NS_P (f)))
-      error ("Can not put GUI menu on this terminal");
-
     XSETFRAME (Vmenu_updating_frame, f);
   }
 #endif /* HAVE_MENUS */
@@ -1287,7 +1304,8 @@ no quit occurs and `x-popup-menu' returns nil.  */)
 #ifdef HAVE_MENUS
 #ifdef HAVE_WINDOW_SYSTEM
   /* Hide a previous tip, if any.  */
-  Fx_hide_tip ();
+  if (!FRAME_TERMCAP_P (f))
+    Fx_hide_tip ();
 #endif
 
 #ifdef HAVE_NTGUI     /* FIXME: Is it really w32-specific?  --Stef  */
@@ -1296,7 +1314,7 @@ no quit occurs and `x-popup-menu' returns nil.  */)
      can occur if you press ESC or click outside a menu without selecting
      a menu item.
   */
-  if (current_popup_menu)
+  if (current_popup_menu && FRAME_W32_P (f))
     {
       discard_menu_items ();
       FRAME_DISPLAY_INFO (f)->grabbed = 0;
@@ -1310,26 +1328,34 @@ no quit occurs and `x-popup-menu' returns nil.  */)
 #endif
 
   /* Display them in a menu.  */
-  block_input ();
 
   /* FIXME: Use a terminal hook!  */
 #if defined HAVE_NTGUI
-  selection = w32_menu_show (f, xpos, ypos, for_click,
-                            keymaps, title, &error_name);
-#elif defined HAVE_NS
-  selection = ns_menu_show (f, xpos, ypos, for_click,
-                           keymaps, title, &error_name);
-#else /* MSDOS and X11 */
+  if (FRAME_W32_P (f))
+    selection = w32_menu_show (f, xpos, ypos, for_click,
+                              keymaps, title, &error_name);
+  else
+#endif
+#if defined HAVE_NS
+  if (FRAME_NS_P (f))
+    selection = ns_menu_show (f, xpos, ypos, for_click,
+                             keymaps, title, &error_name);
+  else
+#endif
+#if (defined (HAVE_X_WINDOWS) || defined (MSDOS))
   /* Assume last_event_timestamp is the timestamp of the button event.
      Is this assumption ever violated?  We can't use the timestamp
      stored within POSITION because there the top bits from the actual
      timestamp may be truncated away (Bug#4930).  */
-  selection = xmenu_show (f, xpos, ypos, for_click,
-                         keymaps, title, &error_name,
-                         last_event_timestamp);
+  if (FRAME_X_P (f) || FRAME_MSDOS_P (f))
+    selection = xmenu_show (f, xpos, ypos, for_click,
+                           keymaps, title, &error_name,
+                           last_event_timestamp);
+  else
 #endif
-
-  unblock_input ();
+  if (FRAME_TERMCAP_P (f))
+    selection = tty_menu_show (f, xpos, ypos, for_click,
+                              keymaps, title, &error_name);
 
 #ifdef HAVE_NS
   unbind_to (specpdl_count, Qnil);
@@ -1338,7 +1364,8 @@ no quit occurs and `x-popup-menu' returns nil.  */)
 #endif
 
 #ifdef HAVE_NTGUI     /* FIXME: Is it really w32-specific?  --Stef  */
-  FRAME_DISPLAY_INFO (f)->grabbed = 0;
+  if (FRAME_W32_P (f))
+    FRAME_DISPLAY_INFO (f)->grabbed = 0;
 #endif
 
 #endif /* HAVE_MENUS */