/* X Communication module for terminals which understand the X protocol.
- Copyright (C) 1986, 1988, 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1988, 1993, 1994, 1996 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#define FALSE 0
#endif /* no TRUE */
+Lisp_Object Vmenu_updating_frame;
+
Lisp_Object Qdebug_on_next_call;
Lisp_Object Qmenu_alias;
static int popup_activated_flag;
static int next_menubar_widget_id;
+
+/* This is set nonzero after the user activates the menu bar, and set
+ to zero again after the menu bars are redisplayed by prepare_menu_bar.
+ While it is nonzero, all calls to set_frame_menubar go deep.
+
+ I don't understand why this is needed, but it does seem to be
+ needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
+
+int pending_menu_activation;
\f
#ifdef USE_X_TOOLKIT
But don't make a pane that is empty--ignore that map instead.
P is the number of panes we have made so far. */
for (mapno = 0; mapno < nmaps; mapno++)
- single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal);
+ single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal, 10);
finish_menu_items ();
}
The other arguments are passed along
or point to local variables of the previous function.
If NOTREAL is nonzero,
- don't bother really computing whether an item is enabled. */
+ don't bother really computing whether an item is enabled.
+
+ If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
static void
-single_keymap_panes (keymap, pane_name, prefix, notreal)
+single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
Lisp_Object keymap;
Lisp_Object pane_name;
Lisp_Object prefix;
int notreal;
+ int maxdepth;
{
Lisp_Object pending_maps;
Lisp_Object tail, item, item1, item_string, table;
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+ if (maxdepth <= 0)
+ return;
+
pending_maps = Qnil;
push_menu_pane (pane_name, prefix);
{
push_submenu_start ();
single_keymap_panes (submap, Qnil,
- XCONS (item)->car, notreal);
+ XCONS (item)->car, notreal,
+ maxdepth - 1);
push_submenu_end ();
}
#endif
{
push_submenu_start ();
single_keymap_panes (submap, Qnil,
- character, notreal);
+ character, notreal,
+ maxdepth - 1);
push_submenu_end ();
}
#endif
/* We no longer discard the @ from the beginning of the string here.
Instead, we do this in xmenu_show. */
single_keymap_panes (Fcar (elt), string,
- XCONS (eltcdr)->cdr, notreal);
+ XCONS (eltcdr)->cdr, notreal, maxdepth - 1);
pending_maps = Fcdr (pending_maps);
}
}
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\
+If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.\n\
+Otherwise, REAL-DEFINITION should be a valid key binding definition.\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\
+\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\
CHECK_LIVE_WINDOW (window, 0);
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
- xpos = (FONT_WIDTH (f->output_data.x->font) * XWINDOW (window)->left);
- ypos = (f->output_data.x->line_height * XWINDOW (window)->top);
+ xpos = (FONT_WIDTH (f->output_data.x->font)
+ * XFASTINT (XWINDOW (window)->left));
+ ypos = (f->output_data.x->line_height
+ * XFASTINT (XWINDOW (window)->top));
}
else
/* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
xpos += XINT (x);
ypos += XINT (y);
+
+ XSETFRAME (Vmenu_updating_frame, f);
}
+ Vmenu_updating_frame = Qnil;
#endif /* HAVE_MENUS */
title = Qnil;
/* Search for a string appearing directly as an element of the keymap.
That string is the title of the menu. */
prompt = map_prompt (keymap);
+ if (NILP (title) && !NILP (prompt))
+ title = prompt;
/* Make that be the pane title of the first pane. */
if (!NILP (prompt) && menu_items_n_panes >= 0)
}
else if (WINDOWP (position) || FRAMEP (position))
window = position;
+ else
+ window = Qnil;
/* Decode where to put the menu. */
{
dpyinfo->grabbed &= ~(1 << event.xbutton.button);
popup_activated_flag = 0;
+#ifdef USE_MOTIF /* Pretending that the event came from a
+ Btn1Down seems the only way to convince Motif to
+ activate its callbacks; setting the XmNmenuPost
+ isn't working. --marcus@sysc.pdx.edu. */
+ event.xbutton.button = 1;
+#endif
}
/* If the user presses a key, deactivate the menu.
The user is likely to do that if we get wedged. */
return;
set_frame_menubar (f, 0, 1);
-
BLOCK_INPUT;
XtDispatchEvent ((XEvent *) f->output_data.x->saved_menu_event);
UNBLOCK_INPUT;
-
+#ifdef USE_MOTIF
+ if (f->output_data.x->saved_menu_event->type == ButtonRelease)
+ pending_menu_activation = 1;
+#endif
+
/* Ignore this if we get it a second time. */
f->output_data.x->saved_menu_event->type = 0;
}
push_menu_item (item_name, Qt, item_key, mapvec[i], Qnil);
}
else
- single_keymap_panes (mapvec[i], item_name, item_key, 0);
+ single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
}
/* Create a tree of widget_value objects
int i;
LWLIB_ID id;
+ XSETFRAME (Vmenu_updating_frame, f);
+
if (f->output_data.x->id == 0)
f->output_data.x->id = next_menubar_widget_id++;
id = f->output_data.x->id;
if (! menubar_widget)
deep_p = 1;
+ else if (pending_menu_activation && !deep_p)
+ deep_p = 1;
+ /* Make the first call for any given frame always go deep. */
+ else if (!f->output_data.x->saved_menu_event && !deep_p)
+ {
+ deep_p = 1;
+ f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
+ f->output_data.x->saved_menu_event->type = 0;
+ }
wv = xmalloc_widget_value ();
wv->name = "menubar";
= (Lisp_Object *) alloca (previous_menu_items_used
* sizeof (Lisp_Object));
+ /* If we are making a new widget, its contents are empty,
+ do always reinitialize them. */
+ if (! menubar_widget)
+ previous_menu_items_used = 0;
+
buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
specbind (Qinhibit_quit, Qt);
/* Don't let the debugger step into this code
because it is not reentrant. */
specbind (Qdebug_on_next_call, Qnil);
- record_unwind_protect (Fstore_match_data, Fmatch_data ());
+ record_unwind_protect (Fstore_match_data, Fmatch_data (Qnil, Qnil));
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
for (i = 0; i < previous_menu_items_used; i++)
if (menu_items_used == i
- || (previous_items[i] != XVECTOR (menu_items)->contents[i]))
+ || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
break;
if (i == menu_items_used && i == previous_menu_items_used && i != 0)
{
wv->name = (char *) XSTRING (string)->data;
wv->value = 0;
wv->enabled = 1;
+ /* This prevents lwlib from assuming this
+ menu item is really supposed to be empty. */
+ /* The EMACS_INT cast avoids a warning.
+ This value just has to be different from small integers. */
+ wv->call_data = (void *) (EMACS_INT) (-1);
if (prev_wv)
prev_wv->next = wv;
+ f->output_data.x->menubar_widget->core.border_width)
: 0);
+#if 0 /* Experimentally, we now get the right results
+ for -geometry -0-0 without this. 24 Aug 96, rms. */
#ifdef USE_LUCID
if (FRAME_EXTERNAL_MENU_BAR (f))
{
menubar_size += ibw;
}
#endif /* USE_LUCID */
+#endif /* 0 */
f->output_data.x->menubar_height = menubar_size;
}
int id;
menubar_widget = f->output_data.x->menubar_widget;
+
+ f->output_data.x->menubar_height = 0;
if (menubar_widget)
{
/* F is the frame the menu is for.
X and Y are the frame-relative specified position,
relative to the inside upper left corner of the frame F.
- FOR_CLICK if this menu was invoked for a mouse click.
+ FOR_CLICK is nonzero if this menu was invoked for a mouse click.
KEYMAPS is 1 if this menu was specified with keymaps;
in that case, we return a list containing the chosen item's value
and perhaps also the pane's prefix.
dummy.send_event = 0;
dummy.display = FRAME_X_DISPLAY (f);
dummy.time = CurrentTime;
- dummy.button = 0;
dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
dummy.window = dummy.root;
dummy.subwindow = dummy.root;
dummy.y_root = y;
dummy.x = x;
dummy.y = y;
+ dummy.state = (FRAME_X_DISPLAY_INFO (f)->grabbed >> 1) * Button1Mask;
+ dummy.button = 0;
+ for (i = 0; i < 5; i++)
+ if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
+ dummy.button = i;
/* Don't allow any geometry request from the user. */
XtSetArg (av[ac], XtNgeometry, 0); ac++;
i++;
continue;
}
- if (nb_buttons >= 10)
+ if (nb_buttons >= 9)
{
free_menubar_widget_value_tree (first_wv);
*error = "Too many dialog items";
Qdebug_on_next_call = intern ("debug-on-next-call");
staticpro (&Qdebug_on_next_call);
+ DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
+ "Frame for which we are updating a menu.\n\
+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;