extern XtAppContext Xt_app_con;
static Lisp_Object xdialog_show ();
-void popup_get_selection ();
+static void popup_get_selection ();
/* Define HAVE_BOXES if menus can handle radio and toggle buttons. */
int, int, int *));
static void list_of_panes P_ ((Lisp_Object));
static void list_of_items P_ ((Lisp_Object));
+
+extern EMACS_TIME timer_check P_ ((int));
\f
/* This holds a Lisp vector that holds the results of decoding
the keymaps or alist-of-alists that specify a menu.
static Lisp_Object menu_items;
+/* If non-nil, means that the global vars defined here are already in use.
+ Used to detect cases where we try to re-enter this non-reentrant code. */
+static Lisp_Object menu_items_inuse;
+
/* Number of slots currently allocated in menu_items. */
static int menu_items_allocated;
menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
}
+ if (!NILP (menu_items_inuse))
+ error ("Trying to use a menu from within a menu-entry");
+ menu_items_inuse = Qt;
menu_items_used = 0;
menu_items_n_panes = 0;
menu_items_submenu_depth = 0;
{
}
+static Lisp_Object
+unuse_menu_items (dummy)
+ int dummy;
+{
+ return menu_items_inuse = Qnil;
+}
+
/* Call when finished using the data for the current menu
in menu_items. */
menu_items = Qnil;
menu_items_allocated = 0;
}
+ xassert (NILP (menu_items_inuse));
}
/* Make the menu_items vector twice as large. */
Lisp_Object x, y, window;
int keymaps = 0;
int for_click = 0;
+ int specpdl_count = SPECPDL_INDEX ();
struct gcpro gcpro1;
#ifdef HAVE_MENUS
xpos += XINT (x);
ypos += XINT (y);
-
- XSETFRAME (Vmenu_updating_frame, f);
}
Vmenu_updating_frame = Qnil;
#endif /* HAVE_MENUS */
+ record_unwind_protect (unuse_menu_items, Qnil);
title = Qnil;
GCPRO1 (title);
keymaps = 0;
}
+ unbind_to (specpdl_count, Qnil);
+
if (NILP (position))
{
discard_menu_items ();
Lisp_Object title;
char *error_name;
Lisp_Object selection;
+ int specpdl_count = SPECPDL_INDEX ();
/* Decode the dialog items from what was specified. */
title = Fcar (contents);
CHECK_STRING (title);
+ record_unwind_protect (unuse_menu_items, Qnil);
list_of_panes (Fcons (contents, Qnil));
selection = xdialog_show (f, 0, title, &error_name);
UNBLOCK_INPUT;
+ unbind_to (specpdl_count, Qnil);
discard_menu_items ();
if (error_name) error (error_name);
\f
#ifdef USE_X_TOOLKIT
+/* Define a queue to save up for later unreading
+ all X events that don't pertain to the menu. */
+struct event_queue
+ {
+ XEvent event;
+ struct event_queue *next;
+ };
+
+/* It is ok that this queue is a static variable,
+ because init_menu_items won't allow the menu mechanism
+ to be entered recursively. */
+static struct event_queue *popup_get_selection_queue;
+
+static Lisp_Object popup_get_selection_unwind ();
+
/* Loop in Xt until the menu pulldown or dialog popup has been
popped down (deactivated). This is used for x-popup-menu
- and x-popup-dialog; it is not used for the menu bar any more.
+ and x-popup-dialog; it is not used for the menu bar.
+
+ If DO_TIMERS is nonzero, run timers.
NOTE: All calls to popup_get_selection should be protected
with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
-void
-popup_get_selection (initial_event, dpyinfo, id)
+static void
+popup_get_selection (initial_event, dpyinfo, id, do_timers)
XEvent *initial_event;
struct x_display_info *dpyinfo;
LWLIB_ID id;
+ int do_timers;
{
XEvent event;
-
- /* Define a queue to save up for later unreading
- all X events that don't pertain to the menu. */
- struct event_queue
- {
- XEvent event;
- struct event_queue *next;
- };
-
- struct event_queue *queue = NULL;
struct event_queue *queue_tmp;
+ int count = SPECPDL_INDEX ();
+
+ popup_get_selection_queue = NULL;
+
+ record_unwind_protect (popup_get_selection_unwind, Qnil);
if (initial_event)
event = *initial_event;
{
queue_tmp = (struct event_queue *) xmalloc (sizeof *queue_tmp);
queue_tmp->event = event;
- queue_tmp->next = queue;
- queue = queue_tmp;
+ queue_tmp->next = popup_get_selection_queue;
+ popup_get_selection_queue = queue_tmp;
}
else
XtDispatchEvent (&event);
- if (!popup_activated ())
+ /* If the event deactivated the menu, we are finished. */
+ if (!popup_activated_flag)
break;
+
+ /* If we have no events to run, consider timers. */
+ if (do_timers && !XtAppPending (Xt_app_con))
+ timer_check (1);
+
XtAppNextEvent (Xt_app_con, &event);
}
- /* Unread any events that we got but did not handle. */
- while (queue != NULL)
+ unbind_to (count, Qnil);
+}
+
+/* Unread any events that popup_get_selection read but did not handle. */
+
+static Lisp_Object
+popup_get_selection_unwind (ignore)
+ Lisp_Object ignore;
+{
+ while (popup_get_selection_queue != NULL)
{
- queue_tmp = queue;
+ struct event_queue *queue_tmp;
+ queue_tmp = popup_get_selection_queue;
XPutBackEvent (queue_tmp->event.xany.display, &queue_tmp->event);
- queue = queue_tmp->next;
+ popup_get_selection_queue = queue_tmp->next;
xfree ((char *)queue_tmp);
/* Cause these events to get read as soon as we UNBLOCK_INPUT. */
interrupt_input_pending = 1;
set_frame_menubar (f, 0, 1);
BLOCK_INPUT;
- XtDispatchEvent ((XEvent *) f->output_data.x->saved_menu_event);
+ XtDispatchEvent (f->output_data.x->saved_menu_event);
UNBLOCK_INPUT;
#ifdef USE_MOTIF
if (f->output_data.x->saved_menu_event->type == ButtonRelease)
UNBLOCK_INPUT;
}
\f
-/* Set up data i menu_items for a menu bar item
+/* Set up data in menu_items for a menu bar item
whose event type is ITEM_KEY (with string ITEM_NAME)
and whose contents come from the list of keymaps MAPS. */
But don't make a pane that is empty--ignore that map instead. */
for (i = 0; i < len; i++)
{
- if (SYMBOLP (mapvec[i])
- || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i])))
+ if (!KEYMAPP (mapvec[i]))
{
/* Here we have a command at top level in the menu bar
as opposed to a submenu. */
Qnil, Qnil, Qnil, Qnil);
}
else
- single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
+ {
+ Lisp_Object prompt;
+ prompt = Fkeymap_prompt (mapvec[i]);
+ single_keymap_panes (mapvec[i],
+ !NILP (prompt) ? prompt : item_name,
+ item_key, 0, 10);
+ }
}
return top_level_items;
static widget_value *
digest_single_submenu (start, end, top_level_items)
- int start, end;
+ int start, end, top_level_items;
{
widget_value *wv, *prev_wv, *save_wv, *first_wv;
int i;
save_wv = 0;
prev_wv = 0;
- /* Loop over all panes and items made during this call
- and construct a tree of widget_value objects.
- Ignore the panes and items made by previous calls to
- single_submenu, even though those are also in menu_items. */
+ /* Loop over all panes and items made by the preceding call
+ to parse_single_submenu and construct a tree of widget_value objects.
+ Ignore the panes and items used by previous calls to
+ digest_single_submenu, even though those are also in menu_items. */
i = start;
while (i < end)
{
widget_value *wv, *first_wv, *prev_wv = 0;
int i, last_i;
int *submenu_start, *submenu_end;
- int *submenu_top_level_items;
+ int *submenu_top_level_items, *submenu_n_panes;
LWLIB_ID id;
specbind (Qdebug_on_next_call, Qnil);
record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ record_unwind_protect (unuse_menu_items, Qnil);
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
+ submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
submenu_top_level_items
= (int *) alloca (XVECTOR (items)->size * sizeof (int *));
init_menu_items ();
menu_items_n_panes = 0;
submenu_top_level_items[i]
= parse_single_submenu (key, string, maps);
+ submenu_n_panes[i] = menu_items_n_panes;
submenu_end[i] = menu_items_used;
}
for (i = 0; i < last_i; i += 4)
{
+ menu_items_n_panes = submenu_n_panes[i];
wv = digest_single_submenu (submenu_start[i], submenu_end[i],
submenu_top_level_items[i]);
if (prev_wv)
if (i == menu_items_used && i == previous_menu_items_used && i != 0)
{
free_menubar_widget_value_tree (first_wv);
- menu_items = Qnil;
+ discard_menu_items ();
return;
}
f->menu_bar_vector = menu_items;
f->menu_bar_items_used = menu_items_used;
- menu_items = Qnil;
+ discard_menu_items ();
}
else
{
popup_activated_flag = 1;
/* Process events that apply to the menu. */
- popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id);
+ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0);
/* fp turned off the following statement and wrote a comment
that it is unnecessary--that the menu has already disappeared.
popup_activated_flag = 0;
}
+/* ARG is the LWLIB ID of the dialog box, represented
+ as a Lisp object as (HIGHPART . LOWPART). */
+
+Lisp_Object
+xdialog_show_unwind (arg)
+ Lisp_Object arg;
+{
+ LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
+ | XINT (XCDR (arg)));
+ BLOCK_INPUT;
+ lw_destroy_all_widgets (id);
+ UNBLOCK_INPUT;
+ popup_activated_flag = 0;
+ return Qnil;
+}
+
static char * button_names [] = {
"button1", "button2", "button3", "button4", "button5",
"button6", "button7", "button8", "button9", "button10" };
{
int i, nb_buttons=0;
LWLIB_ID dialog_id;
- Widget menu;
char dialog_name[6];
widget_value *wv, *first_wv = 0, *prev_wv = 0;
/* Actually create the dialog. */
dialog_id = widget_id_tick++;
- menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
- f->output_data.x->widget, 1, 0,
- dialog_selection_callback, 0, 0);
+ lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
+ f->output_data.x->widget, 1, 0,
+ dialog_selection_callback, 0, 0);
lw_modify_all_widgets (dialog_id, first_wv->contents, 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. */
+ /* Display the dialog box. */
lw_pop_up_all_widgets (dialog_id);
popup_activated_flag = 1;
- /* Process events that apply to the menu. */
- popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
+ /* Process events that apply to the dialog box.
+ Also handle timers. */
+ {
+ int count = SPECPDL_INDEX ();
- lw_destroy_all_widgets (dialog_id);
+ /* xdialog_show_unwind is responsible for popping the dialog box down. */
+ record_unwind_protect (xdialog_show_unwind,
+ Fcons (make_number (dialog_id >> (4 * sizeof (LWLIB_ID))),
+ make_number (dialog_id & ~(-1 << (4 * sizeof (LWLIB_ID))))));
- /* Find the selected item, and its pane, to return
- the proper value. */
+ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id, 1);
+
+ unbind_to (count, Qnil);
+ }
+
+ /* Find the selected item and pane, and return the corresponding value. */
if (menu_item_selection != 0)
{
Lisp_Object prefix;
{
staticpro (&menu_items);
menu_items = Qnil;
+ menu_items_inuse = Qnil;
Qdebug_on_next_call = intern ("debug-on-next-call");
staticpro (&Qdebug_on_next_call);