]> code.delx.au - gnu-emacs/blobdiff - src/xmenu.c
Mention setsid after vfork.
[gnu-emacs] / src / xmenu.c
index 6de1dcb2bd15c40877994c6eafccd834ad0c4df3..d240355ef2f274c626a772f4238f57d05d8248be 100644 (file)
@@ -1,12 +1,12 @@
 /* X Communication module for terminals which understand the X protocol.
    Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 2003,
-                 2004, 2005, 2006 Free Software Foundation, Inc.
+                 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -97,10 +97,10 @@ Boston, MA 02110-1301, USA.  */
 #define FALSE 0
 #endif /* no TRUE */
 
-Lisp_Object Vmenu_updating_frame;
-
 Lisp_Object Qdebug_on_next_call;
 
+extern Lisp_Object Vmenu_updating_frame;
+
 extern Lisp_Object Qmenu_bar;
 
 extern Lisp_Object QCtoggle, QCradio;
@@ -327,6 +327,7 @@ restore_menu_items (saved)
   menu_items_n_panes = XINT (XCAR (saved));
   saved = XCDR (saved);  
   menu_items_submenu_depth = XINT (XCAR (saved));
+  return Qnil;
 }
 
 /* Push the whole state of menu_items processing onto the specpdl.
@@ -821,7 +822,7 @@ no quit occurs and `x-popup-menu' returns nil.  */)
   int xpos = 0, ypos = 0;
   Lisp_Object title;
   char *error_name = NULL;
-  Lisp_Object selection;
+  Lisp_Object selection = Qnil;
   FRAME_PTR f = NULL;
   Lisp_Object x, y, window;
   int keymaps = 0;
@@ -1181,6 +1182,10 @@ x_menu_set_in_use (in_use)
 {
   menu_items_inuse = in_use ? Qt : Qnil;
   popup_activated_flag = in_use;
+#ifdef USE_X_TOOLKIT
+  if (popup_activated_flag)
+    x_activate_timeout_atimer ();
+#endif
 }
 
 /* Wait for an X event to arrive or for a timer to expire.  */
@@ -1300,9 +1305,124 @@ popup_get_selection (initial_event, dpyinfo, id, do_timers)
     }
 }
 
+DEFUN ("menu-bar-open", Fmenu_bar_open, Smenu_bar_open, 0, 1, "i",
+       doc: /* Start key navigation of the menu bar in FRAME.
+This initially opens the first menu bar item and you can then navigate with the
+arrow keys, select a menu entry with the return key or cancel with the
+escape key.  If FRAME has no menu bar this function does nothing.
+
+If FRAME is nil or not given, use the selected frame.  */)
+     (frame)
+     Lisp_Object frame;
+{
+  XEvent ev;
+  FRAME_PTR f = check_x_frame (frame);
+  Widget menubar;
+  BLOCK_INPUT;
+
+  if (FRAME_EXTERNAL_MENU_BAR (f))
+    set_frame_menubar (f, 0, 1);
+
+  menubar = FRAME_X_OUTPUT (f)->menubar_widget;
+  if (menubar)
+    {
+      Window child;
+      int error_p = 0;
+
+      x_catch_errors (FRAME_X_DISPLAY (f));
+      memset (&ev, 0, sizeof ev);
+      ev.xbutton.display = FRAME_X_DISPLAY (f);
+      ev.xbutton.window = XtWindow (menubar);
+      ev.xbutton.root = FRAME_X_DISPLAY_INFO (f)->root_window;
+      ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
+      ev.xbutton.button = Button1;
+      ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
+      ev.xbutton.same_screen = True;
+
+#ifdef USE_MOTIF
+      {
+        Arg al[2];
+        WidgetList list;
+        Cardinal nr;
+        XtSetArg (al[0], XtNchildren, &list);
+        XtSetArg (al[1], XtNnumChildren, &nr);
+        XtGetValues (menubar, al, 2);
+        ev.xbutton.window = XtWindow (list[0]);
+      }
+#endif
+
+      XTranslateCoordinates (FRAME_X_DISPLAY (f),
+                             /* From-window, to-window.  */
+                             ev.xbutton.window, ev.xbutton.root,
+
+                             /* From-position, to-position.  */
+                             ev.xbutton.x, ev.xbutton.y,
+                             &ev.xbutton.x_root, &ev.xbutton.y_root,
+
+                             /* Child of win.  */
+                             &child);
+      error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
+      x_uncatch_errors ();
+
+      if (! error_p)
+        {
+          ev.type = ButtonPress;
+          ev.xbutton.state = 0;
+
+          XtDispatchEvent (&ev);
+          ev.xbutton.type = ButtonRelease;
+          ev.xbutton.state = Button1Mask;
+          XtDispatchEvent (&ev);
+        }
+    }
+
+  UNBLOCK_INPUT;
+
+  return Qnil;
+}
 #endif /* USE_X_TOOLKIT */
 
+
 #ifdef USE_GTK
+DEFUN ("menu-bar-open", Fmenu_bar_open, Smenu_bar_open, 0, 1, "i",
+       doc: /* Start key navigation of the menu bar in FRAME.
+This initially opens the first menu bar item and you can then navigate with the
+arrow keys, select a menu entry with the return key or cancel with the
+escape key.  If FRAME has no menu bar this function does nothing.
+
+If FRAME is nil or not given, use the selected frame.  */)
+     (frame)
+     Lisp_Object frame;
+{
+  GtkWidget *menubar;
+  FRAME_PTR f;
+
+  /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
+     BLOCK_INPUT.  */
+
+  BLOCK_INPUT;
+  f = check_x_frame (frame);
+
+  if (FRAME_EXTERNAL_MENU_BAR (f))
+    set_frame_menubar (f, 0, 1);
+
+  menubar = FRAME_X_OUTPUT (f)->menubar_widget;
+  if (menubar)
+    {
+      /* Activate the first menu.  */
+      GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
+
+      gtk_menu_shell_select_item (GTK_MENU_SHELL (menubar),
+                                  GTK_WIDGET (children->data));
+
+      popup_activated_flag = 1;
+      g_list_free (children);
+    }
+  UNBLOCK_INPUT;
+
+  return Qnil;
+}
+
 /* Loop util popup_activated_flag is set to zero in a callback.
    Used for popup menus and dialogs. */
 
@@ -1368,14 +1488,6 @@ x_activate_menubar (f)
   f->output_data.x->saved_menu_event->type = 0;
 }
 
-/* Detect if a dialog or menu has been posted.  */
-
-int
-popup_activated ()
-{
-  return popup_activated_flag;
-}
-
 /* This callback is invoked when the user selects a menubar cascade
    pushbutton, but before the pulldown menu is posted.  */
 
@@ -1387,6 +1499,9 @@ popup_activate_callback (widget, id, client_data)
      XtPointer client_data;
 {
   popup_activated_flag = 1;
+#ifdef USE_X_TOOLKIT
+  x_activate_timeout_atimer ();
+#endif
 }
 #endif
 
@@ -2180,21 +2295,27 @@ set_frame_menubar (f, first_time, deep_p)
       /* If there has been no change in the Lisp-level contents
         of the menu bar, skip redisplaying it.  Just exit.  */
 
+      /* 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])))
          break;
       if (i == menu_items_used && i == previous_menu_items_used && i != 0)
        {
+         /* The menu items have not changed.  Don't bother updating
+            the menus in any form, since it would be a no-op.  */
          free_menubar_widget_value_tree (first_wv);
          discard_menu_items ();
          unbind_to (specpdl_count, Qnil);
          return;
        }
 
+      /* The menu items are different, so store them in the frame.  */
       f->menu_bar_vector = menu_items;
       f->menu_bar_items_used = menu_items_used;
 
+      /* This calls restore_menu_items to restore menu_items, etc.,
+        as they were outside.  */
       unbind_to (specpdl_count, Qnil);
 
       /* Now GC cannot happen during the lifetime of the widget_value,
@@ -2681,6 +2802,7 @@ create_and_show_popup_menu (f, first_wv, x, y, for_click)
   /* Display the menu.  */
   lw_popup_menu (menu, (XEvent *) &dummy);
   popup_activated_flag = 1;
+  x_activate_timeout_atimer ();
 
   {
     int fact = 4 * sizeof (LWLIB_ID);
@@ -3058,6 +3180,7 @@ create_and_show_dialog (f, first_wv)
   /* Display the dialog box.  */
   lw_pop_up_all_widgets (dialog_id);
   popup_activated_flag = 1;
+  x_activate_timeout_atimer ();
 
   /* Process events that apply to the dialog box.
      Also handle timers.  */
@@ -3210,6 +3333,14 @@ xdialog_show (f, keymaps, title, header, error_name)
   /* No selection has been chosen yet.  */
   menu_item_selection = 0;
 
+  /* 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
+     is not done when a dialog is shown.  If redisplay could be done in the
+     X event loop (i.e. the X event loop does not run in a signal handler)
+     this would not be needed.  */
+  Fredisplay (Qt);
+
   /* Actually create and show the dialog.  */
   create_and_show_dialog (f, first_wv);
 
@@ -3630,6 +3761,27 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 #endif /* not USE_X_TOOLKIT */
 
 #endif /* HAVE_MENUS */
+
+/* Detect if a dialog or menu has been posted.  */
+
+int
+popup_activated ()
+{
+  return popup_activated_flag;
+}
+
+/* The following is used by delayed window autoselection.  */
+
+DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
+       doc: /* Return t if a menu or popup dialog is active.  */)
+     ()
+{
+#ifdef HAVE_MENUS
+  return (popup_activated ()) ? Qt : Qnil;
+#else
+  return Qnil;
+#endif /* HAVE_MENUS */
+}
 \f
 void
 syms_of_xmenu ()
@@ -3641,17 +3793,19 @@ syms_of_xmenu ()
   Qdebug_on_next_call = intern ("debug-on-next-call");
   staticpro (&Qdebug_on_next_call);
 
-  DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
-              doc: /* Frame for which we are updating a menu.
-The enable predicate for a menu command should check this variable.  */);
-  Vmenu_updating_frame = Qnil;
-
 #ifdef USE_X_TOOLKIT
   widget_id_tick = (1<<16);
   next_menubar_widget_id = 1;
 #endif
 
   defsubr (&Sx_popup_menu);
+  defsubr (&Smenu_or_popup_active_p);
+
+#if defined (USE_GTK) || defined (USE_X_TOOLKIT)
+  defsubr (&Smenu_bar_open);
+  Ffset (intern ("accelerate-menu"), intern (Smenu_bar_open.symbol_name));
+#endif
+
 #ifdef HAVE_MENUS
   defsubr (&Sx_popup_dialog);
 #endif