X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/cfd794af4214ae0e5587ab8b1f4e5fcb355a0f12..23ffeb9015ca3669995b9a5d47cfc09b7643d9b9:/src/menu.c diff --git a/src/menu.c b/src/menu.c index b65401c6f4..5a8ea34242 100644 --- a/src/menu.c +++ b/src/menu.c @@ -1,6 +1,6 @@ /* 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. @@ -66,9 +66,6 @@ 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. */ -#if ! (defined USE_GTK || defined USE_MOTIF) -static -#endif Lisp_Object menu_items_inuse; /* Number of slots currently allocated in menu_items. */ @@ -357,7 +354,7 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk 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)) { @@ -392,8 +389,11 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk { 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; } } @@ -402,24 +402,30 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk /* 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), @@ -635,8 +641,9 @@ digest_single_submenu (int start, int end, bool top_level_items) 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; @@ -838,11 +845,12 @@ digest_single_submenu (int start, int end, bool top_level_items) 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; } @@ -893,9 +901,10 @@ find_and_call_menu_selection (struct frame *f, int menu_bar_items_used, 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; @@ -957,11 +966,13 @@ find_and_call_menu_selection (struct frame *f, int menu_bar_items_used, 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 */ @@ -976,10 +987,11 @@ find_and_return_menu_selection (struct frame *f, bool keymaps, void *client_data 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) { @@ -1021,11 +1033,13 @@ find_and_return_menu_selection (struct frame *f, bool keymaps, void *client_data 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 */ @@ -1236,7 +1250,7 @@ no quit occurs and `x-popup-menu' returns nil. */) { 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); @@ -1413,9 +1427,12 @@ no quit occurs and `x-popup-menu' returns nil. */) 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); @@ -1434,6 +1451,38 @@ no quit occurs and `x-popup-menu' returns nil. */) 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. @@ -1466,24 +1515,7 @@ for instance using the window manager, then this produces a quit and 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); @@ -1514,6 +1546,11 @@ for instance using the window manager, then this produces a quit and 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 @@ -1525,51 +1562,21 @@ for instance using the window manager, then this produces a quit and 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