(x_activate_menubar): Allow any event, not just ButtonPress.
[bpt/emacs.git] / src / xmenu.c
index 95aa47b..ee78f29 100644 (file)
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* X pop-up deck-of-cards menu facility for gnuemacs.
  *
@@ -87,6 +88,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 Lisp_Object Qdebug_on_next_call;
 
+Lisp_Object Qmenu_alias;
+
 extern Lisp_Object Qmenu_enable;
 extern Lisp_Object Qmenu_bar;
 extern Lisp_Object Qmouse_click, Qevent_kind;
@@ -395,7 +398,8 @@ menu_item_equiv_key (item_string, item1, descrip_ptr)
       /* If the command is an alias for another
         (such as easymenu.el and lmenu.el set it up),
         see if the original command name has equivalent keys.  */
-      if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function))
+      if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
+         && ! NILP (Fget (def, Qmenu_alias)))
        savedkey = Fwhere_is_internal (XSYMBOL (def)->function,
                                       Qnil, Qt, Qnil);
       else
@@ -673,7 +677,7 @@ single_keymap_panes (keymap, pane_name, prefix, notreal)
     }
 }
 \f
-/* Push all the panes and items of a menu decsribed by the
+/* Push all the panes and items of a menu described by the
    alist-of-alists MENU.
    This handles old-fashioned calls to x-popup-menu.  */
 
@@ -770,6 +774,7 @@ cached information about equivalent key sequences.")
   int for_click = 0;
   struct gcpro gcpro1;
 
+#ifdef HAVE_MENUS
   if (! NILP (position))
     {
       check_x ();
@@ -843,6 +848,7 @@ cached information about equivalent key sequences.")
       xpos += XINT (x);
       ypos += XINT (y);
     }
+#endif /* HAVE_MENUS */
 
   title = Qnil;
   GCPRO1 (title);
@@ -922,6 +928,7 @@ cached information about equivalent key sequences.")
       return Qnil;
     }
 
+#ifdef HAVE_MENUS
   /* Display them in a menu.  */
   BLOCK_INPUT;
 
@@ -932,11 +939,14 @@ cached information about equivalent key sequences.")
   discard_menu_items ();
 
   UNGCPRO;
+#endif /* HAVE_MENUS */
 
   if (error_name) error (error_name);
   return selection;
 }
 
+#ifdef HAVE_MENUS
+
 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
   "Pop up a dialog box and return user's selection.\n\
 POSITION specifies which frame to use.\n\
@@ -1051,7 +1061,8 @@ on the left of the dialog box and all following items on the right.\n\
 #ifdef USE_X_TOOLKIT
 
 /* Loop in Xt until the menu pulldown or dialog popup has been
-   popped down (deactivated).
+   popped down (deactivated).  This is used for x-popup-menu
+   and x-popup-dialog; it is not used for the menu bar any more.
 
    NOTE: All calls to popup_get_selection should be protected
    with BLOCK_INPUT, UNBLOCK_INPUT wrappers.  */
@@ -1085,10 +1096,15 @@ popup_get_selection (initial_event, dpyinfo, id)
       /* Handle expose events for editor frames right away.  */
       if (event.type == Expose)
        process_expose_from_menu (event);
-      /* Make sure we don't consider buttons grabbed after menu goes.  */
+      /* Make sure we don't consider buttons grabbed after menu goes.
+        And make sure to deactivate for any ButtonRelease,
+        even if XtDispatchEvent doesn't do that.  */
       else if (event.type == ButtonRelease
               && dpyinfo->display == event.xbutton.display)
-       dpyinfo->grabbed &= ~(1 << event.xbutton.button);
+        {
+          dpyinfo->grabbed &= ~(1 << event.xbutton.button);
+          popup_activated_flag = 0;
+        }
       /* If the user presses a key, deactivate the menu.
         The user is likely to do that if we get wedged.  */
       else if (event.type == KeyPress
@@ -1107,11 +1123,13 @@ popup_get_selection (initial_event, dpyinfo, id)
        }
 
       /* Queue all events not for this popup,
-        except for Expose, which we've already handled.
+        except for Expose, which we've already handled, and ButtonRelease.
         Note that the X window is associated with the frame if this
         is a menu bar popup, but not if it's a dialog box.  So we use
         x_non_menubar_window_to_frame, not x_any_window_to_frame.  */
       if (event.type != Expose
+          && !(event.type == ButtonRelease
+               && dpyinfo->display == event.xbutton.display)
          && (event.xany.display != dpyinfo->display
              || x_non_menubar_window_to_frame (dpyinfo, event.xany.window)))
        {
@@ -1149,7 +1167,7 @@ popup_get_selection (initial_event, dpyinfo, id)
    menu_bar_activate_event out of the Emacs event queue.
 
    To activate the menu bar, we use the X button-press event
-   that was saved in saved_button_event.
+   that was saved in saved_menu_event.
    That makes the toolkit do its thing.
 
    But first we recompute the menu bar contents (the whole tree).
@@ -1161,17 +1179,17 @@ popup_get_selection (initial_event, dpyinfo, id)
 x_activate_menubar (f)
      FRAME_PTR f;
 {
-  if (f->output_data.x->saved_button_event->type != ButtonPress)
+  if (!f->output_data.x->saved_menu_event->type)
     return;
 
   set_frame_menubar (f, 0, 1);
 
   BLOCK_INPUT;
-  XtDispatchEvent ((XEvent *) f->output_data.x->saved_button_event);
+  XtDispatchEvent ((XEvent *) f->output_data.x->saved_menu_event);
   UNBLOCK_INPUT;
 
   /* Ignore this if we get it a second time.  */
-  f->output_data.x->saved_button_event->type = 0;
+  f->output_data.x->saved_menu_event->type = 0;
 }
 
 /* Detect if a dialog or menu has been posted.  */
@@ -1291,6 +1309,19 @@ popup_deactivate_callback (widget, id, client_data)
   popup_activated_flag = 0;
 }
 
+/* Allocate a widget_value, blocking input.  */
+
+widget_value *
+xmalloc_widget_value ()
+{
+  widget_value *value;
+
+  BLOCK_INPUT;
+  value = malloc_widget_value ();
+  UNBLOCK_INPUT;
+
+  return value;
+}
 
 /* This recursively calls free_widget_value on the tree of widgets.
    It must free all data that was malloc'ed for these widget_values.
@@ -1356,8 +1387,12 @@ single_submenu (item_key, item_name, maps)
      But don't make a pane that is empty--ignore that map instead.  */
   for (i = 0; i < len; i++)
     {
-      if (SYMBOLP (mapvec[i]))
+      if (SYMBOLP (mapvec[i])
+         || (CONSP (mapvec[i])
+             && NILP (Fkeymapp (mapvec[i]))))
        {
+         /* Here we have a command at top level in the menu bar
+            as opposed to a submenu.  */
          top_level_items = 1;
          push_menu_pane (Qnil, Qnil);
          push_menu_item (item_name, Qt, item_key, mapvec[i], Qnil);
@@ -1371,7 +1406,7 @@ single_submenu (item_key, item_name, maps)
 
   submenu_stack
     = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
-  wv = malloc_widget_value ();
+  wv = xmalloc_widget_value ();
   wv->name = "menu";
   wv->value = 0;
   wv->enabled = 1;
@@ -1425,7 +1460,7 @@ single_submenu (item_key, item_name, maps)
             with its items as a submenu beneath it.  */
          if (strcmp (pane_string, ""))
            {
-             wv = malloc_widget_value ();
+             wv = xmalloc_widget_value ();
              if (save_wv)
                save_wv->next = wv;
              else
@@ -1452,7 +1487,7 @@ single_submenu (item_key, item_name, maps)
            = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
          def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
 
-         wv = malloc_widget_value ();
+         wv = xmalloc_widget_value ();
          if (prev_wv) 
            prev_wv->next = wv;
          else
@@ -1568,7 +1603,7 @@ set_frame_menubar (f, first_time, deep_p)
   if (! menubar_widget)
     deep_p = 1;
 
-  wv = malloc_widget_value ();
+  wv = xmalloc_widget_value ();
   wv->name = "menubar";
   wv->value = 0;
   wv->enabled = 1;
@@ -1607,7 +1642,7 @@ set_frame_menubar (f, first_time, deep_p)
         really recompute the menubar from the value.  */
       if (! NILP (Vlucid_menu_bar_dirty_flag))
        call0 (Qrecompute_lucid_menubar);
-      call1 (Vrun_hooks, Qmenu_bar_update_hook);
+      safe_run_hooks (Qmenu_bar_update_hook);
       FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
 
       items = FRAME_MENU_BAR_ITEMS (f);
@@ -1622,7 +1657,7 @@ set_frame_menubar (f, first_time, deep_p)
       menu_items = f->menu_bar_vector;
       menu_items_allocated = XVECTOR (menu_items)->size;
       init_menu_items ();
-      for (i = 0; i < XVECTOR (items)->size; i += 3)
+      for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
          Lisp_Object key, string, maps;
 
@@ -1665,7 +1700,7 @@ set_frame_menubar (f, first_time, deep_p)
       /* Now GC cannot happen during the lifetime of the widget_value,
         so it's safe to store data from a Lisp_String.  */
       wv = first_wv->contents;
-      for (i = 0; i < XVECTOR (items)->size; i += 3)
+      for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
          Lisp_Object string;
          string = XVECTOR (items)->contents[i + 1];
@@ -1685,7 +1720,7 @@ set_frame_menubar (f, first_time, deep_p)
         just the top level menu bar strings.  */
 
       items = FRAME_MENU_BAR_ITEMS (f);
-      for (i = 0; i < XVECTOR (items)->size; i += 3)
+      for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
          Lisp_Object string;
 
@@ -1693,7 +1728,7 @@ set_frame_menubar (f, first_time, deep_p)
          if (NILP (string))
            break;
 
-         wv = malloc_widget_value ();
+         wv = xmalloc_widget_value ();
          wv->name = (char *) XSTRING (string)->data;
          wv->value = 0;
          wv->enabled = 1;
@@ -1765,7 +1800,7 @@ set_frame_menubar (f, first_time, deep_p)
   UNBLOCK_INPUT;
 }
 
-/* Called from Fx_create_frame to create the inital menubar of a frame
+/* Called from Fx_create_frame to create the initial menubar of a frame
    before it is mapped, so that the window is mapped with the menubar already
    there instead of us tacking it on later and thrashing the window after it
    is visible.  */
@@ -1881,7 +1916,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 
   /* Create a tree of widget_value objects
      representing the panes and their items.  */
-  wv = malloc_widget_value ();
+  wv = xmalloc_widget_value ();
   wv->name = "menu";
   wv->value = 0;
   wv->enabled = 1;
@@ -1933,7 +1968,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
             with its items as a submenu beneath it.  */
          if (!keymaps && strcmp (pane_string, ""))
            {
-             wv = malloc_widget_value ();
+             wv = xmalloc_widget_value ();
              if (save_wv)
                save_wv->next = wv;
              else
@@ -1964,7 +1999,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
            = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
          def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
 
-         wv = malloc_widget_value ();
+         wv = xmalloc_widget_value ();
          if (prev_wv) 
            prev_wv->next = wv;
          else 
@@ -1988,9 +2023,9 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   /* Deal with the title, if it is non-nil.  */
   if (!NILP (title))
     {
-      widget_value *wv_title = malloc_widget_value ();
-      widget_value *wv_sep1 = malloc_widget_value ();
-      widget_value *wv_sep2 = malloc_widget_value ();
+      widget_value *wv_title = xmalloc_widget_value ();
+      widget_value *wv_sep1 = xmalloc_widget_value ();
+      widget_value *wv_sep2 = xmalloc_widget_value ();
 
       wv_sep2->name = "--";
       wv_sep2->next = first_wv->contents;
@@ -2193,7 +2228,7 @@ xdialog_show (f, keymaps, title, error)
     prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
     pane_string = (NILP (pane_name)
                   ? "" : (char *) XSTRING (pane_name)->data);  
-    prev_wv = malloc_widget_value ();
+    prev_wv = xmalloc_widget_value ();
     prev_wv->value = pane_string;
     if (keymaps && !NILP (prefix))
       prev_wv->name++;
@@ -2234,7 +2269,7 @@ xdialog_show (f, keymaps, title, error)
            return Qnil;
          }
 
-       wv = malloc_widget_value ();
+       wv = xmalloc_widget_value ();
        prev_wv->next = wv;
        wv->name = (char *) button_names[nb_buttons];
        if (!NILP (descrip))
@@ -2256,7 +2291,7 @@ xdialog_show (f, keymaps, title, error)
     if (! boundary_seen)
       left_count = nb_buttons - nb_buttons / 2;
 
-    wv = malloc_widget_value ();
+    wv = xmalloc_widget_value ();
     wv->name = dialog_name;
 
     /* Dialog boxes use a really stupid name encoding
@@ -2616,12 +2651,17 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 }
 
 #endif /* not USE_X_TOOLKIT */
+
+#endif /* HAVE_MENUS */
 \f
 syms_of_xmenu ()
 {
   staticpro (&menu_items);
   menu_items = Qnil;
 
+  Qmenu_alias = intern ("menu-alias");
+  staticpro (&Qmenu_alias);
+
   Qdebug_on_next_call = intern ("debug-on-next-call");
   staticpro (&Qdebug_on_next_call);
 
@@ -2631,5 +2671,7 @@ syms_of_xmenu ()
 #endif
 
   defsubr (&Sx_popup_menu);
+#ifdef HAVE_MENUS
   defsubr (&Sx_popup_dialog);
+#endif
 }