(xmenu_show): Undo part of March 11 change:
[bpt/emacs.git] / src / xmenu.c
index 1d3bf19..0d616b6 100644 (file)
@@ -608,7 +608,7 @@ list_of_items (pane)
     {
       item = Fcar (tail);
       if (STRINGP (item))
-       push_menu_item (item, Qnil, Qnil);
+       push_menu_item (item, Qnil, Qnil, Qnil);
       else
        {
          CHECK_CONS (item, 0);
@@ -619,7 +619,7 @@ list_of_items (pane)
     }
 }
 \f
-DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 1, 2, 0,
+DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
   "Pop up a deck-of-cards menu and return user's selection.\n\
 POSITION is a position specification.  This is either a mouse button event\n\
 or a list ((XOFFSET YOFFSET) WINDOW)\n\
@@ -672,13 +672,19 @@ cached information about equivalent key sequences.")
       if (EQ (position, Qt))
        {
          /* Use the mouse's current position.  */
-         FRAME_PTR new_f;
+         FRAME_PTR new_f = 0;
          Lisp_Object bar_window;
          int part;
          unsigned long time;
 
-         (*mouse_position_hook) (&new_f, &bar_window, &part, &x, &y, &time);
-         XSET (window, Lisp_Frame, new_f);
+         if (new_f != 0)
+           XSET (window, Lisp_Frame, new_f);
+         else
+           {
+             window = selected_window;
+             XFASTINT (x) = 0;
+             XFASTINT (y) = 0;
+           }
        }
       else
        {
@@ -828,134 +834,106 @@ cached information about equivalent key sequences.")
   return selection;
 }
 
-DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 1, 2, 0,
+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 is a position specification.  This is either a mouse button event\n\
-or a list ((XOFFSET YOFFSET) WINDOW)\n\
-where XOFFSET and YOFFSET are positions in characters from the top left\n\
-corner of WINDOW's frame.  (WINDOW may be a frame object instead of a window.)\n\
-This controls the position of the center of the first line\n\
-in the first pane of the menu, not the top left of the menu as a whole.\n\
-If POSITION is t, it means to use the current mouse position.\n\
-\n\
-MENU is a specifier for a menu.  For the simplest case, MENU is a keymap.\n\
-The menu items come from key bindings that have a menu string as well as\n\
-a definition; actually, the \"definition\" in such a key binding looks like\n\
-\(STRING . REAL-DEFINITION).  To give the menu a title, put a string into\n\
-the keymap as a top-level element.\n\n\
-You can also use a list of keymaps as MENU.\n\
-  Then each keymap makes a separate pane.\n\
-When MENU is a keymap or a list of keymaps, the return value\n\
-is a list of events.\n\n\
-Alternatively, you can specify a menu of multiple panes\n\
-  with a list of the form (TITLE PANE1 PANE2...),\n\
-where each pane is a list of form (TITLE ITEM1 ITEM2...).\n\
-Each ITEM is normally a cons cell (STRING . VALUE);\n\
-but a string can appear as an item--that makes a nonselectable line\n\
-in the menu.\n\
-With this form of menu, the return value is VALUE from the chosen item.\n\
+POSITION specifies which frame to use.\n\
+This is normally a mouse button event or a window or frame.\n\
+If POSITION is t, it means to use the frame the mouse is on.\n\
+The dialog box appears in the middle of the specified frame.\n\
 \n\
-If POSITION is nil, don't display the menu at all, just precalculate the\n\
-cached information about equivalent key sequences.")
-  (position, menu)
-     Lisp_Object position, menu;
+CONTENTS specifies the alternatives to display in the dialog box.\n\
+It is a list of the form (TITLE ITEM1 ITEM2...).\n\
+Each ITEM is a cons cell (STRING . VALUE).\n\
+The return value is VALUE from the chosen item.")
+  (position, contents)
+     Lisp_Object position, contents;
 {
-#ifndef USE_X_TOOLKIT
-  return Fx_popup_menu (position, menu);
-#else
-  int number_of_panes, panes;
-  Lisp_Object keymap, tem;
-  int xpos, ypos;
-  Lisp_Object title;
-  char *error_name;
-  Lisp_Object selection;
-  int i, j;
   FRAME_PTR f;
-  Lisp_Object x, y, window;
-  int keymaps = 0;
-  int menubarp = 0;
-  struct gcpro gcpro1;
+  Lisp_Object window;
 
   check_x ();
 
-  if (! NILP (position))
+  /* Decode the first argument: find the window or frame to use.  */
+  if (EQ (position, Qt))
     {
-      /* Decode the first argument: find the window and the coordinates.  */
-      if (EQ (position, Qt))
-       {
-         /* Use the mouse's current position.  */
-         FRAME_PTR new_f;
-         Lisp_Object bar_window;
-         int part;
-         unsigned long time;
-
-         (*mouse_position_hook) (&new_f, &bar_window, &part, &x, &y, &time);
-         XSET (window, Lisp_Frame, new_f);
-       }
-
-      CHECK_NUMBER (x, 0);
-      CHECK_NUMBER (y, 0);
-
-      /* Decode where to put the menu.  */
-
-      if (XTYPE (window) == Lisp_Frame)
-       {
-         f = XFRAME (window);
+      /* Use the mouse's current position.  */
+      FRAME_PTR new_f = 0;
+      Lisp_Object bar_window;
+      int part;
+      unsigned long time;
+      Lisp_Object x, y;
 
-         xpos = 0;
-         ypos = 0;
-       }
-      else if (XTYPE (window) == Lisp_Window)
-       {
-         CHECK_LIVE_WINDOW (window, 0);
-         f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
+      (*mouse_position_hook) (&new_f, &bar_window, &part, &x, &y, &time);
 
-         xpos = (FONT_WIDTH (f->display.x->font) * XWINDOW (window)->left);
-         ypos = (FONT_HEIGHT (f->display.x->font) * XWINDOW (window)->top);
-       }
+      if (new_f != 0)
+       XSET (window, Lisp_Frame, new_f);
       else
-       /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
-          but I don't want to make one now.  */
-       CHECK_WINDOW (window, 0);
-
-      xpos += XINT (x);
-      ypos += XINT (y);
+       window = selected_window;
     }
-
-  title = Qnil;
-  GCPRO1 (title);
-
-  /* Decode the dialog items from what was specified.  */
+  else if (CONSP (position))
     {
-      /* We were given an old-fashioned menu.  */
-      title = Fcar (menu);
-      CHECK_STRING (title, 1);
+      Lisp_Object tem;
+      tem = Fcar (position);
+      if (XTYPE (tem) == Lisp_Cons)
+       window = Fcar (Fcdr (position));
+      else
+       {
+         tem = Fcar (Fcdr (position));  /* EVENT_START (position) */
+         window = Fcar (tem);       /* POSN_WINDOW (tem) */
+       }
+    }
+  else if (WINDOWP (position) || FRAMEP (position))
+    window = position;
 
-      list_of_panes (Fcdr (menu));
+  /* Decode where to put the menu.  */
 
-      keymaps = 0;
-    }
-  
-  if (NILP (position))
+  if (XTYPE (window) == Lisp_Frame)
+    f = XFRAME (window);
+  else if (XTYPE (window) == Lisp_Window)
     {
-      discard_menu_items ();
-      UNGCPRO;
-      return Qnil;
+      CHECK_LIVE_WINDOW (window, 0);
+      f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
     }
+  else
+    /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
+       but I don't want to make one now.  */
+    CHECK_WINDOW (window, 0);
 
-  /* Display them in a dialog box.  */
-  BLOCK_INPUT;
+#ifndef USE_X_TOOLKIT
+  /* Display a menu with these alternatives
+     in the middle of frame F.  */
+  {
+    Lisp_Object x, y, frame, newpos;
+    XSET (frame, Lisp_Frame, f);
+    XSET (x, Lisp_Int, x_pixel_width (f) / 2);
+    XSET (y, Lisp_Int, x_pixel_height (f) / 2);
+    newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
+
+    return Fx_popup_menu (newpos,
+                         Fcons (Fcar (contents), Fcons (contents, Qnil)));
+  }
+#else
+  {
+    Lisp_Object title;
+    char *error_name;
+    Lisp_Object selection;
 
-  selection = xdialog_show (f, xpos, ypos, menubarp,
-                           keymaps, title, &error_name);
-  UNBLOCK_INPUT;
+    /* Decode the dialog items from what was specified.  */
+    title = Fcar (contents);
+    CHECK_STRING (title, 1);
 
-  discard_menu_items ();
+    list_of_panes (Fcons (contents, Qnil));
 
-  UNGCPRO;
+    /* Display them in a dialog box.  */
+    BLOCK_INPUT;
+    selection = xdialog_show (f, 0, 0, title, &error_name);
+    UNBLOCK_INPUT;
 
-  if (error_name) error (error_name);
-  return selection;
+    discard_menu_items ();
+
+    if (error_name) error (error_name);
+    return selection;
+  }
 #endif
 }
 \f
@@ -1115,7 +1093,7 @@ free_menubar_widget_value_tree (wv)
 extern void EmacsFrameSetCharSize ();
 
 static void
-update_one_frame_psheets (f)
+update_frame_menubar (f)
      FRAME_PTR f;
 {
   struct x_display *x = f->display.x;
@@ -1167,8 +1145,9 @@ update_one_frame_psheets (f)
 }
 
 void
-set_frame_menubar (f)
+set_frame_menubar (f, first_time)
      FRAME_PTR f;
+     int first_time;
 {
   Widget menubar_widget = f->display.x->menubar_widget;
   int id = (int) f;
@@ -1184,7 +1163,8 @@ set_frame_menubar (f)
   wv->enabled = 1;
   save_wv = first_wv = wv;
 
-  items = FRAME_MENU_BAR_ITEMS (f);
+  if (NILP (items = FRAME_MENU_BAR_ITEMS (f)))
+    items = FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
 
   for (i = 0; i < XVECTOR (items)->size; i += 3)
     {
@@ -1224,7 +1204,9 @@ set_frame_menubar (f)
   
   free_menubar_widget_value_tree (first_wv);
 
-  update_one_frame_psheets (f);
+  /* Don't update the menubar the first time it is created via x_window.  */
+  if (!first_time)
+    update_frame_menubar (f);
 
   UNBLOCK_INPUT;
 }
@@ -1246,6 +1228,16 @@ free_frame_menubar (f)
       UNBLOCK_INPUT;
     }
 }
+/* Called from Fx_create_frame to create the inital 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.  */
+void
+initialize_frame_menubar (f)
+     FRAME_PTR f;
+{
+  set_frame_menubar (f, 1);
+}
 \f
 /* Nonzero if position X, Y relative to inside of frame F
    is in some other menu bar item.  */
@@ -1639,10 +1631,11 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
       dispatch_dummy_expose (f->display.x->menubar_widget, x, y);
     }
 
-#if 0 /* No need to do that. The menu has disappeared.  */
+  /* fp turned off the following statement and wrote a comment
+     that it is unnecessary--that the menu has already disappeared.
+     I observer that is not so. -- rms.  */
   /* Make sure the menu disappears.  */
   lw_destroy_all_widgets (menu_id); 
-#endif
 
   /* Unread any events that we got but did not handle.  */
   while (queue != NULL) 
@@ -1713,10 +1706,8 @@ static char * button_names [] = {
   "button6", "button7", "button8", "button9", "button10" };
 
 static Lisp_Object
-xdialog_show (f, x, y, menubarp, keymaps, title, error)
+xdialog_show (f, menubarp, keymaps, title, error)
      FRAME_PTR f;
-     int x;
-     int y;
      int menubarp;
      int keymaps;
      Lisp_Object title;
@@ -1726,6 +1717,7 @@ xdialog_show (f, x, y, menubarp, keymaps, title, error)
   int dialog_id;
   Widget menu;
   XlwMenuWidget menubar = (XlwMenuWidget) f->display.x->menubar_widget;
+  char dialog_name[6];
 
   /* This is the menu bar item (if any) that led to this menu.  */
   widget_value *menubar_item = 0;
@@ -1745,6 +1737,12 @@ xdialog_show (f, x, y, menubarp, keymaps, title, error)
 
   *error = NULL;
 
+  if (menu_items_n_panes > 1)
+    {
+      *error = "Multiple panes in dialog box";
+      return Qnil;
+    }
+
   /* Create a tree of widget_value objects
      representing the text label and buttons.  */
   {
@@ -1774,9 +1772,22 @@ xdialog_show (f, x, y, menubarp, keymaps, title, error)
        descrip
          = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
        
+       if (NILP (item_name))
+         {
+           free_menubar_widget_value_tree (first_wv);
+           *error = "Submenu in dialog items";
+           return Qnil;
+         }
+       if (nb_buttons >= 10)
+         {
+           free_menubar_widget_value_tree (first_wv);
+           *error = "Too many dialog items";
+           return Qnil;
+         }
+
        wv = malloc_widget_value ();
        prev_wv->next = wv;
-       wv->name = (char *) button_names [nb_buttons];
+       wv->name = (char *) button_names[nb_buttons];
        if (!NILP (descrip))
          wv->key = XSTRING (descrip)->data;
        wv->value = XSTRING (item_name)->data;
@@ -1789,7 +1800,18 @@ xdialog_show (f, x, y, menubarp, keymaps, title, error)
       }
 
     wv = malloc_widget_value ();
-    wv->name = "Q2BR1";
+    wv->name = dialog_name;
+
+    /* Dialog boxes use a really stupid name encoding
+       which specifies how many buttons to use
+       and how many buttons are on the right.
+       The Q means something also.  */
+    dialog_name[0] = 'Q';
+    dialog_name[1] = '0' + nb_buttons;
+    dialog_name[2] = 'B';
+    dialog_name[3] = 'R';
+    dialog_name[4] = '0' + nb_buttons / 2;
+    dialog_name[5] = 0;
     wv->contents = first_wv;
     first_wv = wv;
 
@@ -1800,15 +1822,16 @@ xdialog_show (f, x, y, menubarp, keymaps, title, error)
   menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
                           f->display.x->widget, 1, 0,
                           dialog_selection_callback, 0);
+#if 0 /* This causes crashes, and seems to be redundant -- rms.  */
   lw_modify_all_widgets (dialog_id, first_wv, True);
-  lw_modify_all_widgets (dialog_id, first_wv->contents, True);
+#endif
+  lw_modify_all_widgets (dialog_id, first_wv->contents->next, True);
   /* Free the widget_value objects we used to specify the contents.  */
   free_menubar_widget_value_tree (first_wv);
 
   /* No selection has been chosen yet.  */
   menu_item_selection = 0;
 
-
   /* Display the menu.  */
   lw_pop_up_all_widgets (dialog_id);
 
@@ -2033,7 +2056,8 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
     }
   if (ulx < 0) x -= ulx;
   if (uly < 0) y -= uly;
-    
+
+  XMenuSetAEQ (menu, TRUE);
   XMenuSetFreeze (menu, TRUE);
   pane = selidx = 0;