This commit was generated by cvs2svn to compensate for changes in r1705,
[chise/xemacs-chise.git.1] / src / menubar.c
index 7b1fb16..7641aae 100644 (file)
@@ -21,8 +21,13 @@ Boston, MA 02111-1307, USA.  */
 
 /* Synched up with: Not in FSF. */
 
-/* #### There ain't much here because menubars have not been
-   properly abstracted yet. */
+/* Authorship:
+
+   Created by Ben Wing as part of device-abstraction work for 19.12.
+   Menu filters and many other keywords added by Stig for 19.12.
+   Menu accelerators c. 1997? by ??.  Moved here from event-stream.c.
+   Much other work post-1996 by ??.
+*/
 
 #include <config.h>
 #include "lisp.h"
@@ -31,6 +36,7 @@ Boston, MA 02111-1307, USA.  */
 #include "device.h"
 #include "frame.h"
 #include "gui.h"
+#include "keymap.h"
 #include "menubar.h"
 #include "redisplay.h"
 #include "window.h"
@@ -54,6 +60,30 @@ int popup_menu_titles;
 
 Lisp_Object Vmenubar_pointer_glyph;
 
+/* prefix key(s) that must match in order to activate menu.
+   This is ugly.  fix me.
+   */
+Lisp_Object Vmenu_accelerator_prefix;
+
+/* list of modifier keys to match accelerator for top level menus */
+Lisp_Object Vmenu_accelerator_modifiers;
+
+/* whether menu accelerators are enabled */
+Lisp_Object Vmenu_accelerator_enabled;
+
+/* keymap for auxiliary menu accelerator functions */
+Lisp_Object Vmenu_accelerator_map;
+
+Lisp_Object Qmenu_force;
+Lisp_Object Qmenu_fallback;
+Lisp_Object Qmenu_quit;
+Lisp_Object Qmenu_up;
+Lisp_Object Qmenu_down;
+Lisp_Object Qmenu_left;
+Lisp_Object Qmenu_right;
+Lisp_Object Qmenu_select;
+Lisp_Object Qmenu_escape;
+
 static int
 menubar_variable_changed (Lisp_Object sym, Lisp_Object *val,
                          Lisp_Object in_object, int flags)
@@ -95,21 +125,23 @@ menubar_visible_p_changed_in_frame (Lisp_Object specifier, struct frame *f,
 }
 
 Lisp_Object
-current_frame_menubar (CONST struct frame* f)
+current_frame_menubar (const struct frame* f)
 {
   struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
   return symbol_value_in_buffer (Qcurrent_menubar, w->buffer);
 }
 
 Lisp_Object
-menu_parse_submenu_keywords (Lisp_Object desc, struct gui_item* pgui_item)
+menu_parse_submenu_keywords (Lisp_Object desc, Lisp_Object gui_item)
 {
+  Lisp_Gui_Item *pgui_item = XGUI_ITEM (gui_item);
+
   /* Menu descriptor should be a list */
   CHECK_CONS (desc);
 
   /* First element may be menu name, although can be omitted.
      Let's think that if stuff begins with anything than a keyword
-     or a list (submenu), this is a menu name, expected to be a stirng */
+     or a list (submenu), this is a menu name, expected to be a string */
   if (!KEYWORDP (XCAR (desc)) && !CONSP (XCAR (desc)))
     {
       CHECK_STRING (XCAR (desc));
@@ -130,7 +162,7 @@ menu_parse_submenu_keywords (Lisp_Object desc, struct gui_item* pgui_item)
       desc = XCDR (desc);
       if (!NILP (desc))
        CHECK_CONS (desc);
-      gui_item_add_keyval_pair (pgui_item, key, val);
+      gui_item_add_keyval_pair (gui_item, key, val, ERROR_ME);
     }
 
   /* Return the rest - supposed to be a list of items */
@@ -151,12 +183,12 @@ See also 'find-menu-item'.
        (desc, path))
 {
   Lisp_Object path_entry, submenu_desc, submenu;
-  struct gcpro gcpro1;
-  struct gui_item gui_item;
+  struct gcpro gcpro1, gcpro2;
+  Lisp_Object gui_item = allocate_gui_item ();
+  Lisp_Gui_Item* pgui_item = XGUI_ITEM (gui_item);
+
+  GCPRO2 (gui_item, desc);
 
-  gui_item_init (&gui_item);
-  GCPRO_GUI_ITEM (&gui_item);
-  
   EXTERNAL_LIST_LOOP (path_entry, path)
     {
       /* Verify that DESC describes a menu, not single item */
@@ -164,15 +196,15 @@ See also 'find-menu-item'.
        RETURN_UNGCPRO (Qnil);
 
       /* Parse this menu */
-      desc = menu_parse_submenu_keywords (desc, &gui_item);
+      desc = menu_parse_submenu_keywords (desc, gui_item);
 
       /* Check that this (sub)menu is active */
-      if (!gui_item_active_p (&gui_item))
+      if (!gui_item_active_p (gui_item))
        RETURN_UNGCPRO (Qnil);
 
       /* Apply :filter */
-      if (!NILP (gui_item.filter))
-       desc = call1 (gui_item.filter, desc);
+      if (!NILP (pgui_item->filter))
+       desc = call1 (pgui_item->filter, desc);
 
       /* Find the next menu on the path inside this one */
       EXTERNAL_LIST_LOOP (submenu_desc, desc)
@@ -191,7 +223,7 @@ See also 'find-menu-item'.
 
     descend:
       /* Prepare for the next iteration */
-      gui_item_init (&gui_item);
+      gui_item_init (gui_item);
     }
 
   /* We have successfully descended down the end of the path */
@@ -290,11 +322,12 @@ See menubar.el for many more examples.
 DEFUN ("normalize-menu-item-name", Fnormalize_menu_item_name, 1, 2, 0, /*
 Convert a menu item name string into normal form, and return the new string.
 Menu item names should be converted to normal form before being compared.
+This removes %_'s (accelerator indications) and converts %% to %.
 */
        (name, buffer))
 {
   struct buffer *buf = decode_buffer (buffer, 0);
-  struct Lisp_String *n;
+  Lisp_String *n;
   Charcount end;
   int i;
   Bufbyte *name_data;
@@ -338,6 +371,10 @@ Menu item names should be converted to normal form before being compared.
       INC_CHARPTR (name_data);
     }
 
+  if (string_result_ptr - string_result == XSTRING_LENGTH (name)
+      && !memcmp (string_result, XSTRING_DATA (name), XSTRING_LENGTH (name)))
+    return name;
+
   return make_string (string_result, string_result_ptr - string_result);
 }
 
@@ -345,6 +382,18 @@ void
 syms_of_menubar (void)
 {
   defsymbol (&Qcurrent_menubar, "current-menubar");
+
+  defsymbol (&Qmenu_force, "menu-force");
+  defsymbol (&Qmenu_fallback, "menu-fallback");
+
+  defsymbol (&Qmenu_quit, "menu-quit");
+  defsymbol (&Qmenu_up, "menu-up");
+  defsymbol (&Qmenu_down, "menu-down");
+  defsymbol (&Qmenu_left, "menu-left");
+  defsymbol (&Qmenu_right, "menu-right");
+  defsymbol (&Qmenu_select, "menu-select");
+  defsymbol (&Qmenu_escape, "menu-escape");
+
   DEFSUBR (Fpopup_menu);
   DEFSUBR (Fnormalize_menu_item_name);
   DEFSUBR (Fmenu_find_real_submenu);
@@ -353,32 +402,21 @@ syms_of_menubar (void)
 void
 vars_of_menubar (void)
 {
-  {
-    /* put in Vblank_menubar a menubar value which has no visible
-     * items.  This is a bit tricky due to various quirks.  We
-     * could use '(["" nil nil]), but this is apparently equivalent
-     * to '(nil), and a new frame created with this menubar will
-     * get a vertically-squished menubar.  If we use " " as the
-     * button title instead of "", we get an etched button border.
-     * So we use
-     *  '(("No active menubar" ["" nil nil]))
-     * which creates a menu whose title is "No active menubar",
-     * and this works fine.
-     */
-
-    Lisp_Object menu_item[3];
-    static CONST char *blank_msg = "No active menubar";
-
-    menu_item[0] = build_string ("");
-    menu_item[1] = Qnil;
-    menu_item[2] = Qnil;
-    Vblank_menubar = Fcons (Fcons (build_string (blank_msg),
-                                  Fcons (Fvector (3, &menu_item[0]),
-                                         Qnil)),
-                           Qnil);
-    Vblank_menubar = Fpurecopy (Vblank_menubar);
-    staticpro (&Vblank_menubar);
-  }
+  /* put in Vblank_menubar a menubar value which has no visible
+   * items.  This is a bit tricky due to various quirks.  We
+   * could use '(["" nil nil]), but this is apparently equivalent
+   * to '(nil), and a new frame created with this menubar will
+   * get a vertically-squished menubar.  If we use " " as the
+   * button title instead of "", we get an etched button border.
+   * So we use
+   *  '(("No active menubar" ["" nil nil]))
+   * which creates a menu whose title is "No active menubar",
+   * and this works fine.
+   */
+
+  Vblank_menubar = list1 (list2 (build_string ("No active menubar"),
+                                vector3 (build_string (""), Qnil, Qnil)));
+  staticpro (&Vblank_menubar);
 
   DEFVAR_BOOL ("popup-menu-titles", &popup_menu_titles /*
 If true, popup menus will have title bars at the top.
@@ -406,8 +444,18 @@ This is the string that will be displayed in the parent menu, if any.  For
 toplevel menus, it is ignored.  This string is not displayed in the menu
 itself.
 
-Immediately following the name string of the menu, any of three
-optional keyword-value pairs is permitted.
+Menu accelerators can be indicated in the string by putting the
+sequence "%_" before the character corresponding to the key that will
+invoke the menu or menu item.  Uppercase and lowercase accelerators
+are equivalent.  The sequence "%%" is also special, and is translated
+into a single %.
+
+If no menu accelerator is present in the string, XEmacs will act as if
+the first character has been tagged as an accelerator.
+
+Immediately following the name string of the menu, various optional
+keyword-value pairs are permitted: currently, :filter, :active, :included,
+and :config. (See below.)
 
 If an element of a menu (or menubar) is a string, then that string will be
 presented as unselectable text.
@@ -415,6 +463,29 @@ presented as unselectable text.
 If an element of a menu is a string consisting solely of hyphens, then that
 item will be presented as a solid horizontal line.
 
+If an element of a menu is a string beginning with "--:", it will be
+presented as a line whose appearance is controlled by the rest of the
+text in the string.  The allowed line specs are system-dependent, and
+currently work only under X Windows (with Lucid and Motif menubars);
+otherwise, a solid horizontal line is presented, as if the string were
+all hyphens.
+
+The possibilities are:
+
+  "--:singleLine"
+  "--:doubleLine"
+  "--:singleDashedLine"
+  "--:doubleDashedLine"
+  "--:noLine"
+  "--:shadowEtchedIn"
+  "--:shadowEtchedOut"
+  "--:shadowEtchedInDash"
+  "--:shadowEtchedOutDash"
+  "--:shadowDoubleEtchedIn" (Lucid menubars only)
+  "--:shadowDoubleEtchedOut" (Lucid menubars only)
+  "--:shadowDoubleEtchedInDash" (Lucid menubars only)
+  "--:shadowDoubleEtchedOutDash" (Lucid menubars only)
+
 If an element of a menu is a list, it is treated as a submenu.  The name of
 that submenu (the first element in the list) will be used as the name of the
 item representing this menu on the parent.
@@ -424,33 +495,39 @@ division between the set of menubar-items which are flushleft and those
 which are flushright.
 
 Otherwise, the element must be a vector, which describes a menu item.
-A menu item can have any of the following forms:
+A menu item is of the following form:
+
+ [ "name" callback :<keyword> <value> :<keyword> <value> ... ]
+
+The following forms are also accepted for compatibility, but deprecated:
 
  [ "name" callback <active-p> ]
  [ "name" callback <active-p> <suffix> ]
- [ "name" callback :<keyword> <value>  :<keyword> <value> ... ]
 
 The name is the string to display on the menu; it is filtered through the
 resource database, so it is possible for resources to override what string
-is actually displayed.
+is actually displayed.  Menu accelerator indicators (the sequence `%_') are
+also processed; see above.  If the name is not a string, it will be
+evaluated with `eval', and the result should be a string.
 
 If the `callback' of a menu item is a symbol, then it must name a command.
 It will be invoked with `call-interactively'.  If it is a list, then it is
 evaluated with `eval'.
 
-The possible keywords are this:
+In the deprecated forms, <active-p> is equivalent to using the :active
+keyword, and <suffix> is equivalent to using the :suffix keyword.
 
- :active   <form>    Same as <active-p> in the first two forms: the
-                     expression is evaluated just before the menu is
+The possible keywords are:
+
+ :active   <form>    The expression is evaluated just before the menu is
                      displayed, and the menu will be selectable only if
                      the result is non-nil.
 
- :suffix   <form>    Same as <suffix> in the second form: the expression
-                     is evaluated just before the menu is displayed and
-                    resulting string is appended to the displayed name,
-                    providing a convenient way of adding the name of a
-                    command's ``argument'' to the menu, like
-                    ``Kill Buffer NAME''.
+ :suffix   <form>    The expression is evaluated just before the menu is
+                     displayed and the resulting string is appended to
+                     the displayed name, providing a convenient way of
+                     adding the name of a command's ``argument'' to the
+                     menu, like ``Kill Buffer NAME''.
 
  :keys     "string"  Normally, the keyboard equivalents of commands in
                      menus are displayed when the `callback' is a symbol.
@@ -486,41 +563,46 @@ The possible keywords are this:
                         :included (memq symbol menubar-configuration)
                     See the variable `menubar-configuration'.
 
- :filter <function>  A menu filter can only be used in a menu item list.
-                    (i.e.:  not in a menu item itself).  It is used to
-                    sensitize or incrementally create a submenu only when
-                    it is selected by the user and not every time the
-                    menubar is activated.  The filter function is passed
-                    the list of menu items in the submenu and must return a
-                    list of menu items to be used for the menu.  It is
-                    called only when the menu is about to be displayed, so
-                    other menus may already be displayed.  Vile and
-                    terrible things will happen if a menu filter function
-                    changes the current buffer, window, or frame.  It
-                    also should not raise, lower, or iconify any frames.
-                    Basically, the filter function should have no
-                    side-effects.
+ :filter <function>  A menu filter can only be used at the beginning of a
+                     submenu description (i.e. not in a menu item itself).
+                    (Remember that most of the keywords can take evaluated
+                    expressions as well as constants.)  The filter is used to
+                    incrementally create a submenu only when it is selected
+                     by the user and not every time the menubar is activated.
+                     The filter function is passed the list of menu items in
+                     the submenu and must return the modified list to be
+                    actually used.  The filter MUST NOT destructively modify
+                     the list of menu items passed to it.  It is called only
+                    when the menu is about to be displayed, so other menus
+                    may already be displayed.  Vile and terrible things will
+                    happen if a menu filter function changes the current
+                    buffer, window, or frame.  It also should not raise,
+                    lower, or iconify any frames.  Basically, the filter
+                    function should have no side-effects.
+
+ :key-sequence keys  Used in FSF Emacs as an hint to an equivalent keybinding.
+                     Ignored by XEmacs for easymenu.el compatibility.
+                    (XEmacs computes this information automatically.)
 
 For example:
 
- ("File"
+ ("%_File"
   :filter file-menu-filter     ; file-menu-filter is a function that takes
                                ; one argument (a list of menu items) and
                                ; returns a list of menu items
-  [ "Save As..."    write-file  t ]
-  [ "Revert Buffer" revert-buffer (buffer-modified-p) ]
-  [ "Read Only"     toggle-read-only :style toggle
+  [ "Save %_As..."    write-file  t ]
+  [ "%_Revert Buffer" revert-buffer (buffer-modified-p) ]
+  [ "R%_ead Only"     toggle-read-only :style toggle
                      :selected buffer-read-only ]
   )
 
-See x-menubar.el for many more examples.
+See menubar-items.el for many more examples.
 
 After the menubar is clicked upon, but before any menus are popped up,
 the functions on the `activate-menubar-hook' are invoked to make top-level
 changes to the menus and menubar.  Note, however, that the use of menu
 filters (using the :filter keyword) is usually a more efficient way to
-dynamically alter or sensitize menus.
-*/, menubar_variable_changed);
+dynamically alter or sensitize menus.  */, menubar_variable_changed);
 
   Vcurrent_menubar = Qnil;
 
@@ -566,6 +648,80 @@ If unspecified in a particular domain, the window-system-provided
 default pointer is used.
 */ );
 
+  DEFVAR_LISP ("menu-accelerator-prefix", &Vmenu_accelerator_prefix /*
+Prefix key(s) that must be typed before menu accelerators will be activated.
+Set this to a value acceptable by define-key.
+
+NOTE: This currently only has any effect under X Windows.
+*/ );
+  Vmenu_accelerator_prefix = Qnil;
+
+  DEFVAR_LISP ("menu-accelerator-modifiers", &Vmenu_accelerator_modifiers /*
+Modifier keys which must be pressed to get to the top level menu accelerators.
+This is a list of modifier key symbols.  All modifier keys must be held down
+while a valid menu accelerator key is pressed in order for the top level
+menu to become active.
+
+NOTE: This currently only has any effect under X Windows.
+
+See also menu-accelerator-enabled and menu-accelerator-prefix.
+*/ );
+  Vmenu_accelerator_modifiers = list1 (Qmeta);
+
+  DEFVAR_LISP ("menu-accelerator-enabled", &Vmenu_accelerator_enabled /*
+Whether menu accelerator keys can cause the menubar to become active.
+If 'menu-force or 'menu-fallback, then menu accelerator keys can
+be used to activate the top level menu.  Once the menubar becomes active, the
+accelerator keys can be used regardless of the value of this variable.
+
+menu-force is used to indicate that the menu accelerator key takes
+precedence over bindings in the current keymap(s).  menu-fallback means
+that bindings in the current keymap take precedence over menu accelerator keys.
+Thus a top level menu with an accelerator of "T" would be activated on a
+keypress of Meta-t if menu-accelerator-enabled is menu-force.
+However, if menu-accelerator-enabled is menu-fallback, then
+Meta-t will not activate the menubar and will instead run the function
+transpose-words, to which it is normally bound.
+
+See also menu-accelerator-modifiers and menu-accelerator-prefix.
+*/ );
+  Vmenu_accelerator_enabled = Qnil;
+
+  DEFVAR_LISP ("menu-accelerator-map", &Vmenu_accelerator_map /*
+Keymap for use when the menubar is active.
+The actions menu-quit, menu-up, menu-down, menu-left, menu-right,
+menu-select and menu-escape can be mapped to keys in this map.
+NOTE: This currently only has any effect under X Windows.
+
+menu-quit    Immediately deactivate the menubar and any open submenus without
+             selecting an item.
+menu-up      Move the menu cursor up one row in the current menu.  If the
+             move extends past the top of the menu, wrap around to the bottom.
+menu-down    Move the menu cursor down one row in the current menu.  If the
+             move extends past the bottom of the menu, wrap around to the top.
+             If executed while the cursor is in the top level menu, move down
+             into the selected menu.
+menu-left    Move the cursor from a submenu into the parent menu.  If executed
+             while the cursor is in the top level menu, move the cursor to the
+             left.  If the move extends past the left edge of the menu, wrap
+             around to the right edge.
+menu-right   Move the cursor into a submenu.  If the cursor is located in the
+             top level menu or is not currently on a submenu heading, then move
+             the cursor to the next top level menu entry.  If the move extends
+             past the right edge of the menu, wrap around to the left edge.
+menu-select  Activate the item under the cursor.  If the cursor is located on
+             a submenu heading, then move the cursor into the submenu.
+menu-escape  Pop up to the next level of menus.  Moves from a submenu into its
+             parent menu.  From the top level menu, this deactivates the
+             menubar.
+
+This keymap can also contain normal key-command bindings, in which case the
+menubar is deactivated and the corresponding command is executed.
+
+The action bindings used by the menu accelerator code are designed to mimic
+the actions of menu traversal keys in a commonly used PC operating system.
+*/ );
+
   Fprovide (intern ("menubar"));
 }
 
@@ -580,11 +736,9 @@ This is a specifier; use `set-specifier' to change it.
 
   set_specifier_fallback (Vmenubar_visible_p, list1 (Fcons (Qnil, Qt)));
   set_specifier_caching (Vmenubar_visible_p,
-                        slot_offset (struct window,
-                                     menubar_visible_p),
+                        offsetof (struct window, menubar_visible_p),
                         menubar_visible_p_changed,
-                        slot_offset (struct frame,
-                                     menubar_visible_p),
+                        offsetof (struct frame, menubar_visible_p),
                         menubar_visible_p_changed_in_frame);
 }
 
@@ -592,4 +746,6 @@ void
 complex_vars_of_menubar (void)
 {
   Vmenubar_pointer_glyph = Fmake_glyph_internal (Qpointer);
+
+  Vmenu_accelerator_map = Fmake_keymap (Qnil);
 }