diff options
| author | Eli Zaretskii | 2013-10-08 20:49:20 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2013-10-08 20:49:20 +0300 |
| commit | 4ed774157d1687cc5236ecaf088dc48442e92431 (patch) | |
| tree | 4dd32cb0104172c6b12f90c2651f58f0040bfe20 /src | |
| parent | 06286513730d013c2033d1dae892349e5eec98d9 (diff) | |
| parent | f3370a94fd887e9e01db81a86e42036d12dcda9b (diff) | |
| download | emacs-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/ChangeLog | 113 | ||||
| -rw-r--r-- | src/alloc.c | 2 | ||||
| -rw-r--r-- | src/cm.h | 2 | ||||
| -rw-r--r-- | src/dispextern.h | 6 | ||||
| -rw-r--r-- | src/dispnew.c | 81 | ||||
| -rw-r--r-- | src/editfns.c | 25 | ||||
| -rw-r--r-- | src/fns.c | 7 | ||||
| -rw-r--r-- | src/frame.h | 3 | ||||
| -rw-r--r-- | src/keyboard.c | 164 | ||||
| -rw-r--r-- | src/keyboard.h | 2 | ||||
| -rw-r--r-- | src/menu.c | 568 | ||||
| -rw-r--r-- | src/menu.h | 3 | ||||
| -rw-r--r-- | src/msdos.c | 7 | ||||
| -rw-r--r-- | src/nsmenu.m | 34 | ||||
| -rw-r--r-- | src/nsterm.h | 4 | ||||
| -rw-r--r-- | src/term.c | 1121 | ||||
| -rw-r--r-- | src/termchar.h | 3 | ||||
| -rw-r--r-- | src/termhooks.h | 8 | ||||
| -rw-r--r-- | src/w32console.c | 32 | ||||
| -rw-r--r-- | src/w32fns.c | 5 | ||||
| -rw-r--r-- | src/w32inevt.c | 7 | ||||
| -rw-r--r-- | src/w32menu.c | 147 | ||||
| -rw-r--r-- | src/w32term.h | 8 | ||||
| -rw-r--r-- | src/window.c | 33 | ||||
| -rw-r--r-- | src/xdisp.c | 121 | ||||
| -rw-r--r-- | src/xmenu.c | 206 | ||||
| -rw-r--r-- | src/xterm.h | 4 |
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 @@ | |||
| 1 | 2013-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 | |||
| 1 | 2013-10-08 Dmitry Antipov <dmantipov@yandex.ru> | 114 | 2013-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 | ||
| 3412 | Lisp_Object | 3411 | Lisp_Object |
| 3413 | make_save_ptr (void *a) | 3412 | make_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 | ||
| 3423 | Lisp_Object | 3421 | Lisp_Object |
| 3424 | make_save_ptr_int (void *a, ptrdiff_t b) | 3422 | make_save_ptr_int (void *a, ptrdiff_t b) |
| @@ -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 *); | |||
| 3256 | extern int cursor_in_mouse_face_p (struct window *w); | 3256 | extern int cursor_in_mouse_face_p (struct window *w); |
| 3257 | extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *, | 3257 | extern 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); |
| 3259 | extern 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 | ||
| 3428 | int popup_activated (void); | 3429 | int popup_activated (void); |
| 3429 | 3430 | ||
| 3431 | /* Defined in dispnew.c */ | ||
| 3432 | |||
| 3430 | extern Lisp_Object buffer_posn_from_coords (struct window *, | 3433 | extern 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 *); |
| 3443 | extern void redraw_frame (struct frame *); | 3446 | extern void redraw_frame (struct frame *); |
| 3444 | extern bool update_frame (struct frame *, bool, bool); | 3447 | extern bool update_frame (struct frame *, bool, bool); |
| 3448 | extern void update_frame_with_menu (struct frame *); | ||
| 3445 | extern void bitch_at_user (void); | 3449 | extern void bitch_at_user (void); |
| 3446 | extern void adjust_frame_glyphs (struct frame *); | 3450 | extern void adjust_frame_glyphs (struct frame *); |
| 3447 | void free_glyphs (struct frame *); | 3451 | void free_glyphs (struct frame *); |
| @@ -3467,7 +3471,7 @@ void change_frame_size (struct frame *, int, int, bool, bool, bool); | |||
| 3467 | void init_display (void); | 3471 | void init_display (void); |
| 3468 | void syms_of_display (void); | 3472 | void syms_of_display (void); |
| 3469 | extern Lisp_Object Qredisplay_dont_pause; | 3473 | extern Lisp_Object Qredisplay_dont_pause; |
| 3470 | void spec_glyph_lookup_face (struct window *, GLYPH *); | 3474 | extern 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. */ | ||
| 3095 | void | ||
| 3096 | update_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 | } |
| @@ -2434,8 +2434,8 @@ a space; `yes-or-no-p' adds \"(yes or no) \" to it. | |||
| 2434 | The user must confirm the answer with RET, and can edit it until it | 2434 | The user must confirm the answer with RET, and can edit it until it |
| 2435 | has been confirmed. | 2435 | has been confirmed. |
| 2436 | 2436 | ||
| 2437 | Under a windowing system a dialog box will be used if `last-nonmenu-event' | 2437 | If dialog boxes are supported, a dialog box will be used |
| 2438 | is nil, and `use-dialog-box' is non-nil. */) | 2438 | if `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); |
| 1249 | extern void x_activate_menubar (struct frame *); | 1249 | extern void x_activate_menubar (struct frame *); |
| 1250 | extern void x_real_positions (struct frame *, int *, int *); | 1250 | extern void x_real_positions (struct frame *, int *, int *); |
| 1251 | extern void x_set_menu_bar_lines (struct frame *, | ||
| 1252 | Lisp_Object, | ||
| 1253 | Lisp_Object); | ||
| 1254 | extern void free_frame_menubar (struct frame *); | 1251 | extern void free_frame_menubar (struct frame *); |
| 1255 | extern void x_free_frame_resources (struct frame *); | 1252 | extern 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. */ |
| 292 | static Lisp_Object Qmouse_movement; | 292 | Lisp_Object Qmouse_movement; |
| 293 | static Lisp_Object Qscroll_bar_movement; | 293 | static Lisp_Object Qscroll_bar_movement; |
| 294 | Lisp_Object Qswitch_frame; | 294 | Lisp_Object Qswitch_frame; |
| 295 | static Lisp_Object Qfocus_in, Qfocus_out; | 295 | static Lisp_Object Qfocus_in, Qfocus_out; |
| @@ -354,6 +354,8 @@ Lisp_Object Qvertical_line; | |||
| 354 | static Lisp_Object Qvertical_scroll_bar; | 354 | static Lisp_Object Qvertical_scroll_bar; |
| 355 | Lisp_Object Qmenu_bar; | 355 | Lisp_Object Qmenu_bar; |
| 356 | 356 | ||
| 357 | static Lisp_Object Qecho_keystrokes; | ||
| 358 | |||
| 357 | static void recursive_edit_unwind (Lisp_Object buffer); | 359 | static void recursive_edit_unwind (Lisp_Object buffer); |
| 358 | static Lisp_Object command_loop (void); | 360 | static Lisp_Object command_loop (void); |
| 359 | static Lisp_Object Qcommand_execute; | 361 | static Lisp_Object Qcommand_execute; |
| @@ -1305,7 +1307,7 @@ some_mouse_moved (void) | |||
| 1305 | sans error-handling encapsulation. */ | 1307 | sans error-handling encapsulation. */ |
| 1306 | 1308 | ||
| 1307 | static int read_key_sequence (Lisp_Object *, int, Lisp_Object, | 1309 | static int read_key_sequence (Lisp_Object *, int, Lisp_Object, |
| 1308 | bool, bool, bool); | 1310 | bool, bool, bool, bool); |
| 1309 | void safe_run_hooks (Lisp_Object); | 1311 | void safe_run_hooks (Lisp_Object); |
| 1310 | static void adjust_point_for_property (ptrdiff_t, bool); | 1312 | static 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 | ||
| 1696 | Lisp_Object | ||
| 1697 | read_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. */ | ||
| 5413 | static bool | ||
| 5414 | toolkit_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) | |||
| 8824 | static int | 8884 | static int |
| 8825 | read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, | 8885 | read_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; | |||
| 450 | extern Lisp_Object Qevent_kind; | 450 | extern Lisp_Object Qevent_kind; |
| 451 | 451 | ||
| 452 | /* The values of Qevent_kind properties. */ | 452 | /* The values of Qevent_kind properties. */ |
| 453 | extern Lisp_Object Qmouse_click; | 453 | extern Lisp_Object Qmouse_click, Qmouse_movement; |
| 454 | 454 | ||
| 455 | extern Lisp_Object Qhelp_echo; | 455 | extern 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. */ |
| 55 | static bool | ||
| 56 | have_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 | ||
| 58 | Lisp_Object menu_items; | 65 | Lisp_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. */ | ||
| 463 | static Lisp_Object | ||
| 464 | encode_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. */ |
| 460 | static void | 474 | static 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 | ||
| 1039 | int | ||
| 1040 | menu_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 | |||
| 1056 | DEFUN ("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. | ||
| 1059 | X and Y are frame-relative pixel coordinates, assumed to define | ||
| 1060 | a location within the menu bar. | ||
| 1061 | If FRAME is nil or omitted, it defaults to the selected frame. | ||
| 1062 | |||
| 1063 | Value is the symbol of the menu at X/Y, or nil if the specified | ||
| 1064 | coordinates are not within the FRAME's menu bar. The symbol can | ||
| 1065 | be used to look up the menu like this: | ||
| 1066 | |||
| 1067 | (lookup-key MAP [menu-bar SYMBOL]) | ||
| 1068 | |||
| 1069 | where MAP is either the current global map or the current local map, | ||
| 1070 | since menu-bar items come from both. | ||
| 1071 | |||
| 1072 | This function can return non-nil only on a text-terminal frame | ||
| 1073 | or on an X frame that doesn't use any GUI toolkit. Otherwise, | ||
| 1074 | Emacs does not manage the menu bar and cannot convert coordinates | ||
| 1075 | into 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 | |||
| 1014 | DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0, | 1118 | DEFUN ("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. |
| 1016 | POSITION is a position specification. This is either a mouse button event | 1120 | POSITION 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 | |||
| 1056 | no quit occurs and `x-popup-menu' returns nil. */) | 1160 | no 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 | |||
| 1478 | DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, | ||
| 1479 | doc: /* Pop up a dialog box and return user's selection. | ||
| 1480 | POSITION specifies which frame to use. | ||
| 1481 | This is normally a mouse button event or a window or frame. | ||
| 1482 | If POSITION is t, it means to use the frame the mouse is on. | ||
| 1483 | The dialog box appears in the middle of the specified frame. | ||
| 1484 | |||
| 1485 | CONTENTS specifies the alternatives to display in the dialog box. | ||
| 1486 | It is a list of the form (DIALOG ITEM1 ITEM2...). | ||
| 1487 | Each ITEM is a cons cell (STRING . VALUE). | ||
| 1488 | The return value is VALUE from the chosen item. | ||
| 1489 | |||
| 1490 | An ITEM may also be just a string--that makes a nonselectable item. | ||
| 1491 | An ITEM may also be nil--that means to put all preceding items | ||
| 1492 | on the left of the dialog box and all following items on the right. | ||
| 1493 | \(By default, approximately half appear on each side.) | ||
| 1494 | |||
| 1495 | If HEADER is non-nil, the frame title for the box is "Information", | ||
| 1496 | otherwise it is "Question". | ||
| 1497 | |||
| 1498 | If the user gets rid of the dialog box without making a valid choice, | ||
| 1499 | for 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 | |||
| 1352 | void | 1615 | void |
| 1353 | syms_of_menu (void) | 1616 | syms_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 **); |
| 52 | extern Lisp_Object xmenu_show (struct frame *, int, int, bool, bool, | 52 | extern Lisp_Object xmenu_show (struct frame *, int, int, bool, bool, |
| 53 | Lisp_Object, const char **, Time); | 53 | Lisp_Object, const char **, Time); |
| 54 | extern Lisp_Object tty_menu_show (struct frame *, int, int, int, int, | ||
| 55 | Lisp_Object, int, const char **); | ||
| 56 | extern 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. */ | ||
| 1383 | void | ||
| 1384 | x_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 | ||
| 1391 | extern Lisp_Object Qbackground_color; | 1384 | extern 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 | ||
| 1451 | Lisp_Object | 1454 | Lisp_Object |
| 1452 | ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header) | 1455 | ns_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 | ||
| 1919 | DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, | ||
| 1920 | doc: /* Pop up a dialog box and return user's selection. | ||
| 1921 | POSITION specifies which frame to use. | ||
| 1922 | This is normally a mouse button event or a window or frame. | ||
| 1923 | If POSITION is t, it means to use the frame the mouse is on. | ||
| 1924 | The dialog box appears in the middle of the specified frame. | ||
| 1925 | |||
| 1926 | CONTENTS specifies the alternatives to display in the dialog box. | ||
| 1927 | It is a list of the form (DIALOG ITEM1 ITEM2...). | ||
| 1928 | Each ITEM is a cons cell (STRING . VALUE). | ||
| 1929 | The return value is VALUE from the chosen item. | ||
| 1930 | |||
| 1931 | An ITEM may also be just a string--that makes a nonselectable item. | ||
| 1932 | An ITEM may also be nil--that means to put all preceding items | ||
| 1933 | on the left of the dialog box and all following items on the right. | ||
| 1934 | \(By default, approximately half appear on each side.) | ||
| 1935 | |||
| 1936 | If HEADER is non-nil, the frame title for the box is "Information", | ||
| 1937 | otherwise it is "Question". | ||
| 1938 | |||
| 1939 | If the user gets rid of the dialog box without making a valid choice, | ||
| 1940 | for 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 | |||
| 1947 | DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0, | 1922 | DEFUN ("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, | |||
| 850 | extern Lisp_Object find_and_return_menu_selection (struct frame *f, | 850 | extern Lisp_Object find_and_return_menu_selection (struct frame *f, |
| 851 | bool keymaps, | 851 | bool keymaps, |
| 852 | void *client_data); | 852 | void *client_data); |
| 853 | extern Lisp_Object ns_popup_dialog (Lisp_Object position, Lisp_Object contents, | 853 | extern 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 |
| 857 | extern void ns_run_ascript (void); | 857 | extern 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. */ | ||
| 2796 | static 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. */ | ||
| 2799 | static int menu_help_paneno, menu_help_itemno; | ||
| 2800 | |||
| 2801 | static Lisp_Object Qtty_menu_navigation_map, Qtty_menu_exit; | ||
| 2802 | static Lisp_Object Qtty_menu_prev_item, Qtty_menu_next_item; | ||
| 2803 | static Lisp_Object Qtty_menu_next_menu, Qtty_menu_prev_menu; | ||
| 2804 | static Lisp_Object Qtty_menu_select, Qtty_menu_ignore; | ||
| 2805 | static Lisp_Object Qtty_menu_mouse_movement; | ||
| 2806 | |||
| 2807 | typedef 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 | |||
| 2821 | static tty_menu * | ||
| 2822 | tty_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 | |||
| 2834 | static void | ||
| 2835 | tty_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 | |||
| 2861 | static tty_menu * | ||
| 2862 | tty_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 | |||
| 2880 | static void | ||
| 2881 | tty_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 | |||
| 2900 | static void | ||
| 2901 | mouse_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 | |||
| 2922 | static void | ||
| 2923 | tty_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 | |||
| 2966 | int | ||
| 2967 | have_menus_p (void) { return 1; } | ||
| 2968 | |||
| 2969 | /* Create a new pane and place it on the outer-most level. */ | ||
| 2970 | |||
| 2971 | static int | ||
| 2972 | tty_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 | |||
| 3002 | int | ||
| 3003 | tty_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 | |||
| 3037 | void | ||
| 3038 | tty_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 | |||
| 3047 | struct 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 | |||
| 3059 | static struct glyph_matrix * | ||
| 3060 | save_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 | |||
| 3105 | static void | ||
| 3106 | restore_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 | |||
| 3144 | static void | ||
| 3145 | free_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. */ | ||
| 3168 | static void | ||
| 3169 | screen_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. */ | ||
| 3182 | static int | ||
| 3183 | read_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. */ | ||
| 3253 | static int | ||
| 3254 | tty_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 | |||
| 3464 | void | ||
| 3465 | tty_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 | |||
| 3487 | static void | ||
| 3488 | tty_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 | |||
| 3509 | static void | ||
| 3510 | tty_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. */ | ||
| 3520 | static int | ||
| 3521 | tty_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. */ | ||
| 3549 | static void | ||
| 3550 | tty_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 | |||
| 3600 | Lisp_Object | ||
| 3601 | tty_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, | |||
| 656 | extern void close_gpm (int gpm_fd); | 656 | extern void close_gpm (int gpm_fd); |
| 657 | #endif | 657 | #endif |
| 658 | 658 | ||
| 659 | #ifdef WINDOWSNT | ||
| 660 | extern int cursorX (struct tty_display_info *); | ||
| 661 | extern int cursorY (struct tty_display_info *); | ||
| 662 | #else | ||
| 663 | #define cursorX(t) curX(t) | ||
| 664 | #define cursorY(t) curY(t) | ||
| 665 | #endif | ||
| 666 | |||
| 659 | INLINE_HEADER_END | 667 | INLINE_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; | |||
| 62 | static WORD char_attr_normal; | 62 | static WORD char_attr_normal; |
| 63 | static DWORD prev_console_mode; | 63 | static DWORD prev_console_mode; |
| 64 | 64 | ||
| 65 | static CONSOLE_CURSOR_INFO console_cursor_info; | ||
| 65 | #ifndef USE_SEPARATE_SCREEN | 66 | #ifndef USE_SEPARATE_SCREEN |
| 66 | static CONSOLE_CURSOR_INFO prev_console_cursor; | 67 | static 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 | ||
| 99 | void | ||
| 100 | w32con_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 | |||
| 107 | void | ||
| 108 | w32con_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. */ |
| 99 | static void | 116 | static void |
| 100 | w32con_clear_to_end (struct frame *f) | 117 | w32con_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". */ | ||
| 575 | int | ||
| 576 | cursorX (struct tty_display_info *tty) | ||
| 577 | { | ||
| 578 | return cursor_coords.X; | ||
| 579 | } | ||
| 580 | |||
| 581 | int | ||
| 582 | cursorY (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 *); | |||
| 115 | void w32_free_menu_strings (HWND); | 115 | void w32_free_menu_strings (HWND); |
| 116 | 116 | ||
| 117 | #ifdef HAVE_MENUS | 117 | #ifdef HAVE_MENUS |
| 118 | 118 | #ifdef HAVE_DIALOGS | |
| 119 | DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, | 119 | Lisp_Object |
| 120 | doc: /* Pop up a dialog box and return user's selection. | 120 | w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) |
| 121 | POSITION specifies which frame to use. | ||
| 122 | This is normally a mouse button event or a window or frame. | ||
| 123 | If POSITION is t, it means to use the frame the mouse is on. | ||
| 124 | The dialog box appears in the middle of the specified frame. | ||
| 125 | |||
| 126 | CONTENTS specifies the alternatives to display in the dialog box. | ||
| 127 | It is a list of the form (TITLE ITEM1 ITEM2...). | ||
| 128 | Each ITEM is a cons cell (STRING . VALUE). | ||
| 129 | The return value is VALUE from the chosen item. | ||
| 130 | |||
| 131 | An ITEM may also be just a string--that makes a nonselectable item. | ||
| 132 | An ITEM may also be nil--that means to put all preceding items | ||
| 133 | on the left of the dialog box and all following items on the right. | ||
| 134 | \(By default, approximately half appear on each side.) | ||
| 135 | |||
| 136 | If HEADER is non-nil, the frame title for the box is "Information", | ||
| 137 | otherwise 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 | ||
| 265 | extern Lisp_Object x_get_focus_frame (struct frame *); | 265 | extern Lisp_Object x_get_focus_frame (struct frame *); |
| 266 | 266 | ||
| 267 | /* w32console.c */ | ||
| 268 | extern void w32con_hide_cursor (void); | ||
| 269 | extern 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 | ||
| 802 | extern Lisp_Object w32_popup_dialog (struct frame *, Lisp_Object, Lisp_Object); | ||
| 803 | #endif | ||
| 804 | |||
| 797 | extern void syms_of_w32term (void); | 805 | extern void syms_of_w32term (void); |
| 798 | extern void syms_of_w32menu (void); | 806 | extern void syms_of_w32menu (void); |
| 799 | extern void syms_of_w32fns (void); | 807 | extern 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. */ | ||
| 20589 | static void | ||
| 20590 | deep_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 | |||
| 20643 | void | ||
| 20644 | display_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 | |||
| 197 | DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, | ||
| 198 | doc: /* Pop up a dialog box and return user's selection. | ||
| 199 | POSITION specifies which frame to use. | ||
| 200 | This is normally a mouse button event or a window or frame. | ||
| 201 | If POSITION is t, it means to use the frame the mouse is on. | ||
| 202 | The dialog box appears in the middle of the specified frame. | ||
| 203 | |||
| 204 | CONTENTS specifies the alternatives to display in the dialog box. | ||
| 205 | It is a list of the form (DIALOG ITEM1 ITEM2...). | ||
| 206 | Each ITEM is a cons cell (STRING . VALUE). | ||
| 207 | The return value is VALUE from the chosen item. | ||
| 208 | |||
| 209 | An ITEM may also be just a string--that makes a nonselectable item. | ||
| 210 | An ITEM may also be nil--that means to put all preceding items | ||
| 211 | on the left of the dialog box and all following items on the right. | ||
| 212 | \(By default, approximately half appear on each side.) | ||
| 213 | |||
| 214 | If HEADER is non-nil, the frame title for the box is "Information", | ||
| 215 | otherwise it is "Question". | ||
| 216 | |||
| 217 | If the user gets rid of the dialog box without making a valid choice, | ||
| 218 | for 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 | ||
| 2030 | Lisp_Object | ||
| 2031 | xw_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 | ||
| 1039 | extern 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 |
| 1039 | extern void x_menu_set_in_use (int); | 1043 | extern void x_menu_set_in_use (int); |
| 1040 | #endif | 1044 | #endif |