diff options
| author | Eli Zaretskii | 2012-06-02 17:57:51 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2012-06-02 17:57:51 +0300 |
| commit | b5e9cbb6fdce4b7e8c5cd6ad1addf6e4af35da67 (patch) | |
| tree | c6a1b2060e5d56677f6785c2241311527fa917fa | |
| parent | f51b6486fc8b0e3fa7fd08cbf83b27ef0d5efe1a (diff) | |
| download | emacs-b5e9cbb6fdce4b7e8c5cd6ad1addf6e4af35da67.tar.gz emacs-b5e9cbb6fdce4b7e8c5cd6ad1addf6e4af35da67.zip | |
Initial incomplete version of tty menus. tty_menu_activate not done yet.
| -rw-r--r-- | src/dispextern.h | 55 | ||||
| -rw-r--r-- | src/dispnew.c | 33 | ||||
| -rw-r--r-- | src/menu.c | 29 | ||||
| -rw-r--r-- | src/menu.h | 2 | ||||
| -rw-r--r-- | src/msdos.c | 7 | ||||
| -rw-r--r-- | src/term.c | 801 | ||||
| -rw-r--r-- | src/termhooks.h | 6 | ||||
| -rw-r--r-- | src/w32console.c | 15 | ||||
| -rw-r--r-- | src/window.c | 29 | ||||
| -rw-r--r-- | src/xdisp.c | 71 |
10 files changed, 998 insertions, 50 deletions
diff --git a/src/dispextern.h b/src/dispextern.h index 979ade70bfc..65df553c831 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -3115,6 +3115,7 @@ extern int clear_mouse_face (Mouse_HLInfo *); | |||
| 3115 | extern int cursor_in_mouse_face_p (struct window *w); | 3115 | extern int cursor_in_mouse_face_p (struct window *w); |
| 3116 | extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *, | 3116 | extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *, |
| 3117 | int, int, enum draw_glyphs_face); | 3117 | int, int, enum draw_glyphs_face); |
| 3118 | extern void display_tty_menu_item (const char *, int, int, int, int); | ||
| 3118 | 3119 | ||
| 3119 | /* Flags passed to try_window. */ | 3120 | /* Flags passed to try_window. */ |
| 3120 | #define TRY_WINDOW_CHECK_MARGINS (1 << 0) | 3121 | #define TRY_WINDOW_CHECK_MARGINS (1 << 0) |
| @@ -3278,6 +3279,8 @@ extern void hide_hourglass (void); | |||
| 3278 | 3279 | ||
| 3279 | int popup_activated (void); | 3280 | int popup_activated (void); |
| 3280 | 3281 | ||
| 3282 | /* Defined in dispnew.c */ | ||
| 3283 | |||
| 3281 | extern Lisp_Object buffer_posn_from_coords (struct window *, | 3284 | extern Lisp_Object buffer_posn_from_coords (struct window *, |
| 3282 | int *, int *, | 3285 | int *, int *, |
| 3283 | struct display_pos *, | 3286 | struct display_pos *, |
| @@ -3292,35 +3295,35 @@ extern Lisp_Object marginal_area_string (struct window *, enum window_part, | |||
| 3292 | Lisp_Object *, | 3295 | Lisp_Object *, |
| 3293 | int *, int *, int *, int *); | 3296 | int *, int *, int *, int *); |
| 3294 | extern void redraw_frame (struct frame *); | 3297 | extern void redraw_frame (struct frame *); |
| 3295 | extern void cancel_line (int, struct frame *); | ||
| 3296 | extern void init_desired_glyphs (struct frame *); | ||
| 3297 | extern int update_frame (struct frame *, int, int); | 3298 | extern int update_frame (struct frame *, int, int); |
| 3299 | extern void update_frame_with_menu (struct frame *); | ||
| 3298 | extern void bitch_at_user (void); | 3300 | extern void bitch_at_user (void); |
| 3299 | void adjust_glyphs (struct frame *); | 3301 | extern void adjust_glyphs (struct frame *); |
| 3300 | void free_glyphs (struct frame *); | 3302 | extern void free_glyphs (struct frame *); |
| 3301 | void free_window_matrices (struct window *); | 3303 | extern void free_window_matrices (struct window *); |
| 3302 | void check_glyph_memory (void); | 3304 | extern void check_glyph_memory (void); |
| 3303 | void mirrored_line_dance (struct glyph_matrix *, int, int, int *, char *); | 3305 | extern void mirrored_line_dance (struct glyph_matrix *, int, int, int *, |
| 3304 | void clear_glyph_matrix (struct glyph_matrix *); | 3306 | char *); |
| 3305 | void clear_current_matrices (struct frame *f); | 3307 | extern void clear_glyph_matrix (struct glyph_matrix *); |
| 3306 | void clear_desired_matrices (struct frame *); | 3308 | extern void clear_current_matrices (struct frame *f); |
| 3307 | void shift_glyph_matrix (struct window *, struct glyph_matrix *, | 3309 | extern void clear_desired_matrices (struct frame *); |
| 3308 | int, int, int); | 3310 | extern void shift_glyph_matrix (struct window *, struct glyph_matrix *, |
| 3309 | void rotate_matrix (struct glyph_matrix *, int, int, int); | 3311 | int, int, int); |
| 3310 | void increment_matrix_positions (struct glyph_matrix *, | 3312 | extern void rotate_matrix (struct glyph_matrix *, int, int, int); |
| 3311 | int, int, ptrdiff_t, ptrdiff_t); | 3313 | extern void increment_matrix_positions (struct glyph_matrix *, |
| 3312 | void blank_row (struct window *, struct glyph_row *, int); | 3314 | int, int, ptrdiff_t, ptrdiff_t); |
| 3313 | void enable_glyph_matrix_rows (struct glyph_matrix *, int, int, int); | 3315 | extern void blank_row (struct window *, struct glyph_row *, int); |
| 3314 | void clear_glyph_row (struct glyph_row *); | 3316 | extern void enable_glyph_matrix_rows (struct glyph_matrix *, int, int, int); |
| 3315 | void prepare_desired_row (struct glyph_row *); | 3317 | extern void clear_glyph_row (struct glyph_row *); |
| 3316 | void set_window_update_flags (struct window *, int); | 3318 | extern void prepare_desired_row (struct glyph_row *); |
| 3317 | void update_single_window (struct window *, int); | 3319 | extern void set_window_update_flags (struct window *, int); |
| 3318 | void do_pending_window_change (int); | 3320 | extern void update_single_window (struct window *, int); |
| 3319 | void change_frame_size (struct frame *, int, int, int, int, int); | 3321 | extern void do_pending_window_change (int); |
| 3320 | void init_display (void); | 3322 | extern void change_frame_size (struct frame *, int, int, int, int, int); |
| 3321 | void syms_of_display (void); | 3323 | extern void init_display (void); |
| 3324 | extern void syms_of_display (void); | ||
| 3322 | extern Lisp_Object Qredisplay_dont_pause; | 3325 | extern Lisp_Object Qredisplay_dont_pause; |
| 3323 | void spec_glyph_lookup_face (struct window *, GLYPH *); | 3326 | extern void spec_glyph_lookup_face (struct window *, GLYPH *); |
| 3324 | 3327 | ||
| 3325 | /* Defined in terminal.c */ | 3328 | /* Defined in terminal.c */ |
| 3326 | 3329 | ||
diff --git a/src/dispnew.c b/src/dispnew.c index a23f2b9a959..0c975124479 100644 --- a/src/dispnew.c +++ b/src/dispnew.c | |||
| @@ -3337,6 +3337,39 @@ update_frame (struct frame *f, int force_p, int inhibit_hairy_id_p) | |||
| 3337 | return paused_p; | 3337 | return paused_p; |
| 3338 | } | 3338 | } |
| 3339 | 3339 | ||
| 3340 | /* Update a TTY frame F that has a menu dropped down over some of its | ||
| 3341 | glyphs. This is like the second part of update_frame, but it | ||
| 3342 | doesn't call build_frame_matrix, because we already have the | ||
| 3343 | desired matrix prepared, and don't want it to be overwritten by the | ||
| 3344 | text of the normal display. */ | ||
| 3345 | void | ||
| 3346 | update_frame_with_menu (struct frame *f) | ||
| 3347 | { | ||
| 3348 | struct window *root_window = XWINDOW (f->root_window); | ||
| 3349 | |||
| 3350 | xassert (FRAME_TERMCAP_P (f)); | ||
| 3351 | |||
| 3352 | /* We are working on frame matrix basis. Set the frame on whose | ||
| 3353 | frame matrix we operate. */ | ||
| 3354 | set_frame_matrix_frame (f); | ||
| 3355 | |||
| 3356 | /* Update the display */ | ||
| 3357 | update_begin (f); | ||
| 3358 | paused_p = update_frame_1 (f, 1, 1); | ||
| 3359 | update_end (f); | ||
| 3360 | |||
| 3361 | if (FRAME_TTY (f)->termscript) | ||
| 3362 | fflush (FRAME_TTY (f)->termscript); | ||
| 3363 | fflush (FRAME_TTY (f)->output); | ||
| 3364 | /* Check window matrices for lost pointers. */ | ||
| 3365 | #if GLYPH_DEBUG | ||
| 3366 | check_window_matrix_pointers (root_window); | ||
| 3367 | add_frame_display_history (f, paused_p); | ||
| 3368 | #endif | ||
| 3369 | |||
| 3370 | /* Reset flags indicating that a window should be updated. */ | ||
| 3371 | set_window_update_flags (root_window, 0); | ||
| 3372 | } | ||
| 3340 | 3373 | ||
| 3341 | 3374 | ||
| 3342 | /************************************************************************ | 3375 | /************************************************************************ |
diff --git a/src/menu.c b/src/menu.c index 9ccfffd768c..7a7db9f07ff 100644 --- a/src/menu.c +++ b/src/menu.c | |||
| @@ -1323,20 +1323,31 @@ no quit occurs and `x-popup-menu' returns nil. */) | |||
| 1323 | 1323 | ||
| 1324 | /* FIXME: Use a terminal hook! */ | 1324 | /* FIXME: Use a terminal hook! */ |
| 1325 | #if defined HAVE_NTGUI | 1325 | #if defined HAVE_NTGUI |
| 1326 | selection = w32_menu_show (f, xpos, ypos, for_click, | 1326 | if (FRAME_W32_P (f)) |
| 1327 | keymaps, title, &error_name); | 1327 | selection = w32_menu_show (f, xpos, ypos, for_click, |
| 1328 | #elif defined HAVE_NS | 1328 | keymaps, title, &error_name); |
| 1329 | selection = ns_menu_show (f, xpos, ypos, for_click, | 1329 | else |
| 1330 | keymaps, title, &error_name); | 1330 | #endif |
| 1331 | #else /* MSDOS and X11 */ | 1331 | #if defined HAVE_NS |
| 1332 | if (FRAME_NS_P (f)) | ||
| 1333 | selection = ns_menu_show (f, xpos, ypos, for_click, | ||
| 1334 | keymaps, title, &error_name); | ||
| 1335 | else | ||
| 1336 | #endif | ||
| 1337 | #if (defined (HAVE_X_WINDOWS) || defined (MSDOS)) | ||
| 1332 | /* Assume last_event_timestamp is the timestamp of the button event. | 1338 | /* Assume last_event_timestamp is the timestamp of the button event. |
| 1333 | Is this assumption ever violated? We can't use the timestamp | 1339 | Is this assumption ever violated? We can't use the timestamp |
| 1334 | stored within POSITION because there the top bits from the actual | 1340 | stored within POSITION because there the top bits from the actual |
| 1335 | timestamp may be truncated away (Bug#4930). */ | 1341 | timestamp may be truncated away (Bug#4930). */ |
| 1336 | selection = xmenu_show (f, xpos, ypos, for_click, | 1342 | if (FRAME_X_P (f) || FRAME_MSDOS_P (f)) |
| 1337 | keymaps, title, &error_name, | 1343 | selection = xmenu_show (f, xpos, ypos, for_click, |
| 1338 | last_event_timestamp); | 1344 | keymaps, title, &error_name, |
| 1345 | last_event_timestamp); | ||
| 1346 | else | ||
| 1339 | #endif | 1347 | #endif |
| 1348 | if (FRAME_TERMCAP_P (f)) | ||
| 1349 | selection = tty_menu_show (f, xpos, ypos, for_click, | ||
| 1350 | keymaps, title, &error_name); | ||
| 1340 | 1351 | ||
| 1341 | UNBLOCK_INPUT; | 1352 | UNBLOCK_INPUT; |
| 1342 | 1353 | ||
diff --git a/src/menu.h b/src/menu.h index cb22a5255d6..12b2fcc6a7d 100644 --- a/src/menu.h +++ b/src/menu.h | |||
| @@ -51,4 +51,6 @@ extern Lisp_Object ns_menu_show (FRAME_PTR, int, int, int, int, | |||
| 51 | Lisp_Object, const char **); | 51 | Lisp_Object, const char **); |
| 52 | extern Lisp_Object xmenu_show (FRAME_PTR, int, int, int, int, | 52 | extern Lisp_Object xmenu_show (FRAME_PTR, int, int, int, int, |
| 53 | Lisp_Object, const char **, Time); | 53 | Lisp_Object, const char **, Time); |
| 54 | extern Lisp_Object tty_menu_show (FRAME_PTR, int, int, int, int, | ||
| 55 | Lisp_Object, const char **); | ||
| 54 | #endif /* MENU_H */ | 56 | #endif /* MENU_H */ |
diff --git a/src/msdos.c b/src/msdos.c index c6213b566b8..95d16438005 100644 --- a/src/msdos.c +++ b/src/msdos.c | |||
| @@ -1389,13 +1389,6 @@ IT_delete_glyphs (struct frame *f, int n) | |||
| 1389 | abort (); | 1389 | abort (); |
| 1390 | } | 1390 | } |
| 1391 | 1391 | ||
| 1392 | /* set-window-configuration on window.c needs this. */ | ||
| 1393 | void | ||
| 1394 | x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | ||
| 1395 | { | ||
| 1396 | set_menu_bar_lines (f, value, oldval); | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | /* This was copied from xfaces.c */ | 1392 | /* This was copied from xfaces.c */ |
| 1400 | 1393 | ||
| 1401 | extern Lisp_Object Qbackground_color; | 1394 | extern Lisp_Object Qbackground_color; |
diff --git a/src/term.c b/src/term.c index 3d7a677374c..188c476961b 100644 --- a/src/term.c +++ b/src/term.c | |||
| @@ -58,6 +58,10 @@ static int been_here = -1; | |||
| 58 | #include "xterm.h" | 58 | #include "xterm.h" |
| 59 | #endif | 59 | #endif |
| 60 | 60 | ||
| 61 | #ifdef HAVE_MENUS | ||
| 62 | #include "menu.h" | ||
| 63 | #endif | ||
| 64 | |||
| 61 | #ifndef O_RDWR | 65 | #ifndef O_RDWR |
| 62 | #define O_RDWR 2 | 66 | #define O_RDWR 2 |
| 63 | #endif | 67 | #endif |
| @@ -2834,6 +2838,803 @@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop, | |||
| 2834 | #endif /* HAVE_GPM */ | 2838 | #endif /* HAVE_GPM */ |
| 2835 | 2839 | ||
| 2836 | 2840 | ||
| 2841 | /*********************************************************************** | ||
| 2842 | Menus | ||
| 2843 | ***********************************************************************/ | ||
| 2844 | |||
| 2845 | #if defined (HAVE_MENUS) && !defined (MSDOS) | ||
| 2846 | |||
| 2847 | /* TTY menu implementation and main ideas are borrowed from msdos.c. | ||
| 2848 | |||
| 2849 | However, unlike on MSDOS, where the menu text is drawn directly to | ||
| 2850 | the screen, on a TTY we use display_string (see xdisp.c) to put the | ||
| 2851 | glyphs produced from the menu items into the desired_matrix glyph | ||
| 2852 | matrix, and then call update_frame to deliver the results to the | ||
| 2853 | glass. The previous contents of the screen, in the form of the | ||
| 2854 | current_matrix, is stashed away, and used to restore screen | ||
| 2855 | contents when the menu selection changes or when the final | ||
| 2856 | selection is made and the menu should be popped down. | ||
| 2857 | |||
| 2858 | The idea of this implementation was suggested by Gerd Moellmann. */ | ||
| 2859 | |||
| 2860 | #define TTYM_FAILURE -1 | ||
| 2861 | #define TTYM_SUCCESS 1 | ||
| 2862 | #define TTYM_NO_SELECT 2 | ||
| 2863 | #define TTYM_IA_SELECT 3 | ||
| 2864 | |||
| 2865 | /* These hold text of the current and the previous menu help messages. */ | ||
| 2866 | static const char *menu_help_message, *prev_menu_help_message; | ||
| 2867 | /* Pane number and item number of the menu item which generated the | ||
| 2868 | last menu help message. */ | ||
| 2869 | static int menu_help_paneno, menu_help_itemno; | ||
| 2870 | |||
| 2871 | typedef struct tty_menu_struct | ||
| 2872 | { | ||
| 2873 | int count; | ||
| 2874 | char **text; | ||
| 2875 | struct tty_menu_struct **submenu; | ||
| 2876 | int *panenumber; /* Also used as enable. */ | ||
| 2877 | int allocated; | ||
| 2878 | int panecount; | ||
| 2879 | int width; | ||
| 2880 | const char **help_text; | ||
| 2881 | } tty_menu; | ||
| 2882 | |||
| 2883 | /* Create a brand new menu structure. */ | ||
| 2884 | |||
| 2885 | static tty_menu * | ||
| 2886 | tty_menu_create (void) | ||
| 2887 | { | ||
| 2888 | tty_menu *menu; | ||
| 2889 | |||
| 2890 | menu = (tty_menu *) xmalloc (sizeof (tty_menu)); | ||
| 2891 | menu->allocated = menu->count = menu->panecount = menu->width = 0; | ||
| 2892 | return menu; | ||
| 2893 | } | ||
| 2894 | |||
| 2895 | /* Allocate some (more) memory for MENU ensuring that there is room for one | ||
| 2896 | for item. */ | ||
| 2897 | |||
| 2898 | static void | ||
| 2899 | tty_menu_make_room (tty_menu *menu) | ||
| 2900 | { | ||
| 2901 | if (menu->allocated == 0) | ||
| 2902 | { | ||
| 2903 | int count = menu->allocated = 10; | ||
| 2904 | menu->text = (char **) xmalloc (count * sizeof (char *)); | ||
| 2905 | menu->submenu = (tty_menu **) xmalloc (count * sizeof (tty_menu *)); | ||
| 2906 | menu->panenumber = (int *) xmalloc (count * sizeof (int)); | ||
| 2907 | menu->help_text = (const char **) xmalloc (count * sizeof (char *)); | ||
| 2908 | } | ||
| 2909 | else if (menu->allocated == menu->count) | ||
| 2910 | { | ||
| 2911 | int count = menu->allocated = menu->allocated + 10; | ||
| 2912 | menu->text | ||
| 2913 | = (char **) xrealloc (menu->text, count * sizeof (char *)); | ||
| 2914 | menu->submenu | ||
| 2915 | = (tty_menu **) xrealloc (menu->submenu, count * sizeof (tty_menu *)); | ||
| 2916 | menu->panenumber | ||
| 2917 | = (int *) xrealloc (menu->panenumber, count * sizeof (int)); | ||
| 2918 | menu->help_text | ||
| 2919 | = (const char **) xrealloc (menu->help_text, count * sizeof (char *)); | ||
| 2920 | } | ||
| 2921 | } | ||
| 2922 | |||
| 2923 | /* Search the given menu structure for a given pane number. */ | ||
| 2924 | |||
| 2925 | static tty_menu * | ||
| 2926 | tty_menu_search_pane (tty_menu *menu, int pane) | ||
| 2927 | { | ||
| 2928 | int i; | ||
| 2929 | tty_menu *try; | ||
| 2930 | |||
| 2931 | for (i = 0; i < menu->count; i++) | ||
| 2932 | if (menu->submenu[i]) | ||
| 2933 | { | ||
| 2934 | if (pane == menu->panenumber[i]) | ||
| 2935 | return menu->submenu[i]; | ||
| 2936 | if ((try = tty_menu_search_pane (menu->submenu[i], pane))) | ||
| 2937 | return try; | ||
| 2938 | } | ||
| 2939 | return (tty_menu *) 0; | ||
| 2940 | } | ||
| 2941 | |||
| 2942 | /* Determine how much screen space a given menu needs. */ | ||
| 2943 | |||
| 2944 | static void | ||
| 2945 | tty_menu_calc_size (tty_menu *menu, int *width, int *height) | ||
| 2946 | { | ||
| 2947 | int i, h2, w2, maxsubwidth, maxheight; | ||
| 2948 | |||
| 2949 | maxsubwidth = 0; | ||
| 2950 | maxheight = menu->count; | ||
| 2951 | for (i = 0; i < menu->count; i++) | ||
| 2952 | { | ||
| 2953 | if (menu->submenu[i]) | ||
| 2954 | { | ||
| 2955 | tty_menu_calc_size (menu->submenu[i], &w2, &h2); | ||
| 2956 | if (w2 > maxsubwidth) maxsubwidth = w2; | ||
| 2957 | if (i + h2 > maxheight) maxheight = i + h2; | ||
| 2958 | } | ||
| 2959 | } | ||
| 2960 | *width = menu->width + maxsubwidth; | ||
| 2961 | *height = maxheight; | ||
| 2962 | } | ||
| 2963 | |||
| 2964 | /* Display MENU at (X,Y) using FACES. */ | ||
| 2965 | |||
| 2966 | #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \ | ||
| 2967 | do \ | ||
| 2968 | { \ | ||
| 2969 | (GLYPH).type = CHAR_GLYPH; \ | ||
| 2970 | SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \ | ||
| 2971 | (GLYPH).charpos = -1; \ | ||
| 2972 | } \ | ||
| 2973 | while (0) | ||
| 2974 | |||
| 2975 | static void | ||
| 2976 | tty_menu_display (tty_menu *menu, int y, int x, int pn, int *faces, | ||
| 2977 | int disp_help) | ||
| 2978 | { | ||
| 2979 | int i, face, width, mx = -1, my = -1, enabled, mousehere, row, col; | ||
| 2980 | struct frame *sf = SELECTED_FRAME (); | ||
| 2981 | struct tty_display_info *tty = FRAME_TTY (sf); | ||
| 2982 | #if defined (HAVE_MOUSE) || defined (HAVE_GPM) | ||
| 2983 | Lisp_Object lmx, lmy, lisp_dummy; | ||
| 2984 | enum scroll_bar_part part_dummy; | ||
| 2985 | Time time_dummy; | ||
| 2986 | |||
| 2987 | if (FRAME_TERMINAL (sf)->mouse_position_hook) | ||
| 2988 | (*FRAME_TERMINAL (sf)->mouse_position_hook) (&sf, -1, | ||
| 2989 | &lispy_dummy, &party_dummy, | ||
| 2990 | &lmx, &lmy, | ||
| 2991 | &time_dummy); | ||
| 2992 | if (!NILP (lmx)) | ||
| 2993 | { | ||
| 2994 | mx = XINT (lmx); | ||
| 2995 | my = XINT (lmy); | ||
| 2996 | } | ||
| 2997 | else | ||
| 2998 | { | ||
| 2999 | mx = x; | ||
| 3000 | my = y; | ||
| 3001 | } | ||
| 3002 | #else | ||
| 3003 | /* FIXME: need to set mx and my from cursor movement commands. */ | ||
| 3004 | mx = x; | ||
| 3005 | my = y; | ||
| 3006 | #endif | ||
| 3007 | |||
| 3008 | menu_help_message = NULL; | ||
| 3009 | |||
| 3010 | width = menu->width; | ||
| 3011 | col = curX (tty); | ||
| 3012 | row = curY (tty); | ||
| 3013 | #if 0 | ||
| 3014 | IT_update_begin (sf); /* FIXME: do we need an update_begin_hook? */ | ||
| 3015 | #endif | ||
| 3016 | for (i = 0; i < menu->count; i++) | ||
| 3017 | { | ||
| 3018 | int max_width = width + 2; | ||
| 3019 | |||
| 3020 | cursor_to (sf, y + i, x); | ||
| 3021 | enabled | ||
| 3022 | = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]); | ||
| 3023 | mousehere = (y + i == my && x <= mx && mx < x + max_width); | ||
| 3024 | face = faces[enabled + mousehere * 2]; | ||
| 3025 | /* Display the menu help string for the i-th menu item even if | ||
| 3026 | the menu item is currently disabled. That's what the GUI | ||
| 3027 | code does. */ | ||
| 3028 | if (disp_help && enabled + mousehere * 2 >= 2) | ||
| 3029 | { | ||
| 3030 | menu_help_message = menu->help_text[i]; | ||
| 3031 | menu_help_paneno = pn - 1; | ||
| 3032 | menu_help_itemno = i; | ||
| 3033 | } | ||
| 3034 | display_tty_menu_item (menu->text[i], face, y + i, x, | ||
| 3035 | menu->submenu[i] != NULL); | ||
| 3036 | } | ||
| 3037 | update_frame_with_menu (sf); | ||
| 3038 | cursor_to (sf, row, col); | ||
| 3039 | } | ||
| 3040 | |||
| 3041 | /* --------------------------- X Menu emulation ---------------------- */ | ||
| 3042 | |||
| 3043 | /* Report availability of menus. */ | ||
| 3044 | |||
| 3045 | int | ||
| 3046 | have_menus_p (void) { return 1; } | ||
| 3047 | |||
| 3048 | /* Create a new pane and place it on the outer-most level. */ | ||
| 3049 | |||
| 3050 | int | ||
| 3051 | tty_menu_add_pane (Display *foo, tty_menu *menu, const char *txt) | ||
| 3052 | { | ||
| 3053 | int len; | ||
| 3054 | const char *p; | ||
| 3055 | |||
| 3056 | tty_menu_make_room (menu); | ||
| 3057 | menu->submenu[menu->count] = tty_menu_create (); | ||
| 3058 | menu->text[menu->count] = (char *)txt; | ||
| 3059 | menu->panenumber[menu->count] = ++menu->panecount; | ||
| 3060 | menu->help_text[menu->count] = NULL; | ||
| 3061 | menu->count++; | ||
| 3062 | |||
| 3063 | /* Update the menu width, if necessary. */ | ||
| 3064 | for (len = 0, p = txt; *p; ) | ||
| 3065 | { | ||
| 3066 | int ch_len; | ||
| 3067 | int ch = STRING_CHAR_AND_LENGTH (p, ch_len); | ||
| 3068 | |||
| 3069 | len += CHAR_WIDTH (ch); | ||
| 3070 | p += ch_len; | ||
| 3071 | } | ||
| 3072 | |||
| 3073 | if (len > menu->width) | ||
| 3074 | menu->width = len; | ||
| 3075 | |||
| 3076 | return menu->panecount; | ||
| 3077 | } | ||
| 3078 | |||
| 3079 | /* Create a new item in a menu pane. */ | ||
| 3080 | |||
| 3081 | int | ||
| 3082 | tty_menu_add_selection (tty_menu *menu, int pane, | ||
| 3083 | char *txt, int enable, char const *help_text) | ||
| 3084 | { | ||
| 3085 | int len; | ||
| 3086 | char *p; | ||
| 3087 | |||
| 3088 | if (pane) | ||
| 3089 | if (!(menu = tty_menu_search_pane (menu, pane))) | ||
| 3090 | return TTYM_FAILURE; | ||
| 3091 | tty_menu_make_room (menu); | ||
| 3092 | menu->submenu[menu->count] = (tty_menu *) 0; | ||
| 3093 | menu->text[menu->count] = txt; | ||
| 3094 | menu->panenumber[menu->count] = enable; | ||
| 3095 | menu->help_text[menu->count] = help_text; | ||
| 3096 | menu->count++; | ||
| 3097 | |||
| 3098 | /* Update the menu width, if necessary. */ | ||
| 3099 | for (len = 0, p = txt; *p; ) | ||
| 3100 | { | ||
| 3101 | int ch_len; | ||
| 3102 | int ch = STRING_CHAR_AND_LENGTH (p, ch_len); | ||
| 3103 | |||
| 3104 | len += CHAR_WIDTH (ch); | ||
| 3105 | p += ch_len; | ||
| 3106 | } | ||
| 3107 | |||
| 3108 | if (len > menu->width) | ||
| 3109 | menu->width = len; | ||
| 3110 | |||
| 3111 | return TTYM_SUCCESS; | ||
| 3112 | } | ||
| 3113 | |||
| 3114 | /* Decide where the menu would be placed if requested at (X,Y). */ | ||
| 3115 | |||
| 3116 | void | ||
| 3117 | tty_menu_locate (tty_menu *menu, int x, int y, | ||
| 3118 | int *ulx, int *uly, int *width, int *height) | ||
| 3119 | { | ||
| 3120 | tty_menu_calc_size (menu, width, height); | ||
| 3121 | *ulx = x + 1; | ||
| 3122 | *uly = y; | ||
| 3123 | *width += 2; | ||
| 3124 | } | ||
| 3125 | |||
| 3126 | struct tty_menu_state | ||
| 3127 | { | ||
| 3128 | void *screen_behind; | ||
| 3129 | tty_menu *menu; | ||
| 3130 | int pane; | ||
| 3131 | int x, y; | ||
| 3132 | }; | ||
| 3133 | |||
| 3134 | |||
| 3135 | /* Display menu, wait for user's response, and return that response. */ | ||
| 3136 | |||
| 3137 | int | ||
| 3138 | tty_menu_activate (tty_menu *menu, int *pane, int *selidx, | ||
| 3139 | int x0, int y0, char **txt, | ||
| 3140 | void (*help_callback)(char const *, int, int)) | ||
| 3141 | { | ||
| 3142 | struct tty_menu_state *state; | ||
| 3143 | int statecount, x, y, i, b, screensize, leave, result, onepane; | ||
| 3144 | int title_faces[4]; /* face to display the menu title */ | ||
| 3145 | int faces[4], buffers_num_deleted = 0; | ||
| 3146 | struct frame *sf = SELECTED_FRAME (); | ||
| 3147 | Lisp_Object saved_echo_area_message, selectface; | ||
| 3148 | |||
| 3149 | /* Don't allow non-positive x0 and y0, lest the menu will wrap | ||
| 3150 | around the display. */ | ||
| 3151 | if (x0 <= 0) | ||
| 3152 | x0 = 1; | ||
| 3153 | if (y0 <= 0) | ||
| 3154 | y0 = 1; | ||
| 3155 | |||
| 3156 | /* We will process all the mouse events directly, so we had | ||
| 3157 | better prevent dos_rawgetc from stealing them from us. */ | ||
| 3158 | mouse_preempted++; | ||
| 3159 | |||
| 3160 | state = alloca (menu->panecount * sizeof (struct tty_menu_state)); | ||
| 3161 | screensize = screen_size * 2; | ||
| 3162 | faces[0] | ||
| 3163 | = lookup_derived_face (sf, intern ("tty-menu-disabled-face"), | ||
| 3164 | DEFAULT_FACE_ID, 1); | ||
| 3165 | faces[1] | ||
| 3166 | = lookup_derived_face (sf, intern ("tty-menu-enabled-face"), | ||
| 3167 | DEFAULT_FACE_ID, 1); | ||
| 3168 | selectface = intern ("tty-menu-selected-face"); | ||
| 3169 | faces[2] = lookup_derived_face (sf, selectface, | ||
| 3170 | faces[0], 1); | ||
| 3171 | faces[3] = lookup_derived_face (sf, selectface, | ||
| 3172 | faces[1], 1); | ||
| 3173 | |||
| 3174 | /* Make sure the menu title is always displayed with | ||
| 3175 | `msdos-menu-active-face', no matter where the mouse pointer is. */ | ||
| 3176 | for (i = 0; i < 4; i++) | ||
| 3177 | title_faces[i] = faces[3]; | ||
| 3178 | |||
| 3179 | statecount = 1; | ||
| 3180 | |||
| 3181 | /* Don't let the title for the "Buffers" popup menu include a | ||
| 3182 | digit (which is ugly). | ||
| 3183 | |||
| 3184 | This is a terrible kludge, but I think the "Buffers" case is | ||
| 3185 | the only one where the title includes a number, so it doesn't | ||
| 3186 | seem to be necessary to make this more general. */ | ||
| 3187 | if (strncmp (menu->text[0], "Buffers 1", 9) == 0) | ||
| 3188 | { | ||
| 3189 | menu->text[0][7] = '\0'; | ||
| 3190 | buffers_num_deleted = 1; | ||
| 3191 | } | ||
| 3192 | |||
| 3193 | #if 0 | ||
| 3194 | /* We need to save the current echo area message, so that we could | ||
| 3195 | restore it below, before we exit. See the commentary below, | ||
| 3196 | before the call to message_with_string. */ | ||
| 3197 | saved_echo_area_message = Fcurrent_message (); | ||
| 3198 | #endif | ||
| 3199 | state[0].menu = menu; | ||
| 3200 | mouse_off (); /* FIXME */ | ||
| 3201 | ScreenRetrieve (state[0].screen_behind = xmalloc (screensize)); /* FIXME */ | ||
| 3202 | |||
| 3203 | /* Turn off the cursor. Otherwise it shows through the menu | ||
| 3204 | panes, which is ugly. */ | ||
| 3205 | show_cursor (0); /* FIXME: need a new hook. */ | ||
| 3206 | |||
| 3207 | /* Display the menu title. */ | ||
| 3208 | tty_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0); | ||
| 3209 | if (buffers_num_deleted) | ||
| 3210 | menu->text[0][7] = ' '; | ||
| 3211 | if ((onepane = menu->count == 1 && menu->submenu[0])) | ||
| 3212 | { | ||
| 3213 | menu->width = menu->submenu[0]->width; | ||
| 3214 | state[0].menu = menu->submenu[0]; | ||
| 3215 | } | ||
| 3216 | else | ||
| 3217 | { | ||
| 3218 | state[0].menu = menu; | ||
| 3219 | } | ||
| 3220 | state[0].x = x0 - 1; | ||
| 3221 | state[0].y = y0; | ||
| 3222 | state[0].pane = onepane; | ||
| 3223 | |||
| 3224 | mouse_last_x = -1; /* A hack that forces display. */ | ||
| 3225 | leave = 0; | ||
| 3226 | while (!leave) | ||
| 3227 | { | ||
| 3228 | if (!mouse_visible) mouse_on (); | ||
| 3229 | mouse_check_moved (); | ||
| 3230 | if (sf->mouse_moved) | ||
| 3231 | { | ||
| 3232 | sf->mouse_moved = 0; | ||
| 3233 | result = TTYM_IA_SELECT; | ||
| 3234 | mouse_get_xy (&x, &y); | ||
| 3235 | for (i = 0; i < statecount; i++) | ||
| 3236 | if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2) | ||
| 3237 | { | ||
| 3238 | int dy = y - state[i].y; | ||
| 3239 | if (0 <= dy && dy < state[i].menu->count) | ||
| 3240 | { | ||
| 3241 | if (!state[i].menu->submenu[dy]) | ||
| 3242 | { | ||
| 3243 | if (state[i].menu->panenumber[dy]) | ||
| 3244 | result = TTYM_SUCCESS; | ||
| 3245 | else | ||
| 3246 | result = TTYM_IA_SELECT; | ||
| 3247 | } | ||
| 3248 | *pane = state[i].pane - 1; | ||
| 3249 | *selidx = dy; | ||
| 3250 | /* We hit some part of a menu, so drop extra menus that | ||
| 3251 | have been opened. That does not include an open and | ||
| 3252 | active submenu. */ | ||
| 3253 | if (i != statecount - 2 | ||
| 3254 | || state[i].menu->submenu[dy] != state[i+1].menu) | ||
| 3255 | while (i != statecount - 1) | ||
| 3256 | { | ||
| 3257 | statecount--; | ||
| 3258 | mouse_off (); | ||
| 3259 | ScreenUpdate (state[statecount].screen_behind); | ||
| 3260 | xfree (state[statecount].screen_behind); | ||
| 3261 | } | ||
| 3262 | if (i == statecount - 1 && state[i].menu->submenu[dy]) | ||
| 3263 | { | ||
| 3264 | tty_menu_display (state[i].menu, | ||
| 3265 | state[i].y, | ||
| 3266 | state[i].x, | ||
| 3267 | state[i].pane, | ||
| 3268 | faces, 1); | ||
| 3269 | state[statecount].menu = state[i].menu->submenu[dy]; | ||
| 3270 | state[statecount].pane = state[i].menu->panenumber[dy]; | ||
| 3271 | mouse_off (); | ||
| 3272 | ScreenRetrieve (state[statecount].screen_behind | ||
| 3273 | = xmalloc (screensize)); | ||
| 3274 | state[statecount].x | ||
| 3275 | = state[i].x + state[i].menu->width + 2; | ||
| 3276 | state[statecount].y = y; | ||
| 3277 | statecount++; | ||
| 3278 | } | ||
| 3279 | } | ||
| 3280 | } | ||
| 3281 | tty_menu_display (state[statecount - 1].menu, | ||
| 3282 | state[statecount - 1].y, | ||
| 3283 | state[statecount - 1].x, | ||
| 3284 | state[statecount - 1].pane, | ||
| 3285 | faces, 1); | ||
| 3286 | } | ||
| 3287 | else | ||
| 3288 | { | ||
| 3289 | if ((menu_help_message || prev_menu_help_message) | ||
| 3290 | && menu_help_message != prev_menu_help_message) | ||
| 3291 | { | ||
| 3292 | help_callback (menu_help_message, | ||
| 3293 | menu_help_paneno, menu_help_itemno); | ||
| 3294 | show_cursor (0); | ||
| 3295 | prev_menu_help_message = menu_help_message; | ||
| 3296 | } | ||
| 3297 | /* We are busy-waiting for the mouse to move, so let's be nice | ||
| 3298 | to other Windows applications by releasing our time slice. */ | ||
| 3299 | __dpmi_yield (); | ||
| 3300 | } | ||
| 3301 | for (b = 0; b < mouse_button_count && !leave; b++) | ||
| 3302 | { | ||
| 3303 | /* Only leave if user both pressed and released the mouse, and in | ||
| 3304 | that order. This avoids popping down the menu pane unless | ||
| 3305 | the user is really done with it. */ | ||
| 3306 | if (mouse_pressed (b, &x, &y)) | ||
| 3307 | { | ||
| 3308 | while (mouse_button_depressed (b, &x, &y)) | ||
| 3309 | __dpmi_yield (); | ||
| 3310 | leave = 1; | ||
| 3311 | } | ||
| 3312 | (void) mouse_released (b, &x, &y); | ||
| 3313 | } | ||
| 3314 | } | ||
| 3315 | |||
| 3316 | mouse_off (); | ||
| 3317 | ScreenUpdate (state[0].screen_behind); | ||
| 3318 | |||
| 3319 | #if 0 | ||
| 3320 | /* We have a situation here. ScreenUpdate has just restored the | ||
| 3321 | screen contents as it was before we started drawing this menu. | ||
| 3322 | That includes any echo area message that could have been | ||
| 3323 | displayed back then. (In reality, that echo area message will | ||
| 3324 | almost always be the ``keystroke echo'' that echoes the sequence | ||
| 3325 | of menu items chosen by the user.) However, if the menu had some | ||
| 3326 | help messages, then displaying those messages caused Emacs to | ||
| 3327 | forget about the original echo area message. So when | ||
| 3328 | ScreenUpdate restored it, it created a discrepancy between the | ||
| 3329 | actual screen contents and what Emacs internal data structures | ||
| 3330 | know about it. | ||
| 3331 | |||
| 3332 | To avoid this conflict, we force Emacs to restore the original | ||
| 3333 | echo area message as we found it when we entered this function. | ||
| 3334 | The irony of this is that we then erase the restored message | ||
| 3335 | right away, so the only purpose of restoring it is so that | ||
| 3336 | erasing it works correctly... */ | ||
| 3337 | if (! NILP (saved_echo_area_message)) | ||
| 3338 | message_with_string ("%s", saved_echo_area_message, 0); | ||
| 3339 | message (0); | ||
| 3340 | #endif | ||
| 3341 | while (statecount--) | ||
| 3342 | xfree (state[statecount].screen_behind); | ||
| 3343 | show_cursor (1); /* turn cursor back on */ | ||
| 3344 | /* Clean up any mouse events that are waiting inside Emacs event queue. | ||
| 3345 | These events are likely to be generated before the menu was even | ||
| 3346 | displayed, probably because the user pressed and released the button | ||
| 3347 | (which invoked the menu) too quickly. If we don't remove these events, | ||
| 3348 | Emacs will process them after we return and surprise the user. */ | ||
| 3349 | discard_mouse_events (); | ||
| 3350 | mouse_clear_clicks (); | ||
| 3351 | if (!kbd_buffer_events_waiting (1)) | ||
| 3352 | clear_input_pending (); | ||
| 3353 | /* Allow mouse events generation by dos_rawgetc. */ | ||
| 3354 | mouse_preempted--; | ||
| 3355 | return result; | ||
| 3356 | } | ||
| 3357 | |||
| 3358 | /* Dispose of a menu. */ | ||
| 3359 | |||
| 3360 | void | ||
| 3361 | tty_menu_destroy (tty_menu *menu) | ||
| 3362 | { | ||
| 3363 | int i; | ||
| 3364 | if (menu->allocated) | ||
| 3365 | { | ||
| 3366 | for (i = 0; i < menu->count; i++) | ||
| 3367 | if (menu->submenu[i]) | ||
| 3368 | tty_menu_destroy (menu->submenu[i]); | ||
| 3369 | xfree (menu->text); | ||
| 3370 | xfree (menu->submenu); | ||
| 3371 | xfree (menu->panenumber); | ||
| 3372 | xfree (menu->help_text); | ||
| 3373 | } | ||
| 3374 | xfree (menu); | ||
| 3375 | menu_help_message = prev_menu_help_message = NULL; | ||
| 3376 | } | ||
| 3377 | |||
| 3378 | Lisp_Object | ||
| 3379 | tty_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, | ||
| 3380 | Lisp_Object title, const char **error_name) | ||
| 3381 | { | ||
| 3382 | tty_menu *menu; | ||
| 3383 | int pane, selidx, lpane, status; | ||
| 3384 | Lisp_Object entry, pane_prefix; | ||
| 3385 | char *datap; | ||
| 3386 | int ulx, uly, width, height; | ||
| 3387 | int dispwidth, dispheight; | ||
| 3388 | int i, j, lines, maxlines; | ||
| 3389 | int maxwidth; | ||
| 3390 | int dummy_int; | ||
| 3391 | unsigned int dummy_uint; | ||
| 3392 | ptrdiff_t specpdl_count = SPECPDL_INDEX (); | ||
| 3393 | |||
| 3394 | if (! FRAME_TERMCAP_P (f)) | ||
| 3395 | abort (); | ||
| 3396 | |||
| 3397 | *error_name = 0; | ||
| 3398 | if (menu_items_n_panes == 0) | ||
| 3399 | return Qnil; | ||
| 3400 | |||
| 3401 | if (menu_items_used <= MENU_ITEMS_PANE_LENGTH) | ||
| 3402 | { | ||
| 3403 | *error_name = "Empty menu"; | ||
| 3404 | return Qnil; | ||
| 3405 | } | ||
| 3406 | |||
| 3407 | /* Make the menu on that window. */ | ||
| 3408 | menu = tty_menu_create (); | ||
| 3409 | if (menu == NULL) | ||
| 3410 | { | ||
| 3411 | *error_name = "Can't create menu"; | ||
| 3412 | return Qnil; | ||
| 3413 | } | ||
| 3414 | |||
| 3415 | /* Don't GC while we prepare and show the menu, because we give the | ||
| 3416 | menu functions pointers to the contents of strings. */ | ||
| 3417 | inhibit_garbage_collection (); | ||
| 3418 | |||
| 3419 | /* Adjust coordinates to be root-window-relative. */ | ||
| 3420 | x += f->left_pos; | ||
| 3421 | y += f->top_pos; | ||
| 3422 | |||
| 3423 | /* Create all the necessary panes and their items. */ | ||
| 3424 | maxwidth = maxlines = lines = i = 0; | ||
| 3425 | lpane = TTYM_FAILURE; | ||
| 3426 | while (i < menu_items_used) | ||
| 3427 | { | ||
| 3428 | if (EQ (XVECTOR (menu_items)->contents[i], Qt)) | ||
| 3429 | { | ||
| 3430 | /* Create a new pane. */ | ||
| 3431 | Lisp_Object pane_name, prefix; | ||
| 3432 | const char *pane_string; | ||
| 3433 | |||
| 3434 | maxlines = max (maxlines, lines); | ||
| 3435 | lines = 0; | ||
| 3436 | pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; | ||
| 3437 | prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; | ||
| 3438 | pane_string = (NILP (pane_name) | ||
| 3439 | ? "" : SSDATA (pane_name)); | ||
| 3440 | if (keymaps && !NILP (prefix)) | ||
| 3441 | pane_string++; | ||
| 3442 | |||
| 3443 | lpane = tty_menu_add_pane (menu, pane_string); | ||
| 3444 | if (lpane == TTYM_FAILURE) | ||
| 3445 | { | ||
| 3446 | tty_menu_destroy (menu); | ||
| 3447 | *error_name = "Can't create pane"; | ||
| 3448 | return Qnil; | ||
| 3449 | } | ||
| 3450 | i += MENU_ITEMS_PANE_LENGTH; | ||
| 3451 | |||
| 3452 | /* Find the width of the widest item in this pane. */ | ||
| 3453 | j = i; | ||
| 3454 | while (j < menu_items_used) | ||
| 3455 | { | ||
| 3456 | Lisp_Object item; | ||
| 3457 | item = XVECTOR (menu_items)->contents[j]; | ||
| 3458 | if (EQ (item, Qt)) | ||
| 3459 | break; | ||
| 3460 | if (NILP (item)) | ||
| 3461 | { | ||
| 3462 | j++; | ||
| 3463 | continue; | ||
| 3464 | } | ||
| 3465 | width = SBYTES (item); | ||
| 3466 | if (width > maxwidth) | ||
| 3467 | maxwidth = width; | ||
| 3468 | |||
| 3469 | j += MENU_ITEMS_ITEM_LENGTH; | ||
| 3470 | } | ||
| 3471 | } | ||
| 3472 | /* Ignore a nil in the item list. | ||
| 3473 | It's meaningful only for dialog boxes. */ | ||
| 3474 | else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) | ||
| 3475 | i += 1; | ||
| 3476 | else | ||
| 3477 | { | ||
| 3478 | /* Create a new item within current pane. */ | ||
| 3479 | Lisp_Object item_name, enable, descrip, help; | ||
| 3480 | char *item_data; | ||
| 3481 | char const *help_string; | ||
| 3482 | |||
| 3483 | item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; | ||
| 3484 | enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; | ||
| 3485 | descrip | ||
| 3486 | = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; | ||
| 3487 | help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; | ||
| 3488 | help_string = STRINGP (help) ? SSDATA (help) : NULL; | ||
| 3489 | |||
| 3490 | if (!NILP (descrip)) | ||
| 3491 | { | ||
| 3492 | /* if alloca is fast, use that to make the space, | ||
| 3493 | to reduce gc needs. */ | ||
| 3494 | item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1); | ||
| 3495 | memcpy (item_data, SSDATA (item_name), SBYTES (item_name)); | ||
| 3496 | for (j = SCHARS (item_name); j < maxwidth; j++) | ||
| 3497 | item_data[j] = ' '; | ||
| 3498 | memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip)); | ||
| 3499 | item_data[j + SBYTES (descrip)] = 0; | ||
| 3500 | } | ||
| 3501 | else | ||
| 3502 | item_data = SSDATA (item_name); | ||
| 3503 | |||
| 3504 | if (lpane == TTYM_FAILURE | ||
| 3505 | || (tty_menu_add_selection (menu, lpane, item_data, | ||
| 3506 | !NILP (enable), help_string) | ||
| 3507 | == TTYM_FAILURE)) | ||
| 3508 | { | ||
| 3509 | tty_menu_destroy (menu); | ||
| 3510 | *error_name = "Can't add selection to menu"; | ||
| 3511 | return Qnil; | ||
| 3512 | } | ||
| 3513 | i += MENU_ITEMS_ITEM_LENGTH; | ||
| 3514 | lines++; | ||
| 3515 | } | ||
| 3516 | } | ||
| 3517 | |||
| 3518 | maxlines = max (maxlines, lines); | ||
| 3519 | |||
| 3520 | /* All set and ready to fly. */ | ||
| 3521 | dispwidth = f->text_cols; | ||
| 3522 | dispheight = f->text_lines; | ||
| 3523 | x = min (x, dispwidth); | ||
| 3524 | y = min (y, dispheight); | ||
| 3525 | x = max (x, 1); | ||
| 3526 | y = max (y, 1); | ||
| 3527 | tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height); | ||
| 3528 | if (ulx+width > dispwidth) | ||
| 3529 | { | ||
| 3530 | x -= (ulx + width) - dispwidth; | ||
| 3531 | ulx = dispwidth - width; | ||
| 3532 | } | ||
| 3533 | if (uly+height > dispheight) | ||
| 3534 | { | ||
| 3535 | y -= (uly + height) - dispheight; | ||
| 3536 | uly = dispheight - height; | ||
| 3537 | } | ||
| 3538 | |||
| 3539 | if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1) | ||
| 3540 | { | ||
| 3541 | /* Move the menu away of the echo area, to avoid overwriting the | ||
| 3542 | menu with help echo messages or vice versa. */ | ||
| 3543 | if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window)) | ||
| 3544 | { | ||
| 3545 | y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)); | ||
| 3546 | uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)); | ||
| 3547 | } | ||
| 3548 | else | ||
| 3549 | { | ||
| 3550 | y--; | ||
| 3551 | uly--; | ||
| 3552 | } | ||
| 3553 | } | ||
| 3554 | |||
| 3555 | if (ulx < 0) x -= ulx; | ||
| 3556 | if (uly < 0) y -= uly; | ||
| 3557 | |||
| 3558 | if (! for_click) | ||
| 3559 | { | ||
| 3560 | /* If position was not given by a mouse click, adjust so upper left | ||
| 3561 | corner of the menu as a whole ends up at given coordinates. This | ||
| 3562 | is what x-popup-menu says in its documentation. */ | ||
| 3563 | x += width/2; | ||
| 3564 | y += 1.5*height/(maxlines+2); | ||
| 3565 | } | ||
| 3566 | |||
| 3567 | pane = selidx = 0; | ||
| 3568 | |||
| 3569 | record_unwind_protect (pop_down_menu, | ||
| 3570 | Fcons (make_save_value (f, 0), | ||
| 3571 | make_save_value (menu, 0))); | ||
| 3572 | |||
| 3573 | /* Help display under X won't work because XMenuActivate contains | ||
| 3574 | a loop that doesn't give Emacs a chance to process it. */ | ||
| 3575 | menu_help_frame = f; | ||
| 3576 | status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap, | ||
| 3577 | menu_help_callback); | ||
| 3578 | entry = pane_prefix = Qnil; | ||
| 3579 | |||
| 3580 | switch (status) | ||
| 3581 | { | ||
| 3582 | case TTYM_SUCCESS: | ||
| 3583 | /* Find the item number SELIDX in pane number PANE. */ | ||
| 3584 | i = 0; | ||
| 3585 | while (i < menu_items_used) | ||
| 3586 | { | ||
| 3587 | if (EQ (XVECTOR (menu_items)->contents[i], Qt)) | ||
| 3588 | { | ||
| 3589 | if (pane == 0) | ||
| 3590 | pane_prefix | ||
| 3591 | = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; | ||
| 3592 | pane--; | ||
| 3593 | i += MENU_ITEMS_PANE_LENGTH; | ||
| 3594 | } | ||
| 3595 | else | ||
| 3596 | { | ||
| 3597 | if (pane == -1) | ||
| 3598 | { | ||
| 3599 | if (selidx == 0) | ||
| 3600 | { | ||
| 3601 | entry | ||
| 3602 | = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE]; | ||
| 3603 | if (keymaps != 0) | ||
| 3604 | { | ||
| 3605 | entry = Fcons (entry, Qnil); | ||
| 3606 | if (!NILP (pane_prefix)) | ||
| 3607 | entry = Fcons (pane_prefix, entry); | ||
| 3608 | } | ||
| 3609 | break; | ||
| 3610 | } | ||
| 3611 | selidx--; | ||
| 3612 | } | ||
| 3613 | i += MENU_ITEMS_ITEM_LENGTH; | ||
| 3614 | } | ||
| 3615 | } | ||
| 3616 | break; | ||
| 3617 | |||
| 3618 | case TTYM_FAILURE: | ||
| 3619 | *error_name = "Can't activate menu"; | ||
| 3620 | case TTYM_IA_SELECT: | ||
| 3621 | break; | ||
| 3622 | case TTYM_NO_SELECT: | ||
| 3623 | /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means | ||
| 3624 | the menu was invoked with a mouse event as POSITION). */ | ||
| 3625 | if (! for_click) | ||
| 3626 | Fsignal (Qquit, Qnil); | ||
| 3627 | break; | ||
| 3628 | } | ||
| 3629 | |||
| 3630 | unbind_to (specpdl_count, Qnil); | ||
| 3631 | |||
| 3632 | return entry; | ||
| 3633 | } | ||
| 3634 | |||
| 3635 | #endif /* HAVE_MENUS && !MSDOS */ | ||
| 3636 | |||
| 3637 | |||
| 2837 | #ifndef MSDOS | 3638 | #ifndef MSDOS |
| 2838 | /*********************************************************************** | 3639 | /*********************************************************************** |
| 2839 | Initialization | 3640 | Initialization |
diff --git a/src/termhooks.h b/src/termhooks.h index 4cad4825cdd..a15f829288a 100644 --- a/src/termhooks.h +++ b/src/termhooks.h | |||
| @@ -665,3 +665,9 @@ extern unsigned char *encode_terminal_code (struct glyph *, int, | |||
| 665 | #ifdef HAVE_GPM | 665 | #ifdef HAVE_GPM |
| 666 | extern void close_gpm (int gpm_fd); | 666 | extern void close_gpm (int gpm_fd); |
| 667 | #endif | 667 | #endif |
| 668 | |||
| 669 | #ifdef WINDOWSNT | ||
| 670 | extern int curX (struct tty_display_info *); | ||
| 671 | extern int curY (struct tty_display_info *); | ||
| 672 | #endif | ||
| 673 | |||
diff --git a/src/w32console.c b/src/w32console.c index 22f329e239d..1f90f872d49 100644 --- a/src/w32console.c +++ b/src/w32console.c | |||
| @@ -603,6 +603,21 @@ Wcm_clear (struct tty_display_info *tty) | |||
| 603 | } | 603 | } |
| 604 | 604 | ||
| 605 | 605 | ||
| 606 | /* Report the current cursor position. The following two functions | ||
| 607 | mirror cm.h macros and are used in term.c's tty menu code, so they | ||
| 608 | are not really "stubs". */ | ||
| 609 | int | ||
| 610 | curX (struct tty_display_info *tty) | ||
| 611 | { | ||
| 612 | return cursor_coords.X; | ||
| 613 | } | ||
| 614 | |||
| 615 | int | ||
| 616 | curY (struct tty_display_info *tty) | ||
| 617 | { | ||
| 618 | return cursor_coords.Y; | ||
| 619 | } | ||
| 620 | |||
| 606 | /*********************************************************************** | 621 | /*********************************************************************** |
| 607 | Faces | 622 | Faces |
| 608 | ***********************************************************************/ | 623 | ***********************************************************************/ |
diff --git a/src/window.c b/src/window.c index 54ad0af4c3f..563b52a0ca4 100644 --- a/src/window.c +++ b/src/window.c | |||
| @@ -5464,18 +5464,24 @@ the return value is nil. Otherwise the value is t. */) | |||
| 5464 | || data->frame_cols != previous_frame_cols) | 5464 | || data->frame_cols != previous_frame_cols) |
| 5465 | change_frame_size (f, data->frame_lines, | 5465 | change_frame_size (f, data->frame_lines, |
| 5466 | data->frame_cols, 0, 0, 0); | 5466 | data->frame_cols, 0, 0, 0); |
| 5467 | #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS) | 5467 | #ifdef HAVE_MENUS |
| 5468 | if (data->frame_menu_bar_lines | 5468 | if (data->frame_menu_bar_lines |
| 5469 | != previous_frame_menu_bar_lines) | 5469 | != previous_frame_menu_bar_lines) |
| 5470 | x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines), | 5470 | { |
| 5471 | make_number (0)); | 5471 | if (FRAME_WINDOW_P (f)) |
| 5472 | x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines), | ||
| 5473 | make_number (0)); | ||
| 5474 | else /* TTY or MSDOS */ | ||
| 5475 | set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines), | ||
| 5476 | make_number (0)); | ||
| 5477 | } | ||
| 5478 | #endif | ||
| 5472 | #ifdef HAVE_WINDOW_SYSTEM | 5479 | #ifdef HAVE_WINDOW_SYSTEM |
| 5473 | if (data->frame_tool_bar_lines | 5480 | if (data->frame_tool_bar_lines |
| 5474 | != previous_frame_tool_bar_lines) | 5481 | != previous_frame_tool_bar_lines) |
| 5475 | x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines), | 5482 | x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines), |
| 5476 | make_number (0)); | 5483 | make_number (0)); |
| 5477 | #endif | 5484 | #endif |
| 5478 | #endif | ||
| 5479 | 5485 | ||
| 5480 | /* "Swap out" point from the selected window's buffer | 5486 | /* "Swap out" point from the selected window's buffer |
| 5481 | into the window itself. (Normally the pointm of the selected | 5487 | into the window itself. (Normally the pointm of the selected |
| @@ -5688,16 +5694,23 @@ the return value is nil. Otherwise the value is t. */) | |||
| 5688 | || previous_frame_cols != FRAME_COLS (f)) | 5694 | || previous_frame_cols != FRAME_COLS (f)) |
| 5689 | change_frame_size (f, previous_frame_lines, previous_frame_cols, | 5695 | change_frame_size (f, previous_frame_lines, previous_frame_cols, |
| 5690 | 0, 0, 0); | 5696 | 0, 0, 0); |
| 5691 | #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS) | 5697 | #ifdef HAVE_MENUS |
| 5692 | if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f)) | 5698 | if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f)) |
| 5693 | x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines), | 5699 | { |
| 5694 | make_number (0)); | 5700 | if (FRAME_WINDOW_P (f)) |
| 5701 | x_set_menu_bar_lines (f, | ||
| 5702 | make_number (previous_frame_menu_bar_lines), | ||
| 5703 | make_number (0)); | ||
| 5704 | else /* TTY or MSDOS */ | ||
| 5705 | set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines), | ||
| 5706 | make_number (0)); | ||
| 5707 | } | ||
| 5708 | #endif | ||
| 5695 | #ifdef HAVE_WINDOW_SYSTEM | 5709 | #ifdef HAVE_WINDOW_SYSTEM |
| 5696 | if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f)) | 5710 | if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f)) |
| 5697 | x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines), | 5711 | x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines), |
| 5698 | make_number (0)); | 5712 | make_number (0)); |
| 5699 | #endif | 5713 | #endif |
| 5700 | #endif | ||
| 5701 | 5714 | ||
| 5702 | /* Now, free glyph matrices in windows that were not reused. */ | 5715 | /* Now, free glyph matrices in windows that were not reused. */ |
| 5703 | for (i = n = 0; i < n_leaf_windows; ++i) | 5716 | for (i = n = 0; i < n_leaf_windows; ++i) |
diff --git a/src/xdisp.c b/src/xdisp.c index 0763fc19c73..52163db7456 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -19961,7 +19961,78 @@ display_menu_bar (struct window *w) | |||
| 19961 | compute_line_metrics (&it); | 19961 | compute_line_metrics (&it); |
| 19962 | } | 19962 | } |
| 19963 | 19963 | ||
| 19964 | #ifdef HAVE_MENUS | ||
| 19965 | /* Display one menu item on a TTY, by overwriting the glyphs in the | ||
| 19966 | desired glyph matrix with glyphs produced from the menu item text. | ||
| 19967 | Called from term.c to display TTY drop-down menus one item at a | ||
| 19968 | time. | ||
| 19964 | 19969 | ||
| 19970 | ITEM_TEXT is the menu item text as a C string. | ||
| 19971 | |||
| 19972 | FACE_ID is the face ID to be used for this menu item. FACE_ID | ||
| 19973 | could specify one of 3 faces: a face for an enabled item, a face | ||
| 19974 | for a disabled item, or a face for a selected item. | ||
| 19975 | |||
| 19976 | X and Y are coordinates of the first glyph in the desired matrix to | ||
| 19977 | be overwritten by the menu item. Since this is a TTY, Y is the | ||
| 19978 | glyph row and X is the glyph number in the row, where to start | ||
| 19979 | displaying the item. | ||
| 19980 | |||
| 19981 | SUBMENU non-zero means this menu item drops down a submenu, which | ||
| 19982 | should be indicated by displaying a proper visual cue after the | ||
| 19983 | item text. */ | ||
| 19984 | |||
| 19985 | void | ||
| 19986 | display_tty_menu_item (const char *item_text, int face_id, int x, int y, | ||
| 19987 | int submenu) | ||
| 19988 | { | ||
| 19989 | struct it it; | ||
| 19990 | struct frame *f = SELECTED_FRAME (); | ||
| 19991 | int saved_used, saved_truncated; | ||
| 19992 | struct glyph_row *row; | ||
| 19993 | |||
| 19994 | xassert (FRAME_TERMCAP_P (f)); | ||
| 19995 | |||
| 19996 | init_iterator (&it, w, -1, -1, f->desired_matrix->rows + y, MENU_FACE_ID); | ||
| 19997 | it.first_visible_x = 0; | ||
| 19998 | it.last_visible_x = FRAME_COLS (f); | ||
| 19999 | row = it.glyph_row; | ||
| 20000 | row->full_width_p = 1; | ||
| 20001 | |||
| 20002 | /* Arrange for the menu item glyphs to start at X and have the | ||
| 20003 | desired face. */ | ||
| 20004 | it.current_x = it.hpos = x; | ||
| 20005 | saved_used = row->used[TEXT_AREA]; | ||
| 20006 | saved_truncated = row->truncated_on_right_p; | ||
| 20007 | row->used[TEXT_AREA] = x - row->used[LEFT_MARGIN_AREA]; | ||
| 20008 | it.face_id = face_id; | ||
| 20009 | |||
| 20010 | /* FIXME: This should be controlled by a user option. See the | ||
| 20011 | comments in redisplay_tool_bar and display_mode_line about this. | ||
| 20012 | Also, if paragraph_embedding could ever be R2L, changes will be | ||
| 20013 | needed to avoid shifting to the right the row characters in | ||
| 20014 | term.c:append_glyph. */ | ||
| 20015 | it.paragraph_embedding = L2R; | ||
| 20016 | |||
| 20017 | if (submenu) | ||
| 20018 | { | ||
| 20019 | /* Indicate with ">" that there's a submenu. */ | ||
| 20020 | display_string (item_text, Qnil, Qnil, 0, 0, &it, | ||
| 20021 | strlen (item_text), 0, FRAME_COLS (f) - 2, -1); | ||
| 20022 | display_string (">", Qnil, Qnil, 0, 0, &it, 1, 0, 0, -1); | ||
| 20023 | } | ||
| 20024 | else | ||
| 20025 | { | ||
| 20026 | /* Display the menu item, pad with one space. */ | ||
| 20027 | display_string (item_text, Qnil, Qnil, 0, 0, &it, | ||
| 20028 | strlen (item_text) + 1, 0, 0, -1); | ||
| 20029 | } | ||
| 20030 | |||
| 20031 | row->used[TEXT_AREA] = saved_used; | ||
| 20032 | row->truncated_on_right_p = saved_truncated; | ||
| 20033 | row->hash - row_hash (row); | ||
| 20034 | } | ||
| 20035 | #endif /* HAVE_MENUS */ | ||
| 19965 | 20036 | ||
| 19966 | /*********************************************************************** | 20037 | /*********************************************************************** |
| 19967 | Mode Line | 20038 | Mode Line |