/* Platform-independent code for terminal communications.
-Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2014 Free Software
+Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2015 Free Software
Foundation, Inc.
This file is part of GNU Emacs.
/* 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. */
-#if ! (defined USE_GTK || defined USE_MOTIF)
-static
-#endif
Lisp_Object menu_items_inuse;
/* Number of slots currently allocated in menu_items. */
front of them. */
if (!have_boxes ())
{
- Lisp_Object prefix = Qnil;
+ char const *prefix = 0;
Lisp_Object type = AREF (item_properties, ITEM_PROPERTY_TYPE);
if (!NILP (type))
{
{
if (!submenu && SREF (tem, 0) != '\0'
&& SREF (tem, 0) != '-')
- ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
- concat2 (build_string (" "), tem));
+ {
+ AUTO_STRING (spaces, " ");
+ ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
+ concat2 (spaces, tem));
+ }
idx += MENU_ITEMS_ITEM_LENGTH;
}
}
/* Calculate prefix, if any, for this item. */
if (EQ (type, QCtoggle))
- prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
+ prefix = NILP (selected) ? "[ ] " : "[X] ";
else if (EQ (type, QCradio))
- prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
+ prefix = NILP (selected) ? "( ) " : "(*) ";
}
/* Not a button. If we have earlier buttons, then we need a prefix. */
else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
&& SREF (item_string, 0) != '-')
- prefix = build_string (" ");
+ prefix = " ";
- if (!NILP (prefix))
- item_string = concat2 (prefix, item_string);
+ if (prefix)
+ {
+ AUTO_STRING (prefix_obj, prefix);
+ item_string = concat2 (prefix_obj, item_string);
+ }
}
if ((FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame))
|| FRAME_MSDOS_P (XFRAME (Vmenu_updating_frame)))
&& !NILP (map))
/* Indicate visually that this is a submenu. */
- item_string = concat2 (item_string, build_string (" >"));
+ {
+ AUTO_STRING (space_gt, " >");
+ item_string = concat2 (item_string, space_gt);
+ }
push_menu_item (item_string, enabled, key,
AREF (item_properties, ITEM_PROPERTY_DEF),
widget_value **submenu_stack;
bool panes_seen = 0;
struct frame *f = XFRAME (Vmenu_updating_frame);
+ USE_SAFE_ALLOCA;
- submenu_stack = alloca (menu_items_used * sizeof *submenu_stack);
+ SAFE_NALLOCA (submenu_stack, 1, menu_items_used);
wv = make_widget_value ("menu", NULL, true, Qnil);
wv->button_type = BUTTON_TYPE_NONE;
first_wv = wv;
that was originally a button, return it by itself. */
if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
{
- wv = first_wv->contents;
- xfree (first_wv);
- return wv;
+ wv = first_wv;
+ first_wv = first_wv->contents;
+ xfree (wv);
}
+ SAFE_FREE ();
return first_wv;
}
Lisp_Object *subprefix_stack;
int submenu_depth = 0;
int i;
+ USE_SAFE_ALLOCA;
entry = Qnil;
- subprefix_stack = alloca (menu_bar_items_used * sizeof *subprefix_stack);
+ SAFE_NALLOCA (subprefix_stack, 1, menu_bar_items_used);
prefix = Qnil;
i = 0;
buf.arg = entry;
kbd_buffer_store_event (&buf);
- return;
+ break;
}
i += MENU_ITEMS_ITEM_LENGTH;
}
}
+
+ SAFE_FREE ();
}
#endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */
int i;
Lisp_Object *subprefix_stack;
int submenu_depth = 0;
+ USE_SAFE_ALLOCA;
prefix = entry = Qnil;
i = 0;
- subprefix_stack = alloca (menu_items_used * word_size);
+ SAFE_ALLOCA_LISP (subprefix_stack, menu_items_used);
while (i < menu_items_used)
{
if (!NILP (subprefix_stack[j]))
entry = Fcons (subprefix_stack[j], entry);
}
+ SAFE_FREE ();
return entry;
}
i += MENU_ITEMS_ITEM_LENGTH;
}
}
+ SAFE_FREE ();
return Qnil;
}
#endif /* HAVE_NS */
{
int cur_x, cur_y;
- mouse_position_for_popup (new_f, &cur_x, &cur_y);
+ x_relative_mouse_position (new_f, &cur_x, &cur_y);
/* cur_x/y may be negative, so use make_number. */
x = make_number (cur_x);
y = make_number (cur_y);
record_unwind_protect_void (discard_menu_items);
#endif
- /* Display them in a menu. */
- selection = FRAME_TERMINAL (f)->menu_show_hook (f, xpos, ypos, menuflags,
- title, &error_name);
+ /* Display them in a menu, but not if F is the initial frame that
+ doesn't have its hooks set (e.g., in a batch session), because
+ such a frame cannot display menus. */
+ if (!FRAME_INITIAL_P (f))
+ selection = FRAME_TERMINAL (f)->menu_show_hook (f, xpos, ypos, menuflags,
+ title, &error_name);
#ifdef HAVE_NS
unbind_to (specpdl_count, Qnil);
return selection;
}
+/* If F's terminal is not capable of displaying a popup dialog,
+ emulate it with a menu. */
+
+static Lisp_Object
+emulate_dialog_with_menu (struct frame *f, Lisp_Object contents)
+{
+ Lisp_Object x, y, frame, newpos, prompt = Fcar (contents);
+ int x_coord, y_coord;
+
+ if (FRAME_WINDOW_P (f))
+ {
+ x_coord = FRAME_PIXEL_WIDTH (f);
+ y_coord = FRAME_PIXEL_HEIGHT (f);
+ }
+ else
+ {
+ x_coord = FRAME_COLS (f);
+ /* Center the title at frame middle. (TTY menus have
+ their upper-left corner at the given position.) */
+ if (STRINGP (prompt))
+ x_coord -= SCHARS (prompt);
+ y_coord = FRAME_TOTAL_LINES (f);
+ }
+
+ XSETFRAME (frame, f);
+ XSETINT (x, x_coord / 2);
+ XSETINT (y, y_coord / 2);
+ newpos = list2 (list2 (x, y), frame);
+
+ return Fx_popup_menu (newpos, list2 (prompt, contents));
+}
+
DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
doc: /* Pop up a dialog box and return user's selection.
POSITION specifies which frame to use.
if (EQ (position, Qt)
|| (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
|| EQ (XCAR (position), Qtool_bar))))
- {
-#if 0 /* Using the frame the mouse is on may not be right. */
- /* Use the mouse's current position. */
- struct frame *new_f = SELECTED_FRAME ();
- Lisp_Object bar_window;
- enum scroll_bar_part part;
- Time time;
- Lisp_Object x, y;
-
- (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
-
- if (new_f != 0)
- XSETFRAME (window, new_f);
- else
- window = selected_window;
-#endif
- window = selected_window;
- }
+ window = selected_window;
else if (CONSP (position))
{
Lisp_Object tem = XCAR (position);
but I don't want to make one now. */
CHECK_WINDOW (window);
+ /* Note that xw_popup_dialog can call menu code, so
+ Vmenu_updating_frame should be set (Bug#17891). */
+ eassert (f && FRAME_LIVE_P (f));
+ XSETFRAME (Vmenu_updating_frame, f);
+
/* 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
string contents, because Fredisplay may GC and relocate them. */
Fredisplay (Qt);
-#if defined USE_X_TOOLKIT || defined USE_GTK
- if (FRAME_WINDOW_P (f))
- return xw_popup_dialog (f, header, contents);
-#endif
-#ifdef HAVE_NTGUI
- if (FRAME_W32_P (f))
+ /* Display the popup dialog by a terminal-specific hook ... */
+ if (FRAME_TERMINAL (f)->popup_dialog_hook)
{
- Lisp_Object selection = w32_popup_dialog (f, header, contents);
-
+ Lisp_Object selection
+ = FRAME_TERMINAL (f)->popup_dialog_hook (f, header, contents);
+#ifdef HAVE_NTGUI
+ /* NTGUI supports only simple dialogs with Yes/No choices. For
+ other dialogs, it returns the symbol 'unsupported--w32-dialog',
+ as a signal for the caller to fall back to the emulation code. */
if (!EQ (selection, Qunsupported__w32_dialog))
+#endif
return selection;
}
-#endif
-#ifdef HAVE_NS
- if (FRAME_NS_P (f))
- return ns_popup_dialog (position, header, contents);
-#endif
- /* Display a menu with these alternatives
- in the middle of frame F. */
- {
- Lisp_Object x, y, frame, newpos, prompt;
- int x_coord, y_coord;
-
- prompt = Fcar (contents);
- if (FRAME_WINDOW_P (f))
- {
- x_coord = FRAME_PIXEL_WIDTH (f);
- y_coord = FRAME_PIXEL_HEIGHT (f);
- }
- else
- {
- x_coord = FRAME_COLS (f);
- /* Center the title at frame middle. (TTY menus have their
- upper-left corner at the given position.) */
- if (STRINGP (prompt))
- x_coord -= SCHARS (prompt);
- y_coord = FRAME_LINES (f);
- }
- XSETFRAME (frame, f);
- XSETINT (x, x_coord / 2);
- XSETINT (y, y_coord / 2);
- newpos = list2 (list2 (x, y), frame);
-
- return Fx_popup_menu (newpos, list2 (prompt, contents));
- }
+ /* ... or emulate it with a menu. */
+ return emulate_dialog_with_menu (f, contents);
}
void