X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/e5d77022e8429ca757746ed5d7cf9e2420703e8e..0087ade67a7c8e31b32579a353381fb00b53a112:/src/term.c diff --git a/src/term.c b/src/term.c index 3663c44ff9..fc6fa10318 100644 --- a/src/term.c +++ b/src/term.c @@ -1,5 +1,6 @@ /* terminal control module for terminals described by TERMCAP - Copyright (C) 1985, 1986, 1987, 1992 Free Software Foundation, Inc. + Copyright (C) 1985, 86, 87, 93, 94, 95, 98 + Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -15,32 +16,64 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +/* New redisplay, TTY faces by Gerd Moellmann . */ + +#include #include #include -#include "config.h" +#include #include "termchar.h" #include "termopts.h" -#include "cm.h" -#undef NULL #include "lisp.h" -#include "screen.h" +#include "charset.h" +#include "coding.h" +#include "frame.h" #include "disptab.h" #include "termhooks.h" #include "keyboard.h" +#include "dispextern.h" +#include "window.h" + +#ifdef HAVE_TERMCAP_H +#include +#endif + +#include "cm.h" +#ifdef HAVE_X_WINDOWS +#include "xterm.h" +#endif + +static void turn_on_face P_ ((struct frame *, int face_id)); +static void turn_off_face P_ ((struct frame *, int face_id)); +static void tty_show_cursor P_ ((void)); +static void tty_hide_cursor P_ ((void)); #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) -#define OUTPUT(a) tputs (a, SCREEN_HEIGHT (selected_screen) - curY, cmputc) +#define OUTPUT(a) \ + tputs (a, (int) (FRAME_HEIGHT (XFRAME (selected_frame)) - curY), cmputc) #define OUTPUT1(a) tputs (a, 1, cmputc) #define OUTPUTL(a, lines) tputs (a, lines, cmputc) -#define OUTPUT_IF(a) { if (a) tputs (a, SCREEN_HEIGHT (selected_screen) - curY, cmputc); } -#define OUTPUT1_IF(a) { if (a) tputs (a, 1, cmputc); } -/* Terminal charateristics that higher levels want to look at. +#define OUTPUT_IF(a) \ + do { \ + if (a) \ + tputs (a, (int) (FRAME_HEIGHT (XFRAME (selected_frame)) \ + - curY), cmputc); \ + } while (0) + +#define OUTPUT1_IF(a) do { if (a) tputs (a, 1, cmputc); } while (0) + +/* Function to use to ring the bell. */ + +Lisp_Object Vring_bell_function; + +/* Terminal characteristics that higher levels want to look at. These are all extern'd in termchar.h */ int must_write_spaces; /* Nonzero means spaces in the text @@ -52,69 +85,156 @@ int line_ins_del_ok; /* Terminal can insert and delete lines */ int char_ins_del_ok; /* Terminal can insert and delete chars */ int scroll_region_ok; /* Terminal supports setting the scroll window */ -int memory_below_screen; /* Terminal remembers lines +int scroll_region_cost; /* Cost of setting a scroll window, + measured in characters */ +int memory_below_frame; /* Terminal remembers lines scrolled off bottom */ int fast_clear_end_of_line; /* Terminal has a `ce' string */ -int dont_calculate_costs; /* Nonzero means don't bother computing */ - /* various cost tables; we won't use them. */ - -/* Nonzero means no need to redraw the entire screen on resuming +/* Nonzero means no need to redraw the entire frame on resuming a suspended Emacs. This is useful on terminals with multiple pages, where one page is used for Emacs and another for all else. */ + int no_redraw_on_reenter; /* Hook functions that you can set to snap out the functions in this file. These are all extern'd in termhooks.h */ -int (*cursor_to_hook) (); -int (*raw_cursor_to_hook) (); +void (*cursor_to_hook) P_ ((int, int)); +void (*raw_cursor_to_hook) P_ ((int, int)); +void (*clear_to_end_hook) P_ ((void)); +void (*clear_frame_hook) P_ ((void)); +void (*clear_end_of_line_hook) P_ ((int)); + +void (*ins_del_lines_hook) P_ ((int, int)); + +void (*change_line_highlight_hook) P_ ((int, int, int, int)); +void (*reassert_line_highlight_hook) P_ ((int, int)); + +void (*delete_glyphs_hook) P_ ((int)); + +void (*ring_bell_hook) P_ ((void)); + +void (*reset_terminal_modes_hook) P_ ((void)); +void (*set_terminal_modes_hook) P_ ((void)); +void (*update_begin_hook) P_ ((struct frame *)); +void (*update_end_hook) P_ ((struct frame *)); +void (*set_terminal_window_hook) P_ ((int)); +void (*insert_glyphs_hook) P_ ((struct glyph *, int)); +void (*write_glyphs_hook) P_ ((struct glyph *, int)); +void (*delete_glyphs_hook) P_ ((int)); -int (*clear_to_end_hook) (); -int (*clear_screen_hook) (); -int (*clear_end_of_line_hook) (); +int (*read_socket_hook) P_ ((int, struct input_event *, int, int)); -int (*ins_del_lines_hook) (); +void (*frame_up_to_date_hook) P_ ((struct frame *)); -int (*change_line_highlight_hook) (); -int (*reassert_line_highlight_hook) (); +/* Return the current position of the mouse. -int (*insert_glyphs_hook) (); -int (*write_glyphs_hook) (); -int (*delete_glyphs_hook) (); + Set *f to the frame the mouse is in, or zero if the mouse is in no + Emacs frame. If it is set to zero, all the other arguments are + garbage. -int (*ring_bell_hook) (); + If the motion started in a scroll bar, set *bar_window to the + scroll bar's window, *part to the part the mouse is currently over, + *x to the position of the mouse along the scroll bar, and *y to the + overall length of the scroll bar. -int (*reset_terminal_modes_hook) (); -int (*set_terminal_modes_hook) (); -int (*update_begin_hook) (); -int (*update_end_hook) (); -int (*set_terminal_window_hook) (); + Otherwise, set *bar_window to Qnil, and *x and *y to the column and + row of the character cell the mouse is over. -int (*read_socket_hook) (); + Set *time to the time the mouse was at the returned position. -/* Return the current position of the mouse. This should clear - mouse_moved until the next motion event arrives. */ -void (*mouse_position_hook) ( /* SCREEN_PTR *s, - Lisp_Object *x, - Lisp_Object *y, - unsigned long *time */ ); + This should clear mouse_moved until the next motion + event arrives. */ +void (*mouse_position_hook) P_ ((FRAME_PTR *f, int insist, + Lisp_Object *bar_window, + enum scroll_bar_part *part, + Lisp_Object *x, + Lisp_Object *y, + unsigned long *time)); -/* When reading from a minibuffer in a different screen, Emacs wants - to shift the highlight from the selected screen to the minibuffer's - screen; under X, this means it lies about where the focus is. +/* When reading from a minibuffer in a different frame, Emacs wants + to shift the highlight from the selected frame to the mini-buffer's + frame; under X, this means it lies about where the focus is. This hook tells the window system code to re-decide where to put the highlight. */ -void (*screen_rehighlight_hook) ( /* SCREEN_PTR s */ ); +void (*frame_rehighlight_hook) P_ ((FRAME_PTR f)); + +/* If we're displaying frames using a window system that can stack + frames on top of each other, this hook allows you to bring a frame + to the front, or bury it behind all the other windows. If this + hook is zero, that means the device we're displaying on doesn't + support overlapping frames, so there's no need to raise or lower + anything. + + If RAISE is non-zero, F is brought to the front, before all other + windows. If RAISE is zero, F is sent to the back, behind all other + windows. */ +void (*frame_raise_lower_hook) P_ ((FRAME_PTR f, int raise)); + +/* Set the vertical scroll bar for WINDOW to have its upper left corner + at (TOP, LEFT), and be LENGTH rows high. Set its handle to + indicate that we are displaying PORTION characters out of a total + of WHOLE characters, starting at POSITION. If WINDOW doesn't yet + have a scroll bar, create one for it. */ + +void (*set_vertical_scroll_bar_hook) + P_ ((struct window *window, + int portion, int whole, int position)); + + +/* The following three hooks are used when we're doing a thorough + redisplay of the frame. We don't explicitly know which scroll bars + are going to be deleted, because keeping track of when windows go + away is a real pain - can you say set-window-configuration? + Instead, we just assert at the beginning of redisplay that *all* + scroll bars are to be removed, and then save scroll bars from the + fiery pit when we actually redisplay their window. */ + +/* Arrange for all scroll bars on FRAME to be removed at the next call + to `*judge_scroll_bars_hook'. A scroll bar may be spared if + `*redeem_scroll_bar_hook' is applied to its window before the judgment. + + This should be applied to each frame each time its window tree is + redisplayed, even if it is not displaying scroll bars at the moment; + if the HAS_SCROLL_BARS flag has just been turned off, only calling + this and the judge_scroll_bars_hook will get rid of them. + + If non-zero, this hook should be safe to apply to any frame, + whether or not it can support scroll bars, and whether or not it is + currently displaying them. */ +void (*condemn_scroll_bars_hook) P_ ((FRAME_PTR frame)); + +/* Unmark WINDOW's scroll bar for deletion in this judgement cycle. + Note that it's okay to redeem a scroll bar that is not condemned. */ +void (*redeem_scroll_bar_hook) P_ ((struct window *window)); + +/* Remove all scroll bars on FRAME that haven't been saved since the + last call to `*condemn_scroll_bars_hook'. + + This should be applied to each frame after each time its window + tree is redisplayed, even if it is not displaying scroll bars at the + moment; if the HAS_SCROLL_BARS flag has just been turned off, only + calling this and condemn_scroll_bars_hook will get rid of them. + + If non-zero, this hook should be safe to apply to any frame, + whether or not it can support scroll bars, and whether or not it is + currently displaying them. */ +void (*judge_scroll_bars_hook) P_ ((FRAME_PTR FRAME)); + +/* Hook to call in estimate_mode_line_height, if any. */ + +int (* estimate_mode_line_height_hook) P_ ((struct frame *f, enum face_id)); + /* Strings, numbers and flags taken from the termcap entry. */ -char *TS_ins_line; /* termcap "al" */ +char *TS_ins_line; /* "al" */ char *TS_ins_multi_lines; /* "AL" (one parameter, # lines to insert) */ char *TS_bell; /* "bl" */ char *TS_clr_to_bottom; /* "cd" */ char *TS_clr_line; /* "ce", clear to end of line */ -char *TS_clr_screen; /* "cl" */ +char *TS_clr_frame; /* "cl" */ char *TS_set_scroll_region; /* "cs" (2 params, first line and last line) */ char *TS_set_scroll_region_1; /* "cS" (4 params: total lines, lines above scroll region, lines below it, @@ -142,16 +262,68 @@ char *TS_rev_scroll; /* "sr" */ char *TS_end_termcap_modes; /* "te" */ char *TS_termcap_modes; /* "ti" */ char *TS_visible_bell; /* "vb" */ -char *TS_end_visual_mode; /* "ve" */ -char *TS_visual_mode; /* "vi" */ +char *TS_cursor_normal; /* "ve" */ +char *TS_cursor_visible; /* "vs" */ +char *TS_cursor_invisible; /* "vi" */ char *TS_set_window; /* "wi" (4 params, start and end of window, each as vpos and hpos) */ +/* "md" -- turn on bold (extra bright mode). */ + +char *TS_enter_bold_mode; + +/* "mh" -- turn on half-bright mode. */ + +char *TS_enter_dim_mode; + +/* "mb" -- enter blinking mode. */ + +char *TS_enter_blink_mode; + +/* "mr" -- enter reverse video mode. */ + +char *TS_enter_reverse_mode; + +/* "us"/"ue" -- start/end underlining. */ + +char *TS_exit_underline_mode, *TS_enter_underline_mode; + +/* "ug" -- number of blanks left by underline. */ + +int TN_magic_cookie_glitch_ul; + +/* "as"/"ae" -- start/end alternate character set. Not really + supported, yet. */ + +char *TS_enter_alt_charset_mode, *TS_exit_alt_charset_mode; + +/* "me" -- switch appearances off. */ + +char *TS_exit_attribute_mode; + +/* "Co" -- number of colors. */ + +int TN_max_colors; + +/* "pa" -- max. number of color pairs on screen. Not handled yet. + Could be a problem if not equal to TN_max_colors * TN_max_colors. */ + +int TN_max_pairs; + +/* "op" -- SVr4 set default pair to its original value. */ + +char *TS_orig_pair; + +/* "AF"/"AB" or "Sf"/"Sb"-- set ANSI or SVr4 foreground/background color. + 1 param, the color index. */ + +char *TS_set_foreground, *TS_set_background; + int TF_hazeltine; /* termcap hz flag. */ int TF_insmode_motion; /* termcap mi flag: can move while in insert mode. */ int TF_standout_motion; /* termcap mi flag: can move while in standout mode. */ -int TF_underscore; /* termcap ul flag: _ underlines if overstruck on - nonblank position. Must clear before writing _. */ +int TF_underscore; /* termcap ul flag: _ underlines if over-struck on + non-blank position. Must clear before writing _. */ int TF_teleray; /* termcap xt flag: many weird consequences. For t1061. */ @@ -171,8 +343,17 @@ static int se_is_so; /* 1 if same string both enters and leaves /* internal state */ +/* The largest frame width in any call to calculate_costs. */ + +int max_frame_width; + +/* The largest frame height in any call to calculate_costs. */ + +int max_frame_height; + /* Number of chars of space used for standout marker at beginning of line, or'd with 0100. Zero if no standout marker at all. + The length of these vectors is max_frame_height. Used IFF TN_standout_width >= 0. */ @@ -180,30 +361,71 @@ static char *chars_wasted; static char *copybuf; /* nonzero means supposed to write text in standout mode. */ + int standout_requested; int insert_mode; /* Nonzero when in insert mode. */ int standout_mode; /* Nonzero when in standout mode. */ /* Size of window specified by higher levels. - This is the number of lines, from the top of screen downwards, + This is the number of lines, from the top of frame downwards, which can participate in insert-line/delete-line operations. - Effectively it excludes the bottom screen_height - specified_window_size + Effectively it excludes the bottom frame_height - specified_window_size lines from those operations. */ int specified_window; -/* Screen currently being redisplayed; 0 if not currently redisplaying. +/* Frame currently being redisplayed; 0 if not currently redisplaying. (Direct output does not count). */ -SCREEN_PTR updating_screen; +FRAME_PTR updating_frame; + +/* Provided for lisp packages. */ + +static int system_uses_terminfo; char *tparam (); + +extern char *tgetstr (); + +#ifdef WINDOWSNT + +/* We aren't X windows, but we aren't termcap either. This makes me + uncertain as to what value to use for frame.output_method. For + this file, we'll define FRAME_TERMCAP_P to be zero so that our + output hooks get called instead of the termcap functions. Probably + the best long-term solution is to define an output_windows_nt... */ + +#undef FRAME_TERMCAP_P +#define FRAME_TERMCAP_P(_f_) 0 +#endif /* WINDOWSNT */ + +void ring_bell () { - if (! SCREEN_IS_TERMCAP (selected_screen)) + if (! NILP (Vring_bell_function)) + { + Lisp_Object function; + + /* Temporarily set the global variable to nil + so that if we get an error, it stays nil + and we don't call it over and over. + + We don't specbind it, because that would carefully + restore the bad value if there's an error + and make the loop of errors happen anyway. */ + function = Vring_bell_function; + Vring_bell_function = Qnil; + + call0 (function); + + Vring_bell_function = function; + return; + } + + if (! FRAME_TERMCAP_P (XFRAME (selected_frame))) { (*ring_bell_hook) (); return; @@ -211,81 +433,97 @@ ring_bell () OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell); } +void set_terminal_modes () { - if (! SCREEN_IS_TERMCAP (selected_screen)) + if (! FRAME_TERMCAP_P (XFRAME (selected_frame))) { (*set_terminal_modes_hook) (); return; } OUTPUT_IF (TS_termcap_modes); - OUTPUT_IF (TS_visual_mode); + OUTPUT_IF (TS_cursor_visible); OUTPUT_IF (TS_keypad_mode); losecursor (); } +void reset_terminal_modes () { - if (! SCREEN_IS_TERMCAP (selected_screen)) + if (! FRAME_TERMCAP_P (XFRAME (selected_frame))) { - (*reset_terminal_modes_hook) (); + if (reset_terminal_modes_hook) + (*reset_terminal_modes_hook) (); return; } if (TN_standout_width < 0) turn_off_highlight (); turn_off_insert (); OUTPUT_IF (TS_end_keypad_mode); - OUTPUT_IF (TS_end_visual_mode); + OUTPUT_IF (TS_cursor_normal); OUTPUT_IF (TS_end_termcap_modes); + OUTPUT_IF (TS_orig_pair); /* Output raw CR so kernel can track the cursor hpos. */ /* But on magic-cookie terminals this can erase an end-standout marker and - cause the rest of the screen to be in standout, so move down first. */ + cause the rest of the frame to be in standout, so move down first. */ if (TN_standout_width >= 0) cmputc ('\n'); cmputc ('\r'); } -update_begin (s) - SCREEN_PTR s; +void +update_begin (f) + FRAME_PTR f; { - updating_screen = s; - if (! SCREEN_IS_TERMCAP (updating_screen)) - (*update_begin_hook) (s); + updating_frame = f; + if (! FRAME_TERMCAP_P (updating_frame)) + (*update_begin_hook) (f); + else + tty_hide_cursor (); } -update_end (s) - SCREEN_PTR s; +void +update_end (f) + FRAME_PTR f; { - if (! SCREEN_IS_TERMCAP (updating_screen)) + if (! FRAME_TERMCAP_P (updating_frame)) { - (*update_end_hook) (s); - updating_screen = 0; + (*update_end_hook) (f); + updating_frame = 0; return; } + + if (!XWINDOW (selected_window)->cursor_off_p) + tty_show_cursor (); + turn_off_insert (); background_highlight (); standout_requested = 0; - updating_screen = 0; + updating_frame = 0; } +void set_terminal_window (size) int size; { - if (! SCREEN_IS_TERMCAP (updating_screen)) + if (! FRAME_TERMCAP_P (updating_frame)) { (*set_terminal_window_hook) (size); return; } - specified_window = size ? size : SCREEN_HEIGHT (selected_screen); + specified_window = size ? size : FRAME_HEIGHT (XFRAME (selected_frame)); if (!scroll_region_ok) return; set_scroll_region (0, specified_window); } +void set_scroll_region (start, stop) int start, stop; { char *buf; + struct frame *sf = XFRAME (selected_frame); + if (TS_set_scroll_region) { buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1); @@ -293,19 +531,20 @@ set_scroll_region (start, stop) else if (TS_set_scroll_region_1) { buf = tparam (TS_set_scroll_region_1, 0, 0, - SCREEN_HEIGHT (selected_screen), start, - SCREEN_HEIGHT (selected_screen) - stop, - SCREEN_HEIGHT (selected_screen)); + FRAME_HEIGHT (sf), start, + FRAME_HEIGHT (sf) - stop, + FRAME_HEIGHT (sf)); } else { - buf = tparam (TS_set_window, 0, 0, start, 0, stop, SCREEN_WIDTH (selected_screen)); + buf = tparam (TS_set_window, 0, 0, start, 0, stop, FRAME_WIDTH (sf)); } OUTPUT (buf); - free (buf); + xfree (buf); losecursor (); } +void turn_on_insert () { if (!insert_mode) @@ -313,6 +552,7 @@ turn_on_insert () insert_mode = 1; } +void turn_off_insert () { if (insert_mode) @@ -327,6 +567,7 @@ turn_off_insert () These functions are called on all terminals, but do nothing on terminals whose standout mode does not work that way. */ +void turn_off_highlight () { if (TN_standout_width < 0) @@ -337,6 +578,7 @@ turn_off_highlight () } } +void turn_on_highlight () { if (TN_standout_width < 0) @@ -347,10 +589,31 @@ turn_on_highlight () } } + +/* Make cursor invisible. */ + +static void +tty_hide_cursor () +{ + OUTPUT_IF (TS_cursor_invisible); +} + + +/* Ensure that cursor is visible. */ + +static void +tty_show_cursor () +{ + OUTPUT_IF (TS_cursor_normal); + OUTPUT_IF (TS_cursor_visible); +} + + /* Set standout mode to the state it should be in for empty space inside windows. What this is, depends on the user option inverse-video. */ +void background_highlight () { if (TN_standout_width >= 0) @@ -363,7 +626,7 @@ background_highlight () /* Set standout mode to the mode specified for the text to be output. */ -static +static void highlight_if_desired () { if (TN_standout_width >= 0) @@ -376,7 +639,7 @@ highlight_if_desired () /* Handle standout mode for terminals in which TN_standout_width >= 0. On these terminals, standout is controlled by markers that - live inside the screen memory. TN_standout_width is the width + live inside the terminal's memory. TN_standout_width is the width that the marker occupies in memory. Standout runs from the marker to the end of the line on some terminals, or to the next turn-off-standout marker (TS_end_standout_mode) string @@ -385,6 +648,7 @@ highlight_if_desired () /* Write a standout marker or end-standout marker at the front of the line at vertical position vpos. */ +void write_standout_marker (flag, vpos) int flag, vpos; { @@ -402,11 +666,13 @@ write_standout_marker (flag, vpos) Call this when about to modify line at position VPOS and not change whether it is highlighted. */ +void reassert_line_highlight (highlight, vpos) int highlight; int vpos; { - if (! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen))) + struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame); + if (! FRAME_TERMCAP_P (f)) { (*reassert_line_highlight_hook) (highlight, vpos); return; @@ -414,7 +680,7 @@ reassert_line_highlight (highlight, vpos) if (TN_standout_width < 0) /* Handle terminals where standout takes affect at output time */ standout_requested = highlight; - else if (chars_wasted[vpos] == 0) + else if (chars_wasted && chars_wasted[vpos] == 0) /* For terminals with standout markers, write one on this line if there isn't one already. */ write_standout_marker (highlight, vpos); @@ -423,13 +689,14 @@ reassert_line_highlight (highlight, vpos) /* Call this when about to modify line at position VPOS and change whether it is highlighted. */ -change_line_highlight (new_highlight, vpos, first_unused_hpos) - int new_highlight, vpos, first_unused_hpos; +void +change_line_highlight (new_highlight, vpos, y, first_unused_hpos) + int new_highlight, vpos, y, first_unused_hpos; { standout_requested = new_highlight; - if (! SCREEN_IS_TERMCAP (updating_screen)) + if (! FRAME_TERMCAP_P (updating_frame)) { - (*change_line_highlight_hook) (new_highlight, vpos, first_unused_hpos); + (*change_line_highlight_hook) (new_highlight, vpos, y, first_unused_hpos); return; } @@ -444,7 +711,7 @@ change_line_highlight (new_highlight, vpos, first_unused_hpos) /* On Teleray, make sure to erase the SO marker. */ if (TF_teleray) { - cmgoto (curY - 1, SCREEN_WIDTH (selected_screen) - 4); + cmgoto (curY - 1, FRAME_WIDTH (XFRAME (selected_frame)) - 4); OUTPUT ("\033S"); curY++; /* ESC S moves to next line where the TS_standout_mode was */ curX = 0; @@ -457,36 +724,44 @@ change_line_highlight (new_highlight, vpos, first_unused_hpos) } -/* Move to absolute position, specified origin 0 */ +/* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are + frame-relative coordinates. */ -cursor_to (row, col) - int row, col; +void +cursor_to (vpos, hpos) + int vpos, hpos; { - if (! SCREEN_IS_TERMCAP ((updating_screen - ? updating_screen - : selected_screen)) - && cursor_to_hook) + struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame); + + if (! FRAME_TERMCAP_P (f) && cursor_to_hook) { - (*cursor_to_hook) (row, col); + (*cursor_to_hook) (vpos, hpos); return; } - col += chars_wasted[row] & 077; - if (curY == row && curX == col) + /* Detect the case where we are called from reset_sys_modes + and the costs have never been calculated. Do nothing. */ + if (chars_wasted == 0) + return; + + hpos += chars_wasted[vpos] & 077; + if (curY == vpos && curX == hpos) return; if (!TF_standout_motion) background_highlight (); if (!TF_insmode_motion) turn_off_insert (); - cmgoto (row, col); + cmgoto (vpos, hpos); } /* Similar but don't take any account of the wasted characters. */ +void raw_cursor_to (row, col) int row, col; { - if (! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen))) + struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame); + if (! FRAME_TERMCAP_P (f)) { (*raw_cursor_to_hook) (row, col); return; @@ -502,12 +777,13 @@ raw_cursor_to (row, col) /* Erase operations */ -/* clear from cursor to end of screen */ +/* clear from cursor to end of frame */ +void clear_to_end () { register int i; - if (clear_to_end_hook && SCREEN_IS_TERMCAP (updating_screen)) + if (clear_to_end_hook && ! FRAME_TERMCAP_P (updating_frame)) { (*clear_to_end_hook) (); return; @@ -516,33 +792,37 @@ clear_to_end () { background_highlight (); OUTPUT (TS_clr_to_bottom); - bzero (chars_wasted + curY, SCREEN_HEIGHT (selected_screen) - curY); + bzero (chars_wasted + curY, + FRAME_HEIGHT (XFRAME (selected_frame)) - curY); } else { - for (i = curY; i < SCREEN_HEIGHT (selected_screen); i++) + for (i = curY; i < FRAME_HEIGHT (XFRAME (selected_frame)); i++) { cursor_to (i, 0); - clear_end_of_line_raw (SCREEN_WIDTH (selected_screen)); + clear_end_of_line_raw (FRAME_WIDTH (XFRAME (selected_frame))); } } } -/* Clear entire screen */ +/* Clear entire frame */ -clear_screen () +void +clear_frame () { - if (clear_screen_hook - && ! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen))) + struct frame *sf = XFRAME (selected_frame); + + if (clear_frame_hook + && ! FRAME_TERMCAP_P ((updating_frame ? updating_frame : sf))) { - (*clear_screen_hook) (); + (*clear_frame_hook) (); return; } - if (TS_clr_screen) + if (TS_clr_frame) { background_highlight (); - OUTPUT (TS_clr_screen); - bzero (chars_wasted, SCREEN_HEIGHT (selected_screen)); + OUTPUT (TS_clr_frame); + bzero (chars_wasted, FRAME_HEIGHT (sf)); cmat (0, 0); } else @@ -559,13 +839,14 @@ clear_screen () Note that the cursor may be moved. */ +void clear_end_of_line (first_unused_hpos) int first_unused_hpos; { - static GLYPH buf[1] = {SPACEGLYPH}; - if (SCREEN_IS_TERMCAP (selected_screen) + if (FRAME_TERMCAP_P (XFRAME (selected_frame)) + && chars_wasted != 0 && TN_standout_width == 0 && curX == 0 && chars_wasted[curY] != 0) - write_glyphs (buf, 1); + write_glyphs (&space_glyph, 1); clear_end_of_line_raw (first_unused_hpos); } @@ -575,20 +856,26 @@ clear_end_of_line (first_unused_hpos) Note that the cursor may be moved, on terminals lacking a `ce' string. */ +void clear_end_of_line_raw (first_unused_hpos) int first_unused_hpos; { register int i; if (clear_end_of_line_hook - && ! SCREEN_IS_TERMCAP ((updating_screen - ? updating_screen - : selected_screen))) + && ! FRAME_TERMCAP_P ((updating_frame + ? updating_frame + : XFRAME (selected_frame)))) { (*clear_end_of_line_hook) (first_unused_hpos); return; } + /* Detect the case where we are called from reset_sys_modes + and the costs have never been calculated. Do nothing. */ + if (chars_wasted == 0) + return; + first_unused_hpos += chars_wasted[curY] & 077; if (curX >= first_unused_hpos) return; @@ -602,11 +889,12 @@ clear_end_of_line_raw (first_unused_hpos) } else { /* have to do it the hard way */ + struct frame *sf = XFRAME (selected_frame); turn_off_insert (); - /* Do not write in last row last col with Autowrap on. */ - if (AutoWrap && curY == SCREEN_HEIGHT (selected_screen) - 1 - && first_unused_hpos == SCREEN_WIDTH (selected_screen)) + /* Do not write in last row last col with Auto-wrap on. */ + if (AutoWrap && curY == FRAME_HEIGHT (sf) - 1 + && first_unused_hpos == FRAME_WIDTH (sf)) first_unused_hpos--; for (i = curX; i < first_unused_hpos; i++) @@ -619,17 +907,112 @@ clear_end_of_line_raw (first_unused_hpos) } } +/* Encode SRC_LEN glyphs starting at SRC to terminal output codes and + store them at DST. Do not write more than DST_LEN bytes. That may + require stopping before all SRC_LEN input glyphs have been + converted. -write_glyphs (string, len) - register GLYPH *string; - register int len; + We store the number of glyphs actually converted in *CONSUMED. The + return value is the number of bytes store in DST. */ + +int +encode_terminal_code (src, dst, src_len, dst_len, consumed) + struct glyph *src; + int src_len; + unsigned char *dst; + int dst_len, *consumed; { + struct glyph *src_start = src, *src_end = src + src_len; + unsigned char *dst_start = dst, *dst_end = dst + dst_len; register GLYPH g; + unsigned int c; + unsigned char workbuf[4], *buf; + int len; register int tlen = GLYPH_TABLE_LENGTH; register Lisp_Object *tbase = GLYPH_TABLE_BASE; + int result; + struct coding_system *coding; + + coding = (CODING_REQUIRE_ENCODING (&terminal_coding) + ? &terminal_coding + : &safe_terminal_coding); + + while (src < src_end) + { + g = GLYPH_FROM_CHAR_GLYPH (*src); + + /* We must skip glyphs to be padded for a wide character. */ + if (! CHAR_GLYPH_PADDING_P (*src)) + { + c = src->u.ch.code; + if (! GLYPH_CHAR_VALID_P (c)) + { + c = ' '; + g = MAKE_GLYPH (sf, c, GLYPH_FACE (sf, g)); + } + if (COMPOSITE_CHAR_P (c)) + { + /* If C is a composite character, we can display + only the first component. */ + g = cmpchar_table[COMPOSITE_CHAR_ID (c)]->glyph[0], + c = GLYPH_CHAR (sf, g); + } + if (c < tlen) + { + /* G has an entry in Vglyph_table, + so process any alias before testing for simpleness. */ + GLYPH_FOLLOW_ALIASES (tbase, tlen, g); + c = GLYPH_CHAR (sf, g); + } + if (GLYPH_SIMPLE_P (tbase, tlen, g)) + /* We set the multi-byte form of C at BUF. */ + len = CHAR_STRING (c, workbuf, buf); + else + { + /* We have a string in Vglyph_table. */ + len = GLYPH_LENGTH (tbase, g); + buf = GLYPH_STRING (tbase, g); + } + + result = encode_coding (coding, buf, dst, len, dst_end - dst); + len -= coding->consumed; + dst += coding->produced; + if (result == CODING_FINISH_INSUFFICIENT_DST + || (result == CODING_FINISH_INSUFFICIENT_SRC + && len > dst_end - dst)) + /* The remaining output buffer is too short. We must + break the loop here without increasing SRC so that the + next call of this function starts from the same glyph. */ + break; + + if (len > 0) + { + /* This is the case that a code of the range 0200..0237 + exists in buf. We must just write out such a code. */ + buf += coding->consumed; + while (len--) + *dst++ = *buf++; + } + } + src++; + } + + *consumed = src - src_start; + return (dst - dst_start); +} + + +void +write_glyphs (string, len) + register struct glyph *string; + register int len; +{ + int produced, consumed; + struct frame *sf = XFRAME (selected_frame); + struct frame *f = updating_frame ? updating_frame : sf; if (write_glyphs_hook - && ! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen))) + && ! FRAME_TERMCAP_P (f)) { (*write_glyphs_hook) (string, len); return; @@ -638,76 +1021,109 @@ write_glyphs (string, len) highlight_if_desired (); turn_off_insert (); - /* Don't dare write in last column of bottom line, if AutoWrap, - since that would scroll the whole screen on some terminals. */ + /* Don't dare write in last column of bottom line, if Auto-Wrap, + since that would scroll the whole frame on some terminals. */ if (AutoWrap - && curY + 1 == SCREEN_HEIGHT (selected_screen) - && (curX + len - (chars_wasted[curY] & 077) - == SCREEN_WIDTH (selected_screen))) + && curY + 1 == FRAME_HEIGHT (sf) + && (curX + len - (chars_wasted[curY] & 077) == FRAME_WIDTH (sf))) len --; + if (len <= 0) + return; cmplus (len); - while (--len >= 0) + + /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at + the tail. */ + terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK; + + while (len > 0) { - g = *string++; - /* Check quickly for G beyond length of table. - That implies it isn't an alias and is simple. */ - if (g >= tlen) + /* Identify a run of glyphs with the same face. */ + int face_id = string->u.ch.face_id; + int n; + + for (n = 1; n < len; ++n) + if (string[n].u.ch.face_id != face_id) + break; + + /* Turn appearance modes of the face of the run on. */ + turn_on_face (f, face_id); + + while (n > 0) { - simple: - putc (g & 0xff, stdout); - if (ferror (stdout)) - clearerr (stdout); - if (termscript) - putc (g & 0xff, termscript); - } - else - { - /* G has an entry in Vglyph_table, - so process any alias and then test for simpleness. */ - while (GLYPH_ALIAS_P (tbase, tlen, g)) - g = GLYPH_ALIAS (tbase, g); - if (GLYPH_SIMPLE_P (tbase, tlen, g)) - goto simple; - else + /* We use a shared conversion buffer of the current size + (1024 bytes at least). Usually it is sufficient, but if + not, we just repeat the loop. */ + produced = encode_terminal_code (string, conversion_buffer, + n, conversion_buffer_size, + &consumed); + if (produced > 0) { - /* Here if G (or its definition as an alias) is not simple. */ - fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g), - stdout); + fwrite (conversion_buffer, 1, produced, stdout); if (ferror (stdout)) clearerr (stdout); if (termscript) - fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g), - termscript); + fwrite (conversion_buffer, 1, produced, termscript); } + len -= consumed; + n -= consumed; + string += consumed; } + + /* Turn appearance modes off. */ + turn_off_face (f, face_id); } + + /* We may have to output some codes to terminate the writing. */ + if (CODING_REQUIRE_FLUSHING (&terminal_coding)) + { + terminal_coding.mode |= CODING_MODE_LAST_BLOCK; + encode_coding (&terminal_coding, "", conversion_buffer, + 0, conversion_buffer_size); + if (terminal_coding.produced > 0) + { + fwrite (conversion_buffer, 1, terminal_coding.produced, stdout); + if (ferror (stdout)) + clearerr (stdout); + if (termscript) + fwrite (conversion_buffer, 1, terminal_coding.produced, + termscript); + } + } + + cmcheckmagic (); } /* If start is zero, insert blanks instead of a string at start */ +void insert_glyphs (start, len) - register GLYPH *start; + register struct glyph *start; register int len; { char *buf; - register GLYPH g; - register int tlen = GLYPH_TABLE_LENGTH; - register Lisp_Object *tbase = GLYPH_TABLE_BASE; + GLYPH g; + struct frame *f, *sf; + + if (len <= 0) + return; - if (insert_glyphs_hook && ! SCREEN_IS_TERMCAP (updating_screen)) + if (insert_glyphs_hook) { (*insert_glyphs_hook) (start, len); return; } + + sf = XFRAME (selected_frame); + f = updating_frame ? updating_frame : sf; highlight_if_desired (); if (TS_ins_multi_chars) { buf = tparam (TS_ins_multi_chars, 0, 0, len); OUTPUT1 (buf); - free (buf); + xfree (buf); if (start) write_glyphs (start, len); return; @@ -715,43 +1131,63 @@ insert_glyphs (start, len) turn_on_insert (); cmplus (len); - while (--len >= 0) + /* The bit CODING_MODE_LAST_BLOCK should be set to 1 only at the tail. */ + terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK; + while (len-- > 0) { + int produced, consumed; + struct glyph glyph; + OUTPUT1_IF (TS_ins_char); if (!start) g = SPACEGLYPH; else - g = *start++; - - if (GLYPH_SIMPLE_P (tbase, tlen, g)) { - putc (g & 0xff, stdout); - if (ferror (stdout)) - clearerr (stdout); - if (termscript) - putc (g & 0xff, termscript); + g = GLYPH_FROM_CHAR_GLYPH (*start); + ++start; + /* We must open sufficient space for a character which + occupies more than one column. */ + while (len && CHAR_GLYPH_PADDING_P (*start)) + { + OUTPUT1_IF (TS_ins_char); + start++, len--; + } } - else + + if (len <= 0) + /* This is the last glyph. */ + terminal_coding.mode |= CODING_MODE_LAST_BLOCK; + + /* We use shared conversion buffer of the current size (1024 + bytes at least). It is surely sufficient for just one glyph. */ + SET_CHAR_GLYPH_FROM_GLYPH (glyph, g); + turn_on_face (f, glyph.u.ch.face_id); + produced = encode_terminal_code (&glyph, conversion_buffer, + 1, conversion_buffer_size, &consumed); + if (produced > 0) { - fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g), stdout); + fwrite (conversion_buffer, 1, produced, stdout); if (ferror (stdout)) clearerr (stdout); if (termscript) - fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g), - termscript); + fwrite (conversion_buffer, 1, produced, termscript); } - OUTPUT1_IF (TS_pad_inserted_char); - } + OUTPUT1_IF (TS_pad_inserted_char); + turn_off_face (f, glyph.u.ch.face_id); + } + + cmcheckmagic (); } +void delete_glyphs (n) register int n; { char *buf; register int i; - if (delete_glyphs_hook && ! SCREEN_IS_TERMCAP (updating_screen)) + if (delete_glyphs_hook && ! FRAME_TERMCAP_P (updating_frame)) { (*delete_glyphs_hook) (n); return; @@ -771,7 +1207,7 @@ delete_glyphs (n) { buf = tparam (TS_del_multi_chars, 0, 0, n); OUTPUT1 (buf); - free (buf); + xfree (buf); } else for (i = 0; i < n; i++) @@ -782,22 +1218,26 @@ delete_glyphs (n) /* Insert N lines at vpos VPOS. If N is negative, delete -N lines. */ +void ins_del_lines (vpos, n) int vpos, n; { char *multi = n > 0 ? TS_ins_multi_lines : TS_del_multi_lines; char *single = n > 0 ? TS_ins_line : TS_del_line; char *scroll = n > 0 ? TS_rev_scroll : TS_fwd_scroll; + struct frame *sf; register int i = n > 0 ? n : -n; register char *buf; - if (ins_del_lines_hook && ! SCREEN_IS_TERMCAP (updating_screen)) + if (ins_del_lines_hook && ! FRAME_TERMCAP_P (updating_frame)) { (*ins_del_lines_hook) (vpos, n); return; } + sf = XFRAME (selected_frame); + /* If the lines below the insertion are being pushed into the end of the window, this is the same as clearing; and we know the lines are already clear, since the matching @@ -807,7 +1247,7 @@ ins_del_lines (vpos, n) as there will be a matching inslines later that will flush them. */ if (scroll_region_ok && vpos + i >= specified_window) return; - if (!memory_below_screen && vpos + i >= SCREEN_HEIGHT (selected_screen)) + if (!memory_below_frame && vpos + i >= FRAME_HEIGHT (sf)) return; if (multi) @@ -816,7 +1256,7 @@ ins_del_lines (vpos, n) background_highlight (); buf = tparam (multi, 0, 0, i); OUTPUT (buf); - free (buf); + xfree (buf); } else if (single) { @@ -842,10 +1282,10 @@ ins_del_lines (vpos, n) if (TN_standout_width >= 0) { - register lower_limit + register int lower_limit = (scroll_region_ok ? specified_window - : SCREEN_HEIGHT (selected_screen)); + : FRAME_HEIGHT (sf)); if (n < 0) { @@ -861,9 +1301,9 @@ ins_del_lines (vpos, n) bzero (&chars_wasted[vpos], n); } } - if (!scroll_region_ok && memory_below_screen && n < 0) + if (!scroll_region_ok && memory_below_frame && n < 0) { - cursor_to (SCREEN_HEIGHT (selected_screen) + n, 0); + cursor_to (FRAME_HEIGHT (sf) + n, 0); clear_to_end (); } } @@ -912,17 +1352,18 @@ per_line_cost (str) #ifndef old /* char_ins_del_cost[n] is cost of inserting N characters. - char_ins_del_cost[-n] is cost of deleting N characters. */ + char_ins_del_cost[-n] is cost of deleting N characters. + The length of this vector is based on max_frame_width. */ int *char_ins_del_vector; -#define char_ins_del_cost(s) (&char_ins_del_vector[SCREEN_WIDTH ((s))]) +#define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_WIDTH ((f))]) #endif /* ARGSUSED */ static void -calculate_ins_del_char_costs (screen) - SCREEN_PTR screen; +calculate_ins_del_char_costs (frame) + FRAME_PTR frame; { int ins_startup_cost, del_startup_cost; int ins_cost_per_char, del_cost_per_char; @@ -968,44 +1409,43 @@ calculate_ins_del_char_costs (screen) } /* Delete costs are at negative offsets */ - p = &char_ins_del_cost (screen)[0]; - for (i = SCREEN_WIDTH (selected_screen); --i >= 0;) + p = &char_ins_del_cost (frame)[0]; + for (i = FRAME_WIDTH (frame); --i >= 0;) *--p = (del_startup_cost += del_cost_per_char); /* Doing nothing is free */ - p = &char_ins_del_cost (screen)[0]; + p = &char_ins_del_cost (frame)[0]; *p++ = 0; /* Insert costs are at positive offsets */ - for (i = SCREEN_WIDTH (screen); --i >= 0;) + for (i = FRAME_WIDTH (frame); --i >= 0;) *p++ = (ins_startup_cost += ins_cost_per_char); } -#ifdef HAVE_X_WINDOWS -extern int x_screen_planes; -#endif - -calculate_costs (screen) - SCREEN_PTR screen; +void +calculate_costs (frame) + FRAME_PTR frame; { - register char *s = TS_set_scroll_region ? - TS_set_scroll_region - : TS_set_scroll_region_1; + register char *f = (TS_set_scroll_region + ? TS_set_scroll_region + : TS_set_scroll_region_1); - if (dont_calculate_costs) - return; + FRAME_COST_BAUD_RATE (frame) = baud_rate; + scroll_region_cost = string_cost (f); #ifdef HAVE_X_WINDOWS - if (SCREEN_IS_X (screen)) + if (FRAME_X_P (frame)) { - do_line_insertion_deletion_costs (screen, 0, ".5*", 0, ".5*", - 0, 0, x_screen_planes); + do_line_insertion_deletion_costs (frame, 0, ".5*", 0, ".5*", + 0, 0, + x_screen_planes (frame)); + scroll_region_cost = 0; return; } #endif /* These variables are only used for terminal stuff. They are allocated - once for the terminal screen of X-windows emacs, but not used afterwards. + once for the terminal frame of X-windows emacs, but not used afterwards. char_ins_del_vector (i.e., char_ins_del_cost) isn't used because X turns off char_ins_del_ok. @@ -1013,53 +1453,147 @@ calculate_costs (screen) chars_wasted and copybuf are only used here in term.c in cases where the term hook isn't called. */ + max_frame_height = max (max_frame_height, FRAME_HEIGHT (frame)); + max_frame_width = max (max_frame_width, FRAME_WIDTH (frame)); + if (chars_wasted != 0) - chars_wasted = (char *) xrealloc (chars_wasted, SCREEN_HEIGHT (screen)); + chars_wasted = (char *) xrealloc (chars_wasted, max_frame_height); else - chars_wasted = (char *) xmalloc (SCREEN_HEIGHT (screen)); + chars_wasted = (char *) xmalloc (max_frame_height); if (copybuf != 0) - copybuf = (char *) xrealloc (copybuf, SCREEN_HEIGHT (screen)); + copybuf = (char *) xrealloc (copybuf, max_frame_height); else - copybuf = (char *) xmalloc (SCREEN_HEIGHT (screen)); + copybuf = (char *) xmalloc (max_frame_height); if (char_ins_del_vector != 0) char_ins_del_vector = (int *) xrealloc (char_ins_del_vector, (sizeof (int) - + 2 * SCREEN_WIDTH (screen) * sizeof (int))); + + 2 * max_frame_width * sizeof (int))); else char_ins_del_vector = (int *) xmalloc (sizeof (int) - + 2 * SCREEN_WIDTH (screen) * sizeof (int)); + + 2 * max_frame_width * sizeof (int)); - bzero (chars_wasted, SCREEN_HEIGHT (screen)); - bzero (copybuf, SCREEN_HEIGHT (screen)); + bzero (chars_wasted, max_frame_height); + bzero (copybuf, max_frame_height); bzero (char_ins_del_vector, (sizeof (int) - + 2 * SCREEN_WIDTH (screen) * sizeof (int))); + + 2 * max_frame_width * sizeof (int))); - if (s && (!TS_ins_line && !TS_del_line)) - do_line_insertion_deletion_costs (screen, + if (f && (!TS_ins_line && !TS_del_line)) + do_line_insertion_deletion_costs (frame, TS_rev_scroll, TS_ins_multi_lines, TS_fwd_scroll, TS_del_multi_lines, - s, s, 1); + f, f, 1); else - do_line_insertion_deletion_costs (screen, + do_line_insertion_deletion_costs (frame, TS_ins_line, TS_ins_multi_lines, TS_del_line, TS_del_multi_lines, 0, 0, 1); - calculate_ins_del_char_costs (screen); + calculate_ins_del_char_costs (frame); /* Don't use TS_repeat if its padding is worse than sending the chars */ if (TS_repeat && per_line_cost (TS_repeat) * baud_rate < 9000) RPov = string_cost (TS_repeat); else - RPov = SCREEN_WIDTH (screen) * 2; + RPov = FRAME_WIDTH (frame) * 2; cmcostinit (); /* set up cursor motion costs */ } +struct fkey_table { + char *cap, *name; +}; + + /* Termcap capability names that correspond directly to X keysyms. + Some of these (marked "terminfo") aren't supplied by old-style + (Berkeley) termcap entries. They're listed in X keysym order; + except we put the keypad keys first, so that if they clash with + other keys (as on the IBM PC keyboard) they get overridden. + */ + +static struct fkey_table keys[] = +{ + "kh", "home", /* termcap */ + "kl", "left", /* termcap */ + "ku", "up", /* termcap */ + "kr", "right", /* termcap */ + "kd", "down", /* termcap */ + "%8", "prior", /* terminfo */ + "%5", "next", /* terminfo */ + "@7", "end", /* terminfo */ + "@1", "begin", /* terminfo */ + "*6", "select", /* terminfo */ + "%9", "print", /* terminfo */ + "@4", "execute", /* terminfo --- actually the `command' key */ + /* + * "insert" --- see below + */ + "&8", "undo", /* terminfo */ + "%0", "redo", /* terminfo */ + "%7", "menu", /* terminfo --- actually the `options' key */ + "@0", "find", /* terminfo */ + "@2", "cancel", /* terminfo */ + "%1", "help", /* terminfo */ + /* + * "break" goes here, but can't be reliably intercepted with termcap + */ + "&4", "reset", /* terminfo --- actually `restart' */ + /* + * "system" and "user" --- no termcaps + */ + "kE", "clearline", /* terminfo */ + "kA", "insertline", /* terminfo */ + "kL", "deleteline", /* terminfo */ + "kI", "insertchar", /* terminfo */ + "kD", "deletechar", /* terminfo */ + "kB", "backtab", /* terminfo */ + /* + * "kp_backtab", "kp-space", "kp-tab" --- no termcaps + */ + "@8", "kp-enter", /* terminfo */ + /* + * "kp-f1", "kp-f2", "kp-f3" "kp-f4", + * "kp-multiply", "kp-add", "kp-separator", + * "kp-subtract", "kp-decimal", "kp-divide", "kp-0"; + * --- no termcaps for any of these. + */ + "K4", "kp-1", /* terminfo */ + /* + * "kp-2" --- no termcap + */ + "K5", "kp-3", /* terminfo */ + /* + * "kp-4" --- no termcap + */ + "K2", "kp-5", /* terminfo */ + /* + * "kp-6" --- no termcap + */ + "K1", "kp-7", /* terminfo */ + /* + * "kp-8" --- no termcap + */ + "K3", "kp-9", /* terminfo */ + /* + * "kp-equal" --- no termcap + */ + "k1", "f1", + "k2", "f2", + "k3", "f3", + "k4", "f4", + "k5", "f5", + "k6", "f6", + "k7", "f7", + "k8", "f8", + "k9", "f9", + }; + +static char **term_get_fkeys_arg; +static Lisp_Object term_get_fkeys_1 (); + /* Find the escape codes sent by the function keys for Vfunction_key_map. This function scans the termcap function key sequence entries, and adds entries to Vfunction_key_map for each function key it finds. */ @@ -1068,55 +1602,459 @@ void term_get_fkeys (address) char **address; { - extern char *tgetstr (); - struct fkey_table { - char *cap, *name; - }; - static struct fkey_table keys[] = { - "kl", "left", - "kr", "right", - "ku", "up", - "kd", "down", - "kh", "home", - "k1", "f1", - "k2", "f2", - "k3", "f3", - "k4", "f4", - "k5", "f5", - "k6", "f6", - "k7", "f7", - "k8", "f8", - "k9", "f9", - "k0", "f10", - "kH", "home-down", - "ka", "clear-tabs", - "kt", "clear-tab", - "kT", "set-tab", - "kC", "clear", - "kL", "deleteline", - "kM", "exit-insert", - "kE", "clear-eol", - "kS", "clear-eos", - "kI", "insert", - "kA", "insertline", - "kN", "next", - "kP", "prior", - "kF", "scroll-forward", - "kR", "scroll-reverse" - }; + /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp + errors during the call. The only errors should be from Fdefine_key + when given a key sequence containing an invalid prefix key. If the + termcap defines function keys which use a prefix that is already bound + to a command by the default bindings, we should silently ignore that + function key specification, rather than giving the user an error and + refusing to run at all on such a terminal. */ + + extern Lisp_Object Fidentity (); + term_get_fkeys_arg = address; + internal_condition_case (term_get_fkeys_1, Qerror, Fidentity); +} + +static Lisp_Object +term_get_fkeys_1 () +{ int i; + char **address = term_get_fkeys_arg; + + /* This can happen if CANNOT_DUMP or with strange options. */ + if (!initialized) + Vfunction_key_map = Fmake_sparse_keymap (Qnil); + for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++) { char *sequence = tgetstr (keys[i].cap, address); if (sequence) - Fdefine_key (Vfunction_key_map, - build_string (sequence), - Fmake_vector (make_number (1), intern (keys[i].name))); + Fdefine_key (Vfunction_key_map, build_string (sequence), + Fmake_vector (make_number (1), + intern (keys[i].name))); + } + + /* The uses of the "k0" capability are inconsistent; sometimes it + describes F10, whereas othertimes it describes F0 and "k;" describes F10. + We will attempt to politely accommodate both systems by testing for + "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10. + */ + { + char *k_semi = tgetstr ("k;", address); + char *k0 = tgetstr ("k0", address); + char *k0_name = "f10"; + + if (k_semi) + { + Fdefine_key (Vfunction_key_map, build_string (k_semi), + Fmake_vector (make_number (1), intern ("f10"))); + k0_name = "f0"; + } + + if (k0) + Fdefine_key (Vfunction_key_map, build_string (k0), + Fmake_vector (make_number (1), intern (k0_name))); + } + + /* Set up cookies for numbered function keys above f10. */ + { + char fcap[3], fkey[4]; + + fcap[0] = 'F'; fcap[2] = '\0'; + for (i = 11; i < 64; i++) + { + if (i <= 19) + fcap[1] = '1' + i - 11; + else if (i <= 45) + fcap[1] = 'A' + i - 20; + else + fcap[1] = 'a' + i - 46; + + { + char *sequence = tgetstr (fcap, address); + if (sequence) + { + sprintf (fkey, "f%d", i); + Fdefine_key (Vfunction_key_map, build_string (sequence), + Fmake_vector (make_number (1), + intern (fkey))); + } + } + } + } + + /* + * Various mappings to try and get a better fit. + */ + { +#define CONDITIONAL_REASSIGN(cap1, cap2, sym) \ + if (!tgetstr (cap1, address)) \ + { \ + char *sequence = tgetstr (cap2, address); \ + if (sequence) \ + Fdefine_key (Vfunction_key_map, build_string (sequence), \ + Fmake_vector (make_number (1), \ + intern (sym))); \ + } + + /* if there's no key_next keycap, map key_npage to `next' keysym */ + CONDITIONAL_REASSIGN ("%5", "kN", "next"); + /* if there's no key_prev keycap, map key_ppage to `previous' keysym */ + CONDITIONAL_REASSIGN ("%8", "kP", "prior"); + /* if there's no key_dc keycap, map key_ic to `insert' keysym */ + CONDITIONAL_REASSIGN ("kD", "kI", "insert"); + /* if there's no key_end keycap, map key_ll to 'end' keysym */ + CONDITIONAL_REASSIGN ("@7", "kH", "end"); + + /* IBM has their own non-standard dialect of terminfo. + If the standard name isn't found, try the IBM name. */ + CONDITIONAL_REASSIGN ("kB", "KO", "backtab"); + CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */ + CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */ + CONDITIONAL_REASSIGN ("%7", "ki", "menu"); + CONDITIONAL_REASSIGN ("@7", "kw", "end"); + CONDITIONAL_REASSIGN ("F1", "k<", "f11"); + CONDITIONAL_REASSIGN ("F2", "k>", "f12"); + CONDITIONAL_REASSIGN ("%1", "kq", "help"); + CONDITIONAL_REASSIGN ("*6", "kU", "select"); +#undef CONDITIONAL_REASSIGN + } + + return Qnil; +} + + +/*********************************************************************** + Character Display Information + ***********************************************************************/ + +static void append_glyph P_ ((struct it *)); + + +/* Append glyphs to IT's glyph_row. Called from produce_glyphs for + terminal frames if IT->glyph_row != NULL. IT->c is the character + for which to produce glyphs; IT->face_id contains the character's + face. Padding glyphs are appended if IT->c has a IT->pixel_width > + 1. */ + +static void +append_glyph (it) + struct it *it; +{ + struct glyph *glyph, *end; + int i; + + xassert (it->glyph_row); + glyph = (it->glyph_row->glyphs[it->area] + + it->glyph_row->used[it->area]); + end = it->glyph_row->glyphs[1 + it->area]; + + for (i = 0; + i < it->pixel_width && glyph < end; + ++i) + { + glyph->type = CHAR_GLYPH; + glyph->pixel_width = 1; + glyph->u.ch.code = it->c; + glyph->u.ch.face_id = it->face_id; + glyph->u.ch.padding_p = i > 0; + glyph->charpos = CHARPOS (it->position); + glyph->object = it->object; + + ++it->glyph_row->used[it->area]; + ++glyph; + } +} + + +/* Produce glyphs for the display element described by IT. The + function fills output fields of IT with pixel information like the + pixel width and height of a character, and maybe produces glyphs at + the same time if IT->glyph_row is non-null. See the explanation of + struct display_iterator in dispextern.h for an overview. */ + +void +produce_glyphs (it) + struct it *it; +{ + /* If a hook is installed, let it do the work. */ + xassert (it->what == IT_CHARACTER + || it->what == IT_IMAGE + || it->what == IT_STRETCH); + + /* Nothing but characters are supported on terminal frames. */ + xassert (it->what == IT_CHARACTER); + + if (it->c >= 040 && it->c < 0177) + { + it->pixel_width = it->nglyphs = 1; + if (it->glyph_row) + append_glyph (it); + } + else if (it->c == '\n') + it->pixel_width = it->nglyphs = 0; + else if (it->c == '\t') + { + int absolute_x = (it->current_x - it->prompt_width + + it->continuation_lines_width); + int next_tab_x + = (((1 + absolute_x + it->tab_width - 1) + / it->tab_width) + * it->tab_width); + int nspaces; + + /* If part of the TAB has been displayed on the previous line + which is continued now, continuation_lines_width will have + been incremented already by the part that fitted on the + continued line. So, we will get the right number of spaces + here. */ + nspaces = next_tab_x - absolute_x; + + if (it->glyph_row) + { + int n = nspaces; + + it->c = ' '; + it->pixel_width = it->len = 1; + + while (n--) + append_glyph (it); + + it->c = '\t'; + } + + it->pixel_width = nspaces; + it->nglyphs = nspaces; + } + else + { + /* A multi-byte character. The display width is a per character + value for characters of set CHARSET_COMPOSITION; otherwise + it is fixed for all characters of the set. Some of the + glyphs may have to be ignored because they are already + displayed in a continued line. */ + int charset = CHAR_CHARSET (it->c); + + if (charset == CHARSET_COMPOSITION) + it->pixel_width = cmpchar_table[COMPOSITE_CHAR_ID (it->c)]->width; + else + it->pixel_width = CHARSET_WIDTH (charset); + it->nglyphs = it->pixel_width; + + if (it->glyph_row) + append_glyph (it); + } + + /* Advance current_x by the pixel width as a convenience for + the caller. */ + if (it->area == TEXT_AREA) + it->current_x += it->pixel_width; + it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0; + it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1; +} + + +/* Get information about special display element WHAT in an + environment described by IT. WHAT is one of IT_TRUNCATION or + IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a + non-null glyph_row member. This function ensures that fields like + face_id, c, len of IT are left untouched. */ + +void +produce_special_glyphs (it, what) + struct it *it; + enum display_element_type what; +{ + struct it temp_it; + + temp_it = *it; + temp_it.dp = NULL; + temp_it.what = IT_CHARACTER; + temp_it.len = 1; + temp_it.object = 0; + bzero (&temp_it.current, sizeof temp_it.current); + + if (what == IT_CONTINUATION) + { + /* Continuation glyph. */ + if (it->dp + && INTEGERP (DISP_CONTINUE_GLYPH (it->dp)) + && GLYPH_CHAR_VALID_P (XINT (DISP_CONTINUE_GLYPH (it->dp)))) + { + temp_it.c = FAST_GLYPH_CHAR (XINT (DISP_CONTINUE_GLYPH (it->dp))); + temp_it.len = CHAR_LEN (temp_it.c); + } + else + temp_it.c = '\\'; + + produce_glyphs (&temp_it); + it->pixel_width = temp_it.pixel_width; + it->nglyphs = temp_it.pixel_width; + } + else if (what == IT_TRUNCATION) + { + /* Truncation glyph. */ + if (it->dp + && INTEGERP (DISP_TRUNC_GLYPH (it->dp)) + && GLYPH_CHAR_VALID_P (XINT (DISP_TRUNC_GLYPH (it->dp)))) + { + temp_it.c = FAST_GLYPH_CHAR (XINT (DISP_TRUNC_GLYPH (it->dp))); + temp_it.len = CHAR_LEN (temp_it.c); + } + else + temp_it.c = '$'; + + produce_glyphs (&temp_it); + it->pixel_width = temp_it.pixel_width; + it->nglyphs = temp_it.pixel_width; + } + else + abort (); +} + + +/* Return an estimation of the pixel height of mode or top lines on + frame F. FACE_ID specifies what line's height to estimate. */ + +int +estimate_mode_line_height (f, face_id) + struct frame *f; + enum face_id face_id; +{ + if (estimate_mode_line_height_hook) + return estimate_mode_line_height_hook (f, face_id); + else + return 1; +} + + + +/*********************************************************************** + Faces + ***********************************************************************/ + + +/* Turn appearances of face FACE_ID on tty frame F on. */ + +static void +turn_on_face (f, face_id) + struct frame *f; + int face_id; +{ + struct face *face = FACE_FROM_ID (f, face_id); + + xassert (face != NULL); + + if (face->tty_bold_p) + OUTPUT1_IF (TS_enter_bold_mode); + else if (face->tty_dim_p) + OUTPUT1_IF (TS_enter_dim_mode); + + /* Alternate charset and blinking not yet used. */ + if (face->tty_alt_charset_p) + OUTPUT1_IF (TS_enter_alt_charset_mode); + + if (face->tty_blinking_p) + OUTPUT1_IF (TS_enter_blink_mode); + + if (face->tty_underline_p + /* Don't underline if that's difficult. */ + && TN_magic_cookie_glitch_ul <= 0) + OUTPUT1_IF (TS_enter_underline_mode); + + if (face->tty_reverse_p) + OUTPUT1_IF (TS_enter_reverse_mode); + + if (TN_max_colors > 0) + { + char *p; + + if (face->foreground != FACE_TTY_DEFAULT_COLOR + && TS_set_foreground) + { + p = tparam (TS_set_foreground, NULL, 0, (int) face->foreground); + OUTPUT (p); + xfree (p); + } + + if (face->background != FACE_TTY_DEFAULT_COLOR + && TS_set_background) + { + p = tparam (TS_set_background, NULL, 0, (int) face->background); + OUTPUT (p); + xfree (p); + } } } + + +/* Turn off appearances of face FACE_ID on tty frame F. */ + +static void +turn_off_face (f, face_id) + struct frame *f; + int face_id; +{ + struct face *face = FACE_FROM_ID (f, face_id); + + xassert (face != NULL); + + if (TS_exit_attribute_mode) + { + /* Capability "me" will turn off appearance modes double-bright, + half-bright, reverse-video, standout, underline. It may or + may not turn off alt-char-mode. */ + if (face->tty_bold_p + || face->tty_dim_p + || face->tty_reverse_p + || face->tty_alt_charset_p + || face->tty_blinking_p + || face->tty_underline_p) + OUTPUT1_IF (TS_exit_attribute_mode); + + if (face->tty_alt_charset_p) + OUTPUT_IF (TS_exit_alt_charset_mode); + } + else + { + /* If we don't have "me" we can only have those appearances + that have exit sequences defined. */ + if (face->tty_alt_charset_p) + OUTPUT_IF (TS_exit_alt_charset_mode); + + if (face->tty_underline_p + /* We don't underline if that's difficult. */ + && TN_magic_cookie_glitch_ul <= 0) + OUTPUT_IF (TS_exit_underline_mode); + } + + /* Switch back to default colors. */ + if (TN_max_colors > 0 + && (face->foreground != FACE_TTY_DEFAULT_COLOR + || face->background != FACE_TTY_DEFAULT_COLOR)) + OUTPUT1_IF (TS_orig_pair); +} + + +/* Return non-zero if the terminal is capable to display colors. */ + +DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p, + 0, 0, 0, + "Return non-nil if TTY can display colors.") + () +{ + return TN_max_colors > 0 ? Qt : Qnil; +} + + +/*********************************************************************** + Initialization + ***********************************************************************/ + +void term_init (terminal_type) char *terminal_type; { @@ -1125,22 +2063,76 @@ term_init (terminal_type) char buffer[2044]; register char *p; int status; + struct frame *sf = XFRAME (selected_frame); + +#ifdef WINDOWSNT + initialize_w32_display (); + + Wcm_clear (); + + area = (char *) xmalloc (2044); + + if (area == 0) + abort (); + + FrameRows = FRAME_HEIGHT (sf); + FrameCols = FRAME_WIDTH (sf); + specified_window = FRAME_HEIGHT (sf); + + delete_in_insert_mode = 1; + + UseTabs = 0; + scroll_region_ok = 0; + + /* Seems to insert lines when it's not supposed to, messing + up the display. In doing a trace, it didn't seem to be + called much, so I don't think we're losing anything by + turning it off. */ + + line_ins_del_ok = 0; + char_ins_del_ok = 1; - extern char *tgetstr (); + baud_rate = 19200; + + FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0; + FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none; + + return; +#else /* not WINDOWSNT */ Wcm_clear (); - dont_calculate_costs = 0; status = tgetent (buffer, terminal_type); if (status < 0) - fatal ("Cannot open termcap database file.\n"); + { +#ifdef TERMINFO + fatal ("Cannot open terminfo database file"); +#else + fatal ("Cannot open termcap database file"); +#endif + } if (status == 0) - fatal ("Terminal type %s is not defined.\n", terminal_type); - + { #ifdef TERMINFO - area = (char *) malloc (2044); + fatal ("Terminal type %s is not defined.\n\ +If that is not the actual type of terminal you have,\n\ +use the Bourne shell command `TERM=... export TERM' (C-shell:\n\ +`setenv TERM ...') to specify the correct type. It may be necessary\n\ +to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.", + terminal_type); #else - area = (char *) malloc (strlen (buffer)); + fatal ("Terminal type %s is not defined.\n\ +If that is not the actual type of terminal you have,\n\ +use the Bourne shell command `TERM=... export TERM' (C-shell:\n\ +`setenv TERM ...') to specify the correct type. It may be necessary\n\ +to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.", + terminal_type); +#endif + } +#ifdef TERMINFO + area = (char *) xmalloc (2044); +#else + area = (char *) xmalloc (strlen (buffer)); #endif /* not TERMINFO */ if (area == 0) abort (); @@ -1151,7 +2143,7 @@ term_init (terminal_type) BackTab = tgetstr ("bt", address); TS_clr_to_bottom = tgetstr ("cd", address); TS_clr_line = tgetstr ("ce", address); - TS_clr_screen = tgetstr ("cl", address); + TS_clr_frame = tgetstr ("cl", address); ColPosition = tgetstr ("ch", address); AbsPosition = tgetstr ("cm", address); CR = tgetstr ("cr", address); @@ -1200,35 +2192,80 @@ term_init (terminal_type) TS_termcap_modes = tgetstr ("ti", address); Up = tgetstr ("up", address); TS_visible_bell = tgetstr ("vb", address); - TS_end_visual_mode = tgetstr ("ve", address); - TS_visual_mode = tgetstr ("vs", address); + TS_cursor_normal = tgetstr ("ve", address); + TS_cursor_visible = tgetstr ("vs", address); + TS_cursor_invisible = tgetstr ("vi", address); TS_set_window = tgetstr ("wi", address); + + TS_enter_underline_mode = tgetstr ("us", address); + TS_exit_underline_mode = tgetstr ("ue", address); + TN_magic_cookie_glitch_ul = tgetnum ("ug"); + TS_enter_bold_mode = tgetstr ("md", address); + TS_enter_dim_mode = tgetstr ("mh", address); + TS_enter_blink_mode = tgetstr ("mb", address); + TS_enter_reverse_mode = tgetstr ("mr", address); + TS_enter_alt_charset_mode = tgetstr ("as", address); + TS_exit_alt_charset_mode = tgetstr ("ae", address); + TS_exit_attribute_mode = tgetstr ("me", address); + MultiUp = tgetstr ("UP", address); MultiDown = tgetstr ("DO", address); MultiLeft = tgetstr ("LE", address); MultiRight = tgetstr ("RI", address); - AutoWrap = tgetflag ("am"); - memory_below_screen = tgetflag ("db"); + /* SVr4/ANSI color suppert. If "op" isn't available, don't support + color because we can't switch back to the default foreground and + background. */ + TS_orig_pair = tgetstr ("op", address); + if (TS_orig_pair) + { + TS_set_foreground = tgetstr ("AF", address); + TS_set_background = tgetstr ("AB", address); + if (!TS_set_foreground) + { + /* SVr4. */ + TS_set_foreground = tgetstr ("Sf", address); + TS_set_background = tgetstr ("Sb", address); + } + TN_max_colors = tgetnum ("Co"); + TN_max_pairs = tgetnum ("pa"); + } + + MagicWrap = tgetflag ("xn"); + /* Since we make MagicWrap terminals look like AutoWrap, we need to have + the former flag imply the latter. */ + AutoWrap = MagicWrap || tgetflag ("am"); + memory_below_frame = tgetflag ("db"); TF_hazeltine = tgetflag ("hz"); must_write_spaces = tgetflag ("in"); meta_key = tgetflag ("km") || tgetflag ("MT"); TF_insmode_motion = tgetflag ("mi"); TF_standout_motion = tgetflag ("ms"); TF_underscore = tgetflag ("ul"); - MagicWrap = tgetflag ("xn"); TF_xs = tgetflag ("xs"); TF_teleray = tgetflag ("xt"); term_get_fkeys (address); - /* Get screen size from system, or else from termcap. */ - get_screen_size (&SCREEN_WIDTH (selected_screen), - &SCREEN_HEIGHT (selected_screen)); - if (SCREEN_WIDTH (selected_screen) <= 0) - SCREEN_WIDTH (selected_screen) = tgetnum ("co"); - if (SCREEN_HEIGHT (selected_screen) <= 0) - SCREEN_HEIGHT (selected_screen) = tgetnum ("li"); + /* Get frame size from system, or else from termcap. */ + { + int height, width; + get_frame_size (&width, &height); + FRAME_WIDTH (sf) = width; + FRAME_HEIGHT (sf) = height; + } + + if (FRAME_WIDTH (sf) <= 0) + SET_FRAME_WIDTH (sf, tgetnum ("co")); + else + /* Keep width and external_width consistent */ + SET_FRAME_WIDTH (sf, FRAME_WIDTH (sf)); + if (FRAME_HEIGHT (sf) <= 0) + FRAME_HEIGHT (sf) = tgetnum ("li"); + + if (FRAME_HEIGHT (sf) < 3 || FRAME_WIDTH (sf) < 3) + fatal ("Screen size %dx%d is too small", + FRAME_HEIGHT (sf), FRAME_WIDTH (sf)); min_padding_speed = tgetnum ("pb"); TN_standout_width = tgetnum ("sg"); @@ -1267,6 +2304,17 @@ term_init (terminal_type) TS_standout_mode = tgetstr ("us", address); } + /* If no `se' string, try using a `me' string instead. + If that fails, we can't use standout mode at all. */ + if (TS_end_standout_mode == 0) + { + char *s = tgetstr ("me", address); + if (s != 0) + TS_end_standout_mode = s; + else + TS_standout_mode = 0; + } + if (TF_teleray) { Wcm.cm_tab = 0; @@ -1285,7 +2333,7 @@ term_init (terminal_type) if (!strcmp (terminal_type, "supdup")) { - memory_below_screen = 1; + memory_below_frame = 1; Wcm.cm_losewrap = 1; } if (!strncmp (terminal_type, "c10", 3) @@ -1296,7 +2344,7 @@ term_init (terminal_type) for windows starting at the upper left corner; but that is all Emacs uses. - This string works only if the screen is using + This string works only if the frame is using the top of the video memory, because addressing is memory-relative. So first check the :ti string to see if that is true. @@ -1330,9 +2378,9 @@ term_init (terminal_type) } } - ScreenRows = SCREEN_HEIGHT (selected_screen); - ScreenCols = SCREEN_WIDTH (selected_screen); - specified_window = SCREEN_HEIGHT (selected_screen); + FrameRows = FRAME_HEIGHT (sf); + FrameCols = FRAME_WIDTH (sf); + specified_window = FRAME_HEIGHT (sf); if (Wcm_init () == -1) /* can't do cursor motion */ #ifdef VMS @@ -1340,19 +2388,30 @@ term_init (terminal_type) It lacks the ability to position the cursor.\n\ If that is not the actual type of terminal you have, use either the\n\ DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\ -or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.\n", +or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.", terminal_type); -#else +#else /* not VMS */ +# ifdef TERMINFO fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\ It lacks the ability to position the cursor.\n\ If that is not the actual type of terminal you have,\n\ -use the C-shell command `setenv TERM ...' to specify the correct type.\n\ -It may be necessary to do `unsetenv TERMCAP' as well.\n", +use the Bourne shell command `TERM=... export TERM' (C-shell:\n\ +`setenv TERM ...') to specify the correct type. It may be necessary\n\ +to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.", terminal_type); -#endif - if (SCREEN_HEIGHT (selected_screen) <= 0 - || SCREEN_WIDTH (selected_screen) <= 0) - fatal ("The screen size has not been specified."); +# else /* TERMCAP */ + fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\ +It lacks the ability to position the cursor.\n\ +If that is not the actual type of terminal you have,\n\ +use the Bourne shell command `TERM=... export TERM' (C-shell:\n\ +`setenv TERM ...') to specify the correct type. It may be necessary\n\ +to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.", + terminal_type); +# endif /* TERMINFO */ +#endif /*VMS */ + if (FRAME_HEIGHT (sf) <= 0 + || FRAME_WIDTH (sf) <= 0) + fatal ("The frame size has not been specified"); delete_in_insert_mode = TS_delete_mode && TS_insert_mode @@ -1364,7 +2423,7 @@ It may be necessary to do `unsetenv TERMCAP' as well.\n", /* Remove width of standout marker from usable width of line */ if (TN_standout_width > 0) - SCREEN_WIDTH (selected_screen) -= TN_standout_width; + SET_FRAME_WIDTH (sf, FRAME_WIDTH (sf) - TN_standout_width); UseTabs = tabs_safe_p () && TabWidth == 8; @@ -1386,14 +2445,41 @@ It may be necessary to do `unsetenv TERMCAP' as well.\n", if (read_socket_hook) /* Baudrate is somewhat */ /* meaningless in this case */ baud_rate = 9600; + + FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0; + FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none; +#endif /* WINDOWSNT */ } /* VARARGS 1 */ +void fatal (str, arg1, arg2) char *str, *arg1, *arg2; { fprintf (stderr, "emacs: "); fprintf (stderr, str, arg1, arg2); + fprintf (stderr, "\n"); fflush (stderr); exit (1); } + +void +syms_of_term () +{ + DEFVAR_BOOL ("system-uses-terminfo", &system_uses_terminfo, + "Non-nil means the system uses terminfo rather than termcap.\n\ +This variable can be used by terminal emulator packages."); +#ifdef TERMINFO + system_uses_terminfo = 1; +#else + system_uses_terminfo = 0; +#endif + + DEFVAR_LISP ("ring-bell-function", &Vring_bell_function, + "Non-nil means call this function to ring the bell.\n\ +The function should accept no arguments."); + Vring_bell_function = Qnil; + + defsubr (&Stty_display_color_p); +} +