aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2013-10-08 20:49:20 +0300
committerEli Zaretskii2013-10-08 20:49:20 +0300
commit4ed774157d1687cc5236ecaf088dc48442e92431 (patch)
tree4dd32cb0104172c6b12f90c2651f58f0040bfe20 /src
parent06286513730d013c2033d1dae892349e5eec98d9 (diff)
parentf3370a94fd887e9e01db81a86e42036d12dcda9b (diff)
downloademacs-4ed774157d1687cc5236ecaf088dc48442e92431.tar.gz
emacs-4ed774157d1687cc5236ecaf088dc48442e92431.zip
Support menus on text-mode terminals.
src/xterm.h (xw_popup_dialog): Add prototype. src/xmenu.c (Fx_popup_dialog): Function moved to menu.c. (xmenu_show): Block input here, instead in Fx_popup_menu. (xw_popup_dialog): New function, with X-specific bits of popup dialogs. src/xdisp.c (deep_copy_glyph_row, display_tty_menu_item): New functions. src/window.c (Fset_window_configuration): Use run-time tests of the frame type instead of compile-time conditionals, when menu-bar lines are considered. src/w32term.h (w32con_hide_cursor, w32con_show_cursor) (w32_popup_dialog): New prototypes. src/w32menu.c (Fx_popup_dialog): Function deleted. (w32_popup_dialog): New function, with w32 specific bits of popup dialogs. Block input here. src/w32inevt.c (w32_console_read_socket): Minor change to add debugging TTY events. src/w32fns.c (show_hourglass): If returning early because the frame is not a GUI frame, unblock input. src/w32console.c (w32con_hide_cursor, w32con_show_cursor, cursorX) (cursorY): New functions. src/termhooks.h (cursorX, cursorY): Prototypes of functions on WINDOWSNT, macros that call curX and curY elsewhere. src/termchar.h (struct tty_display_info) <showing_menu>: New flag. src/term.c (tty_hide_cursor, tty_show_cursor) [WINDOWSNT]: Call w32 specific function to hide and show cursor on a text-mode terminal. (tty_menu_struct, struct tty_menu_state): New structures. (tty_menu_create, tty_menu_make_room, tty_menu_search_pane) (tty_menu_calc_size, mouse_get_xy, tty_menu_display) (have_menus_p, tty_menu_add_pane, tty_menu_add_selection) (tty_menu_locate, save_and_enable_current_matrix) (restore_desired_matrix, screen_update, read_menu_input) (tty_menu_activate, tty_menu_destroy, tty_menu_help_callback) (tty_pop_down_menu, tty_menu_last_menubar_item) (tty_menu_new_item_coords, tty_menu_show): New functions. (syms_of_term): New DEFSYMs for tty-menu-* symbols. src/nsterm.h (ns_popup_dialog): Adjust prototype. src/nsmenu.m (ns_menu_show): Block and unblock input here, instead of in x-popup-menu. (ns_popup_dialog): Adapt order of arguments to the other *_menu_show implementations. (Fx_popup_dialog): Function deleted. src/msdos.c (x_set_menu_bar_lines): Delete unused function. src/menu.h (tty_menu_show, menu_item_width): provide prototypes. src/menu.c (have_boxes): New function. (single_keymap_panes): Use it instead of a compile-time conditional. (single_menu_item): Use run-time tests of the frame type instead of compile-time conditionals. (encode_menu_string): New function. (list_of_items, list_of_panes): Use it instead of ENCODE_STRING the macro, since different types of frame need different encoding of menu items. (digest_single_submenu): Use run-time tests of frame type instead of, or in addition to, compile-time conditionals. (menu_item_width, Fmenu_bar_menu_at_x_y): New functions. (Fx_popup_menu): Detect when the function is called from keyboard on a TTY. Don't barf when invoked on a text-mode frame. Check frame type at run time, instead of compile-time conditionals for invoking terminal-specific menu-show functions. Call tty_menu_show on text-mode frames. (Fx_popup_dialog): Moved here from xmenu.c. Test frame types at run time to determine which alternative to invoke; support dialogs on TTYs. src/keyboard.h <Qmouse_movement>: Declare. src/keyboard.c <Qmouse_movement>: Now extern. <Qecho_keystrokes>: New static variable. (read_key_sequence): Accept an additional argument, a flag to prevent redisplay during reading of the key sequence. All callers changed. (read_menu_command): New function. (read_char): When COMMANDFLAG is -2, do not redisplay and do not autosave. (toolkit_menubar_in_use): New function. (make_lispy_event): Use it instead of a compile-time test. src/fns.c (Fyes_or_no_p) [HAVE_MENUS]: Don't condition on window-system being available. src/editfns.c (Fmessage_box) [HAVE_MENUS]: Don't condition the call to x-popup-dialog on the frame type, they all now support popup dialogs. src/dispnew.c (save_current_matrix): Save the margin areas. (restore_current_matrix): Restore margin areas. (update_frame_with_menu): New function. src/dispextern.h (display_tty_menu_item, update_frame_with_menu): Add prototypes. src/alloc.c (make_save_ptr): Now compiled unconditionally. lisp/tmm.el (tmm-menubar): Adapt doc string to TTY menus functionality. lisp/tooltip.el (tooltip-mode): Don't error out on TTYs. lisp/menu-bar.el (popup-menu, popup-menu-normalize-position): Moved here from mouse.el. (popup-menu): Support menu-bar navigation on TTYs using C-f/C-b and arrow keys. (tty-menu-navigation-map): New map for TTY menu navigation. lisp/loadup.el ("tooltip"): Load even if x-show-tip is not available. lisp/frame.el (display-mouse-p): Report text-mode mouse as available on w32. (display-popup-menus-p): Report availability if mouse is available; don't condition on window-system. lisp/faces.el (tty-menu-enabled-face, tty-menu-disabled-face) (tty-menu-selected-face): New faces. configure.ac (HAVE_MENUS): Define unconditionally. doc/emacs/screen.texi (Menu Bar): Adapt to TTY menus. doc/emacs/frames.texi (Frames): Mention menu support on text terminals. doc/emacs/files.texi (Visiting): Mention the "File" menu-bar menu. doc/emacs/display.texi (Standard Faces): Mention TTY faces for menus. doc/lispref/keymaps.texi (Defining Menus, Mouse Menus, Menu Bar): Modify wording to the effect that menus are supported on TTYs. doc/lisprefframes.texi (Pop-Up Menus, Dialog Boxes) (Display Feature Testing): Update for menu support on TTYs. etc/NEWS: Mention the new features.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog113
-rw-r--r--src/alloc.c2
-rw-r--r--src/cm.h2
-rw-r--r--src/dispextern.h6
-rw-r--r--src/dispnew.c81
-rw-r--r--src/editfns.c25
-rw-r--r--src/fns.c7
-rw-r--r--src/frame.h3
-rw-r--r--src/keyboard.c164
-rw-r--r--src/keyboard.h2
-rw-r--r--src/menu.c568
-rw-r--r--src/menu.h3
-rw-r--r--src/msdos.c7
-rw-r--r--src/nsmenu.m34
-rw-r--r--src/nsterm.h4
-rw-r--r--src/term.c1121
-rw-r--r--src/termchar.h3
-rw-r--r--src/termhooks.h8
-rw-r--r--src/w32console.c32
-rw-r--r--src/w32fns.c5
-rw-r--r--src/w32inevt.c7
-rw-r--r--src/w32menu.c147
-rw-r--r--src/w32term.h8
-rw-r--r--src/window.c33
-rw-r--r--src/xdisp.c121
-rw-r--r--src/xmenu.c206
-rw-r--r--src/xterm.h4
27 files changed, 2169 insertions, 547 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index fc2f7a9d57c..e30194d1dfb 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,116 @@
12013-10-08 Eli Zaretskii <eliz@gnu.org>
2
3 Support menus on text-mode terminals.
4 * xterm.h (xw_popup_dialog): Add prototype.
5
6 * xmenu.c (Fx_popup_dialog): Function moved to menu.c.
7 (xmenu_show): Block input here, instead in Fx_popup_menu.
8 (xw_popup_dialog): New function, with X-specific bits of popup
9 dialogs.
10
11 * xdisp.c (deep_copy_glyph_row, display_tty_menu_item): New
12 functions.
13
14 * window.c (Fset_window_configuration): Use run-time tests of the
15 frame type instead of compile-time conditionals, when menu-bar
16 lines are considered.
17
18 * w32term.h (w32con_hide_cursor, w32con_show_cursor)
19 (w32_popup_dialog): New prototypes.
20
21 * w32menu.c (Fx_popup_dialog): Function deleted.
22 (w32_popup_dialog): New function, with w32 specific bits of popup
23 dialogs. Block input here.
24
25 * w32inevt.c (w32_console_read_socket): Minor change to add
26 debugging TTY events.
27
28 * w32fns.c (show_hourglass): If returning early because the frame
29 is not a GUI frame, unblock input.
30
31 * w32console.c (w32con_hide_cursor, w32con_show_cursor, cursorX)
32 (cursorY): New functions.
33
34 * termhooks.h (cursorX, cursorY): Prototypes of functions on
35 WINDOWSNT, macros that call curX and curY elsewhere.
36
37 * termchar.h (struct tty_display_info) <showing_menu>: New flag.
38
39 * term.c (tty_hide_cursor, tty_show_cursor) [WINDOWSNT]: Call w32
40 specific function to hide and show cursor on a text-mode terminal.
41 (tty_menu_struct, struct tty_menu_state): New structures.
42 (tty_menu_create, tty_menu_make_room, tty_menu_search_pane)
43 (tty_menu_calc_size, mouse_get_xy, tty_menu_display)
44 (have_menus_p, tty_menu_add_pane, tty_menu_add_selection)
45 (tty_menu_locate, save_and_enable_current_matrix)
46 (restore_desired_matrix, screen_update, read_menu_input)
47 (tty_menu_activate, tty_menu_destroy, tty_menu_help_callback)
48 (tty_pop_down_menu, tty_menu_last_menubar_item)
49 (tty_menu_new_item_coords, tty_menu_show): New functions.
50 (syms_of_term): New DEFSYMs for tty-menu-* symbols.
51
52 * nsterm.h (ns_popup_dialog): Adjust prototype.
53
54 * nsmenu.m (ns_menu_show): Block and unblock input here, instead
55 of in x-popup-menu.
56 (ns_popup_dialog): Adapt order of arguments to the other
57 *_menu_show implementations.
58 (Fx_popup_dialog): Function deleted.
59
60 * msdos.c (x_set_menu_bar_lines): Delete unused function.
61
62 * menu.h (tty_menu_show, menu_item_width): provide prototypes.
63
64 * menu.c (have_boxes): New function.
65 (single_keymap_panes): Use it instead of a compile-time
66 conditional.
67 (single_menu_item): Use run-time tests of the frame type instead
68 of compile-time conditionals.
69 (encode_menu_string): New function.
70 (list_of_items, list_of_panes): Use it instead of ENCODE_STRING
71 the macro, since different types of frame need different encoding
72 of menu items.
73 (digest_single_submenu): Use run-time tests of frame type instead
74 of, or in addition to, compile-time conditionals.
75 (menu_item_width, Fmenu_bar_menu_at_x_y): New functions.
76 (Fx_popup_menu): Detect when the function is called from keyboard
77 on a TTY. Don't barf when invoked on a text-mode frame. Check
78 frame type at run time, instead of compile-time conditionals for
79 invoking terminal-specific menu-show functions. Call
80 tty_menu_show on text-mode frames.
81 (Fx_popup_dialog): Moved here from xmenu.c. Test frame types at
82 run time to determine which alternative to invoke; support dialogs
83 on TTYs.
84
85 * keyboard.h <Qmouse_movement>: Declare.
86
87 * keyboard.c <Qmouse_movement>: Now extern.
88 <Qecho_keystrokes>: New static variable.
89 (read_key_sequence): Accept an additional argument, a flag to
90 prevent redisplay during reading of the key sequence. All callers
91 changed.
92 (read_menu_command): New function.
93 (read_char): When COMMANDFLAG is -2, do not redisplay and do not
94 autosave.
95 (toolkit_menubar_in_use): New function.
96 (make_lispy_event): Use it instead of a compile-time test.
97
98 * fns.c (Fyes_or_no_p) [HAVE_MENUS]: Don't condition on
99 window-system being available.
100
101 * editfns.c (Fmessage_box) [HAVE_MENUS]: Don't condition the call
102 to x-popup-dialog on the frame type, they all now support popup
103 dialogs.
104
105 * dispnew.c (save_current_matrix): Save the margin areas.
106 (restore_current_matrix): Restore margin areas.
107 (update_frame_with_menu): New function.
108
109 * dispextern.h (display_tty_menu_item, update_frame_with_menu):
110 Add prototypes.
111
112 * alloc.c (make_save_ptr): Now compiled unconditionally.
113
12013-10-08 Dmitry Antipov <dmantipov@yandex.ru> 1142013-10-08 Dmitry Antipov <dmantipov@yandex.ru>
2 115
3 * dispnew.c (set_window_update_flags): Add buffer arg. Adjust comment. 116 * dispnew.c (set_window_update_flags): Add buffer arg. Adjust comment.
diff --git a/src/alloc.c b/src/alloc.c
index 2a00767682d..17f1b19b3c0 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3408,7 +3408,6 @@ make_save_obj_obj_obj_obj (Lisp_Object a, Lisp_Object b, Lisp_Object c,
3408 return val; 3408 return val;
3409} 3409}
3410 3410
3411#if defined HAVE_NS || defined HAVE_NTGUI
3412Lisp_Object 3411Lisp_Object
3413make_save_ptr (void *a) 3412make_save_ptr (void *a)
3414{ 3413{
@@ -3418,7 +3417,6 @@ make_save_ptr (void *a)
3418 p->data[0].pointer = a; 3417 p->data[0].pointer = a;
3419 return val; 3418 return val;
3420} 3419}
3421#endif
3422 3420
3423Lisp_Object 3421Lisp_Object
3424make_save_ptr_int (void *a, ptrdiff_t b) 3422make_save_ptr_int (void *a, ptrdiff_t b)
diff --git a/src/cm.h b/src/cm.h
index 6d49dda9419..f3455b79569 100644
--- a/src/cm.h
+++ b/src/cm.h
@@ -139,7 +139,7 @@ struct cm
139#define MultiDownCost(tty) (tty)->Wcm->cc_multidown 139#define MultiDownCost(tty) (tty)->Wcm->cc_multidown
140#define MultiLeftCost(tty) (tty)->Wcm->cc_multileft 140#define MultiLeftCost(tty) (tty)->Wcm->cc_multileft
141#define MultiRightCost(tty) (tty)->Wcm->cc_multiright 141#define MultiRightCost(tty) (tty)->Wcm->cc_multiright
142#endif 142#endif /* NoCMShortHand */
143 143
144#define cmat(tty,row,col) (curY(tty) = (row), curX(tty) = (col)) 144#define cmat(tty,row,col) (curY(tty) = (row), curX(tty) = (col))
145#define cmplus(tty,n) \ 145#define cmplus(tty,n) \
diff --git a/src/dispextern.h b/src/dispextern.h
index 2f6b730865d..10cd3169408 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -3256,6 +3256,7 @@ extern int clear_mouse_face (Mouse_HLInfo *);
3256extern int cursor_in_mouse_face_p (struct window *w); 3256extern int cursor_in_mouse_face_p (struct window *w);
3257extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *, 3257extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *,
3258 int, int, enum draw_glyphs_face); 3258 int, int, enum draw_glyphs_face);
3259extern void display_tty_menu_item (const char *, int, int, int, int, int);
3259 3260
3260/* Flags passed to try_window. */ 3261/* Flags passed to try_window. */
3261#define TRY_WINDOW_CHECK_MARGINS (1 << 0) 3262#define TRY_WINDOW_CHECK_MARGINS (1 << 0)
@@ -3427,6 +3428,8 @@ extern void hide_hourglass (void);
3427 3428
3428int popup_activated (void); 3429int popup_activated (void);
3429 3430
3431/* Defined in dispnew.c */
3432
3430extern Lisp_Object buffer_posn_from_coords (struct window *, 3433extern Lisp_Object buffer_posn_from_coords (struct window *,
3431 int *, int *, 3434 int *, int *,
3432 struct display_pos *, 3435 struct display_pos *,
@@ -3442,6 +3445,7 @@ extern Lisp_Object marginal_area_string (struct window *, enum window_part,
3442 int *, int *, int *, int *); 3445 int *, int *, int *, int *);
3443extern void redraw_frame (struct frame *); 3446extern void redraw_frame (struct frame *);
3444extern bool update_frame (struct frame *, bool, bool); 3447extern bool update_frame (struct frame *, bool, bool);
3448extern void update_frame_with_menu (struct frame *);
3445extern void bitch_at_user (void); 3449extern void bitch_at_user (void);
3446extern void adjust_frame_glyphs (struct frame *); 3450extern void adjust_frame_glyphs (struct frame *);
3447void free_glyphs (struct frame *); 3451void free_glyphs (struct frame *);
@@ -3467,7 +3471,7 @@ void change_frame_size (struct frame *, int, int, bool, bool, bool);
3467void init_display (void); 3471void init_display (void);
3468void syms_of_display (void); 3472void syms_of_display (void);
3469extern Lisp_Object Qredisplay_dont_pause; 3473extern Lisp_Object Qredisplay_dont_pause;
3470void spec_glyph_lookup_face (struct window *, GLYPH *); 3474extern void spec_glyph_lookup_face (struct window *, GLYPH *);
3471 3475
3472/* Defined in terminal.c */ 3476/* Defined in terminal.c */
3473 3477
diff --git a/src/dispnew.c b/src/dispnew.c
index 8507a330a92..f5d213e03f4 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -1844,9 +1844,28 @@ save_current_matrix (struct frame *f)
1844 struct glyph_row *from = f->current_matrix->rows + i; 1844 struct glyph_row *from = f->current_matrix->rows + i;
1845 struct glyph_row *to = saved->rows + i; 1845 struct glyph_row *to = saved->rows + i;
1846 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph); 1846 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
1847
1847 to->glyphs[TEXT_AREA] = xmalloc (nbytes); 1848 to->glyphs[TEXT_AREA] = xmalloc (nbytes);
1848 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes); 1849 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
1849 to->used[TEXT_AREA] = from->used[TEXT_AREA]; 1850 to->used[TEXT_AREA] = from->used[TEXT_AREA];
1851 to->enabled_p = from->enabled_p;
1852 to->hash = from->hash;
1853 if (from->used[LEFT_MARGIN_AREA])
1854 {
1855 nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph);
1856 to->glyphs[LEFT_MARGIN_AREA] = (struct glyph *) xmalloc (nbytes);
1857 memcpy (to->glyphs[LEFT_MARGIN_AREA],
1858 from->glyphs[LEFT_MARGIN_AREA], nbytes);
1859 to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA];
1860 }
1861 if (from->used[RIGHT_MARGIN_AREA])
1862 {
1863 nbytes = from->used[RIGHT_MARGIN_AREA] * sizeof (struct glyph);
1864 to->glyphs[RIGHT_MARGIN_AREA] = (struct glyph *) xmalloc (nbytes);
1865 memcpy (to->glyphs[RIGHT_MARGIN_AREA],
1866 from->glyphs[RIGHT_MARGIN_AREA], nbytes);
1867 to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
1868 }
1850 } 1869 }
1851 1870
1852 return saved; 1871 return saved;
@@ -1866,9 +1885,30 @@ restore_current_matrix (struct frame *f, struct glyph_matrix *saved)
1866 struct glyph_row *from = saved->rows + i; 1885 struct glyph_row *from = saved->rows + i;
1867 struct glyph_row *to = f->current_matrix->rows + i; 1886 struct glyph_row *to = f->current_matrix->rows + i;
1868 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph); 1887 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
1888
1869 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes); 1889 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
1870 to->used[TEXT_AREA] = from->used[TEXT_AREA]; 1890 to->used[TEXT_AREA] = from->used[TEXT_AREA];
1871 xfree (from->glyphs[TEXT_AREA]); 1891 xfree (from->glyphs[TEXT_AREA]);
1892 nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph);
1893 if (nbytes)
1894 {
1895 memcpy (to->glyphs[LEFT_MARGIN_AREA],
1896 from->glyphs[LEFT_MARGIN_AREA], nbytes);
1897 to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA];
1898 xfree (from->glyphs[LEFT_MARGIN_AREA]);
1899 }
1900 else
1901 to->used[LEFT_MARGIN_AREA] = 0;
1902 nbytes = from->used[RIGHT_MARGIN_AREA] * sizeof (struct glyph);
1903 if (nbytes)
1904 {
1905 memcpy (to->glyphs[RIGHT_MARGIN_AREA],
1906 from->glyphs[RIGHT_MARGIN_AREA], nbytes);
1907 to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
1908 xfree (from->glyphs[RIGHT_MARGIN_AREA]);
1909 }
1910 else
1911 to->used[RIGHT_MARGIN_AREA] = 0;
1872 } 1912 }
1873 1913
1874 xfree (saved->rows); 1914 xfree (saved->rows);
@@ -3047,6 +3087,47 @@ update_frame (struct frame *f, bool force_p, bool inhibit_hairy_id_p)
3047 return paused_p; 3087 return paused_p;
3048} 3088}
3049 3089
3090/* Update a TTY frame F that has a menu dropped down over some of its
3091 glyphs. This is like the second part of update_frame, but it
3092 doesn't call build_frame_matrix, because we already have the
3093 desired matrix prepared, and don't want it to be overwritten by the
3094 text of the normal display. */
3095void
3096update_frame_with_menu (struct frame *f)
3097{
3098 struct window *root_window = XWINDOW (f->root_window);
3099 bool paused_p;
3100
3101 eassert (FRAME_TERMCAP_P (f));
3102
3103 /* We are working on frame matrix basis. Set the frame on whose
3104 frame matrix we operate. */
3105 set_frame_matrix_frame (f);
3106
3107 /* Update the display */
3108 update_begin (f);
3109 /* Force update_frame_1 not to stop due to pending input, and not
3110 try scrolling. */
3111 paused_p = update_frame_1 (f, 1, 1);
3112 update_end (f);
3113
3114 if (FRAME_TTY (f)->termscript)
3115 fflush (FRAME_TTY (f)->termscript);
3116 fflush (FRAME_TTY (f)->output);
3117 /* Check window matrices for lost pointers. */
3118#if GLYPH_DEBUG
3119#if 0
3120 /* We cannot possibly survive the matrix pointers check, since
3121 we have overwritten parts of the frame glyph matrix without
3122 making any updates to the window matrices. */
3123 check_window_matrix_pointers (root_window);
3124#endif
3125 add_frame_display_history (f, paused_p);
3126#endif
3127
3128 /* Reset flags indicating that a window should be updated. */
3129 set_window_update_flags (root_window, NULL, 0);
3130}
3050 3131
3051 3132
3052/************************************************************************ 3133/************************************************************************
diff --git a/src/editfns.c b/src/editfns.c
index 9847e507766..d4c1f995d61 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3472,22 +3472,17 @@ usage: (message-box FORMAT-STRING &rest ARGS) */)
3472 { 3472 {
3473 Lisp_Object val = Fformat (nargs, args); 3473 Lisp_Object val = Fformat (nargs, args);
3474#ifdef HAVE_MENUS 3474#ifdef HAVE_MENUS
3475 /* The MS-DOS frames support popup menus even though they are 3475 Lisp_Object pane, menu;
3476 not FRAME_WINDOW_P. */ 3476 struct gcpro gcpro1;
3477 if (FRAME_WINDOW_P (XFRAME (selected_frame)) 3477
3478 || FRAME_MSDOS_P (XFRAME (selected_frame))) 3478 pane = list1 (Fcons (build_string ("OK"), Qt));
3479 { 3479 GCPRO1 (pane);
3480 Lisp_Object pane, menu; 3480 menu = Fcons (val, pane);
3481 struct gcpro gcpro1; 3481 Fx_popup_dialog (Qt, menu, Qt);
3482 pane = list1 (Fcons (build_string ("OK"), Qt)); 3482 UNGCPRO;
3483 GCPRO1 (pane); 3483#else /* !HAVE_MENUS */
3484 menu = Fcons (val, pane);
3485 Fx_popup_dialog (Qt, menu, Qt);
3486 UNGCPRO;
3487 return val;
3488 }
3489#endif /* HAVE_MENUS */
3490 message3 (val); 3484 message3 (val);
3485#endif
3491 return val; 3486 return val;
3492 } 3487 }
3493} 3488}
diff --git a/src/fns.c b/src/fns.c
index e4618919640..151977ecdc4 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -2434,8 +2434,8 @@ a space; `yes-or-no-p' adds \"(yes or no) \" to it.
2434The user must confirm the answer with RET, and can edit it until it 2434The user must confirm the answer with RET, and can edit it until it
2435has been confirmed. 2435has been confirmed.
2436 2436
2437Under a windowing system a dialog box will be used if `last-nonmenu-event' 2437If dialog boxes are supported, a dialog box will be used
2438is nil, and `use-dialog-box' is non-nil. */) 2438if `last-nonmenu-event' is nil, and `use-dialog-box' is non-nil. */)
2439 (Lisp_Object prompt) 2439 (Lisp_Object prompt)
2440{ 2440{
2441 register Lisp_Object ans; 2441 register Lisp_Object ans;
@@ -2446,8 +2446,7 @@ is nil, and `use-dialog-box' is non-nil. */)
2446 2446
2447#ifdef HAVE_MENUS 2447#ifdef HAVE_MENUS
2448 if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event)) 2448 if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
2449 && use_dialog_box 2449 && use_dialog_box)
2450 && window_system_available (SELECTED_FRAME ()))
2451 { 2450 {
2452 Lisp_Object pane, menu, obj; 2451 Lisp_Object pane, menu, obj;
2453 redisplay_preserve_echo_area (4); 2452 redisplay_preserve_echo_area (4);
diff --git a/src/frame.h b/src/frame.h
index fca985b1f54..8dfcaae114b 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -1248,9 +1248,6 @@ extern void x_set_tool_bar_lines (struct frame *f,
1248 Lisp_Object oldval); 1248 Lisp_Object oldval);
1249extern void x_activate_menubar (struct frame *); 1249extern void x_activate_menubar (struct frame *);
1250extern void x_real_positions (struct frame *, int *, int *); 1250extern void x_real_positions (struct frame *, int *, int *);
1251extern void x_set_menu_bar_lines (struct frame *,
1252 Lisp_Object,
1253 Lisp_Object);
1254extern void free_frame_menubar (struct frame *); 1251extern void free_frame_menubar (struct frame *);
1255extern void x_free_frame_resources (struct frame *); 1252extern void x_free_frame_resources (struct frame *);
1256 1253
diff --git a/src/keyboard.c b/src/keyboard.c
index 4bfe47f3332..352402349c0 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -289,7 +289,7 @@ static struct input_event * volatile kbd_store_ptr;
289 at inopportune times. */ 289 at inopportune times. */
290 290
291/* Symbols to head events. */ 291/* Symbols to head events. */
292static Lisp_Object Qmouse_movement; 292Lisp_Object Qmouse_movement;
293static Lisp_Object Qscroll_bar_movement; 293static Lisp_Object Qscroll_bar_movement;
294Lisp_Object Qswitch_frame; 294Lisp_Object Qswitch_frame;
295static Lisp_Object Qfocus_in, Qfocus_out; 295static Lisp_Object Qfocus_in, Qfocus_out;
@@ -354,6 +354,8 @@ Lisp_Object Qvertical_line;
354static Lisp_Object Qvertical_scroll_bar; 354static Lisp_Object Qvertical_scroll_bar;
355Lisp_Object Qmenu_bar; 355Lisp_Object Qmenu_bar;
356 356
357static Lisp_Object Qecho_keystrokes;
358
357static void recursive_edit_unwind (Lisp_Object buffer); 359static void recursive_edit_unwind (Lisp_Object buffer);
358static Lisp_Object command_loop (void); 360static Lisp_Object command_loop (void);
359static Lisp_Object Qcommand_execute; 361static Lisp_Object Qcommand_execute;
@@ -1305,7 +1307,7 @@ some_mouse_moved (void)
1305 sans error-handling encapsulation. */ 1307 sans error-handling encapsulation. */
1306 1308
1307static int read_key_sequence (Lisp_Object *, int, Lisp_Object, 1309static int read_key_sequence (Lisp_Object *, int, Lisp_Object,
1308 bool, bool, bool); 1310 bool, bool, bool, bool);
1309void safe_run_hooks (Lisp_Object); 1311void safe_run_hooks (Lisp_Object);
1310static void adjust_point_for_property (ptrdiff_t, bool); 1312static void adjust_point_for_property (ptrdiff_t, bool);
1311 1313
@@ -1431,7 +1433,7 @@ command_loop_1 (void)
1431 1433
1432 /* Read next key sequence; i gets its length. */ 1434 /* Read next key sequence; i gets its length. */
1433 i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0], 1435 i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
1434 Qnil, 0, 1, 1); 1436 Qnil, 0, 1, 1, 0);
1435 1437
1436 /* A filter may have run while we were reading the input. */ 1438 /* A filter may have run while we were reading the input. */
1437 if (! FRAME_LIVE_P (XFRAME (selected_frame))) 1439 if (! FRAME_LIVE_P (XFRAME (selected_frame)))
@@ -1691,6 +1693,31 @@ command_loop_1 (void)
1691 } 1693 }
1692} 1694}
1693 1695
1696Lisp_Object
1697read_menu_command (void)
1698{
1699 Lisp_Object cmd;
1700 Lisp_Object keybuf[30];
1701 ptrdiff_t count = SPECPDL_INDEX ();
1702 int i;
1703
1704 /* We don't want to echo the keystrokes while navigating the
1705 menus. */
1706 specbind (Qecho_keystrokes, make_number (0));
1707
1708 i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
1709 Qnil, 0, 1, 1, 1);
1710
1711 unbind_to (count, Qnil);
1712
1713 if (! FRAME_LIVE_P (XFRAME (selected_frame)))
1714 Fkill_emacs (Qnil);
1715 if (i == 0 || i == -1)
1716 return Qt;
1717
1718 return read_key_sequence_cmd;
1719}
1720
1694/* Adjust point to a boundary of a region that has such a property 1721/* Adjust point to a boundary of a region that has such a property
1695 that should be treated intangible. For the moment, we check 1722 that should be treated intangible. For the moment, we check
1696 `composition', `display' and `invisible' properties. 1723 `composition', `display' and `invisible' properties.
@@ -2358,6 +2385,7 @@ read_decoded_event_from_main_queue (struct timespec *end_time,
2358/* Read a character from the keyboard; call the redisplay if needed. */ 2385/* Read a character from the keyboard; call the redisplay if needed. */
2359/* commandflag 0 means do not autosave, but do redisplay. 2386/* commandflag 0 means do not autosave, but do redisplay.
2360 -1 means do not redisplay, but do autosave. 2387 -1 means do not redisplay, but do autosave.
2388 -2 means do neither.
2361 1 means do both. */ 2389 1 means do both. */
2362 2390
2363/* The arguments MAP is for menu prompting. MAP is a keymap. 2391/* The arguments MAP is for menu prompting. MAP is a keymap.
@@ -2722,7 +2750,7 @@ read_char (int commandflag, Lisp_Object map,
2722 2750
2723 /* Maybe auto save due to number of keystrokes. */ 2751 /* Maybe auto save due to number of keystrokes. */
2724 2752
2725 if (commandflag != 0 2753 if (commandflag != 0 && commandflag != -2
2726 && auto_save_interval > 0 2754 && auto_save_interval > 0
2727 && num_nonmacro_input_events - last_auto_save > max (auto_save_interval, 20) 2755 && num_nonmacro_input_events - last_auto_save > max (auto_save_interval, 20)
2728 && !detect_input_pending_run_timers (0)) 2756 && !detect_input_pending_run_timers (0))
@@ -2774,7 +2802,7 @@ read_char (int commandflag, Lisp_Object map,
2774 9 at 200k, 11 at 300k, and 12 at 500k. It is 15 at 1 meg. */ 2802 9 at 200k, 11 at 300k, and 12 at 500k. It is 15 at 1 meg. */
2775 2803
2776 /* Auto save if enough time goes by without input. */ 2804 /* Auto save if enough time goes by without input. */
2777 if (commandflag != 0 2805 if (commandflag != 0 && commandflag != -2
2778 && num_nonmacro_input_events > last_auto_save 2806 && num_nonmacro_input_events > last_auto_save
2779 && INTEGERP (Vauto_save_timeout) 2807 && INTEGERP (Vauto_save_timeout)
2780 && XINT (Vauto_save_timeout) > 0) 2808 && XINT (Vauto_save_timeout) > 0)
@@ -3870,7 +3898,22 @@ kbd_buffer_get_event (KBOARD **kbp,
3870 } 3898 }
3871 } 3899 }
3872 else 3900 else
3873 wait_reading_process_output (0, 0, -1, 1, Qnil, NULL, 0); 3901 {
3902 bool do_display = true;
3903
3904 if (FRAME_TERMCAP_P (SELECTED_FRAME ()))
3905 {
3906 struct tty_display_info *tty = CURTTY ();
3907
3908 /* When this TTY is displaying a menu, we must prevent
3909 any redisplay, because we modify the frame's glyph
3910 matrix behind the back of the display engine. */
3911 if (tty->showing_menu)
3912 do_display = false;
3913 }
3914
3915 wait_reading_process_output (0, 0, -1, do_display, Qnil, NULL, 0);
3916 }
3874 3917
3875 if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr) 3918 if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
3876 gobble_input (); 3919 gobble_input ();
@@ -5363,6 +5406,20 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
5363 extra_info)))); 5406 extra_info))));
5364} 5407}
5365 5408
5409/* Return non-zero if F is a GUI frame that uses some toolkit-managed
5410 menu bar. This really means that Emacs draws and manages the menu
5411 bar as part of its normal display, and therefore can compute its
5412 geometry. */
5413static bool
5414toolkit_menubar_in_use (struct frame *f)
5415{
5416#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI)
5417 return !(!FRAME_WINDOW_P (f));
5418#else
5419 return false;
5420#endif
5421}
5422
5366/* Given a struct input_event, build the lisp event which represents 5423/* Given a struct input_event, build the lisp event which represents
5367 it. If EVENT is 0, build a mouse movement event from the mouse 5424 it. If EVENT is 0, build a mouse movement event from the mouse
5368 movement buffer, which should have a movement event in it. 5425 movement buffer, which should have a movement event in it.
@@ -5514,64 +5571,64 @@ make_lispy_event (struct input_event *event)
5514 if (event->kind == MOUSE_CLICK_EVENT) 5571 if (event->kind == MOUSE_CLICK_EVENT)
5515 { 5572 {
5516 struct frame *f = XFRAME (event->frame_or_window); 5573 struct frame *f = XFRAME (event->frame_or_window);
5517#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) && ! defined (HAVE_NS)
5518 int row, column; 5574 int row, column;
5519#endif
5520 5575
5521 /* Ignore mouse events that were made on frame that 5576 /* Ignore mouse events that were made on frame that
5522 have been deleted. */ 5577 have been deleted. */
5523 if (! FRAME_LIVE_P (f)) 5578 if (! FRAME_LIVE_P (f))
5524 return Qnil; 5579 return Qnil;
5525 5580
5526#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) && ! defined (HAVE_NS)
5527 /* EVENT->x and EVENT->y are frame-relative pixel 5581 /* EVENT->x and EVENT->y are frame-relative pixel
5528 coordinates at this place. Under old redisplay, COLUMN 5582 coordinates at this place. Under old redisplay, COLUMN
5529 and ROW are set to frame relative glyph coordinates 5583 and ROW are set to frame relative glyph coordinates
5530 which are then used to determine whether this click is 5584 which are then used to determine whether this click is
5531 in a menu (non-toolkit version). */ 5585 in a menu (non-toolkit version). */
5532 pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y), 5586 if (!toolkit_menubar_in_use (f))
5533 &column, &row, NULL, 1);
5534
5535 /* In the non-toolkit version, clicks on the menu bar
5536 are ordinary button events in the event buffer.
5537 Distinguish them, and invoke the menu.
5538
5539 (In the toolkit version, the toolkit handles the menu bar
5540 and Emacs doesn't know about it until after the user
5541 makes a selection.) */
5542 if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)
5543 && (event->modifiers & down_modifier))
5544 { 5587 {
5545 Lisp_Object items, item; 5588 pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
5546 5589 &column, &row, NULL, 1);
5547 /* Find the menu bar item under `column'. */ 5590
5548 item = Qnil; 5591 /* In the non-toolkit version, clicks on the menu bar
5549 items = FRAME_MENU_BAR_ITEMS (f); 5592 are ordinary button events in the event buffer.
5550 for (i = 0; i < ASIZE (items); i += 4) 5593 Distinguish them, and invoke the menu.
5594
5595 (In the toolkit version, the toolkit handles the
5596 menu bar and Emacs doesn't know about it until
5597 after the user makes a selection.) */
5598 if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)
5599 && (event->modifiers & down_modifier))
5551 { 5600 {
5552 Lisp_Object pos, string; 5601 Lisp_Object items, item;
5553 string = AREF (items, i + 1); 5602
5554 pos = AREF (items, i + 3); 5603 /* Find the menu bar item under `column'. */
5555 if (NILP (string)) 5604 item = Qnil;
5556 break; 5605 items = FRAME_MENU_BAR_ITEMS (f);
5557 if (column >= XINT (pos) 5606 for (i = 0; i < ASIZE (items); i += 4)
5558 && column < XINT (pos) + SCHARS (string))
5559 { 5607 {
5560 item = AREF (items, i); 5608 Lisp_Object pos, string;
5561 break; 5609 string = AREF (items, i + 1);
5610 pos = AREF (items, i + 3);
5611 if (NILP (string))
5612 break;
5613 if (column >= XINT (pos)
5614 && column < XINT (pos) + SCHARS (string))
5615 {
5616 item = AREF (items, i);
5617 break;
5618 }
5562 } 5619 }
5563 }
5564 5620
5565 /* ELisp manual 2.4b says (x y) are window relative but 5621 /* ELisp manual 2.4b says (x y) are window
5566 code says they are frame-relative. */ 5622 relative but code says they are
5567 position = list4 (event->frame_or_window, 5623 frame-relative. */
5568 Qmenu_bar, 5624 position = list4 (event->frame_or_window,
5569 Fcons (event->x, event->y), 5625 Qmenu_bar,
5570 make_number (event->timestamp)); 5626 Fcons (event->x, event->y),
5627 make_number (event->timestamp));
5571 5628
5572 return list2 (item, position); 5629 return list2 (item, position);
5630 }
5573 } 5631 }
5574#endif /* not USE_X_TOOLKIT && not USE_GTK && not HAVE_NS */
5575 5632
5576 position = make_lispy_position (f, event->x, event->y, 5633 position = make_lispy_position (f, event->x, event->y,
5577 event->timestamp); 5634 event->timestamp);
@@ -8792,6 +8849,9 @@ test_undefined (Lisp_Object binding)
8792 8849
8793 Echo starting immediately unless `prompt' is 0. 8850 Echo starting immediately unless `prompt' is 0.
8794 8851
8852 If PREVENT_REDISPLAY is non-zero, avoid redisplay by calling
8853 read_char with a suitable COMMANDFLAG argument.
8854
8795 Where a key sequence ends depends on the currently active keymaps. 8855 Where a key sequence ends depends on the currently active keymaps.
8796 These include any minor mode keymaps active in the current buffer, 8856 These include any minor mode keymaps active in the current buffer,
8797 the current buffer's local map, and the global map. 8857 the current buffer's local map, and the global map.
@@ -8824,7 +8884,7 @@ test_undefined (Lisp_Object binding)
8824static int 8884static int
8825read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, 8885read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
8826 bool dont_downcase_last, bool can_return_switch_frame, 8886 bool dont_downcase_last, bool can_return_switch_frame,
8827 bool fix_current_buffer) 8887 bool fix_current_buffer, bool prevent_redisplay)
8828{ 8888{
8829 ptrdiff_t count = SPECPDL_INDEX (); 8889 ptrdiff_t count = SPECPDL_INDEX ();
8830 8890
@@ -8905,8 +8965,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
8905 { 8965 {
8906 if (!NILP (prompt)) 8966 if (!NILP (prompt))
8907 { 8967 {
8908 /* Install the string STR as the beginning of the string of 8968 /* Install the string PROMPT as the beginning of the string
8909 echoing, so that it serves as a prompt for the next 8969 of echoing, so that it serves as a prompt for the next
8910 character. */ 8970 character. */
8911 kset_echo_string (current_kboard, prompt); 8971 kset_echo_string (current_kboard, prompt);
8912 current_kboard->echo_after_prompt = SCHARS (prompt); 8972 current_kboard->echo_after_prompt = SCHARS (prompt);
@@ -9061,7 +9121,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
9061 { 9121 {
9062 KBOARD *interrupted_kboard = current_kboard; 9122 KBOARD *interrupted_kboard = current_kboard;
9063 struct frame *interrupted_frame = SELECTED_FRAME (); 9123 struct frame *interrupted_frame = SELECTED_FRAME ();
9064 key = read_char (NILP (prompt), 9124 /* Calling read_char with COMMANDFLAG = -2 avoids
9125 redisplay in read_char and its subroutines. */
9126 key = read_char (prevent_redisplay ? -2 : NILP (prompt),
9065 current_binding, last_nonmenu_event, 9127 current_binding, last_nonmenu_event,
9066 &used_mouse_menu, NULL); 9128 &used_mouse_menu, NULL);
9067 if ((INTEGERP (key) && XINT (key) == -2) /* wrong_kboard_jmpbuf */ 9129 if ((INTEGERP (key) && XINT (key) == -2) /* wrong_kboard_jmpbuf */
@@ -9757,7 +9819,7 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
9757 9819
9758 i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])), 9820 i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])),
9759 prompt, ! NILP (dont_downcase_last), 9821 prompt, ! NILP (dont_downcase_last),
9760 ! NILP (can_return_switch_frame), 0); 9822 ! NILP (can_return_switch_frame), 0, 0);
9761 9823
9762#if 0 /* The following is fine for code reading a key sequence and 9824#if 0 /* The following is fine for code reading a key sequence and
9763 then proceeding with a lengthy computation, but it's not good 9825 then proceeding with a lengthy computation, but it's not good
@@ -11003,6 +11065,8 @@ syms_of_keyboard (void)
11003 11065
11004 DEFSYM (Qhelp_form_show, "help-form-show"); 11066 DEFSYM (Qhelp_form_show, "help-form-show");
11005 11067
11068 DEFSYM (Qecho_keystrokes, "echo-keystrokes");
11069
11006 Fset (Qinput_method_exit_on_first_char, Qnil); 11070 Fset (Qinput_method_exit_on_first_char, Qnil);
11007 Fset (Qinput_method_use_echo_area, Qnil); 11071 Fset (Qinput_method_use_echo_area, Qnil);
11008 11072
diff --git a/src/keyboard.h b/src/keyboard.h
index 49f87b20a43..8a8505e406b 100644
--- a/src/keyboard.h
+++ b/src/keyboard.h
@@ -450,7 +450,7 @@ extern Lisp_Object Qswitch_frame;
450extern Lisp_Object Qevent_kind; 450extern Lisp_Object Qevent_kind;
451 451
452/* The values of Qevent_kind properties. */ 452/* The values of Qevent_kind properties. */
453extern Lisp_Object Qmouse_click; 453extern Lisp_Object Qmouse_click, Qmouse_movement;
454 454
455extern Lisp_Object Qhelp_echo; 455extern Lisp_Object Qhelp_echo;
456 456
diff --git a/src/menu.c b/src/menu.c
index 44bb5a57317..f741d686cd1 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
30#include "termhooks.h" 30#include "termhooks.h"
31#include "blockinput.h" 31#include "blockinput.h"
32#include "dispextern.h" 32#include "dispextern.h"
33#include "buffer.h"
33 34
34#ifdef USE_X_TOOLKIT 35#ifdef USE_X_TOOLKIT
35#include "../lwlib/lwlib.h" 36#include "../lwlib/lwlib.h"
@@ -50,10 +51,16 @@ extern HMENU current_popup_menu;
50 51
51#include "menu.h" 52#include "menu.h"
52 53
53/* Define HAVE_BOXES if menus can handle radio and toggle buttons. */ 54/* Return non-zero if menus can handle radio and toggle buttons. */
55static bool
56have_boxes (void)
57{
54#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) 58#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI)
55#define HAVE_BOXES 1 59 if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame)))
60 return 1;
56#endif 61#endif
62 return 0;
63}
57 64
58Lisp_Object menu_items; 65Lisp_Object menu_items;
59 66
@@ -283,13 +290,14 @@ single_keymap_panes (Lisp_Object keymap, Lisp_Object pane_name,
283 290
284 push_menu_pane (pane_name, prefix); 291 push_menu_pane (pane_name, prefix);
285 292
286#ifndef HAVE_BOXES 293 if (!have_boxes ())
287 /* Remember index for first item in this pane so we can go back and 294 {
288 add a prefix when (if) we see the first button. After that, notbuttons 295 /* Remember index for first item in this pane so we can go back
289 is set to 0, to mark that we have seen a button and all non button 296 and add a prefix when (if) we see the first button. After
290 items need a prefix. */ 297 that, notbuttons is set to 0, to mark that we have seen a
291 skp.notbuttons = menu_items_used; 298 button and all non button items need a prefix. */
292#endif 299 skp.notbuttons = menu_items_used;
300 }
293 301
294 GCPRO1 (skp.pending_maps); 302 GCPRO1 (skp.pending_maps);
295 map_keymap_canonical (keymap, single_menu_item, Qnil, &skp); 303 map_keymap_canonical (keymap, single_menu_item, Qnil, &skp);
@@ -345,77 +353,72 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
345 return; 353 return;
346 } 354 }
347 355
348#if defined (HAVE_X_WINDOWS) || defined (MSDOS)
349#ifndef HAVE_BOXES
350 /* Simulate radio buttons and toggle boxes by putting a prefix in 356 /* Simulate radio buttons and toggle boxes by putting a prefix in
351 front of them. */ 357 front of them. */
352 { 358 if (!have_boxes ())
353 Lisp_Object prefix = Qnil; 359 {
354 Lisp_Object type = AREF (item_properties, ITEM_PROPERTY_TYPE); 360 Lisp_Object prefix = Qnil;
355 if (!NILP (type)) 361 Lisp_Object type = AREF (item_properties, ITEM_PROPERTY_TYPE);
356 { 362 if (!NILP (type))
357 Lisp_Object selected 363 {
358 = AREF (item_properties, ITEM_PROPERTY_SELECTED); 364 Lisp_Object selected
365 = AREF (item_properties, ITEM_PROPERTY_SELECTED);
359 366
360 if (skp->notbuttons) 367 if (skp->notbuttons)
361 /* The first button. Line up previous items in this menu. */ 368 /* The first button. Line up previous items in this menu. */
362 { 369 {
363 int idx = skp->notbuttons; /* Index for first item this menu. */ 370 int idx = skp->notbuttons; /* Index for first item this menu. */
364 int submenu = 0; 371 int submenu = 0;
365 Lisp_Object tem; 372 Lisp_Object tem;
366 while (idx < menu_items_used) 373 while (idx < menu_items_used)
367 { 374 {
368 tem 375 tem
369 = AREF (menu_items, idx + MENU_ITEMS_ITEM_NAME); 376 = AREF (menu_items, idx + MENU_ITEMS_ITEM_NAME);
370 if (NILP (tem)) 377 if (NILP (tem))
371 { 378 {
372 idx++; 379 idx++;
373 submenu++; /* Skip sub menu. */ 380 submenu++; /* Skip sub menu. */
374 } 381 }
375 else if (EQ (tem, Qlambda)) 382 else if (EQ (tem, Qlambda))
376 { 383 {
377 idx++; 384 idx++;
378 submenu--; /* End sub menu. */ 385 submenu--; /* End sub menu. */
379 } 386 }
380 else if (EQ (tem, Qt)) 387 else if (EQ (tem, Qt))
381 idx += 3; /* Skip new pane marker. */ 388 idx += 3; /* Skip new pane marker. */
382 else if (EQ (tem, Qquote)) 389 else if (EQ (tem, Qquote))
383 idx++; /* Skip a left, right divider. */ 390 idx++; /* Skip a left, right divider. */
384 else 391 else
385 { 392 {
386 if (!submenu && SREF (tem, 0) != '\0' 393 if (!submenu && SREF (tem, 0) != '\0'
387 && SREF (tem, 0) != '-') 394 && SREF (tem, 0) != '-')
388 ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME, 395 ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
389 concat2 (build_string (" "), tem)); 396 concat2 (build_string (" "), tem));
390 idx += MENU_ITEMS_ITEM_LENGTH; 397 idx += MENU_ITEMS_ITEM_LENGTH;
391 } 398 }
392 } 399 }
393 skp->notbuttons = 0; 400 skp->notbuttons = 0;
394 } 401 }
395 402
396 /* Calculate prefix, if any, for this item. */ 403 /* Calculate prefix, if any, for this item. */
397 if (EQ (type, QCtoggle)) 404 if (EQ (type, QCtoggle))
398 prefix = build_string (NILP (selected) ? "[ ] " : "[X] "); 405 prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
399 else if (EQ (type, QCradio)) 406 else if (EQ (type, QCradio))
400 prefix = build_string (NILP (selected) ? "( ) " : "(*) "); 407 prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
401 } 408 }
402 /* Not a button. If we have earlier buttons, then we need a prefix. */ 409 /* Not a button. If we have earlier buttons, then we need a prefix. */
403 else if (!skp->notbuttons && SREF (item_string, 0) != '\0' 410 else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
404 && SREF (item_string, 0) != '-') 411 && SREF (item_string, 0) != '-')
405 prefix = build_string (" "); 412 prefix = build_string (" ");
406 413
407 if (!NILP (prefix)) 414 if (!NILP (prefix))
408 item_string = concat2 (prefix, item_string); 415 item_string = concat2 (prefix, item_string);
409 } 416 }
410#endif /* not HAVE_BOXES */
411 417
412#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) 418 if (FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame))
413 if (!NILP (map)) 419 && !NILP (map))
414 /* Indicate visually that this is a submenu. */ 420 /* Indicate visually that this is a submenu. */
415 item_string = concat2 (item_string, build_string (" >")); 421 item_string = concat2 (item_string, build_string (" >"));
416#endif
417
418#endif /* HAVE_X_WINDOWS || MSDOS */
419 422
420 push_menu_item (item_string, enabled, key, 423 push_menu_item (item_string, enabled, key,
421 AREF (item_properties, ITEM_PROPERTY_DEF), 424 AREF (item_properties, ITEM_PROPERTY_DEF),
@@ -426,7 +429,8 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
426 429
427#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI) 430#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI)
428 /* Display a submenu using the toolkit. */ 431 /* Display a submenu using the toolkit. */
429 if (! (NILP (map) || NILP (enabled))) 432 if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame))
433 && ! (NILP (map) || NILP (enabled)))
430 { 434 {
431 push_submenu_start (); 435 push_submenu_start ();
432 single_keymap_panes (map, Qnil, key, skp->maxdepth - 1); 436 single_keymap_panes (map, Qnil, key, skp->maxdepth - 1);
@@ -455,6 +459,16 @@ keymap_panes (Lisp_Object *keymaps, ptrdiff_t nmaps)
455 finish_menu_items (); 459 finish_menu_items ();
456} 460}
457 461
462/* Encode a menu string as appropriate for menu-updating-frame's type. */
463static Lisp_Object
464encode_menu_string (Lisp_Object str)
465{
466 /* TTY menu strings are encoded by write_glyphs, when they are
467 delivered to the glass, so no need to encode them here. */
468 if (FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame)))
469 return str;
470 return ENCODE_MENU_STRING (str);
471}
458 472
459/* Push the items in a single pane defined by the alist PANE. */ 473/* Push the items in a single pane defined by the alist PANE. */
460static void 474static void
@@ -466,13 +480,13 @@ list_of_items (Lisp_Object pane)
466 { 480 {
467 item = XCAR (tail); 481 item = XCAR (tail);
468 if (STRINGP (item)) 482 if (STRINGP (item))
469 push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt, 483 push_menu_item (encode_menu_string (item), Qnil, Qnil, Qt,
470 Qnil, Qnil, Qnil, Qnil); 484 Qnil, Qnil, Qnil, Qnil);
471 else if (CONSP (item)) 485 else if (CONSP (item))
472 { 486 {
473 item1 = XCAR (item); 487 item1 = XCAR (item);
474 CHECK_STRING (item1); 488 CHECK_STRING (item1);
475 push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item), 489 push_menu_item (encode_menu_string (item1), Qt, XCDR (item),
476 Qt, Qnil, Qnil, Qnil, Qnil); 490 Qt, Qnil, Qnil, Qnil, Qnil);
477 } 491 }
478 else 492 else
@@ -497,7 +511,7 @@ list_of_panes (Lisp_Object menu)
497 elt = XCAR (tail); 511 elt = XCAR (tail);
498 pane_name = Fcar (elt); 512 pane_name = Fcar (elt);
499 CHECK_STRING (pane_name); 513 CHECK_STRING (pane_name);
500 push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil); 514 push_menu_pane (encode_menu_string (pane_name), Qnil);
501 pane_data = Fcdr (elt); 515 pane_data = Fcdr (elt);
502 CHECK_CONS (pane_data); 516 CHECK_CONS (pane_data);
503 list_of_items (pane_data); 517 list_of_items (pane_data);
@@ -614,6 +628,7 @@ digest_single_submenu (int start, int end, bool top_level_items)
614 int submenu_depth = 0; 628 int submenu_depth = 0;
615 widget_value **submenu_stack; 629 widget_value **submenu_stack;
616 bool panes_seen = 0; 630 bool panes_seen = 0;
631 struct frame *f = XFRAME (Vmenu_updating_frame);
617 632
618 submenu_stack = alloca (menu_items_used * sizeof *submenu_stack); 633 submenu_stack = alloca (menu_items_used * sizeof *submenu_stack);
619 wv = xmalloc_widget_value (); 634 wv = xmalloc_widget_value ();
@@ -663,30 +678,35 @@ digest_single_submenu (int start, int end, bool top_level_items)
663 678
664 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); 679 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
665 680
666#ifdef HAVE_NTGUI 681 /* TTY menus display menu items via tty_write_glyphs, which
667 if (STRINGP (pane_name)) 682 will encode the strings as appropriate. */
683 if (!FRAME_TERMCAP_P (f))
668 { 684 {
669 if (unicode_append_menu) 685#ifdef HAVE_NTGUI
670 /* Encode as UTF-8 for now. */ 686 if (STRINGP (pane_name))
671 pane_name = ENCODE_UTF_8 (pane_name); 687 {
672 else if (STRING_MULTIBYTE (pane_name)) 688 if (unicode_append_menu)
673 pane_name = ENCODE_SYSTEM (pane_name); 689 /* Encode as UTF-8 for now. */
690 pane_name = ENCODE_UTF_8 (pane_name);
691 else if (STRING_MULTIBYTE (pane_name))
692 pane_name = ENCODE_SYSTEM (pane_name);
674 693
675 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); 694 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
676 } 695 }
677#elif defined (USE_LUCID) && defined (HAVE_XFT) 696#elif defined (USE_LUCID) && defined (HAVE_XFT)
678 if (STRINGP (pane_name)) 697 if (STRINGP (pane_name))
679 { 698 {
680 pane_name = ENCODE_UTF_8 (pane_name); 699 pane_name = ENCODE_UTF_8 (pane_name);
681 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); 700 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
682 } 701 }
683#elif !defined (HAVE_MULTILINGUAL_MENU) 702#elif !defined (HAVE_MULTILINGUAL_MENU)
684 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) 703 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
685 { 704 {
686 pane_name = ENCODE_MENU_STRING (pane_name); 705 pane_name = ENCODE_MENU_STRING (pane_name);
687 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); 706 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
688 } 707 }
689#endif 708#endif
709 }
690 710
691 pane_string = (NILP (pane_name) 711 pane_string = (NILP (pane_name)
692 ? "" : SSDATA (pane_name)); 712 ? "" : SSDATA (pane_name));
@@ -737,47 +757,52 @@ digest_single_submenu (int start, int end, bool top_level_items)
737 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED); 757 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
738 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); 758 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
739 759
740#ifdef HAVE_NTGUI 760 /* TTY menu items and their descriptions will be encoded by
741 if (STRINGP (item_name)) 761 tty_write_glyphs. */
762 if (!FRAME_TERMCAP_P (f))
742 { 763 {
743 if (unicode_append_menu) 764#ifdef HAVE_NTGUI
744 item_name = ENCODE_UTF_8 (item_name); 765 if (STRINGP (item_name))
745 else if (STRING_MULTIBYTE (item_name)) 766 {
746 item_name = ENCODE_SYSTEM (item_name); 767 if (unicode_append_menu)
768 item_name = ENCODE_UTF_8 (item_name);
769 else if (STRING_MULTIBYTE (item_name))
770 item_name = ENCODE_SYSTEM (item_name);
747 771
748 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); 772 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
749 } 773 }
750 774
751 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) 775 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
752 { 776 {
753 descrip = ENCODE_SYSTEM (descrip); 777 descrip = ENCODE_SYSTEM (descrip);
754 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); 778 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
755 } 779 }
756#elif USE_LUCID 780#elif USE_LUCID
757 if (STRINGP (item_name)) 781 if (STRINGP (item_name))
758 { 782 {
759 item_name = ENCODE_UTF_8 (item_name); 783 item_name = ENCODE_UTF_8 (item_name);
760 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); 784 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
761 } 785 }
762 786
763 if (STRINGP (descrip)) 787 if (STRINGP (descrip))
764 { 788 {
765 descrip = ENCODE_UTF_8 (descrip); 789 descrip = ENCODE_UTF_8 (descrip);
766 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); 790 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
767 } 791 }
768#elif !defined (HAVE_MULTILINGUAL_MENU) 792#elif !defined (HAVE_MULTILINGUAL_MENU)
769 if (STRING_MULTIBYTE (item_name)) 793 if (STRING_MULTIBYTE (item_name))
770 { 794 {
771 item_name = ENCODE_MENU_STRING (item_name); 795 item_name = ENCODE_MENU_STRING (item_name);
772 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); 796 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
773 } 797 }
774 798
775 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) 799 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
776 { 800 {
777 descrip = ENCODE_MENU_STRING (descrip); 801 descrip = ENCODE_MENU_STRING (descrip);
778 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); 802 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
779 } 803 }
780#endif 804#endif
805 }
781 806
782 wv = xmalloc_widget_value (); 807 wv = xmalloc_widget_value ();
783 if (prev_wv) 808 if (prev_wv)
@@ -1011,6 +1036,85 @@ find_and_return_menu_selection (struct frame *f, bool keymaps, void *client_data
1011} 1036}
1012#endif /* HAVE_NS */ 1037#endif /* HAVE_NS */
1013 1038
1039int
1040menu_item_width (const char *str)
1041{
1042 int len;
1043 const char *p;
1044
1045 for (len = 0, p = str; *p; )
1046 {
1047 int ch_len;
1048 int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
1049
1050 len += CHAR_WIDTH (ch);
1051 p += ch_len;
1052 }
1053 return len;
1054}
1055
1056DEFUN ("menu-bar-menu-at-x-y", Fmenu_bar_menu_at_x_y, Smenu_bar_menu_at_x_y,
1057 2, 3, 0,
1058 doc: /* Return the menu-bar menu on FRAME at pixel coordinates X, Y.
1059X and Y are frame-relative pixel coordinates, assumed to define
1060a location within the menu bar.
1061If FRAME is nil or omitted, it defaults to the selected frame.
1062
1063Value is the symbol of the menu at X/Y, or nil if the specified
1064coordinates are not within the FRAME's menu bar. The symbol can
1065be used to look up the menu like this:
1066
1067 (lookup-key MAP [menu-bar SYMBOL])
1068
1069where MAP is either the current global map or the current local map,
1070since menu-bar items come from both.
1071
1072This function can return non-nil only on a text-terminal frame
1073or on an X frame that doesn't use any GUI toolkit. Otherwise,
1074Emacs does not manage the menu bar and cannot convert coordinates
1075into menu items. */)
1076 (Lisp_Object x, Lisp_Object y, Lisp_Object frame)
1077{
1078 int row, col;
1079 struct frame *f = decode_any_frame (frame);
1080
1081 if (!FRAME_LIVE_P (f))
1082 return Qnil;
1083
1084 pixel_to_glyph_coords (f, XINT (x), XINT (y), &col, &row, NULL, 1);
1085 if (0 <= row && row < FRAME_MENU_BAR_LINES (f))
1086 {
1087 Lisp_Object items, item;
1088 int i;
1089
1090 /* Find the menu bar item under `col'. */
1091 item = Qnil;
1092 items = FRAME_MENU_BAR_ITEMS (f);
1093 /* This loop assumes a single menu-bar line, and will fail to
1094 find an item if it is not in the first line. Note that
1095 make_lispy_event in keyboard.c makes the same assumption. */
1096 for (i = 0; i < ASIZE (items); i += 4)
1097 {
1098 Lisp_Object pos, str;
1099
1100 str = AREF (items, i + 1);
1101 pos = AREF (items, i + 3);
1102 if (NILP (str))
1103 return item;
1104 if (XINT (pos) <= col
1105 /* We use <= so the blank between 2 items on a TTY is
1106 considered part of the previous item. */
1107 && col <= XINT (pos) + menu_item_width (SSDATA (str)))
1108 {
1109 item = AREF (items, i);
1110 return item;
1111 }
1112 }
1113 }
1114 return Qnil;
1115}
1116
1117
1014DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0, 1118DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
1015 doc: /* Pop up a deck-of-cards menu and return user's selection. 1119 doc: /* Pop up a deck-of-cards menu and return user's selection.
1016POSITION is a position specification. This is either a mouse button event 1120POSITION is a position specification. This is either a mouse button event
@@ -1056,7 +1160,7 @@ event (indicating that the user invoked the menu with the mouse) then
1056no quit occurs and `x-popup-menu' returns nil. */) 1160no quit occurs and `x-popup-menu' returns nil. */)
1057 (Lisp_Object position, Lisp_Object menu) 1161 (Lisp_Object position, Lisp_Object menu)
1058{ 1162{
1059 Lisp_Object keymap, tem; 1163 Lisp_Object keymap, tem, tem2;
1060 int xpos = 0, ypos = 0; 1164 int xpos = 0, ypos = 0;
1061 Lisp_Object title; 1165 Lisp_Object title;
1062 const char *error_name = NULL; 1166 const char *error_name = NULL;
@@ -1065,6 +1169,7 @@ no quit occurs and `x-popup-menu' returns nil. */)
1065 Lisp_Object x, y, window; 1169 Lisp_Object x, y, window;
1066 bool keymaps = 0; 1170 bool keymaps = 0;
1067 bool for_click = 0; 1171 bool for_click = 0;
1172 bool kbd_menu_navigation = 0;
1068 ptrdiff_t specpdl_count = SPECPDL_INDEX (); 1173 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1069 struct gcpro gcpro1; 1174 struct gcpro gcpro1;
1070 1175
@@ -1077,8 +1182,6 @@ no quit occurs and `x-popup-menu' returns nil. */)
1077 { 1182 {
1078 bool get_current_pos_p = 0; 1183 bool get_current_pos_p = 0;
1079 1184
1080 check_window_system (SELECTED_FRAME ());
1081
1082 /* Decode the first argument: find the window and the coordinates. */ 1185 /* Decode the first argument: find the window and the coordinates. */
1083 if (EQ (position, Qt) 1186 if (EQ (position, Qt)
1084 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) 1187 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
@@ -1100,6 +1203,22 @@ no quit occurs and `x-popup-menu' returns nil. */)
1100 for_click = 1; 1203 for_click = 1;
1101 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */ 1204 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
1102 window = Fcar (tem); /* POSN_WINDOW (tem) */ 1205 window = Fcar (tem); /* POSN_WINDOW (tem) */
1206 tem2 = Fcar (Fcdr (tem)); /* POSN_POSN (tem) */
1207 /* The kbd_menu_navigation flag is set when the menu was
1208 invoked by F10, which probably means they have no
1209 mouse. In that case, we let them switch between
1210 top-level menu-bar menus by using C-f/C-b and
1211 horizontal arrow keys, since they cannot click the
1212 mouse to open a different submenu. This flag is only
1213 supported by tty_menu_show. We set it when POSITION
1214 and last_nonmenu_event are different, which means we
1215 constructed POSITION by hand (in popup-menu, see
1216 menu-bar.el) to look like a mouse click on the menu bar
1217 event. */
1218 if (!EQ (POSN_POSN (last_nonmenu_event),
1219 POSN_POSN (position))
1220 && CONSP (tem2) && EQ (Fcar (tem2), Qmenu_bar))
1221 kbd_menu_navigation = 1;
1103 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */ 1222 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
1104 x = Fcar (tem); 1223 x = Fcar (tem);
1105 y = Fcdr (tem); 1224 y = Fcdr (tem);
@@ -1194,11 +1313,6 @@ no quit occurs and `x-popup-menu' returns nil. */)
1194 xpos += XINT (x); 1313 xpos += XINT (x);
1195 ypos += XINT (y); 1314 ypos += XINT (y);
1196 1315
1197 /* FIXME: Find a more general check! */
1198 if (!(FRAME_X_P (f) || FRAME_MSDOS_P (f)
1199 || FRAME_W32_P (f) || FRAME_NS_P (f)))
1200 error ("Can not put GUI menu on this terminal");
1201
1202 XSETFRAME (Vmenu_updating_frame, f); 1316 XSETFRAME (Vmenu_updating_frame, f);
1203 } 1317 }
1204#endif /* HAVE_MENUS */ 1318#endif /* HAVE_MENUS */
@@ -1287,7 +1401,8 @@ no quit occurs and `x-popup-menu' returns nil. */)
1287#ifdef HAVE_MENUS 1401#ifdef HAVE_MENUS
1288#ifdef HAVE_WINDOW_SYSTEM 1402#ifdef HAVE_WINDOW_SYSTEM
1289 /* Hide a previous tip, if any. */ 1403 /* Hide a previous tip, if any. */
1290 Fx_hide_tip (); 1404 if (!FRAME_TERMCAP_P (f))
1405 Fx_hide_tip ();
1291#endif 1406#endif
1292 1407
1293#ifdef HAVE_NTGUI /* FIXME: Is it really w32-specific? --Stef */ 1408#ifdef HAVE_NTGUI /* FIXME: Is it really w32-specific? --Stef */
@@ -1296,7 +1411,7 @@ no quit occurs and `x-popup-menu' returns nil. */)
1296 can occur if you press ESC or click outside a menu without selecting 1411 can occur if you press ESC or click outside a menu without selecting
1297 a menu item. 1412 a menu item.
1298 */ 1413 */
1299 if (current_popup_menu) 1414 if (current_popup_menu && FRAME_W32_P (f))
1300 { 1415 {
1301 discard_menu_items (); 1416 discard_menu_items ();
1302 FRAME_DISPLAY_INFO (f)->grabbed = 0; 1417 FRAME_DISPLAY_INFO (f)->grabbed = 0;
@@ -1310,26 +1425,34 @@ no quit occurs and `x-popup-menu' returns nil. */)
1310#endif 1425#endif
1311 1426
1312 /* Display them in a menu. */ 1427 /* Display them in a menu. */
1313 block_input ();
1314 1428
1315 /* FIXME: Use a terminal hook! */ 1429 /* FIXME: Use a terminal hook! */
1316#if defined HAVE_NTGUI 1430#if defined HAVE_NTGUI
1317 selection = w32_menu_show (f, xpos, ypos, for_click, 1431 if (FRAME_W32_P (f))
1318 keymaps, title, &error_name); 1432 selection = w32_menu_show (f, xpos, ypos, for_click,
1319#elif defined HAVE_NS 1433 keymaps, title, &error_name);
1320 selection = ns_menu_show (f, xpos, ypos, for_click, 1434 else
1321 keymaps, title, &error_name); 1435#endif
1322#else /* MSDOS and X11 */ 1436#if defined HAVE_NS
1437 if (FRAME_NS_P (f))
1438 selection = ns_menu_show (f, xpos, ypos, for_click,
1439 keymaps, title, &error_name);
1440 else
1441#endif
1442#if (defined (HAVE_X_WINDOWS) || defined (MSDOS))
1323 /* Assume last_event_timestamp is the timestamp of the button event. 1443 /* Assume last_event_timestamp is the timestamp of the button event.
1324 Is this assumption ever violated? We can't use the timestamp 1444 Is this assumption ever violated? We can't use the timestamp
1325 stored within POSITION because there the top bits from the actual 1445 stored within POSITION because there the top bits from the actual
1326 timestamp may be truncated away (Bug#4930). */ 1446 timestamp may be truncated away (Bug#4930). */
1327 selection = xmenu_show (f, xpos, ypos, for_click, 1447 if (FRAME_X_P (f) || FRAME_MSDOS_P (f))
1328 keymaps, title, &error_name, 1448 selection = xmenu_show (f, xpos, ypos, for_click,
1329 last_event_timestamp); 1449 keymaps, title, &error_name,
1450 last_event_timestamp);
1451 else
1330#endif 1452#endif
1331 1453 if (FRAME_TERMCAP_P (f))
1332 unblock_input (); 1454 selection = tty_menu_show (f, xpos, ypos, for_click, keymaps, title,
1455 kbd_menu_navigation, &error_name);
1333 1456
1334#ifdef HAVE_NS 1457#ifdef HAVE_NS
1335 unbind_to (specpdl_count, Qnil); 1458 unbind_to (specpdl_count, Qnil);
@@ -1338,7 +1461,8 @@ no quit occurs and `x-popup-menu' returns nil. */)
1338#endif 1461#endif
1339 1462
1340#ifdef HAVE_NTGUI /* FIXME: Is it really w32-specific? --Stef */ 1463#ifdef HAVE_NTGUI /* FIXME: Is it really w32-specific? --Stef */
1341 FRAME_DISPLAY_INFO (f)->grabbed = 0; 1464 if (FRAME_W32_P (f))
1465 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1342#endif 1466#endif
1343 1467
1344#endif /* HAVE_MENUS */ 1468#endif /* HAVE_MENUS */
@@ -1349,6 +1473,145 @@ no quit occurs and `x-popup-menu' returns nil. */)
1349 return selection; 1473 return selection;
1350} 1474}
1351 1475
1476#ifdef HAVE_MENUS
1477
1478DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
1479 doc: /* Pop up a dialog box and return user's selection.
1480POSITION specifies which frame to use.
1481This is normally a mouse button event or a window or frame.
1482If POSITION is t, it means to use the frame the mouse is on.
1483The dialog box appears in the middle of the specified frame.
1484
1485CONTENTS specifies the alternatives to display in the dialog box.
1486It is a list of the form (DIALOG ITEM1 ITEM2...).
1487Each ITEM is a cons cell (STRING . VALUE).
1488The return value is VALUE from the chosen item.
1489
1490An ITEM may also be just a string--that makes a nonselectable item.
1491An ITEM may also be nil--that means to put all preceding items
1492on the left of the dialog box and all following items on the right.
1493\(By default, approximately half appear on each side.)
1494
1495If HEADER is non-nil, the frame title for the box is "Information",
1496otherwise it is "Question".
1497
1498If the user gets rid of the dialog box without making a valid choice,
1499for instance using the window manager, then this produces a quit and
1500`x-popup-dialog' does not return. */)
1501 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
1502{
1503 struct frame *f = NULL;
1504 Lisp_Object window;
1505
1506 /* Decode the first argument: find the window or frame to use. */
1507 if (EQ (position, Qt)
1508 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
1509 || EQ (XCAR (position), Qtool_bar))))
1510 {
1511#if 0 /* Using the frame the mouse is on may not be right. */
1512 /* Use the mouse's current position. */
1513 struct frame *new_f = SELECTED_FRAME ();
1514 Lisp_Object bar_window;
1515 enum scroll_bar_part part;
1516 Time time;
1517 Lisp_Object x, y;
1518
1519 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
1520
1521 if (new_f != 0)
1522 XSETFRAME (window, new_f);
1523 else
1524 window = selected_window;
1525#endif
1526 window = selected_window;
1527 }
1528 else if (CONSP (position))
1529 {
1530 Lisp_Object tem = XCAR (position);
1531 if (CONSP (tem))
1532 window = Fcar (XCDR (position));
1533 else
1534 {
1535 tem = Fcar (XCDR (position)); /* EVENT_START (position) */
1536 window = Fcar (tem); /* POSN_WINDOW (tem) */
1537 }
1538 }
1539 else if (WINDOWP (position) || FRAMEP (position))
1540 window = position;
1541 else
1542 window = Qnil;
1543
1544 /* Decode where to put the menu. */
1545
1546 if (FRAMEP (window))
1547 f = XFRAME (window);
1548 else if (WINDOWP (window))
1549 {
1550 CHECK_LIVE_WINDOW (window);
1551 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
1552 }
1553 else
1554 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
1555 but I don't want to make one now. */
1556 CHECK_WINDOW (window);
1557
1558 /* Force a redisplay before showing the dialog. If a frame is created
1559 just before showing the dialog, its contents may not have been fully
1560 drawn, as this depends on timing of events from the X server. Redisplay
1561 is not done when a dialog is shown. If redisplay could be done in the
1562 X event loop (i.e. the X event loop does not run in a signal handler)
1563 this would not be needed.
1564
1565 Do this before creating the widget value that points to Lisp
1566 string contents, because Fredisplay may GC and relocate them. */
1567 Fredisplay (Qt);
1568#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1569 if (FRAME_WINDOW_P (f))
1570 return xw_popup_dialog (f, header, contents);
1571 else
1572#endif
1573#if defined (HAVE_NTGUI) && defined (HAVE_DIALOGS)
1574 if (FRAME_W32_P (f))
1575 return w32_popup_dialog (f, header, contents);
1576 else
1577#endif
1578#ifdef HAVE_NS
1579 if (FRAME_NS_P (f))
1580 return ns_popup_dialog (position, header, contents);
1581 else
1582#endif
1583 /* Display a menu with these alternatives
1584 in the middle of frame F. */
1585 {
1586 Lisp_Object x, y, frame, newpos, prompt;
1587 int x_coord, y_coord;
1588
1589 prompt = Fcar (contents);
1590 if (FRAME_WINDOW_P (f))
1591 {
1592 x_coord = FRAME_PIXEL_WIDTH (f);
1593 y_coord = FRAME_PIXEL_HEIGHT (f);
1594 }
1595 else
1596 {
1597 x_coord = FRAME_COLS (f);
1598 /* Center the title at frame middle. (TTY menus have their
1599 upper-left corner at the given position.) */
1600 if (STRINGP (prompt))
1601 x_coord -= SCHARS (prompt);
1602 y_coord = FRAME_LINES (f);
1603 }
1604 XSETFRAME (frame, f);
1605 XSETINT (x, x_coord / 2);
1606 XSETINT (y, y_coord / 2);
1607 newpos = list2 (list2 (x, y), frame);
1608
1609 return Fx_popup_menu (newpos, list2 (prompt, contents));
1610 }
1611}
1612
1613#endif /* HAVE_MENUS */
1614
1352void 1615void
1353syms_of_menu (void) 1616syms_of_menu (void)
1354{ 1617{
@@ -1357,4 +1620,9 @@ syms_of_menu (void)
1357 menu_items_inuse = Qnil; 1620 menu_items_inuse = Qnil;
1358 1621
1359 defsubr (&Sx_popup_menu); 1622 defsubr (&Sx_popup_menu);
1623
1624#ifdef HAVE_MENUS
1625 defsubr (&Sx_popup_dialog);
1626#endif
1627 defsubr (&Smenu_bar_menu_at_x_y);
1360} 1628}
diff --git a/src/menu.h b/src/menu.h
index 0f94ad8000b..9b3b71d757e 100644
--- a/src/menu.h
+++ b/src/menu.h
@@ -51,4 +51,7 @@ extern Lisp_Object ns_menu_show (struct frame *, int, int, bool, bool,
51 Lisp_Object, const char **); 51 Lisp_Object, const char **);
52extern Lisp_Object xmenu_show (struct frame *, int, int, bool, bool, 52extern Lisp_Object xmenu_show (struct frame *, int, int, bool, bool,
53 Lisp_Object, const char **, Time); 53 Lisp_Object, const char **, Time);
54extern Lisp_Object tty_menu_show (struct frame *, int, int, int, int,
55 Lisp_Object, int, const char **);
56extern int menu_item_width (const char *);
54#endif /* MENU_H */ 57#endif /* MENU_H */
diff --git a/src/msdos.c b/src/msdos.c
index aef75120293..2ba7a16a443 100644
--- a/src/msdos.c
+++ b/src/msdos.c
@@ -1379,13 +1379,6 @@ IT_delete_glyphs (struct frame *f, int n)
1379 emacs_abort (); 1379 emacs_abort ();
1380} 1380}
1381 1381
1382/* set-window-configuration on window.c needs this. */
1383void
1384x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1385{
1386 set_menu_bar_lines (f, value, oldval);
1387}
1388
1389/* This was copied from xfaces.c */ 1382/* This was copied from xfaces.c */
1390 1383
1391extern Lisp_Object Qbackground_color; 1384extern Lisp_Object Qbackground_color;
diff --git a/src/nsmenu.m b/src/nsmenu.m
index 8dde027e986..19f161709d1 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -833,6 +833,8 @@ ns_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
833 ptrdiff_t specpdl_count = SPECPDL_INDEX (); 833 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
834 widget_value *wv, *first_wv = 0; 834 widget_value *wv, *first_wv = 0;
835 835
836 block_input ();
837
836 p.x = x; p.y = y; 838 p.x = x; p.y = y;
837 839
838 /* now parse stage 2 as in ns_update_menubar */ 840 /* now parse stage 2 as in ns_update_menubar */
@@ -1035,6 +1037,7 @@ ns_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
1035 popup_activated_flag = 0; 1037 popup_activated_flag = 0;
1036 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; 1038 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
1037 1039
1040 unblock_input ();
1038 return tem; 1041 return tem;
1039} 1042}
1040 1043
@@ -1449,7 +1452,7 @@ pop_down_menu (void *arg)
1449 1452
1450 1453
1451Lisp_Object 1454Lisp_Object
1452ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header) 1455ns_popup_dialog (Lisp_Object position, Lisp_Object header, Lisp_Object contents)
1453{ 1456{
1454 id dialog; 1457 id dialog;
1455 Lisp_Object window, tem, title; 1458 Lisp_Object window, tem, title;
@@ -1916,34 +1919,6 @@ DEFUN ("ns-reset-menu", Fns_reset_menu, Sns_reset_menu, 0, 0, 0,
1916} 1919}
1917 1920
1918 1921
1919DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
1920 doc: /* Pop up a dialog box and return user's selection.
1921POSITION specifies which frame to use.
1922This is normally a mouse button event or a window or frame.
1923If POSITION is t, it means to use the frame the mouse is on.
1924The dialog box appears in the middle of the specified frame.
1925
1926CONTENTS specifies the alternatives to display in the dialog box.
1927It is a list of the form (DIALOG ITEM1 ITEM2...).
1928Each ITEM is a cons cell (STRING . VALUE).
1929The return value is VALUE from the chosen item.
1930
1931An ITEM may also be just a string--that makes a nonselectable item.
1932An ITEM may also be nil--that means to put all preceding items
1933on the left of the dialog box and all following items on the right.
1934\(By default, approximately half appear on each side.)
1935
1936If HEADER is non-nil, the frame title for the box is "Information",
1937otherwise it is "Question".
1938
1939If the user gets rid of the dialog box without making a valid choice,
1940for instance using the window manager, then this produces a quit and
1941`x-popup-dialog' does not return. */)
1942 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
1943{
1944 return ns_popup_dialog (position, contents, header);
1945}
1946
1947DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0, 1922DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1948 doc: /* Return t if a menu or popup dialog is active. */) 1923 doc: /* Return t if a menu or popup dialog is active. */)
1949 (void) 1924 (void)
@@ -1965,7 +1940,6 @@ syms_of_nsmenu (void)
1965 update menus there. */ 1940 update menus there. */
1966 trackingMenu = 1; 1941 trackingMenu = 1;
1967#endif 1942#endif
1968 defsubr (&Sx_popup_dialog);
1969 defsubr (&Sns_reset_menu); 1943 defsubr (&Sns_reset_menu);
1970 defsubr (&Smenu_or_popup_active_p); 1944 defsubr (&Smenu_or_popup_active_p);
1971 1945
diff --git a/src/nsterm.h b/src/nsterm.h
index e99ed3d289a..263b85d6cf1 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -850,8 +850,8 @@ extern void find_and_call_menu_selection (struct frame *f,
850extern Lisp_Object find_and_return_menu_selection (struct frame *f, 850extern Lisp_Object find_and_return_menu_selection (struct frame *f,
851 bool keymaps, 851 bool keymaps,
852 void *client_data); 852 void *client_data);
853extern Lisp_Object ns_popup_dialog (Lisp_Object position, Lisp_Object contents, 853extern Lisp_Object ns_popup_dialog (Lisp_Object position, Lisp_Object header,
854 Lisp_Object header); 854 Lisp_Object contents);
855 855
856#define NSAPP_DATA2_RUNASSCRIPT 10 856#define NSAPP_DATA2_RUNASSCRIPT 10
857extern void ns_run_ascript (void); 857extern void ns_run_ascript (void);
diff --git a/src/term.c b/src/term.c
index fd5ea5a1b8d..44a83b6a4c8 100644
--- a/src/term.c
+++ b/src/term.c
@@ -56,6 +56,8 @@ static int been_here = -1;
56#include "xterm.h" 56#include "xterm.h"
57#endif 57#endif
58 58
59#include "menu.h"
60
59/* The name of the default console device. */ 61/* The name of the default console device. */
60#ifdef WINDOWSNT 62#ifdef WINDOWSNT
61#define DEV_TTY "CONOUT$" 63#define DEV_TTY "CONOUT$"
@@ -302,7 +304,11 @@ tty_hide_cursor (struct tty_display_info *tty)
302 if (tty->cursor_hidden == 0) 304 if (tty->cursor_hidden == 0)
303 { 305 {
304 tty->cursor_hidden = 1; 306 tty->cursor_hidden = 1;
307#ifdef WINDOWSNT
308 w32con_hide_cursor ();
309#else
305 OUTPUT_IF (tty, tty->TS_cursor_invisible); 310 OUTPUT_IF (tty, tty->TS_cursor_invisible);
311#endif
306 } 312 }
307} 313}
308 314
@@ -315,9 +321,13 @@ tty_show_cursor (struct tty_display_info *tty)
315 if (tty->cursor_hidden) 321 if (tty->cursor_hidden)
316 { 322 {
317 tty->cursor_hidden = 0; 323 tty->cursor_hidden = 0;
324#ifdef WINDOWSNT
325 w32con_show_cursor ();
326#else
318 OUTPUT_IF (tty, tty->TS_cursor_normal); 327 OUTPUT_IF (tty, tty->TS_cursor_normal);
319 if (visible_cursor) 328 if (visible_cursor)
320 OUTPUT_IF (tty, tty->TS_cursor_visible); 329 OUTPUT_IF (tty, tty->TS_cursor_visible);
330#endif
321 } 331 }
322} 332}
323 333
@@ -2755,6 +2765,1107 @@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
2755#endif /* HAVE_GPM */ 2765#endif /* HAVE_GPM */
2756 2766
2757 2767
2768/***********************************************************************
2769 Menus
2770 ***********************************************************************/
2771
2772#if defined (HAVE_MENUS) && !defined (MSDOS)
2773
2774/* TTY menu implementation and main ideas are borrowed from msdos.c.
2775
2776 However, unlike on MSDOS, where the menu text is drawn directly to
2777 the display video memory, on a TTY we use display_string (see
2778 display_tty_menu_item in xdisp.c) to put the glyphs produced from
2779 the menu items directly into the frame's 'desired_matrix' glyph
2780 matrix, and then call update_frame_with_menu to deliver the results
2781 to the glass. The previous contents of the screen, in the form of
2782 the current_matrix, is stashed away, and used to restore screen
2783 contents when the menu selection changes or when the final
2784 selection is made and the menu should be popped down.
2785
2786 The idea of this implementation was suggested by Gerd Moellmann. */
2787
2788#define TTYM_FAILURE -1
2789#define TTYM_SUCCESS 1
2790#define TTYM_NO_SELECT 2
2791#define TTYM_IA_SELECT 3
2792#define TTYM_NEXT 4
2793#define TTYM_PREV 5
2794
2795/* These hold text of the current and the previous menu help messages. */
2796static const char *menu_help_message, *prev_menu_help_message;
2797/* Pane number and item number of the menu item which generated the
2798 last menu help message. */
2799static int menu_help_paneno, menu_help_itemno;
2800
2801static Lisp_Object Qtty_menu_navigation_map, Qtty_menu_exit;
2802static Lisp_Object Qtty_menu_prev_item, Qtty_menu_next_item;
2803static Lisp_Object Qtty_menu_next_menu, Qtty_menu_prev_menu;
2804static Lisp_Object Qtty_menu_select, Qtty_menu_ignore;
2805static Lisp_Object Qtty_menu_mouse_movement;
2806
2807typedef struct tty_menu_struct
2808{
2809 int count;
2810 char **text;
2811 struct tty_menu_struct **submenu;
2812 int *panenumber; /* Also used as enabled flag. */
2813 int allocated;
2814 int panecount;
2815 int width;
2816 const char **help_text;
2817} tty_menu;
2818
2819/* Create a brand new menu structure. */
2820
2821static tty_menu *
2822tty_menu_create (void)
2823{
2824 tty_menu *menu;
2825
2826 menu = (tty_menu *) xmalloc (sizeof (tty_menu));
2827 menu->allocated = menu->count = menu->panecount = menu->width = 0;
2828 return menu;
2829}
2830
2831/* Allocate some (more) memory for MENU ensuring that there is room for one
2832 for item. */
2833
2834static void
2835tty_menu_make_room (tty_menu *menu)
2836{
2837 if (menu->allocated == 0)
2838 {
2839 int count = menu->allocated = 10;
2840 menu->text = (char **) xmalloc (count * sizeof (char *));
2841 menu->submenu = (tty_menu **) xmalloc (count * sizeof (tty_menu *));
2842 menu->panenumber = (int *) xmalloc (count * sizeof (int));
2843 menu->help_text = (const char **) xmalloc (count * sizeof (char *));
2844 }
2845 else if (menu->allocated == menu->count)
2846 {
2847 int count = menu->allocated = menu->allocated + 10;
2848 menu->text
2849 = (char **) xrealloc (menu->text, count * sizeof (char *));
2850 menu->submenu
2851 = (tty_menu **) xrealloc (menu->submenu, count * sizeof (tty_menu *));
2852 menu->panenumber
2853 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
2854 menu->help_text
2855 = (const char **) xrealloc (menu->help_text, count * sizeof (char *));
2856 }
2857}
2858
2859/* Search the given menu structure for a given pane number. */
2860
2861static tty_menu *
2862tty_menu_search_pane (tty_menu *menu, int pane)
2863{
2864 int i;
2865 tty_menu *try;
2866
2867 for (i = 0; i < menu->count; i++)
2868 if (menu->submenu[i])
2869 {
2870 if (pane == menu->panenumber[i])
2871 return menu->submenu[i];
2872 if ((try = tty_menu_search_pane (menu->submenu[i], pane)))
2873 return try;
2874 }
2875 return (tty_menu *) 0;
2876}
2877
2878/* Determine how much screen space a given menu needs. */
2879
2880static void
2881tty_menu_calc_size (tty_menu *menu, int *width, int *height)
2882{
2883 int i, h2, w2, maxsubwidth, maxheight;
2884
2885 maxsubwidth = menu->width;
2886 maxheight = menu->count;
2887 for (i = 0; i < menu->count; i++)
2888 {
2889 if (menu->submenu[i])
2890 {
2891 tty_menu_calc_size (menu->submenu[i], &w2, &h2);
2892 if (w2 > maxsubwidth) maxsubwidth = w2;
2893 if (i + h2 > maxheight) maxheight = i + h2;
2894 }
2895 }
2896 *width = maxsubwidth;
2897 *height = maxheight;
2898}
2899
2900static void
2901mouse_get_xy (int *x, int *y)
2902{
2903 struct frame *sf = SELECTED_FRAME ();
2904 Lisp_Object lmx = Qnil, lmy = Qnil, lisp_dummy;
2905 enum scroll_bar_part part_dummy;
2906 Time time_dummy;
2907
2908 if (FRAME_TERMINAL (sf)->mouse_position_hook)
2909 (*FRAME_TERMINAL (sf)->mouse_position_hook) (&sf, -1,
2910 &lisp_dummy, &part_dummy,
2911 &lmx, &lmy,
2912 &time_dummy);
2913 if (!NILP (lmx))
2914 {
2915 *x = XINT (lmx);
2916 *y = XINT (lmy);
2917 }
2918}
2919
2920/* Display MENU at (X,Y) using FACES. */
2921
2922static void
2923tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
2924 int mx, int my, int disp_help)
2925{
2926 int i, face, width, enabled, mousehere, row, col;
2927 struct frame *sf = SELECTED_FRAME ();
2928 struct tty_display_info *tty = FRAME_TTY (sf);
2929
2930 menu_help_message = NULL;
2931
2932 width = menu->width;
2933 col = cursorX (tty);
2934 row = cursorY (tty);
2935 for (i = 0; i < menu->count; i++)
2936 {
2937 int max_width = width + 2; /* +2 for padding blanks on each side */
2938
2939 cursor_to (sf, y + i, x);
2940 if (menu->submenu[i])
2941 max_width += 2; /* for displaying " >" after the item */
2942 enabled
2943 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2944 mousehere = (y + i == my && x <= mx && mx < x + max_width);
2945 face = faces[enabled + mousehere * 2];
2946 /* Display the menu help string for the i-th menu item even if
2947 the menu item is currently disabled. That's what the GUI
2948 code does. */
2949 if (disp_help && enabled + mousehere * 2 >= 2)
2950 {
2951 menu_help_message = menu->help_text[i];
2952 menu_help_paneno = pn - 1;
2953 menu_help_itemno = i;
2954 }
2955 display_tty_menu_item (menu->text[i], max_width, face, x, y + i,
2956 menu->submenu[i] != NULL);
2957 }
2958 update_frame_with_menu (sf);
2959 cursor_to (sf, row, col);
2960}
2961
2962/* --------------------------- X Menu emulation ---------------------- */
2963
2964/* Report availability of menus. */
2965
2966int
2967have_menus_p (void) { return 1; }
2968
2969/* Create a new pane and place it on the outer-most level. */
2970
2971static int
2972tty_menu_add_pane (tty_menu *menu, const char *txt)
2973{
2974 int len;
2975 const char *p;
2976
2977 tty_menu_make_room (menu);
2978 menu->submenu[menu->count] = tty_menu_create ();
2979 menu->text[menu->count] = (char *)txt;
2980 menu->panenumber[menu->count] = ++menu->panecount;
2981 menu->help_text[menu->count] = NULL;
2982 menu->count++;
2983
2984 /* Update the menu width, if necessary. */
2985 for (len = 0, p = txt; *p; )
2986 {
2987 int ch_len;
2988 int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
2989
2990 len += CHAR_WIDTH (ch);
2991 p += ch_len;
2992 }
2993
2994 if (len > menu->width)
2995 menu->width = len;
2996
2997 return menu->panecount;
2998}
2999
3000/* Create a new item in a menu pane. */
3001
3002int
3003tty_menu_add_selection (tty_menu *menu, int pane,
3004 char *txt, int enable, char const *help_text)
3005{
3006 int len;
3007 char *p;
3008
3009 if (pane)
3010 if (!(menu = tty_menu_search_pane (menu, pane)))
3011 return TTYM_FAILURE;
3012 tty_menu_make_room (menu);
3013 menu->submenu[menu->count] = (tty_menu *) 0;
3014 menu->text[menu->count] = txt;
3015 menu->panenumber[menu->count] = enable;
3016 menu->help_text[menu->count] = help_text;
3017 menu->count++;
3018
3019 /* Update the menu width, if necessary. */
3020 for (len = 0, p = txt; *p; )
3021 {
3022 int ch_len;
3023 int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
3024
3025 len += CHAR_WIDTH (ch);
3026 p += ch_len;
3027 }
3028
3029 if (len > menu->width)
3030 menu->width = len;
3031
3032 return TTYM_SUCCESS;
3033}
3034
3035/* Decide where the menu would be placed if requested at (X,Y). */
3036
3037void
3038tty_menu_locate (tty_menu *menu, int x, int y,
3039 int *ulx, int *uly, int *width, int *height)
3040{
3041 tty_menu_calc_size (menu, width, height);
3042 *ulx = x + 1;
3043 *uly = y;
3044 *width += 2;
3045}
3046
3047struct tty_menu_state
3048{
3049 struct glyph_matrix *screen_behind;
3050 tty_menu *menu;
3051 int pane;
3052 int x, y;
3053};
3054
3055/* Save away the contents of frame F's current frame matrix, and
3056 enable all its rows. Value is a glyph matrix holding the contents
3057 of F's current frame matrix with all its glyph rows enabled. */
3058
3059static struct glyph_matrix *
3060save_and_enable_current_matrix (struct frame *f)
3061{
3062 int i;
3063 struct glyph_matrix *saved = xzalloc (sizeof *saved);
3064 saved->nrows = f->current_matrix->nrows;
3065 saved->rows = xzalloc (saved->nrows * sizeof *saved->rows);
3066
3067 for (i = 0; i < saved->nrows; ++i)
3068 {
3069 struct glyph_row *from = f->current_matrix->rows + i;
3070 struct glyph_row *to = saved->rows + i;
3071 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
3072
3073 to->glyphs[TEXT_AREA] = xmalloc (nbytes);
3074 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
3075 to->used[TEXT_AREA] = from->used[TEXT_AREA];
3076 /* Make sure every row is enabled, or else update_frame will not
3077 redraw them. (Rows that are identical to what is already on
3078 screen will not be redrawn anyway.) */
3079 to->enabled_p = 1;
3080 to->hash = from->hash;
3081 if (from->used[LEFT_MARGIN_AREA])
3082 {
3083 nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph);
3084 to->glyphs[LEFT_MARGIN_AREA] = (struct glyph *) xmalloc (nbytes);
3085 memcpy (to->glyphs[LEFT_MARGIN_AREA],
3086 from->glyphs[LEFT_MARGIN_AREA], nbytes);
3087 to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA];
3088 }
3089 if (from->used[RIGHT_MARGIN_AREA])
3090 {
3091 nbytes = from->used[RIGHT_MARGIN_AREA] * sizeof (struct glyph);
3092 to->glyphs[RIGHT_MARGIN_AREA] = (struct glyph *) xmalloc (nbytes);
3093 memcpy (to->glyphs[RIGHT_MARGIN_AREA],
3094 from->glyphs[RIGHT_MARGIN_AREA], nbytes);
3095 to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
3096 }
3097 }
3098
3099 return saved;
3100}
3101
3102/* Restore the contents of frame F's desired frame matrix from SAVED,
3103 and free memory associated with SAVED. */
3104
3105static void
3106restore_desired_matrix (struct frame *f, struct glyph_matrix *saved)
3107{
3108 int i;
3109
3110 for (i = 0; i < saved->nrows; ++i)
3111 {
3112 struct glyph_row *from = saved->rows + i;
3113 struct glyph_row *to = f->desired_matrix->rows + i;
3114 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
3115
3116 eassert (to->glyphs[TEXT_AREA] != from->glyphs[TEXT_AREA]);
3117 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
3118 to->used[TEXT_AREA] = from->used[TEXT_AREA];
3119 to->enabled_p = from->enabled_p;
3120 to->hash = from->hash;
3121 nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph);
3122 if (nbytes)
3123 {
3124 eassert (to->glyphs[LEFT_MARGIN_AREA] != from->glyphs[LEFT_MARGIN_AREA]);
3125 memcpy (to->glyphs[LEFT_MARGIN_AREA],
3126 from->glyphs[LEFT_MARGIN_AREA], nbytes);
3127 to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA];
3128 }
3129 else
3130 to->used[LEFT_MARGIN_AREA] = 0;
3131 nbytes = from->used[RIGHT_MARGIN_AREA] * sizeof (struct glyph);
3132 if (nbytes)
3133 {
3134 eassert (to->glyphs[RIGHT_MARGIN_AREA] != from->glyphs[RIGHT_MARGIN_AREA]);
3135 memcpy (to->glyphs[RIGHT_MARGIN_AREA],
3136 from->glyphs[RIGHT_MARGIN_AREA], nbytes);
3137 to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
3138 }
3139 else
3140 to->used[RIGHT_MARGIN_AREA] = 0;
3141 }
3142}
3143
3144static void
3145free_saved_screen (struct glyph_matrix *saved)
3146{
3147 int i;
3148
3149 if (!saved)
3150 return; /* already freed */
3151
3152 for (i = 0; i < saved->nrows; ++i)
3153 {
3154 struct glyph_row *from = saved->rows + i;
3155
3156 xfree (from->glyphs[TEXT_AREA]);
3157 if (from->used[LEFT_MARGIN_AREA])
3158 xfree (from->glyphs[LEFT_MARGIN_AREA]);
3159 if (from->used[RIGHT_MARGIN_AREA])
3160 xfree (from->glyphs[RIGHT_MARGIN_AREA]);
3161 }
3162
3163 xfree (saved->rows);
3164 xfree (saved);
3165}
3166
3167/* Update the display of frame F from its saved contents. */
3168static void
3169screen_update (struct frame *f, struct glyph_matrix *mtx)
3170{
3171 restore_desired_matrix (f, mtx);
3172 update_frame_with_menu (f);
3173}
3174
3175/* Read user input and return X and Y coordinates where that input
3176 puts us. We only consider mouse movement and click events and
3177 keyboard movement commands; the rest are ignored.
3178
3179 Value is -1 if C-g was pressed, 1 if an item was selected, 2 or 3
3180 if we need to move to the next or previous menu-bar menu, zero
3181 otherwise. */
3182static int
3183read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
3184 bool *first_time)
3185{
3186 if (*first_time)
3187 {
3188 *first_time = false;
3189 sf->mouse_moved = 1;
3190 }
3191 else
3192 {
3193 extern Lisp_Object read_menu_command (void);
3194 Lisp_Object cmd;
3195 int usable_input = 1;
3196 int st = 0;
3197 struct tty_display_info *tty = FRAME_TTY (sf);
3198 Lisp_Object saved_mouse_tracking = do_mouse_tracking;
3199
3200 /* Signal the keyboard reading routines we are displaying a menu
3201 on this terminal. */
3202 tty->showing_menu = 1;
3203 /* We want mouse movements be reported by read_menu_command. */
3204 do_mouse_tracking = Qt;
3205 do {
3206 cmd = read_menu_command ();
3207 } while (NILP (cmd));
3208 tty->showing_menu = 0;
3209 do_mouse_tracking = saved_mouse_tracking;
3210
3211 if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit))
3212 return -1;
3213 if (EQ (cmd, Qtty_menu_mouse_movement))
3214 {
3215 int mx, my;
3216
3217 mouse_get_xy (&mx, &my);
3218 *x = mx;
3219 *y = my;
3220 }
3221 else if (EQ (cmd, Qtty_menu_next_menu))
3222 {
3223 usable_input = 0;
3224 st = 2;
3225 }
3226 else if (EQ (cmd, Qtty_menu_prev_menu))
3227 {
3228 usable_input = 0;
3229 st = 3;
3230 }
3231 else if (EQ (cmd, Qtty_menu_next_item))
3232 {
3233 if (*y < max_y)
3234 *y += 1;
3235 }
3236 else if (EQ (cmd, Qtty_menu_prev_item))
3237 {
3238 if (*y > min_y)
3239 *y -= 1;
3240 }
3241 else if (EQ (cmd, Qtty_menu_select))
3242 st = 1;
3243 else if (!EQ (cmd, Qtty_menu_ignore))
3244 usable_input = 0;
3245 if (usable_input)
3246 sf->mouse_moved = 1;
3247 return st;
3248 }
3249 return 0;
3250}
3251
3252/* Display menu, wait for user's response, and return that response. */
3253static int
3254tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
3255 int x0, int y0, char **txt,
3256 void (*help_callback)(char const *, int, int),
3257 int kbd_navigation)
3258{
3259 struct tty_menu_state *state;
3260 int statecount, x, y, i, b, leave, result, onepane;
3261 int title_faces[4]; /* face to display the menu title */
3262 int faces[4], buffers_num_deleted = 0;
3263 struct frame *sf = SELECTED_FRAME ();
3264 struct tty_display_info *tty = FRAME_TTY (sf);
3265 bool first_time;
3266 Lisp_Object saved_echo_area_message, selectface;
3267
3268 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3269 around the display. */
3270 if (x0 <= 0)
3271 x0 = 1;
3272 if (y0 <= 0)
3273 y0 = 1;
3274
3275 state = alloca (menu->panecount * sizeof (struct tty_menu_state));
3276 memset (state, 0, sizeof (*state));
3277 faces[0]
3278 = lookup_derived_face (sf, intern ("tty-menu-disabled-face"),
3279 DEFAULT_FACE_ID, 1);
3280 faces[1]
3281 = lookup_derived_face (sf, intern ("tty-menu-enabled-face"),
3282 DEFAULT_FACE_ID, 1);
3283 selectface = intern ("tty-menu-selected-face");
3284 faces[2] = lookup_derived_face (sf, selectface,
3285 faces[0], 1);
3286 faces[3] = lookup_derived_face (sf, selectface,
3287 faces[1], 1);
3288
3289 /* Make sure the menu title is always displayed with
3290 `tty-menu-selected-face', no matter where the mouse pointer is. */
3291 for (i = 0; i < 4; i++)
3292 title_faces[i] = faces[3];
3293
3294 statecount = 1;
3295
3296 /* Don't let the title for the "Buffers" popup menu include a
3297 digit (which is ugly).
3298
3299 This is a terrible kludge, but I think the "Buffers" case is
3300 the only one where the title includes a number, so it doesn't
3301 seem to be necessary to make this more general. */
3302 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3303 {
3304 menu->text[0][7] = '\0';
3305 buffers_num_deleted = 1;
3306 }
3307
3308 /* Force update of the current frame, so that the desired and the
3309 current matrices are identical. */
3310 update_frame_with_menu (sf);
3311 state[0].menu = menu;
3312 state[0].screen_behind = save_and_enable_current_matrix (sf);
3313
3314 /* Display the menu title. We subtract 1 from x0 and y0 because we
3315 want to interpret them as zero-based column and row coordinates,
3316 and also because we want the first item of the menu, not its
3317 title, to appear at x0,y0. */
3318 tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0);
3319
3320 /* Turn off the cursor. Otherwise it shows through the menu
3321 panes, which is ugly. */
3322 tty_hide_cursor (tty);
3323 if (buffers_num_deleted)
3324 menu->text[0][7] = ' ';
3325 if ((onepane = menu->count == 1 && menu->submenu[0]))
3326 {
3327 menu->width = menu->submenu[0]->width;
3328 state[0].menu = menu->submenu[0];
3329 }
3330 else
3331 {
3332 state[0].menu = menu;
3333 }
3334 state[0].x = x0 - 1;
3335 state[0].y = y0;
3336 state[0].pane = onepane;
3337
3338 x = state[0].x;
3339 y = state[0].y;
3340 first_time = true;
3341
3342 leave = 0;
3343 while (!leave)
3344 {
3345 int input_status;
3346 int min_y = state[0].y, max_y = min_y + state[0].menu->count - 1;
3347
3348 input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
3349 if (input_status)
3350 {
3351 leave = 1;
3352 if (input_status == -1)
3353 {
3354 /* Remove the last help-echo, so that it doesn't
3355 re-appear after "Quit". */
3356 show_help_echo (Qnil, Qnil, Qnil, Qnil);
3357 result = TTYM_NO_SELECT;
3358 }
3359 else if (input_status == 2)
3360 {
3361 if (kbd_navigation)
3362 result = TTYM_NEXT;
3363 else
3364 leave = 0;
3365 }
3366 else if (input_status == 3)
3367 {
3368 if (kbd_navigation)
3369 result = TTYM_PREV;
3370 else
3371 leave = 0;
3372 }
3373 }
3374 if (sf->mouse_moved && input_status != -1)
3375 {
3376 sf->mouse_moved = 0;
3377 result = TTYM_IA_SELECT;
3378 for (i = 0; i < statecount; i++)
3379 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3380 {
3381 int dy = y - state[i].y;
3382 if (0 <= dy && dy < state[i].menu->count)
3383 {
3384 if (!state[i].menu->submenu[dy])
3385 {
3386 if (state[i].menu->panenumber[dy])
3387 result = TTYM_SUCCESS;
3388 else
3389 result = TTYM_IA_SELECT;
3390 }
3391 *pane = state[i].pane - 1;
3392 *selidx = dy;
3393 /* We hit some part of a menu, so drop extra menus that
3394 have been opened. That does not include an open and
3395 active submenu. */
3396 if (i != statecount - 2
3397 || state[i].menu->submenu[dy] != state[i+1].menu)
3398 while (i != statecount - 1)
3399 {
3400 statecount--;
3401 screen_update (sf, state[statecount].screen_behind);
3402 state[statecount].screen_behind = NULL;
3403 }
3404 if (i == statecount - 1 && state[i].menu->submenu[dy])
3405 {
3406 tty_menu_display (state[i].menu,
3407 state[i].x,
3408 state[i].y,
3409 state[i].pane,
3410 faces, x, y, 1);
3411 state[statecount].menu = state[i].menu->submenu[dy];
3412 state[statecount].pane = state[i].menu->panenumber[dy];
3413 state[statecount].screen_behind
3414 = save_and_enable_current_matrix (sf);
3415 state[statecount].x
3416 = state[i].x + state[i].menu->width + 2;
3417 state[statecount].y = y;
3418 statecount++;
3419 }
3420 }
3421 }
3422 tty_menu_display (state[statecount - 1].menu,
3423 state[statecount - 1].x,
3424 state[statecount - 1].y,
3425 state[statecount - 1].pane,
3426 faces, x, y, 1);
3427 tty_hide_cursor (tty);
3428 fflush (tty->output);
3429 }
3430
3431 /* Display the help-echo message for the currently-selected menu
3432 item. */
3433 if ((menu_help_message || prev_menu_help_message)
3434 && menu_help_message != prev_menu_help_message)
3435 {
3436 help_callback (menu_help_message,
3437 menu_help_paneno, menu_help_itemno);
3438 tty_hide_cursor (tty);
3439 fflush (tty->output);
3440 prev_menu_help_message = menu_help_message;
3441 }
3442 }
3443
3444 sf->mouse_moved = 0;
3445 screen_update (sf, state[0].screen_behind);
3446 while (statecount--)
3447 free_saved_screen (state[statecount].screen_behind);
3448 tty_show_cursor (tty); /* turn cursor back on */
3449
3450/* Clean up any mouse events that are waiting inside Emacs event queue.
3451 These events are likely to be generated before the menu was even
3452 displayed, probably because the user pressed and released the button
3453 (which invoked the menu) too quickly. If we don't remove these events,
3454 Emacs will process them after we return and surprise the user. */
3455 discard_mouse_events ();
3456 if (!kbd_buffer_events_waiting ())
3457 clear_input_pending ();
3458 SET_FRAME_GARBAGED (sf);
3459 return result;
3460}
3461
3462/* Dispose of a menu. */
3463
3464void
3465tty_menu_destroy (tty_menu *menu)
3466{
3467 int i;
3468 if (menu->allocated)
3469 {
3470 for (i = 0; i < menu->count; i++)
3471 if (menu->submenu[i])
3472 tty_menu_destroy (menu->submenu[i]);
3473 xfree (menu->text);
3474 xfree (menu->submenu);
3475 xfree (menu->panenumber);
3476 xfree (menu->help_text);
3477 }
3478 xfree (menu);
3479 menu_help_message = prev_menu_help_message = NULL;
3480}
3481
3482/* Show help HELP_STRING, or clear help if HELP_STRING is null.
3483
3484 PANE is the pane number, and ITEM is the menu item number in
3485 the menu (currently not used). */
3486
3487static void
3488tty_menu_help_callback (char const *help_string, int pane, int item)
3489{
3490 Lisp_Object *first_item;
3491 Lisp_Object pane_name;
3492 Lisp_Object menu_object;
3493
3494 first_item = XVECTOR (menu_items)->u.contents;
3495 if (EQ (first_item[0], Qt))
3496 pane_name = first_item[MENU_ITEMS_PANE_NAME];
3497 else if (EQ (first_item[0], Qquote))
3498 /* This shouldn't happen, see xmenu_show. */
3499 pane_name = empty_unibyte_string;
3500 else
3501 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
3502
3503 /* (menu-item MENU-NAME PANE-NUMBER) */
3504 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
3505 show_help_echo (help_string ? build_string (help_string) : Qnil,
3506 Qnil, menu_object, make_number (item));
3507}
3508
3509static void
3510tty_pop_down_menu (Lisp_Object arg)
3511{
3512 tty_menu *menu = XSAVE_POINTER (arg, 0);
3513
3514 block_input ();
3515 tty_menu_destroy (menu);
3516 unblock_input ();
3517}
3518
3519/* Return the zero-based index of the last menu-bar item on frame F. */
3520static int
3521tty_menu_last_menubar_item (struct frame *f)
3522{
3523 int i = 0;
3524
3525 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3526 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3527 {
3528 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3529
3530 while (i < ASIZE (items))
3531 {
3532 Lisp_Object str;
3533
3534 str = AREF (items, i + 1);
3535 if (NILP (str))
3536 break;
3537 i += 4;
3538 }
3539 i -= 4; /* went one too far */
3540 }
3541 return i;
3542}
3543
3544/* Find in frame F's menu bar the menu item that is next or previous
3545 to the item at X/Y, and return that item's position in X/Y. WHICH
3546 says which one--next or previous--item to look for. X and Y are
3547 measured in character cells. This should only be called on TTY
3548 frames. */
3549static void
3550tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
3551{
3552 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3553 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3554 {
3555 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3556 int last_i = tty_menu_last_menubar_item (f);
3557 int i, prev_x;
3558
3559 /* This loop assumes a single menu-bar line, and will fail to
3560 find an item if it is not in the first line. Note that
3561 make_lispy_event in keyboard.c makes the same assumption. */
3562 for (i = 0, prev_x = -1; i < ASIZE (items); i += 4)
3563 {
3564 Lisp_Object pos, str;
3565 int ix;
3566
3567 str = AREF (items, i + 1);
3568 pos = AREF (items, i + 3);
3569 if (NILP (str))
3570 return;
3571 ix = XINT (pos);
3572 if (ix <= *x
3573 /* We use <= so the blank between 2 items on a TTY is
3574 considered part of the previous item. */
3575 && *x <= ix + menu_item_width (SSDATA (str)))
3576 {
3577 /* Found current item. Now compute the X coordinate of
3578 the previous or next item. */
3579 if (which == TTYM_NEXT)
3580 {
3581 if (i < last_i)
3582 *x = XINT (AREF (items, i + 4 + 3));
3583 else
3584 *x = 0; /* wrap around to the first item */
3585 }
3586 else if (prev_x < 0)
3587 {
3588 /* Wrap around to the last item. */
3589 *x = XINT (AREF (items, last_i + 3));
3590 }
3591 else
3592 *x = prev_x;
3593 return;
3594 }
3595 prev_x = ix;
3596 }
3597 }
3598}
3599
3600Lisp_Object
3601tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
3602 Lisp_Object title, int kbd_navigation, const char **error_name)
3603{
3604 tty_menu *menu;
3605 int pane, selidx, lpane, status;
3606 Lisp_Object entry, pane_prefix;
3607 char *datap;
3608 int ulx, uly, width, height;
3609 int item_x, item_y;
3610 int dispwidth, dispheight;
3611 int i, j, lines, maxlines;
3612 int maxwidth;
3613 int dummy_int;
3614 unsigned int dummy_uint;
3615 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3616
3617 if (! FRAME_TERMCAP_P (f))
3618 emacs_abort ();
3619
3620 *error_name = 0;
3621 if (menu_items_n_panes == 0)
3622 return Qnil;
3623
3624 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
3625 {
3626 *error_name = "Empty menu";
3627 return Qnil;
3628 }
3629
3630 /* Make the menu on that window. */
3631 menu = tty_menu_create ();
3632 if (menu == NULL)
3633 {
3634 *error_name = "Can't create menu";
3635 return Qnil;
3636 }
3637
3638 /* Don't GC while we prepare and show the menu, because we give the
3639 menu functions pointers to the contents of strings. */
3640 inhibit_garbage_collection ();
3641
3642 /* Adjust coordinates to be root-window-relative. */
3643 item_x = x += f->left_pos;
3644 item_y = y += f->top_pos;
3645
3646 /* Create all the necessary panes and their items. */
3647 maxwidth = maxlines = lines = i = 0;
3648 lpane = TTYM_FAILURE;
3649 while (i < menu_items_used)
3650 {
3651 if (EQ (AREF (menu_items, i), Qt))
3652 {
3653 /* Create a new pane. */
3654 Lisp_Object pane_name, prefix;
3655 const char *pane_string;
3656
3657 maxlines = max (maxlines, lines);
3658 lines = 0;
3659 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
3660 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
3661 pane_string = (NILP (pane_name)
3662 ? "" : SSDATA (pane_name));
3663 if (keymaps && !NILP (prefix))
3664 pane_string++;
3665
3666 lpane = tty_menu_add_pane (menu, pane_string);
3667 if (lpane == TTYM_FAILURE)
3668 {
3669 tty_menu_destroy (menu);
3670 *error_name = "Can't create pane";
3671 return Qnil;
3672 }
3673 i += MENU_ITEMS_PANE_LENGTH;
3674
3675 /* Find the width of the widest item in this pane. */
3676 j = i;
3677 while (j < menu_items_used)
3678 {
3679 Lisp_Object item;
3680 item = AREF (menu_items, j);
3681 if (EQ (item, Qt))
3682 break;
3683 if (NILP (item))
3684 {
3685 j++;
3686 continue;
3687 }
3688 width = SBYTES (item);
3689 if (width > maxwidth)
3690 maxwidth = width;
3691
3692 j += MENU_ITEMS_ITEM_LENGTH;
3693 }
3694 }
3695 /* Ignore a nil in the item list.
3696 It's meaningful only for dialog boxes. */
3697 else if (EQ (AREF (menu_items, i), Qquote))
3698 i += 1;
3699 else
3700 {
3701 /* Create a new item within current pane. */
3702 Lisp_Object item_name, enable, descrip, help;
3703 char *item_data;
3704 char const *help_string;
3705
3706 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
3707 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
3708 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
3709 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
3710 help_string = STRINGP (help) ? SSDATA (help) : NULL;
3711
3712 if (!NILP (descrip))
3713 {
3714 /* if alloca is fast, use that to make the space,
3715 to reduce gc needs. */
3716 item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1);
3717 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
3718 for (j = SCHARS (item_name); j < maxwidth; j++)
3719 item_data[j] = ' ';
3720 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
3721 item_data[j + SBYTES (descrip)] = 0;
3722 }
3723 else
3724 item_data = SSDATA (item_name);
3725
3726 if (lpane == TTYM_FAILURE
3727 || (tty_menu_add_selection (menu, lpane, item_data,
3728 !NILP (enable), help_string)
3729 == TTYM_FAILURE))
3730 {
3731 tty_menu_destroy (menu);
3732 *error_name = "Can't add selection to menu";
3733 return Qnil;
3734 }
3735 i += MENU_ITEMS_ITEM_LENGTH;
3736 lines++;
3737 }
3738 }
3739
3740 maxlines = max (maxlines, lines);
3741
3742 /* All set and ready to fly. */
3743 dispwidth = f->text_cols;
3744 dispheight = f->text_lines;
3745 x = min (x, dispwidth);
3746 y = min (y, dispheight);
3747 x = max (x, 1);
3748 y = max (y, 1);
3749 tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
3750 if (ulx+width > dispwidth)
3751 {
3752 x -= (ulx + width) - dispwidth;
3753 ulx = dispwidth - width;
3754 }
3755 if (uly+height > dispheight)
3756 {
3757 y -= (uly + height) - dispheight;
3758 uly = dispheight - height;
3759 }
3760
3761 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 2)
3762 {
3763 /* Move the menu away of the echo area, to avoid overwriting the
3764 menu with help echo messages or vice versa. */
3765 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
3766 {
3767 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
3768 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
3769 }
3770 else
3771 {
3772 y -= 2;
3773 uly -= 2;
3774 }
3775 }
3776
3777 if (ulx < 0) x -= ulx;
3778 if (uly < 0) y -= uly;
3779
3780#if 0
3781 /* This code doesn't make sense on a TTY, since it can easily annul
3782 the adjustments above that carefully avoid truncation of the menu
3783 items. I think it was written to fix some problem that only
3784 happens on X11. */
3785 if (! for_click)
3786 {
3787 /* If position was not given by a mouse click, adjust so upper left
3788 corner of the menu as a whole ends up at given coordinates. This
3789 is what x-popup-menu says in its documentation. */
3790 x += width/2;
3791 y += 1.5*height/(maxlines+2);
3792 }
3793#endif
3794
3795 pane = selidx = 0;
3796
3797 record_unwind_protect (tty_pop_down_menu, make_save_ptr (menu));
3798
3799 specbind (Qoverriding_terminal_local_map,
3800 Fsymbol_value (Qtty_menu_navigation_map));
3801 status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
3802 tty_menu_help_callback, kbd_navigation);
3803 entry = pane_prefix = Qnil;
3804
3805 switch (status)
3806 {
3807 case TTYM_SUCCESS:
3808 /* Find the item number SELIDX in pane number PANE. */
3809 i = 0;
3810 while (i < menu_items_used)
3811 {
3812 if (EQ (AREF (menu_items, i), Qt))
3813 {
3814 if (pane == 0)
3815 pane_prefix
3816 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
3817 pane--;
3818 i += MENU_ITEMS_PANE_LENGTH;
3819 }
3820 else
3821 {
3822 if (pane == -1)
3823 {
3824 if (selidx == 0)
3825 {
3826 entry
3827 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
3828 if (keymaps != 0)
3829 {
3830 entry = Fcons (entry, Qnil);
3831 if (!NILP (pane_prefix))
3832 entry = Fcons (pane_prefix, entry);
3833 }
3834 break;
3835 }
3836 selidx--;
3837 }
3838 i += MENU_ITEMS_ITEM_LENGTH;
3839 }
3840 }
3841 break;
3842
3843 case TTYM_NEXT:
3844 case TTYM_PREV:
3845 tty_menu_new_item_coords (f, status, &item_x, &item_y);
3846 entry = Fcons (make_number (item_x), make_number (item_y));
3847 break;
3848
3849 case TTYM_FAILURE:
3850 *error_name = "Can't activate menu";
3851 case TTYM_IA_SELECT:
3852 break;
3853 case TTYM_NO_SELECT:
3854 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
3855 the menu was invoked with a mouse event as POSITION). */
3856 if (! for_click)
3857 Fsignal (Qquit, Qnil);
3858 break;
3859 }
3860
3861 unbind_to (specpdl_count, Qnil);
3862
3863 return entry;
3864}
3865
3866#endif /* HAVE_MENUS && !MSDOS */
3867
3868
2758#ifndef MSDOS 3869#ifndef MSDOS
2759/*********************************************************************** 3870/***********************************************************************
2760 Initialization 3871 Initialization
@@ -3514,4 +4625,14 @@ bigger, or it may make it blink, or it may do nothing at all. */);
3514 4625
3515 encode_terminal_src = NULL; 4626 encode_terminal_src = NULL;
3516 encode_terminal_dst = NULL; 4627 encode_terminal_dst = NULL;
4628
4629 DEFSYM (Qtty_menu_next_item, "tty-menu-next-item");
4630 DEFSYM (Qtty_menu_prev_item, "tty-menu-prev-item");
4631 DEFSYM (Qtty_menu_next_menu, "tty-menu-next-menu");
4632 DEFSYM (Qtty_menu_prev_menu, "tty-menu-prev-menu");
4633 DEFSYM (Qtty_menu_select, "tty-menu-select");
4634 DEFSYM (Qtty_menu_ignore, "tty-menu-ignore");
4635 DEFSYM (Qtty_menu_exit, "tty-menu-exit");
4636 DEFSYM (Qtty_menu_mouse_movement, "tty-menu-mouse-movement");
4637 DEFSYM (Qtty_menu_navigation_map, "tty-menu-navigation-map");
3517} 4638}
diff --git a/src/termchar.h b/src/termchar.h
index 11cea34df23..031f4e4034b 100644
--- a/src/termchar.h
+++ b/src/termchar.h
@@ -194,6 +194,9 @@ struct tty_display_info
194 /* Nonzero means use ^S/^Q for flow control. */ 194 /* Nonzero means use ^S/^Q for flow control. */
195 195
196 unsigned flow_control : 1; 196 unsigned flow_control : 1;
197
198 /* Non-zero means we are displaying a TTY menu on this tty. */
199 unsigned showing_menu : 1;
197}; 200};
198 201
199/* A chain of structures for all tty devices currently in use. */ 202/* A chain of structures for all tty devices currently in use. */
diff --git a/src/termhooks.h b/src/termhooks.h
index c2bc42724e2..9cea0c188ec 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -656,6 +656,14 @@ extern unsigned char *encode_terminal_code (struct glyph *, int,
656extern void close_gpm (int gpm_fd); 656extern void close_gpm (int gpm_fd);
657#endif 657#endif
658 658
659#ifdef WINDOWSNT
660extern int cursorX (struct tty_display_info *);
661extern int cursorY (struct tty_display_info *);
662#else
663#define cursorX(t) curX(t)
664#define cursorY(t) curY(t)
665#endif
666
659INLINE_HEADER_END 667INLINE_HEADER_END
660 668
661#endif /* EMACS_TERMHOOKS_H */ 669#endif /* EMACS_TERMHOOKS_H */
diff --git a/src/w32console.c b/src/w32console.c
index 230923934af..285abb310fe 100644
--- a/src/w32console.c
+++ b/src/w32console.c
@@ -62,6 +62,7 @@ static HANDLE prev_screen, cur_screen;
62static WORD char_attr_normal; 62static WORD char_attr_normal;
63static DWORD prev_console_mode; 63static DWORD prev_console_mode;
64 64
65static CONSOLE_CURSOR_INFO console_cursor_info;
65#ifndef USE_SEPARATE_SCREEN 66#ifndef USE_SEPARATE_SCREEN
66static CONSOLE_CURSOR_INFO prev_console_cursor; 67static CONSOLE_CURSOR_INFO prev_console_cursor;
67#endif 68#endif
@@ -95,6 +96,22 @@ w32con_move_cursor (struct frame *f, int row, int col)
95 SetConsoleCursorPosition (cur_screen, cursor_coords); 96 SetConsoleCursorPosition (cur_screen, cursor_coords);
96} 97}
97 98
99void
100w32con_hide_cursor (void)
101{
102 GetConsoleCursorInfo (cur_screen, &console_cursor_info);
103 console_cursor_info.bVisible = FALSE;
104 SetConsoleCursorInfo (cur_screen, &console_cursor_info);
105}
106
107void
108w32con_show_cursor (void)
109{
110 GetConsoleCursorInfo (cur_screen, &console_cursor_info);
111 console_cursor_info.bVisible = TRUE;
112 SetConsoleCursorInfo (cur_screen, &console_cursor_info);
113}
114
98/* Clear from cursor to end of screen. */ 115/* Clear from cursor to end of screen. */
99static void 116static void
100w32con_clear_to_end (struct frame *f) 117w32con_clear_to_end (struct frame *f)
@@ -552,6 +569,21 @@ Wcm_clear (struct tty_display_info *tty)
552} 569}
553 570
554 571
572/* Report the current cursor position. The following two functions
573 are used in term.c's tty menu code, so they are not really
574 "stubs". */
575int
576cursorX (struct tty_display_info *tty)
577{
578 return cursor_coords.X;
579}
580
581int
582cursorY (struct tty_display_info *tty)
583{
584 return cursor_coords.Y;
585}
586
555/*********************************************************************** 587/***********************************************************************
556 Faces 588 Faces
557 ***********************************************************************/ 589 ***********************************************************************/
diff --git a/src/w32fns.c b/src/w32fns.c
index 4cbbe1d5a80..6e52453caea 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -5467,7 +5467,10 @@ show_hourglass (struct atimer *timer)
5467 f = SELECTED_FRAME (); 5467 f = SELECTED_FRAME ();
5468 5468
5469 if (!FRAME_W32_P (f)) 5469 if (!FRAME_W32_P (f))
5470 return; 5470 {
5471 unblock_input ();
5472 return;
5473 }
5471 5474
5472 w32_show_hourglass (f); 5475 w32_show_hourglass (f);
5473 unblock_input (); 5476 unblock_input ();
diff --git a/src/w32inevt.c b/src/w32inevt.c
index ce36f291b00..3c41bec6bb5 100644
--- a/src/w32inevt.c
+++ b/src/w32inevt.c
@@ -712,12 +712,17 @@ w32_console_read_socket (struct terminal *terminal,
712 while (nev > 0) 712 while (nev > 0)
713 { 713 {
714 struct input_event inev; 714 struct input_event inev;
715 /* Having a separate variable with this value makes
716 debugging easier, as otherwise the compiler might
717 rearrange the switch below in a way that makes it hard to
718 track the event type. */
719 unsigned evtype = queue_ptr->EventType;
715 720
716 EVENT_INIT (inev); 721 EVENT_INIT (inev);
717 inev.kind = NO_EVENT; 722 inev.kind = NO_EVENT;
718 inev.arg = Qnil; 723 inev.arg = Qnil;
719 724
720 switch (queue_ptr->EventType) 725 switch (evtype)
721 { 726 {
722 case KEY_EVENT: 727 case KEY_EVENT:
723 add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead); 728 add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead);
diff --git a/src/w32menu.c b/src/w32menu.c
index b52aae55499..6ac02d95a63 100644
--- a/src/w32menu.c
+++ b/src/w32menu.c
@@ -115,129 +115,34 @@ static int fill_in_menu (HMENU, widget_value *);
115void w32_free_menu_strings (HWND); 115void w32_free_menu_strings (HWND);
116 116
117#ifdef HAVE_MENUS 117#ifdef HAVE_MENUS
118 118#ifdef HAVE_DIALOGS
119DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, 119Lisp_Object
120 doc: /* Pop up a dialog box and return user's selection. 120w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
121POSITION specifies which frame to use.
122This is normally a mouse button event or a window or frame.
123If POSITION is t, it means to use the frame the mouse is on.
124The dialog box appears in the middle of the specified frame.
125
126CONTENTS specifies the alternatives to display in the dialog box.
127It is a list of the form (TITLE ITEM1 ITEM2...).
128Each ITEM is a cons cell (STRING . VALUE).
129The return value is VALUE from the chosen item.
130
131An ITEM may also be just a string--that makes a nonselectable item.
132An ITEM may also be nil--that means to put all preceding items
133on the left of the dialog box and all following items on the right.
134\(By default, approximately half appear on each side.)
135
136If HEADER is non-nil, the frame title for the box is "Information",
137otherwise it is "Question". */)
138 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
139{ 121{
140 struct frame *f = NULL; 122 Lisp_Object title;
141 Lisp_Object window; 123 char *error_name;
142 124 Lisp_Object selection;
143 /* Decode the first argument: find the window or frame to use. */
144 if (EQ (position, Qt)
145 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
146 || EQ (XCAR (position), Qtool_bar))))
147 {
148#if 0 /* Using the frame the mouse is on may not be right. */
149 /* Use the mouse's current position. */
150 struct frame *new_f = SELECTED_FRAME ();
151 Lisp_Object bar_window;
152 enum scroll_bar_part part;
153 Time time;
154 Lisp_Object x, y;
155
156 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
157
158 if (new_f != 0)
159 XSETFRAME (window, new_f);
160 else
161 window = selected_window;
162#endif
163 window = selected_window;
164 }
165 else if (CONSP (position))
166 {
167 Lisp_Object tem = XCAR (position);
168 if (CONSP (tem))
169 window = Fcar (XCDR (position));
170 else
171 {
172 tem = Fcar (XCDR (position)); /* EVENT_START (position) */
173 window = Fcar (tem); /* POSN_WINDOW (tem) */
174 }
175 }
176 else if (WINDOWP (position) || FRAMEP (position))
177 window = position;
178 else
179 window = Qnil;
180
181 /* Decode where to put the menu. */
182
183 if (FRAMEP (window))
184 f = XFRAME (window);
185 else if (WINDOWP (window))
186 {
187 CHECK_LIVE_WINDOW (window);
188 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
189 }
190 else
191 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
192 but I don't want to make one now. */
193 CHECK_WINDOW (window);
194 125
195 check_window_system (f); 126 check_window_system (f);
196 127
197#ifndef HAVE_DIALOGS 128 /* Decode the dialog items from what was specified. */
198 129 title = Fcar (contents);
199 { 130 CHECK_STRING (title);
200 /* Handle simple Yes/No choices as MessageBox popups. */
201 if (is_simple_dialog (contents))
202 return simple_dialog_show (f, contents, header);
203 else
204 {
205 /* Display a menu with these alternatives
206 in the middle of frame F. */
207 Lisp_Object x, y, frame, newpos;
208 XSETFRAME (frame, f);
209 XSETINT (x, FRAME_PIXEL_WIDTH (f) / 2);
210 XSETINT (y, FRAME_PIXEL_HEIGHT (f) / 2);
211 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
212 return Fx_popup_menu (newpos,
213 Fcons (Fcar (contents), Fcons (contents, Qnil)));
214 }
215 }
216#else /* HAVE_DIALOGS */
217 {
218 Lisp_Object title;
219 char *error_name;
220 Lisp_Object selection;
221
222 /* Decode the dialog items from what was specified. */
223 title = Fcar (contents);
224 CHECK_STRING (title);
225 131
226 list_of_panes (Fcons (contents, Qnil)); 132 list_of_panes (Fcons (contents, Qnil));
227 133
228 /* Display them in a dialog box. */ 134 /* Display them in a dialog box. */
229 block_input (); 135 block_input ();
230 selection = w32_dialog_show (f, 0, title, header, &error_name); 136 selection = w32_dialog_show (f, 0, title, header, &error_name);
231 unblock_input (); 137 unblock_input ();
232 138
233 discard_menu_items (); 139 discard_menu_items ();
234 FRAME_DISPLAY_INFO (f)->grabbed = 0; 140 FRAME_DISPLAY_INFO (f)->grabbed = 0;
235 141
236 if (error_name) error (error_name); 142 if (error_name) error (error_name);
237 return selection; 143 return selection;
238 }
239#endif /* HAVE_DIALOGS */
240} 144}
145#endif /* HAVE_DIALOGS */
241 146
242/* Activate the menu bar of frame F. 147/* Activate the menu bar of frame F.
243 This is called from keyboard.c when it gets the 148 This is called from keyboard.c when it gets the
@@ -682,6 +587,8 @@ w32_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
682 return Qnil; 587 return Qnil;
683 } 588 }
684 589
590 block_input ();
591
685 /* Create a tree of widget_value objects 592 /* Create a tree of widget_value objects
686 representing the panes and their items. */ 593 representing the panes and their items. */
687 wv = xmalloc_widget_value (); 594 wv = xmalloc_widget_value ();
@@ -940,6 +847,7 @@ w32_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
940 if (!NILP (subprefix_stack[j])) 847 if (!NILP (subprefix_stack[j]))
941 entry = Fcons (subprefix_stack[j], entry); 848 entry = Fcons (subprefix_stack[j], entry);
942 } 849 }
850 unblock_input ();
943 return entry; 851 return entry;
944 } 852 }
945 i += MENU_ITEMS_ITEM_LENGTH; 853 i += MENU_ITEMS_ITEM_LENGTH;
@@ -947,9 +855,13 @@ w32_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
947 } 855 }
948 } 856 }
949 else if (!for_click) 857 else if (!for_click)
950 /* Make "Cancel" equivalent to C-g. */ 858 {
951 Fsignal (Qquit, Qnil); 859 unblock_input ();
860 /* Make "Cancel" equivalent to C-g. */
861 Fsignal (Qquit, Qnil);
862 }
952 863
864 unblock_input ();
953 return Qnil; 865 return Qnil;
954} 866}
955 867
@@ -1717,9 +1629,6 @@ syms_of_w32menu (void)
1717 DEFSYM (Qdebug_on_next_call, "debug-on-next-call"); 1629 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
1718 1630
1719 defsubr (&Smenu_or_popup_active_p); 1631 defsubr (&Smenu_or_popup_active_p);
1720#ifdef HAVE_MENUS
1721 defsubr (&Sx_popup_dialog);
1722#endif
1723} 1632}
1724 1633
1725/* 1634/*
diff --git a/src/w32term.h b/src/w32term.h
index 21b9b6894a7..8244487dfc7 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -264,6 +264,10 @@ extern int w32_kbd_mods_to_emacs (DWORD mods, WORD key);
264 264
265extern Lisp_Object x_get_focus_frame (struct frame *); 265extern Lisp_Object x_get_focus_frame (struct frame *);
266 266
267/* w32console.c */
268extern void w32con_hide_cursor (void);
269extern void w32con_show_cursor (void);
270
267 271
268#define PIX_TYPE COLORREF 272#define PIX_TYPE COLORREF
269 273
@@ -794,6 +798,10 @@ typedef char guichar_t;
794 798
795#define GUI_SDATA(x) ((guichar_t*) SDATA (x)) 799#define GUI_SDATA(x) ((guichar_t*) SDATA (x))
796 800
801#if defined HAVE_DIALOGS
802extern Lisp_Object w32_popup_dialog (struct frame *, Lisp_Object, Lisp_Object);
803#endif
804
797extern void syms_of_w32term (void); 805extern void syms_of_w32term (void);
798extern void syms_of_w32menu (void); 806extern void syms_of_w32menu (void);
799extern void syms_of_w32fns (void); 807extern void syms_of_w32fns (void);
diff --git a/src/window.c b/src/window.c
index 647a0b812e9..ecbe5fa5365 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5540,18 +5540,26 @@ the return value is nil. Otherwise the value is t. */)
5540 || data->frame_cols != previous_frame_cols) 5540 || data->frame_cols != previous_frame_cols)
5541 change_frame_size (f, data->frame_lines, 5541 change_frame_size (f, data->frame_lines,
5542 data->frame_cols, 0, 0, 0); 5542 data->frame_cols, 0, 0, 0);
5543#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS) 5543#ifdef HAVE_MENUS
5544 if (data->frame_menu_bar_lines 5544 if (data->frame_menu_bar_lines
5545 != previous_frame_menu_bar_lines) 5545 != previous_frame_menu_bar_lines)
5546 x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines), 5546 {
5547 make_number (0)); 5547#ifdef HAVE_WINDOW_SYSTEM
5548 if (FRAME_WINDOW_P (f))
5549 x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
5550 make_number (0));
5551 else /* TTY or MSDOS */
5552#endif
5553 set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
5554 make_number (0));
5555 }
5556#endif
5548#ifdef HAVE_WINDOW_SYSTEM 5557#ifdef HAVE_WINDOW_SYSTEM
5549 if (data->frame_tool_bar_lines 5558 if (data->frame_tool_bar_lines
5550 != previous_frame_tool_bar_lines) 5559 != previous_frame_tool_bar_lines)
5551 x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines), 5560 x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines),
5552 make_number (0)); 5561 make_number (0));
5553#endif 5562#endif
5554#endif
5555 5563
5556 /* "Swap out" point from the selected window's buffer 5564 /* "Swap out" point from the selected window's buffer
5557 into the window itself. (Normally the pointm of the selected 5565 into the window itself. (Normally the pointm of the selected
@@ -5738,16 +5746,25 @@ the return value is nil. Otherwise the value is t. */)
5738 || previous_frame_cols != FRAME_COLS (f)) 5746 || previous_frame_cols != FRAME_COLS (f))
5739 change_frame_size (f, previous_frame_lines, previous_frame_cols, 5747 change_frame_size (f, previous_frame_lines, previous_frame_cols,
5740 0, 0, 0); 5748 0, 0, 0);
5741#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS) 5749#ifdef HAVE_MENUS
5742 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f)) 5750 if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
5743 x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines), 5751 {
5744 make_number (0)); 5752#ifdef HAVE_WINDOW_SYSTEM
5753 if (FRAME_WINDOW_P (f))
5754 x_set_menu_bar_lines (f,
5755 make_number (previous_frame_menu_bar_lines),
5756 make_number (0));
5757 else /* TTY or MSDOS */
5758#endif
5759 set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
5760 make_number (0));
5761 }
5762#endif
5745#ifdef HAVE_WINDOW_SYSTEM 5763#ifdef HAVE_WINDOW_SYSTEM
5746 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f)) 5764 if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
5747 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines), 5765 x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
5748 make_number (0)); 5766 make_number (0));
5749#endif 5767#endif
5750#endif
5751 5768
5752 /* Now, free glyph matrices in windows that were not reused. */ 5769 /* Now, free glyph matrices in windows that were not reused. */
5753 for (i = n = 0; i < n_leaf_windows; ++i) 5770 for (i = n = 0; i < n_leaf_windows; ++i)
diff --git a/src/xdisp.c b/src/xdisp.c
index 5d5ce12d096..675ed638335 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -20584,7 +20584,128 @@ display_menu_bar (struct window *w)
20584 compute_line_metrics (&it); 20584 compute_line_metrics (&it);
20585} 20585}
20586 20586
20587#ifdef HAVE_MENUS
20588/* Deep copy of a glyph row, including the glyphs. */
20589static void
20590deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from)
20591{
20592 int area, i, sum_used = 0;
20593 struct glyph *pointers[1 + LAST_AREA];
20594
20595 /* Save glyph pointers of TO. */
20596 memcpy (pointers, to->glyphs, sizeof to->glyphs);
20597
20598 /* Do a structure assignment. */
20599 *to = *from;
20600
20601 /* Restore original pointers of TO. */
20602 memcpy (to->glyphs, pointers, sizeof to->glyphs);
20587 20603
20604 /* Count how many glyphs to copy and update glyph pointers. */
20605 for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
20606 {
20607 if (area > LEFT_MARGIN_AREA)
20608 {
20609 eassert (from->glyphs[area] - from->glyphs[area - 1]
20610 == from->used[area - 1]);
20611 to->glyphs[area] = to->glyphs[area - 1] + to->used[area - 1];
20612 }
20613 sum_used += from->used[area];
20614 }
20615
20616 /* Copy the glyphs. */
20617 eassert (sum_used <= to->glyphs[LAST_AREA] - to->glyphs[LEFT_MARGIN_AREA]);
20618 for (i = 0; i < sum_used; i++)
20619 to->glyphs[LEFT_MARGIN_AREA][i] = from->glyphs[LEFT_MARGIN_AREA][i];
20620}
20621
20622/* Display one menu item on a TTY, by overwriting the glyphs in the
20623 frame F's desired glyph matrix with glyphs produced from the menu
20624 item text. Called from term.c to display TTY drop-down menus one
20625 item at a time.
20626
20627 ITEM_TEXT is the menu item text as a C string.
20628
20629 FACE_ID is the face ID to be used for this menu item. FACE_ID
20630 could specify one of 3 faces: a face for an enabled item, a face
20631 for a disabled item, or a face for a selected item.
20632
20633 X and Y are coordinates of the first glyph in the frame's desired
20634 matrix to be overwritten by the menu item. Since this is a TTY, Y
20635 is the zero-based number of the glyph row and X is the zero-based
20636 glyph number in the row, starting from left, where to start
20637 displaying the item.
20638
20639 SUBMENU non-zero means this menu item drops down a submenu, which
20640 should be indicated by displaying a proper visual cue after the
20641 item text. */
20642
20643void
20644display_tty_menu_item (const char *item_text, int width, int face_id,
20645 int x, int y, int submenu)
20646{
20647 struct it it;
20648 struct frame *f = SELECTED_FRAME ();
20649 struct window *w = XWINDOW (f->selected_window);
20650 int saved_used, saved_truncated, saved_width, saved_reversed;
20651 struct glyph_row *row;
20652 size_t item_len = strlen (item_text);
20653
20654 eassert (FRAME_TERMCAP_P (f));
20655
20656 init_iterator (&it, w, -1, -1, f->desired_matrix->rows + y, MENU_FACE_ID);
20657 it.first_visible_x = 0;
20658 it.last_visible_x = FRAME_COLS (f) - 1;
20659 row = it.glyph_row;
20660 /* Start with the row contents from the current matrix. */
20661 deep_copy_glyph_row (row, f->current_matrix->rows + y);
20662 saved_width = row->full_width_p;
20663 row->full_width_p = 1;
20664 saved_reversed = row->reversed_p;
20665 row->reversed_p = 0;
20666 row->enabled_p = 1;
20667
20668 /* Arrange for the menu item glyphs to start at (X,Y) and have the
20669 desired face. */
20670 it.current_x = it.hpos = x;
20671 it.current_y = it.vpos = y;
20672 saved_used = row->used[TEXT_AREA];
20673 saved_truncated = row->truncated_on_right_p;
20674 row->used[TEXT_AREA] = x;
20675 it.face_id = face_id;
20676 it.line_wrap = TRUNCATE;
20677
20678 /* FIXME: This should be controlled by a user option. See the
20679 comments in redisplay_tool_bar and display_mode_line about this.
20680 Also, if paragraph_embedding could ever be R2L, changes will be
20681 needed to avoid shifting to the right the row characters in
20682 term.c:append_glyph. */
20683 it.paragraph_embedding = L2R;
20684
20685 /* Pad with a space on the left. */
20686 display_string (" ", Qnil, Qnil, 0, 0, &it, 1, 0, FRAME_COLS (f) - 1, -1);
20687 width--;
20688 /* Display the menu item, pad with spaces to WIDTH. */
20689 if (submenu)
20690 {
20691 display_string (item_text, Qnil, Qnil, 0, 0, &it,
20692 item_len, 0, FRAME_COLS (f) - 1, -1);
20693 width -= item_len;
20694 /* Indicate with " >" that there's a submenu. */
20695 display_string (" >", Qnil, Qnil, 0, 0, &it, width, 0,
20696 FRAME_COLS (f) - 1, -1);
20697 }
20698 else
20699 display_string (item_text, Qnil, Qnil, 0, 0, &it,
20700 width, 0, FRAME_COLS (f) - 1, -1);
20701
20702 row->used[TEXT_AREA] = max (saved_used, row->used[TEXT_AREA]);
20703 row->truncated_on_right_p = saved_truncated;
20704 row->hash = row_hash (row);
20705 row->full_width_p = saved_width;
20706 row->reversed_p = saved_reversed;
20707}
20708#endif /* HAVE_MENUS */
20588 20709
20589/*********************************************************************** 20710/***********************************************************************
20590 Mode Line 20711 Mode Line
diff --git a/src/xmenu.c b/src/xmenu.c
index ad8380a3c3e..fe0e229ef20 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -192,149 +192,6 @@ mouse_position_for_popup (struct frame *f, int *x, int *y)
192 192
193#endif /* HAVE_X_WINDOWS */ 193#endif /* HAVE_X_WINDOWS */
194 194
195#ifdef HAVE_MENUS
196
197DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
198 doc: /* Pop up a dialog box and return user's selection.
199POSITION specifies which frame to use.
200This is normally a mouse button event or a window or frame.
201If POSITION is t, it means to use the frame the mouse is on.
202The dialog box appears in the middle of the specified frame.
203
204CONTENTS specifies the alternatives to display in the dialog box.
205It is a list of the form (DIALOG ITEM1 ITEM2...).
206Each ITEM is a cons cell (STRING . VALUE).
207The return value is VALUE from the chosen item.
208
209An ITEM may also be just a string--that makes a nonselectable item.
210An ITEM may also be nil--that means to put all preceding items
211on the left of the dialog box and all following items on the right.
212\(By default, approximately half appear on each side.)
213
214If HEADER is non-nil, the frame title for the box is "Information",
215otherwise it is "Question".
216
217If the user gets rid of the dialog box without making a valid choice,
218for instance using the window manager, then this produces a quit and
219`x-popup-dialog' does not return. */)
220 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
221{
222 struct frame *f = NULL;
223 Lisp_Object window;
224
225 /* Decode the first argument: find the window or frame to use. */
226 if (EQ (position, Qt)
227 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
228 || EQ (XCAR (position), Qtool_bar))))
229 {
230#if 0 /* Using the frame the mouse is on may not be right. */
231 /* Use the mouse's current position. */
232 struct frame *new_f = SELECTED_FRAME ();
233 Lisp_Object bar_window;
234 enum scroll_bar_part part;
235 Time time;
236 Lisp_Object x, y;
237
238 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
239
240 if (new_f != 0)
241 XSETFRAME (window, new_f);
242 else
243 window = selected_window;
244#endif
245 window = selected_window;
246 }
247 else if (CONSP (position))
248 {
249 Lisp_Object tem = XCAR (position);
250 if (CONSP (tem))
251 window = Fcar (XCDR (position));
252 else
253 {
254 tem = Fcar (XCDR (position)); /* EVENT_START (position) */
255 window = Fcar (tem); /* POSN_WINDOW (tem) */
256 }
257 }
258 else if (WINDOWP (position) || FRAMEP (position))
259 window = position;
260 else
261 window = Qnil;
262
263 /* Decode where to put the menu. */
264
265 if (FRAMEP (window))
266 f = XFRAME (window);
267 else if (WINDOWP (window))
268 {
269 CHECK_LIVE_WINDOW (window);
270 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
271 }
272 else
273 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
274 but I don't want to make one now. */
275 CHECK_WINDOW (window);
276
277 check_window_system (f);
278
279 /* Force a redisplay before showing the dialog. If a frame is created
280 just before showing the dialog, its contents may not have been fully
281 drawn, as this depends on timing of events from the X server. Redisplay
282 is not done when a dialog is shown. If redisplay could be done in the
283 X event loop (i.e. the X event loop does not run in a signal handler)
284 this would not be needed.
285
286 Do this before creating the widget value that points to Lisp
287 string contents, because Fredisplay may GC and relocate them. */
288 Fredisplay (Qt);
289
290#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
291 /* Display a menu with these alternatives
292 in the middle of frame F. */
293 {
294 Lisp_Object x, y, frame, newpos;
295 XSETFRAME (frame, f);
296 XSETINT (x, FRAME_PIXEL_WIDTH (f) / 2);
297 XSETINT (y, FRAME_PIXEL_HEIGHT (f) / 2);
298 newpos = list2 (list2 (x, y), frame);
299
300 return Fx_popup_menu (newpos,
301 list2 (Fcar (contents), contents));
302 }
303#else
304 {
305 Lisp_Object title;
306 const char *error_name;
307 Lisp_Object selection;
308 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
309
310 /* Decode the dialog items from what was specified. */
311 title = Fcar (contents);
312 CHECK_STRING (title);
313 record_unwind_protect_void (unuse_menu_items);
314
315 if (NILP (Fcar (Fcdr (contents))))
316 /* No buttons specified, add an "Ok" button so users can pop down
317 the dialog. Also, the lesstif/motif version crashes if there are
318 no buttons. */
319 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
320
321 list_of_panes (list1 (contents));
322
323 /* Display them in a dialog box. */
324 block_input ();
325 selection = xdialog_show (f, 0, title, header, &error_name);
326 unblock_input ();
327
328 unbind_to (specpdl_count, Qnil);
329 discard_menu_items ();
330
331 if (error_name) error ("%s", error_name);
332 return selection;
333 }
334#endif
335}
336
337
338#ifndef MSDOS 195#ifndef MSDOS
339 196
340#if defined USE_GTK || defined USE_MOTIF 197#if defined USE_GTK || defined USE_MOTIF
@@ -1618,6 +1475,8 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
1618 return Qnil; 1475 return Qnil;
1619 } 1476 }
1620 1477
1478 block_input ();
1479
1621 /* Create a tree of widget_value objects 1480 /* Create a tree of widget_value objects
1622 representing the panes and their items. */ 1481 representing the panes and their items. */
1623 wv = xmalloc_widget_value (); 1482 wv = xmalloc_widget_value ();
@@ -1857,6 +1716,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
1857 if (!NILP (subprefix_stack[j])) 1716 if (!NILP (subprefix_stack[j]))
1858 entry = Fcons (subprefix_stack[j], entry); 1717 entry = Fcons (subprefix_stack[j], entry);
1859 } 1718 }
1719 unblock_input ();
1860 return entry; 1720 return entry;
1861 } 1721 }
1862 i += MENU_ITEMS_ITEM_LENGTH; 1722 i += MENU_ITEMS_ITEM_LENGTH;
@@ -1864,9 +1724,13 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
1864 } 1724 }
1865 } 1725 }
1866 else if (!for_click) 1726 else if (!for_click)
1867 /* Make "Cancel" equivalent to C-g. */ 1727 {
1868 Fsignal (Qquit, Qnil); 1728 unblock_input ();
1729 /* Make "Cancel" equivalent to C-g. */
1730 Fsignal (Qquit, Qnil);
1731 }
1869 1732
1733 unblock_input ();
1870 return Qnil; 1734 return Qnil;
1871} 1735}
1872 1736
@@ -2163,6 +2027,41 @@ xdialog_show (struct frame *f,
2163 return Qnil; 2027 return Qnil;
2164} 2028}
2165 2029
2030Lisp_Object
2031xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
2032{
2033 Lisp_Object title;
2034 const char *error_name;
2035 Lisp_Object selection;
2036 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2037
2038 check_window_system (f);
2039
2040 /* Decode the dialog items from what was specified. */
2041 title = Fcar (contents);
2042 CHECK_STRING (title);
2043 record_unwind_protect_void (unuse_menu_items);
2044
2045 if (NILP (Fcar (Fcdr (contents))))
2046 /* No buttons specified, add an "Ok" button so users can pop down
2047 the dialog. Also, the lesstif/motif version crashes if there are
2048 no buttons. */
2049 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
2050
2051 list_of_panes (list1 (contents));
2052
2053 /* Display them in a dialog box. */
2054 block_input ();
2055 selection = xdialog_show (f, 0, title, header, &error_name);
2056 unblock_input ();
2057
2058 unbind_to (specpdl_count, Qnil);
2059 discard_menu_items ();
2060
2061 if (error_name) error ("%s", error_name);
2062 return selection;
2063}
2064
2166#else /* not USE_X_TOOLKIT && not USE_GTK */ 2065#else /* not USE_X_TOOLKIT && not USE_GTK */
2167 2066
2168/* The frame of the last activated non-toolkit menu bar. 2067/* The frame of the last activated non-toolkit menu bar.
@@ -2261,6 +2160,8 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
2261 return Qnil; 2160 return Qnil;
2262 } 2161 }
2263 2162
2163 block_input ();
2164
2264 /* Figure out which root window F is on. */ 2165 /* Figure out which root window F is on. */
2265 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root, 2166 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2266 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint, 2167 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
@@ -2271,6 +2172,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
2271 if (menu == NULL) 2172 if (menu == NULL)
2272 { 2173 {
2273 *error_name = "Can't create menu"; 2174 *error_name = "Can't create menu";
2175 unblock_input ();
2274 return Qnil; 2176 return Qnil;
2275 } 2177 }
2276 2178
@@ -2314,6 +2216,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
2314 { 2216 {
2315 XMenuDestroy (FRAME_X_DISPLAY (f), menu); 2217 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2316 *error_name = "Can't create pane"; 2218 *error_name = "Can't create pane";
2219 unblock_input ();
2317 return Qnil; 2220 return Qnil;
2318 } 2221 }
2319 i += MENU_ITEMS_PANE_LENGTH; 2222 i += MENU_ITEMS_PANE_LENGTH;
@@ -2378,6 +2281,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
2378 { 2281 {
2379 XMenuDestroy (FRAME_X_DISPLAY (f), menu); 2282 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2380 *error_name = "Can't add selection to menu"; 2283 *error_name = "Can't add selection to menu";
2284 unblock_input ();
2381 return Qnil; 2285 return Qnil;
2382 } 2286 }
2383 i += MENU_ITEMS_ITEM_LENGTH; 2287 i += MENU_ITEMS_ITEM_LENGTH;
@@ -2504,10 +2408,14 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
2504 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means 2408 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2505 the menu was invoked with a mouse event as POSITION). */ 2409 the menu was invoked with a mouse event as POSITION). */
2506 if (! for_click) 2410 if (! for_click)
2507 Fsignal (Qquit, Qnil); 2411 {
2412 unblock_input ();
2413 Fsignal (Qquit, Qnil);
2414 }
2508 break; 2415 break;
2509 } 2416 }
2510 2417
2418 unblock_input ();
2511 unbind_to (specpdl_count, Qnil); 2419 unbind_to (specpdl_count, Qnil);
2512 2420
2513 return entry; 2421 return entry;
@@ -2515,8 +2423,6 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
2515 2423
2516#endif /* not USE_X_TOOLKIT */ 2424#endif /* not USE_X_TOOLKIT */
2517 2425
2518#endif /* HAVE_MENUS */
2519
2520#ifndef MSDOS 2426#ifndef MSDOS
2521/* Detect if a dialog or menu has been posted. MSDOS has its own 2427/* Detect if a dialog or menu has been posted. MSDOS has its own
2522 implementation on msdos.c. */ 2428 implementation on msdos.c. */
@@ -2558,8 +2464,4 @@ syms_of_xmenu (void)
2558 Ffset (intern_c_string ("accelerate-menu"), 2464 Ffset (intern_c_string ("accelerate-menu"),
2559 intern_c_string (Sx_menu_bar_open_internal.symbol_name)); 2465 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2560#endif 2466#endif
2561
2562#ifdef HAVE_MENUS
2563 defsubr (&Sx_popup_dialog);
2564#endif
2565} 2467}
diff --git a/src/xterm.h b/src/xterm.h
index 36aa8e52b1c..5ec4851a0e1 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1035,6 +1035,10 @@ extern void x_free_dpy_colors (Display *, Screen *, Colormap,
1035 1035
1036/* Defined in xmenu.c */ 1036/* Defined in xmenu.c */
1037 1037
1038#if defined USE_X_TOOLKIT || defined USE_GTK
1039extern Lisp_Object xw_popup_dialog (struct frame *, Lisp_Object, Lisp_Object);
1040#endif
1041
1038#if defined USE_GTK || defined USE_MOTIF 1042#if defined USE_GTK || defined USE_MOTIF
1039extern void x_menu_set_in_use (int); 1043extern void x_menu_set_in_use (int);
1040#endif 1044#endif