diff options
Diffstat (limited to 'src/term.c')
-rw-r--r-- | src/term.c | 2676 |
1 files changed, 1691 insertions, 985 deletions
diff --git a/src/term.c b/src/term.c index e53e5f78306..234be4a9271 100644 --- a/src/term.c +++ b/src/term.c @@ -26,9 +26,19 @@ Boston, MA 02110-1301, USA. */ #include <ctype.h> #include <string.h> +#include <sys/file.h> + +#include <unistd.h> /* For isatty. */ + +#if HAVE_TERMIOS_H +#include <termios.h> /* For TIOCNOTTY. */ +#endif + +#include <signal.h> + +#include "lisp.h" #include "termchar.h" #include "termopts.h" -#include "lisp.h" #include "charset.h" #include "coding.h" #include "keyboard.h" @@ -38,6 +48,8 @@ Boston, MA 02110-1301, USA. */ #include "dispextern.h" #include "window.h" #include "keymap.h" +#include "syssignal.h" +#include "systty.h" /* For now, don't try to include termcap.h. On some systems, configure finds a non-standard termcap.h that the main build @@ -60,24 +72,42 @@ extern int tgetnum P_ ((char *id)); #include "macterm.h" #endif +#ifndef O_RDWR +#define O_RDWR 2 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#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)); +static void tty_show_cursor P_ ((struct tty_display_info *)); +static void tty_hide_cursor P_ ((struct tty_display_info *)); + +void delete_initial_device P_ ((struct device *)); +void create_tty_output P_ ((struct frame *)); +void delete_tty_output P_ ((struct frame *)); -#define OUTPUT(a) \ - tputs (a, (int) (FRAME_LINES (XFRAME (selected_frame)) - curY), cmputc) -#define OUTPUT1(a) tputs (a, 1, cmputc) -#define OUTPUTL(a, lines) tputs (a, lines, cmputc) +#define OUTPUT(tty, a) \ + emacs_tputs ((tty), a, \ + (int) (FRAME_LINES (XFRAME (selected_frame)) \ + - curY (tty)), \ + cmputc) -#define OUTPUT_IF(a) \ - do { \ - if (a) \ - tputs (a, (int) (FRAME_LINES (XFRAME (selected_frame)) \ - - curY), cmputc); \ - } while (0) +#define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc) +#define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc) -#define OUTPUT1_IF(a) do { if (a) tputs (a, 1, cmputc); } while (0) +#define OUTPUT_IF(tty, a) \ + do { \ + if (a) \ + emacs_tputs ((tty), a, \ + (int) (FRAME_LINES (XFRAME (selected_frame)) \ + - curY (tty) ), \ + cmputc); \ + } while (0) + +#define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0) /* Display space properties */ @@ -87,203 +117,27 @@ extern Lisp_Object Qspace, QCalign_to, QCwidth; 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 - must actually be output; can't just skip - over some columns to leave them blank. */ -int min_padding_speed; /* Speed below which no padding necessary */ +/* Functions to call after suspending a tty. */ +Lisp_Object Vsuspend_tty_functions; -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 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 */ +/* Functions to call after resuming a tty. */ +Lisp_Object Vresume_tty_functions; -/* 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. */ +/* Chain of all displays currently in use. */ +struct device *device_list; -int no_redraw_on_reenter; +/* The initial display device, created by initial_term_init. */ +struct device *initial_device; -/* Hook functions that you can set to snap out the functions in this file. - These are all extern'd in termhooks.h */ +/* Chain of all tty device parameters. */ +struct tty_display_info *tty_list; -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 (*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 (*read_socket_hook) P_ ((int, int, struct input_event *)); - -void (*frame_up_to_date_hook) P_ ((struct frame *)); - -/* Return the current position of the mouse. - - 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. - - 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. - - Otherwise, set *bar_window to Qnil, and *x and *y to the column and - row of the character cell the mouse is over. - - Set *time to the time the mouse was at the returned position. +/* 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; - 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 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 (*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)); - -/* Strings, numbers and flags taken from the termcap entry. */ - -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_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, - total lines again) */ -char *TS_del_char; /* "dc" */ -char *TS_del_multi_chars; /* "DC" (one parameter, # chars to delete) */ -char *TS_del_line; /* "dl" */ -char *TS_del_multi_lines; /* "DL" (one parameter, # lines to delete) */ -char *TS_delete_mode; /* "dm", enter character-delete mode */ -char *TS_end_delete_mode; /* "ed", leave character-delete mode */ -char *TS_end_insert_mode; /* "ei", leave character-insert mode */ -char *TS_ins_char; /* "ic" */ -char *TS_ins_multi_chars; /* "IC" (one parameter, # chars to insert) */ -char *TS_insert_mode; /* "im", enter character-insert mode */ -char *TS_pad_inserted_char; /* "ip". Just padding, no commands. */ -char *TS_end_keypad_mode; /* "ke" */ -char *TS_keypad_mode; /* "ks" */ -char *TS_pad_char; /* "pc", char to use as padding */ -char *TS_repeat; /* "rp" (2 params, # times to repeat - and character to be repeated) */ -char *TS_end_standout_mode; /* "se" */ -char *TS_fwd_scroll; /* "sf" */ -char *TS_standout_mode; /* "so" */ -char *TS_rev_scroll; /* "sr" */ -char *TS_end_termcap_modes; /* "te" */ -char *TS_termcap_modes; /* "ti" */ -char *TS_visible_bell; /* "vb" */ -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) */ - -/* Value of the "NC" (no_color_video) capability, or 0 if not - present. */ - -static int TN_no_color_video; /* Meaning of bits in no_color_video. Each bit set means that the corresponding attribute cannot be combined with colors. */ @@ -301,68 +155,6 @@ enum no_color_bit NC_ALT_CHARSET = 1 << 8 }; -/* "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; - -/* "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 over-struck on - non-blank position. Must clear before writing _. */ -int TF_teleray; /* termcap xt flag: many weird consequences. - For t1061. */ - -static int RPov; /* # chars to start a TS_repeat */ - -static int delete_in_insert_mode; /* delete mode == insert mode */ - -static int se_is_so; /* 1 if same string both enters and leaves - standout mode */ - /* internal state */ /* The largest frame width in any call to calculate_costs. */ @@ -373,33 +165,17 @@ int max_frame_cols; int max_frame_lines; -static int costs_set; /* Nonzero if costs have been calculated. */ - -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 frame downwards, - which can participate in insert-line/delete-line operations. - - Effectively it excludes the bottom frame_lines - specified_window_size - lines from those operations. */ - -int specified_window; +/* Non-zero if we have dropped our controlling tty and therefore + should not open a frame on stdout. */ +static int no_controlling_tty; -/* Frame currently being redisplayed; 0 if not currently redisplaying. - (Direct output does not count). */ - -FRAME_PTR updating_frame; +/* The first unallocated display id. */ +static int next_device_id; /* Provided for lisp packages. */ static int system_uses_terminfo; -/* Flag used in tty_show/hide_cursor. */ - -static int tty_cursor_hidden; - char *tparam (); extern char *tgetstr (); @@ -417,7 +193,7 @@ extern char *tgetstr (); #endif /* WINDOWSNT */ void -ring_bell () +ring_bell (struct frame *f) { if (!NILP (Vring_bell_function)) { @@ -438,170 +214,203 @@ ring_bell () Vring_bell_function = function; } - else if (!FRAME_TERMCAP_P (XFRAME (selected_frame))) - (*ring_bell_hook) (); - else - OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell); + else if (FRAME_DEVICE (f)->ring_bell_hook) + (*FRAME_DEVICE (f)->ring_bell_hook) (f); } +/* Ring the bell on a tty. */ + void -set_terminal_modes () +tty_ring_bell (struct frame *f) { - if (FRAME_TERMCAP_P (XFRAME (selected_frame))) + struct tty_display_info *tty = FRAME_TTY (f); + + if (tty->output) { - if (TS_termcap_modes) - OUTPUT (TS_termcap_modes); - else - { - /* Output enough newlines to scroll all the old screen contents - off the screen, so it won't be overwritten and lost. */ - int i; - for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++) - putchar ('\n'); - } + OUTPUT (tty, (tty->TS_visible_bell && visible_bell + ? tty->TS_visible_bell + : tty->TS_bell)); + fflush (tty->output); + } +} - OUTPUT_IF (TS_cursor_visible); - OUTPUT_IF (TS_keypad_mode); - losecursor (); +/* Set up termcap modes for Emacs. */ + +void +tty_set_terminal_modes (struct device *display) +{ + struct tty_display_info *tty = display->display_info.tty; + + if (tty->output) + { + if (tty->TS_termcap_modes) + OUTPUT (tty, tty->TS_termcap_modes); + else + { + /* Output enough newlines to scroll all the old screen contents + off the screen, so it won't be overwritten and lost. */ + int i; + current_tty = tty; + for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++) + cmputc ('\n'); + } + + OUTPUT_IF (tty, tty->TS_termcap_modes); + OUTPUT_IF (tty, tty->TS_cursor_visible); + OUTPUT_IF (tty, tty->TS_keypad_mode); + losecursor (tty); + fflush (tty->output); } - else - (*set_terminal_modes_hook) (); } +/* Reset termcap modes before exiting Emacs. */ + void -reset_terminal_modes () +tty_reset_terminal_modes (struct device *display) { - if (FRAME_TERMCAP_P (XFRAME (selected_frame))) + struct tty_display_info *tty = display->display_info.tty; + + if (tty->output) { - turn_off_highlight (); - turn_off_insert (); - OUTPUT_IF (TS_end_keypad_mode); - OUTPUT_IF (TS_cursor_normal); - OUTPUT_IF (TS_end_termcap_modes); - OUTPUT_IF (TS_orig_pair); + turn_off_highlight (tty); + turn_off_insert (tty); + OUTPUT_IF (tty, tty->TS_end_keypad_mode); + OUTPUT_IF (tty, tty->TS_cursor_normal); + OUTPUT_IF (tty, tty->TS_end_termcap_modes); + OUTPUT_IF (tty, tty->TS_orig_pair); /* Output raw CR so kernel can track the cursor hpos. */ + current_tty = tty; cmputc ('\r'); + fflush (tty->output); } - else if (reset_terminal_modes_hook) - (*reset_terminal_modes_hook) (); } void -update_begin (f) - struct frame *f; +update_begin (struct frame *f) { - updating_frame = f; - if (!FRAME_TERMCAP_P (f)) - update_begin_hook (f); + if (FRAME_DEVICE (f)->update_begin_hook) + (*FRAME_DEVICE (f)->update_begin_hook) (f); } void -update_end (f) - struct frame *f; +update_end (struct frame *f) { - if (FRAME_TERMCAP_P (f)) - { - if (!XWINDOW (selected_window)->cursor_off_p) - tty_show_cursor (); - turn_off_insert (); - background_highlight (); - } - else - update_end_hook (f); + if (FRAME_DEVICE (f)->update_end_hook) + (*FRAME_DEVICE (f)->update_end_hook) (f); +} + +/* Flag the end of a display update on a termcap display. */ + +void +tty_update_end (struct frame *f) +{ + struct tty_display_info *tty = FRAME_TTY (f); - updating_frame = NULL; + if (!XWINDOW (selected_window)->cursor_off_p) + tty_show_cursor (tty); + turn_off_insert (tty); + background_highlight (tty); } +/* Specify how many text lines, from the top of the window, + should be affected by insert-lines and delete-lines operations. + This, and those operations, are used only within an update + that is bounded by calls to update_begin and update_end. */ + void -set_terminal_window (size) - int size; +set_terminal_window (struct frame *f, int size) { - if (FRAME_TERMCAP_P (updating_frame)) - { - specified_window = size ? size : FRAME_LINES (updating_frame); - if (scroll_region_ok) - set_scroll_region (0, specified_window); - } - else - set_terminal_window_hook (size); + if (FRAME_DEVICE (f)->set_terminal_window_hook) + (*FRAME_DEVICE (f)->set_terminal_window_hook) (f, size); +} + +/* The implementation of set_terminal_window for termcap frames. */ + +void +tty_set_terminal_window (struct frame *f, int size) +{ + struct tty_display_info *tty = FRAME_TTY (f); + + tty->specified_window = size ? size : FRAME_LINES (f); + if (FRAME_SCROLL_REGION_OK (f)) + set_scroll_region (f, 0, tty->specified_window); } void -set_scroll_region (start, stop) - int start, stop; +set_scroll_region (struct frame *f, int start, int 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); - else if (TS_set_scroll_region_1) - buf = tparam (TS_set_scroll_region_1, 0, 0, - FRAME_LINES (sf), start, - FRAME_LINES (sf) - stop, - FRAME_LINES (sf)); + struct tty_display_info *tty = FRAME_TTY (f); + + if (tty->TS_set_scroll_region) + buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1); + else if (tty->TS_set_scroll_region_1) + buf = tparam (tty->TS_set_scroll_region_1, 0, 0, + FRAME_LINES (f), start, + FRAME_LINES (f) - stop, + FRAME_LINES (f)); else - buf = tparam (TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (sf)); + buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f)); - OUTPUT (buf); + OUTPUT (tty, buf); xfree (buf); - losecursor (); + losecursor (tty); } static void -turn_on_insert () +turn_on_insert (struct tty_display_info *tty) { - if (!insert_mode) - OUTPUT (TS_insert_mode); - insert_mode = 1; + if (!tty->insert_mode) + OUTPUT (tty, tty->TS_insert_mode); + tty->insert_mode = 1; } void -turn_off_insert () +turn_off_insert (struct tty_display_info *tty) { - if (insert_mode) - OUTPUT (TS_end_insert_mode); - insert_mode = 0; + if (tty->insert_mode) + OUTPUT (tty, tty->TS_end_insert_mode); + tty->insert_mode = 0; } /* Handle highlighting. */ void -turn_off_highlight () +turn_off_highlight (struct tty_display_info *tty) { - if (standout_mode) - OUTPUT_IF (TS_end_standout_mode); - standout_mode = 0; + if (tty->standout_mode) + OUTPUT_IF (tty, tty->TS_end_standout_mode); + tty->standout_mode = 0; } static void -turn_on_highlight () +turn_on_highlight (struct tty_display_info *tty) { - if (!standout_mode) - OUTPUT_IF (TS_standout_mode); - standout_mode = 1; + if (!tty->standout_mode) + OUTPUT_IF (tty, tty->TS_standout_mode); + tty->standout_mode = 1; } static void -toggle_highlight () +toggle_highlight (struct tty_display_info *tty) { - if (standout_mode) - turn_off_highlight (); + if (tty->standout_mode) + turn_off_highlight (tty); else - turn_on_highlight (); + turn_on_highlight (tty); } /* Make cursor invisible. */ static void -tty_hide_cursor () +tty_hide_cursor (struct tty_display_info *tty) { - if (tty_cursor_hidden == 0) + if (tty->cursor_hidden == 0) { - tty_cursor_hidden = 1; - OUTPUT_IF (TS_cursor_invisible); + tty->cursor_hidden = 1; + OUTPUT_IF (tty, tty->TS_cursor_invisible); } } @@ -609,13 +418,13 @@ tty_hide_cursor () /* Ensure that cursor is visible. */ static void -tty_show_cursor () +tty_show_cursor (struct tty_display_info *tty) { - if (tty_cursor_hidden) + if (tty->cursor_hidden) { - tty_cursor_hidden = 0; - OUTPUT_IF (TS_cursor_normal); - OUTPUT_IF (TS_cursor_visible); + tty->cursor_hidden = 0; + OUTPUT_IF (tty, tty->TS_cursor_normal); + OUTPUT_IF (tty, tty->TS_cursor_visible); } } @@ -625,23 +434,23 @@ tty_show_cursor () depends on the user option inverse-video. */ void -background_highlight () +background_highlight (struct tty_display_info *tty) { if (inverse_video) - turn_on_highlight (); + turn_on_highlight (tty); else - turn_off_highlight (); + turn_off_highlight (tty); } /* Set standout mode to the mode specified for the text to be output. */ static void -highlight_if_desired () +highlight_if_desired (struct tty_display_info *tty) { if (inverse_video) - turn_on_highlight (); + turn_on_highlight (tty); else - turn_off_highlight (); + turn_off_highlight (tty); } @@ -649,76 +458,85 @@ highlight_if_desired () frame-relative coordinates. */ void -cursor_to (vpos, hpos) - int vpos, hpos; +cursor_to (struct frame *f, int vpos, int hpos) { - struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame); + if (FRAME_DEVICE (f)->cursor_to_hook) + (*FRAME_DEVICE (f)->cursor_to_hook) (f, vpos, hpos); +} - if (! FRAME_TERMCAP_P (f) && cursor_to_hook) - { - (*cursor_to_hook) (vpos, hpos); - return; - } +void +tty_cursor_to (struct frame *f, int vpos, int hpos) +{ + struct tty_display_info *tty = FRAME_TTY (f); /* Detect the case where we are called from reset_sys_modes and the costs have never been calculated. Do nothing. */ - if (! costs_set) + if (! tty->costs_set) return; - if (curY == vpos && curX == hpos) + if (curY (tty) == vpos + && curX (tty) == hpos) return; - if (!TF_standout_motion) - background_highlight (); - if (!TF_insmode_motion) - turn_off_insert (); - cmgoto (vpos, hpos); + if (!tty->TF_standout_motion) + background_highlight (tty); + if (!tty->TF_insmode_motion) + turn_off_insert (tty); + cmgoto (tty, vpos, hpos); } /* Similar but don't take any account of the wasted characters. */ void -raw_cursor_to (row, col) - int row, col; +raw_cursor_to (struct frame *f, int row, int col) { - struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame); - if (! FRAME_TERMCAP_P (f)) - { - (*raw_cursor_to_hook) (row, col); - return; - } - if (curY == row && curX == col) + if (FRAME_DEVICE (f)->raw_cursor_to_hook) + (*FRAME_DEVICE (f)->raw_cursor_to_hook) (f, row, col); +} + +void +tty_raw_cursor_to (struct frame *f, int row, int col) +{ + struct tty_display_info *tty = FRAME_TTY (f); + + if (curY (tty) == row + && curX (tty) == col) return; - if (!TF_standout_motion) - background_highlight (); - if (!TF_insmode_motion) - turn_off_insert (); - cmgoto (row, col); + if (!tty->TF_standout_motion) + background_highlight (tty); + if (!tty->TF_insmode_motion) + turn_off_insert (tty); + cmgoto (tty, row, col); } /* Erase operations */ -/* clear from cursor to end of frame */ +/* Clear from cursor to end of frame. */ void -clear_to_end () +clear_to_end (struct frame *f) +{ + if (FRAME_DEVICE (f)->clear_to_end_hook) + (*FRAME_DEVICE (f)->clear_to_end_hook) (f); +} + +/* Clear from cursor to end of frame on a termcap device. */ + +void +tty_clear_to_end (struct frame *f) { register int i; + struct tty_display_info *tty = FRAME_TTY (f); - if (clear_to_end_hook && ! FRAME_TERMCAP_P (updating_frame)) + if (tty->TS_clr_to_bottom) { - (*clear_to_end_hook) (); - return; - } - if (TS_clr_to_bottom) - { - background_highlight (); - OUTPUT (TS_clr_to_bottom); + background_highlight (tty); + OUTPUT (tty, tty->TS_clr_to_bottom); } else { - for (i = curY; i < FRAME_LINES (XFRAME (selected_frame)); i++) + for (i = curY (tty); i < FRAME_LINES (f); i++) { - cursor_to (i, 0); - clear_end_of_line (FRAME_COLS (XFRAME (selected_frame))); + cursor_to (f, i, 0); + clear_end_of_line (f, FRAME_COLS (f)); } } } @@ -726,26 +544,29 @@ clear_to_end () /* Clear entire frame */ void -clear_frame () +clear_frame (struct frame *f) +{ + if (FRAME_DEVICE (f)->clear_frame_hook) + (*FRAME_DEVICE (f)->clear_frame_hook) (f); +} + +/* Clear an entire termcap frame. */ + +void +tty_clear_frame (struct frame *f) { - struct frame *sf = XFRAME (selected_frame); + struct tty_display_info *tty = FRAME_TTY (f); - if (clear_frame_hook - && ! FRAME_TERMCAP_P ((updating_frame ? updating_frame : sf))) - { - (*clear_frame_hook) (); - return; - } - if (TS_clr_frame) + if (tty->TS_clr_frame) { - background_highlight (); - OUTPUT (TS_clr_frame); - cmat (0, 0); + background_highlight (tty); + OUTPUT (tty, tty->TS_clr_frame); + cmat (tty, 0, 0); } else { - cursor_to (0, 0); - clear_to_end (); + cursor_to (f, 0, 0); + clear_to_end (f); } } @@ -755,49 +576,51 @@ clear_frame () Note that the cursor may be moved, on terminals lacking a `ce' string. */ void -clear_end_of_line (first_unused_hpos) - int first_unused_hpos; +clear_end_of_line (struct frame *f, int first_unused_hpos) { - register int i; + if (FRAME_DEVICE (f)->clear_end_of_line_hook) + (*FRAME_DEVICE (f)->clear_end_of_line_hook) (f, first_unused_hpos); +} - if (clear_end_of_line_hook - && ! FRAME_TERMCAP_P ((updating_frame - ? updating_frame - : XFRAME (selected_frame)))) - { - (*clear_end_of_line_hook) (first_unused_hpos); - return; - } +/* An implementation of clear_end_of_line for termcap frames. + + Note that the cursor may be moved, on terminals lacking a `ce' string. */ + +void +tty_clear_end_of_line (struct frame *f, int first_unused_hpos) +{ + register int i; + struct tty_display_info *tty = FRAME_TTY (f); /* Detect the case where we are called from reset_sys_modes and the costs have never been calculated. Do nothing. */ - if (! costs_set) + if (! tty->costs_set) return; - if (curX >= first_unused_hpos) + if (curX (tty) >= first_unused_hpos) return; - background_highlight (); - if (TS_clr_line) + background_highlight (tty); + if (tty->TS_clr_line) { - OUTPUT1 (TS_clr_line); + OUTPUT1 (tty, tty->TS_clr_line); } else { /* have to do it the hard way */ - struct frame *sf = XFRAME (selected_frame); - turn_off_insert (); + turn_off_insert (tty); /* Do not write in last row last col with Auto-wrap on. */ - if (AutoWrap && curY == FRAME_LINES (sf) - 1 - && first_unused_hpos == FRAME_COLS (sf)) + if (AutoWrap (tty) + && curY (tty) == FrameRows (tty) - 1 + && first_unused_hpos == FrameCols (tty)) first_unused_hpos--; - for (i = curX; i < first_unused_hpos; i++) + for (i = curX (tty); i < first_unused_hpos; i++) { - if (termscript) - fputc (' ', termscript); - putchar (' '); + if (tty->termscript) + fputc (' ', tty->termscript); + fputc (' ', tty->output); } - cmplus (first_unused_hpos - curX); + cmplus (tty, first_unused_hpos - curX (tty)); } } @@ -919,43 +742,47 @@ encode_terminal_code (src, src_len, coding) return encode_terminal_buf + nbytes; } + +/* Output LEN glyphs starting at STRING at the nominal cursor position. + Advance the nominal cursor over the text. */ + +void +write_glyphs (struct frame *f, struct glyph *string, int len) +{ + if (FRAME_DEVICE (f)->write_glyphs_hook) + (*FRAME_DEVICE (f)->write_glyphs_hook) (f, string, len); +} + +/* An implementation of write_glyphs for termcap frames. */ + void -write_glyphs (string, len) - register struct glyph *string; - register int len; +tty_write_glyphs (struct frame *f, struct glyph *string, int len) { - struct frame *sf = XFRAME (selected_frame); - struct frame *f = updating_frame ? updating_frame : sf; unsigned char *conversion_buffer; struct coding_system *coding; - if (write_glyphs_hook - && ! FRAME_TERMCAP_P (f)) - { - (*write_glyphs_hook) (string, len); - return; - } + struct tty_display_info *tty = FRAME_TTY (f); - turn_off_insert (); - tty_hide_cursor (); + turn_off_insert (tty); + tty_hide_cursor (tty); /* 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 == FRAME_LINES (sf) - && (curX + len) == FRAME_COLS (sf)) + if (AutoWrap (tty) + && curY (tty) + 1 == FRAME_LINES (f) + && (curX (tty) + len) == FRAME_COLS (f)) len --; if (len <= 0) return; - cmplus (len); + cmplus (tty, len); /* If terminal_coding does any conversion, use it, otherwise use safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here because it always return 1 if the member src_multibyte is 1. */ - coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK - ? &terminal_coding : &safe_terminal_coding); + coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK + ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding); /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at the tail. */ coding->mode &= ~CODING_MODE_LAST_BLOCK; @@ -971,7 +798,7 @@ write_glyphs (string, len) break; /* Turn appearance modes of the face of the run on. */ - highlight_if_desired (); + highlight_if_desired (tty); turn_on_face (f, face_id); if (n == len) @@ -980,61 +807,62 @@ write_glyphs (string, len) conversion_buffer = encode_terminal_code (string, n, coding); if (coding->produced > 0) { - fwrite (conversion_buffer, 1, coding->produced, stdout); - if (ferror (stdout)) - clearerr (stdout); - if (termscript) - fwrite (conversion_buffer, 1, coding->produced, termscript); + fwrite (conversion_buffer, 1, coding->produced, tty->output); + if (ferror (tty->output)) + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, tty->termscript); } len -= n; string += n; /* Turn appearance modes off. */ turn_off_face (f, face_id); - turn_off_highlight (); + turn_off_highlight (tty); } - cmcheckmagic (); + cmcheckmagic (tty); +} + +/* Insert LEN glyphs from START at the nominal cursor position. + + If start is zero, insert blanks instead of a string at start */ + +void +insert_glyphs (struct frame *f, struct glyph *start, int len) +{ + if (len <= 0) + return; + + if (FRAME_DEVICE (f)->insert_glyphs_hook) + (*FRAME_DEVICE (f)->insert_glyphs_hook) (f, start, len); } -/* If start is zero, insert blanks instead of a string at start */ +/* An implementation of insert_glyphs for termcap frames. */ void -insert_glyphs (start, len) - register struct glyph *start; - register int len; +tty_insert_glyphs (struct frame *f, struct glyph *start, int len) { char *buf; struct glyph *glyph = NULL; - struct frame *f, *sf; unsigned char *conversion_buffer; unsigned char space[1]; struct coding_system *coding; - if (len <= 0) - return; - - if (insert_glyphs_hook) - { - (*insert_glyphs_hook) (start, len); - return; - } - - sf = XFRAME (selected_frame); - f = updating_frame ? updating_frame : sf; + struct tty_display_info *tty = FRAME_TTY (f); - if (TS_ins_multi_chars) + if (tty->TS_ins_multi_chars) { - buf = tparam (TS_ins_multi_chars, 0, 0, len); - OUTPUT1 (buf); + buf = tparam (tty->TS_ins_multi_chars, 0, 0, len); + OUTPUT1 (tty, buf); xfree (buf); if (start) - write_glyphs (start, len); + write_glyphs (f, start, len); return; } - turn_on_insert (); - cmplus (len); + turn_on_insert (tty); + cmplus (tty, len); if (! start) space[0] = SPACEGLYPH; @@ -1042,15 +870,15 @@ insert_glyphs (start, len) /* If terminal_coding does any conversion, use it, otherwise use safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here because it always return 1 if the member src_multibyte is 1. */ - coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK - ? &terminal_coding : &safe_terminal_coding); + coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK + ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding); /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at the tail. */ coding->mode &= ~CODING_MODE_LAST_BLOCK; while (len-- > 0) { - OUTPUT1_IF (TS_ins_char); + OUTPUT1_IF (tty, tty->TS_ins_char); if (!start) { conversion_buffer = space; @@ -1058,7 +886,7 @@ insert_glyphs (start, len) } else { - highlight_if_desired (); + highlight_if_desired (tty); turn_on_face (f, start->face_id); glyph = start; ++start; @@ -1066,7 +894,7 @@ insert_glyphs (start, len) occupies more than one column. */ while (len && CHAR_GLYPH_PADDING_P (*start)) { - OUTPUT1_IF (TS_ins_char); + OUTPUT1_IF (tty, tty->TS_ins_char); start++, len--; } @@ -1074,86 +902,92 @@ insert_glyphs (start, len) /* This is the last glyph. */ coding->mode |= CODING_MODE_LAST_BLOCK; - conversion_buffer = encode_terminal_code (glyph, 1, coding); + conversion_buffer = encode_terminal_code (glyph, 1, coding); } if (coding->produced > 0) { - fwrite (conversion_buffer, 1, coding->produced, stdout); - if (ferror (stdout)) - clearerr (stdout); - if (termscript) - fwrite (conversion_buffer, 1, coding->produced, termscript); + fwrite (conversion_buffer, 1, coding->produced, tty->output); + if (ferror (tty->output)) + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, tty->termscript); } - OUTPUT1_IF (TS_pad_inserted_char); + OUTPUT1_IF (tty, tty->TS_pad_inserted_char); if (start) { turn_off_face (f, glyph->face_id); - turn_off_highlight (); + turn_off_highlight (tty); } } - cmcheckmagic (); + cmcheckmagic (tty); +} + +/* Delete N glyphs at the nominal cursor position. */ + +void +delete_glyphs (struct frame *f, int n) +{ + if (FRAME_DEVICE (f)->delete_glyphs_hook) + (*FRAME_DEVICE (f)->delete_glyphs_hook) (f, n); } +/* An implementation of delete_glyphs for termcap frames. */ + void -delete_glyphs (n) - register int n; +tty_delete_glyphs (struct frame *f, int n) { char *buf; register int i; - if (delete_glyphs_hook && ! FRAME_TERMCAP_P (updating_frame)) - { - (*delete_glyphs_hook) (n); - return; - } + struct tty_display_info *tty = FRAME_TTY (f); - if (delete_in_insert_mode) + if (tty->delete_in_insert_mode) { - turn_on_insert (); + turn_on_insert (tty); } else { - turn_off_insert (); - OUTPUT_IF (TS_delete_mode); + turn_off_insert (tty); + OUTPUT_IF (tty, tty->TS_delete_mode); } - if (TS_del_multi_chars) + if (tty->TS_del_multi_chars) { - buf = tparam (TS_del_multi_chars, 0, 0, n); - OUTPUT1 (buf); + buf = tparam (tty->TS_del_multi_chars, 0, 0, n); + OUTPUT1 (tty, buf); xfree (buf); } else for (i = 0; i < n; i++) - OUTPUT1 (TS_del_char); - if (!delete_in_insert_mode) - OUTPUT_IF (TS_end_delete_mode); + OUTPUT1 (tty, tty->TS_del_char); + if (!tty->delete_in_insert_mode) + OUTPUT_IF (tty, tty->TS_end_delete_mode); } /* Insert N lines at vpos VPOS. If N is negative, delete -N lines. */ void -ins_del_lines (vpos, n) - int vpos, n; +ins_del_lines (struct frame *f, int vpos, int 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; + if (FRAME_DEVICE (f)->ins_del_lines_hook) + (*FRAME_DEVICE (f)->ins_del_lines_hook) (f, vpos, n); +} - register int i = n > 0 ? n : -n; - register char *buf; +/* An implementation of ins_del_lines for termcap frames. */ - if (ins_del_lines_hook && ! FRAME_TERMCAP_P (updating_frame)) - { - (*ins_del_lines_hook) (vpos, n); - return; - } +void +tty_ins_del_lines (struct frame *f, int vpos, int n) +{ + struct tty_display_info *tty = FRAME_TTY (f); + char *multi = n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines; + char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line; + char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll; - sf = XFRAME (selected_frame); + register int i = n > 0 ? n : -n; + register char *buf; /* If the lines below the insertion are being pushed into the end of the window, this is the same as clearing; @@ -1162,45 +996,49 @@ ins_del_lines (vpos, n) /* If the lines below the deletion are blank lines coming out of the end of the window, don't bother, as there will be a matching inslines later that will flush them. */ - if (scroll_region_ok && vpos + i >= specified_window) + if (FRAME_SCROLL_REGION_OK (f) + && vpos + i >= tty->specified_window) return; - if (!memory_below_frame && vpos + i >= FRAME_LINES (sf)) + if (!FRAME_MEMORY_BELOW_FRAME (f) + && vpos + i >= FRAME_LINES (f)) return; - + if (multi) { - raw_cursor_to (vpos, 0); - background_highlight (); + raw_cursor_to (f, vpos, 0); + background_highlight (tty); buf = tparam (multi, 0, 0, i); - OUTPUT (buf); + OUTPUT (tty, buf); xfree (buf); } else if (single) { - raw_cursor_to (vpos, 0); - background_highlight (); + raw_cursor_to (f, vpos, 0); + background_highlight (tty); while (--i >= 0) - OUTPUT (single); - if (TF_teleray) - curX = 0; + OUTPUT (tty, single); + if (tty->TF_teleray) + curX (tty) = 0; } else { - set_scroll_region (vpos, specified_window); + set_scroll_region (f, vpos, tty->specified_window); if (n < 0) - raw_cursor_to (specified_window - 1, 0); + raw_cursor_to (f, tty->specified_window - 1, 0); else - raw_cursor_to (vpos, 0); - background_highlight (); + raw_cursor_to (f, vpos, 0); + background_highlight (tty); while (--i >= 0) - OUTPUTL (scroll, specified_window - vpos); - set_scroll_region (0, specified_window); + OUTPUTL (tty, scroll, tty->specified_window - vpos); + set_scroll_region (f, 0, tty->specified_window); } - - if (!scroll_region_ok && memory_below_frame && n < 0) + + if (!FRAME_SCROLL_REGION_OK (f) + && FRAME_MEMORY_BELOW_FRAME (f) + && n < 0) { - cursor_to (FRAME_LINES (sf) + n, 0); - clear_to_end (); + cursor_to (f, FRAME_LINES (f) + n, 0); + clear_to_end (f); } } @@ -1208,8 +1046,7 @@ ins_del_lines (vpos, n) not counting any line-dependent padding. */ int -string_cost (str) - char *str; +string_cost (char *str) { cost = 0; if (str) @@ -1221,8 +1058,7 @@ string_cost (str) counting any line-dependent padding at one line. */ static int -string_cost_one_line (str) - char *str; +string_cost_one_line (char *str) { cost = 0; if (str) @@ -1234,8 +1070,7 @@ string_cost_one_line (str) in tenths of characters. */ int -per_line_cost (str) - register char *str; +per_line_cost (char *str) { cost = 0; if (str) @@ -1258,26 +1093,26 @@ int *char_ins_del_vector; /* ARGSUSED */ static void -calculate_ins_del_char_costs (frame) - FRAME_PTR frame; +calculate_ins_del_char_costs (struct frame *f) { + struct tty_display_info *tty = FRAME_TTY (f); int ins_startup_cost, del_startup_cost; int ins_cost_per_char, del_cost_per_char; register int i; register int *p; - if (TS_ins_multi_chars) + if (tty->TS_ins_multi_chars) { ins_cost_per_char = 0; - ins_startup_cost = string_cost_one_line (TS_ins_multi_chars); + ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars); } - else if (TS_ins_char || TS_pad_inserted_char - || (TS_insert_mode && TS_end_insert_mode)) + else if (tty->TS_ins_char || tty->TS_pad_inserted_char + || (tty->TS_insert_mode && tty->TS_end_insert_mode)) { - ins_startup_cost = (30 * (string_cost (TS_insert_mode) - + string_cost (TS_end_insert_mode))) / 100; - ins_cost_per_char = (string_cost_one_line (TS_ins_char) - + string_cost_one_line (TS_pad_inserted_char)); + ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode) + + string_cost (tty->TS_end_insert_mode))) / 100; + ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char) + + string_cost_one_line (tty->TS_pad_inserted_char)); } else { @@ -1285,18 +1120,18 @@ calculate_ins_del_char_costs (frame) ins_cost_per_char = 0; } - if (TS_del_multi_chars) + if (tty->TS_del_multi_chars) { del_cost_per_char = 0; - del_startup_cost = string_cost_one_line (TS_del_multi_chars); + del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars); } - else if (TS_del_char) + else if (tty->TS_del_char) { - del_startup_cost = (string_cost (TS_delete_mode) - + string_cost (TS_end_delete_mode)); - if (delete_in_insert_mode) + del_startup_cost = (string_cost (tty->TS_delete_mode) + + string_cost (tty->TS_end_delete_mode)); + if (tty->delete_in_insert_mode) del_startup_cost /= 2; - del_cost_per_char = string_cost_one_line (TS_del_char); + del_cost_per_char = string_cost_one_line (tty->TS_del_char); } else { @@ -1305,75 +1140,80 @@ calculate_ins_del_char_costs (frame) } /* Delete costs are at negative offsets */ - p = &char_ins_del_cost (frame)[0]; - for (i = FRAME_COLS (frame); --i >= 0;) + p = &char_ins_del_cost (f)[0]; + for (i = FRAME_COLS (f); --i >= 0;) *--p = (del_startup_cost += del_cost_per_char); /* Doing nothing is free */ - p = &char_ins_del_cost (frame)[0]; + p = &char_ins_del_cost (f)[0]; *p++ = 0; /* Insert costs are at positive offsets */ - for (i = FRAME_COLS (frame); --i >= 0;) + for (i = FRAME_COLS (f); --i >= 0;) *p++ = (ins_startup_cost += ins_cost_per_char); } void -calculate_costs (frame) - FRAME_PTR frame; +calculate_costs (struct frame *frame) { - register char *f = (TS_set_scroll_region - ? TS_set_scroll_region - : TS_set_scroll_region_1); - FRAME_COST_BAUD_RATE (frame) = baud_rate; - scroll_region_cost = string_cost (f); + if (FRAME_TERMCAP_P (frame)) + { + struct tty_display_info *tty = FRAME_TTY (frame); + register char *f = (tty->TS_set_scroll_region + ? tty->TS_set_scroll_region + : tty->TS_set_scroll_region_1); - /* These variables are only used for terminal stuff. They are allocated - once for the terminal frame of X-windows emacs, but not used afterwards. + FRAME_SCROLL_REGION_COST (frame) = string_cost (f); - char_ins_del_vector (i.e., char_ins_del_cost) isn't used because - X turns off char_ins_del_ok. */ + tty->costs_set = 1; - max_frame_lines = max (max_frame_lines, FRAME_LINES (frame)); - max_frame_cols = max (max_frame_cols, FRAME_COLS (frame)); + /* These variables are only used for terminal stuff. They are + allocated once for the terminal frame of X-windows emacs, but not + used afterwards. - costs_set = 1; + char_ins_del_vector (i.e., char_ins_del_cost) isn't used because + X turns off char_ins_del_ok. */ - if (char_ins_del_vector != 0) - char_ins_del_vector - = (int *) xrealloc (char_ins_del_vector, - (sizeof (int) - + 2 * max_frame_cols * sizeof (int))); - else - char_ins_del_vector - = (int *) xmalloc (sizeof (int) - + 2 * max_frame_cols * sizeof (int)); - - bzero (char_ins_del_vector, (sizeof (int) - + 2 * max_frame_cols * sizeof (int))); - - 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, - f, f, 1); - else - do_line_insertion_deletion_costs (frame, - TS_ins_line, TS_ins_multi_lines, - TS_del_line, TS_del_multi_lines, - 0, 0, 1); + max_frame_lines = max (max_frame_lines, FRAME_LINES (frame)); + max_frame_cols = max (max_frame_cols, FRAME_COLS (frame)); + + if (char_ins_del_vector != 0) + char_ins_del_vector + = (int *) xrealloc (char_ins_del_vector, + (sizeof (int) + + 2 * max_frame_cols * sizeof (int))); + else + char_ins_del_vector + = (int *) xmalloc (sizeof (int) + + 2 * max_frame_cols * sizeof (int)); - calculate_ins_del_char_costs (frame); + bzero (char_ins_del_vector, (sizeof (int) + + 2 * max_frame_cols * sizeof (int))); - /* 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 = FRAME_COLS (frame) * 2; - cmcostinit (); /* set up cursor motion costs */ + if (f && (!tty->TS_ins_line && !tty->TS_del_line)) + do_line_insertion_deletion_costs (frame, + tty->TS_rev_scroll, tty->TS_ins_multi_lines, + tty->TS_fwd_scroll, tty->TS_del_multi_lines, + f, f, 1); + else + do_line_insertion_deletion_costs (frame, + tty->TS_ins_line, tty->TS_ins_multi_lines, + tty->TS_del_line, tty->TS_del_multi_lines, + 0, 0, 1); + + calculate_ins_del_char_costs (frame); + + /* Don't use TS_repeat if its padding is worse than sending the chars */ + if (tty->TS_repeat && per_line_cost (tty->TS_repeat) * baud_rate < 9000) + tty->RPov = string_cost (tty->TS_repeat); + else + tty->RPov = FRAME_COLS (frame) * 2; + + cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */ + } } struct fkey_table { @@ -1483,7 +1323,8 @@ static struct fkey_table keys[] = {"!3", "S-undo"} /*shifted undo key*/ }; -static char **term_get_fkeys_arg; +static char **term_get_fkeys_address; +static KBOARD *term_get_fkeys_kboard; static Lisp_Object term_get_fkeys_1 (); /* Find the escape codes sent by the function keys for Vfunction_key_map. @@ -1491,8 +1332,9 @@ static Lisp_Object term_get_fkeys_1 (); adds entries to Vfunction_key_map for each function key it finds. */ void -term_get_fkeys (address) +term_get_fkeys (address, kboard) char **address; + KBOARD *kboard; { /* 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 @@ -1503,7 +1345,8 @@ term_get_fkeys (address) refusing to run at all on such a terminal. */ extern Lisp_Object Fidentity (); - term_get_fkeys_arg = address; + term_get_fkeys_address = address; + term_get_fkeys_kboard = kboard; internal_condition_case (term_get_fkeys_1, Qerror, Fidentity); } @@ -1512,17 +1355,18 @@ term_get_fkeys_1 () { int i; - char **address = term_get_fkeys_arg; - + char **address = term_get_fkeys_address; + KBOARD *kboard = term_get_fkeys_kboard; + /* This can happen if CANNOT_DUMP or with strange options. */ if (!initialized) - Vfunction_key_map = Fmake_sparse_keymap (Qnil); + kboard->Vlocal_function_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), + Fdefine_key (kboard->Vlocal_function_key_map, build_string (sequence), Fmake_vector (make_number (1), intern (keys[i].name))); } @@ -1542,13 +1386,13 @@ term_get_fkeys_1 () if (k0) /* Define f0 first, so that f10 takes precedence in case the key sequences happens to be the same. */ - Fdefine_key (Vfunction_key_map, build_string (k0), + Fdefine_key (kboard->Vlocal_function_key_map, build_string (k0), Fmake_vector (make_number (1), intern ("f0"))); - Fdefine_key (Vfunction_key_map, build_string (k_semi), + Fdefine_key (kboard->Vlocal_function_key_map, build_string (k_semi), Fmake_vector (make_number (1), intern ("f10"))); } else if (k0) - Fdefine_key (Vfunction_key_map, build_string (k0), + Fdefine_key (kboard->Vlocal_function_key_map, build_string (k0), Fmake_vector (make_number (1), intern (k0_name))); } @@ -1571,7 +1415,7 @@ term_get_fkeys_1 () if (sequence) { sprintf (fkey, "f%d", i); - Fdefine_key (Vfunction_key_map, build_string (sequence), + Fdefine_key (kboard->Vlocal_function_key_map, build_string (sequence), Fmake_vector (make_number (1), intern (fkey))); } @@ -1587,10 +1431,10 @@ term_get_fkeys_1 () 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 (sequence) \ + Fdefine_key (kboard->Vlocal_function_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 */ @@ -1925,10 +1769,10 @@ produce_special_glyphs (it, what) from them. Some display attributes may not be used together with color; the termcap capability `NC' specifies which ones. */ -#define MAY_USE_WITH_COLORS_P(ATTR) \ - (TN_max_colors > 0 \ - ? (TN_no_color_video & (ATTR)) == 0 \ - : 1) +#define MAY_USE_WITH_COLORS_P(tty, ATTR) \ + (tty->TN_max_colors > 0 \ + ? (tty->TN_no_color_video & (ATTR)) == 0 \ + : 1) /* Turn appearances of face FACE_ID on tty frame F on. FACE_ID is a realized face ID number, in the face cache. */ @@ -1941,12 +1785,13 @@ turn_on_face (f, face_id) struct face *face = FACE_FROM_ID (f, face_id); long fg = face->foreground; long bg = face->background; + struct tty_display_info *tty = FRAME_TTY (f); /* Do this first because TS_end_standout_mode may be the same as TS_exit_attribute_mode, which turns all appearances off. */ - if (MAY_USE_WITH_COLORS_P (NC_REVERSE)) + if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE)) { - if (TN_max_colors > 0) + if (tty->TN_max_colors > 0) { if (fg >= 0 && bg >= 0) { @@ -1960,13 +1805,13 @@ turn_on_face (f, face_id) { if (fg == FACE_TTY_DEFAULT_FG_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR) - toggle_highlight (); + toggle_highlight (tty); } else { if (fg == FACE_TTY_DEFAULT_BG_COLOR || bg == FACE_TTY_DEFAULT_FG_COLOR) - toggle_highlight (); + toggle_highlight (tty); } } else @@ -1977,55 +1822,55 @@ turn_on_face (f, face_id) { if (fg == FACE_TTY_DEFAULT_FG_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR) - toggle_highlight (); + toggle_highlight (tty); } else { if (fg == FACE_TTY_DEFAULT_BG_COLOR || bg == FACE_TTY_DEFAULT_FG_COLOR) - toggle_highlight (); + toggle_highlight (tty); } } } if (face->tty_bold_p) { - if (MAY_USE_WITH_COLORS_P (NC_BOLD)) - OUTPUT1_IF (TS_enter_bold_mode); + if (MAY_USE_WITH_COLORS_P (tty, NC_BOLD)) + OUTPUT1_IF (tty, tty->TS_enter_bold_mode); } else if (face->tty_dim_p) - if (MAY_USE_WITH_COLORS_P (NC_DIM)) - OUTPUT1_IF (TS_enter_dim_mode); + if (MAY_USE_WITH_COLORS_P (tty, NC_DIM)) + OUTPUT1_IF (tty, tty->TS_enter_dim_mode); /* Alternate charset and blinking not yet used. */ if (face->tty_alt_charset_p - && MAY_USE_WITH_COLORS_P (NC_ALT_CHARSET)) - OUTPUT1_IF (TS_enter_alt_charset_mode); + && MAY_USE_WITH_COLORS_P (tty, NC_ALT_CHARSET)) + OUTPUT1_IF (tty, tty->TS_enter_alt_charset_mode); if (face->tty_blinking_p - && MAY_USE_WITH_COLORS_P (NC_BLINK)) - OUTPUT1_IF (TS_enter_blink_mode); + && MAY_USE_WITH_COLORS_P (tty, NC_BLINK)) + OUTPUT1_IF (tty, tty->TS_enter_blink_mode); - if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (NC_UNDERLINE)) - OUTPUT1_IF (TS_enter_underline_mode); + if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE)) + OUTPUT1_IF (tty, tty->TS_enter_underline_mode); - if (TN_max_colors > 0) + if (tty->TN_max_colors > 0) { char *ts, *p; - ts = standout_mode ? TS_set_background : TS_set_foreground; + ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground; if (fg >= 0 && ts) { - p = tparam (ts, NULL, 0, (int) fg); - OUTPUT (p); + p = tparam (ts, NULL, 0, (int) fg); + OUTPUT (tty, p); xfree (p); } - ts = standout_mode ? TS_set_foreground : TS_set_background; + ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background; if (bg >= 0 && ts) { - p = tparam (ts, NULL, 0, (int) bg); - OUTPUT (p); + p = tparam (ts, NULL, 0, (int) bg); + OUTPUT (tty, p); xfree (p); } } @@ -2040,10 +1885,11 @@ turn_off_face (f, face_id) int face_id; { struct face *face = FACE_FROM_ID (f, face_id); + struct tty_display_info *tty = FRAME_TTY (f); xassert (face != NULL); - if (TS_exit_attribute_mode) + if (tty->TS_exit_attribute_mode) { /* Capability "me" will turn off appearance modes double-bright, half-bright, reverse-video, standout, underline. It may or @@ -2055,32 +1901,32 @@ turn_off_face (f, face_id) || face->tty_blinking_p || face->tty_underline_p) { - OUTPUT1_IF (TS_exit_attribute_mode); - if (strcmp (TS_exit_attribute_mode, TS_end_standout_mode) == 0) - standout_mode = 0; + OUTPUT1_IF (tty, tty->TS_exit_attribute_mode); + if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0) + tty->standout_mode = 0; } if (face->tty_alt_charset_p) - OUTPUT_IF (TS_exit_alt_charset_mode); + OUTPUT_IF (tty, tty->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); + OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode); if (face->tty_underline_p) - OUTPUT_IF (TS_exit_underline_mode); + OUTPUT_IF (tty, tty->TS_exit_underline_mode); } /* Switch back to default colors. */ - if (TN_max_colors > 0 + if (tty->TN_max_colors > 0 && ((face->foreground != FACE_TTY_DEFAULT_COLOR && face->foreground != FACE_TTY_DEFAULT_FG_COLOR) || (face->background != FACE_TTY_DEFAULT_COLOR && face->background != FACE_TTY_DEFAULT_BG_COLOR))) - OUTPUT1_IF (TS_orig_pair); + OUTPUT1_IF (tty, tty->TS_orig_pair); } @@ -2089,46 +1935,54 @@ turn_off_face (f, face_id) colors FG and BG. */ int -tty_capable_p (f, caps, fg, bg) - struct frame *f; +tty_capable_p (tty, caps, fg, bg) + struct tty_display_info *tty; unsigned caps; unsigned long fg, bg; { -#define TTY_CAPABLE_P_TRY(cap, TS, NC_bit) \ - if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(NC_bit))) \ +#define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \ + if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \ return 0; - TTY_CAPABLE_P_TRY (TTY_CAP_INVERSE, TS_standout_mode, NC_REVERSE); - TTY_CAPABLE_P_TRY (TTY_CAP_UNDERLINE, TS_enter_underline_mode, NC_UNDERLINE); - TTY_CAPABLE_P_TRY (TTY_CAP_BOLD, TS_enter_bold_mode, NC_BOLD); - TTY_CAPABLE_P_TRY (TTY_CAP_DIM, TS_enter_dim_mode, NC_DIM); - TTY_CAPABLE_P_TRY (TTY_CAP_BLINK, TS_enter_blink_mode, NC_BLINK); - TTY_CAPABLE_P_TRY (TTY_CAP_ALT_CHARSET, TS_enter_alt_charset_mode, NC_ALT_CHARSET); + TTY_CAPABLE_P_TRY (tty, TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE); + TTY_CAPABLE_P_TRY (tty, TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode, NC_UNDERLINE); + TTY_CAPABLE_P_TRY (tty, TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD); + TTY_CAPABLE_P_TRY (tty, TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM); + TTY_CAPABLE_P_TRY (tty, TTY_CAP_BLINK, tty->TS_enter_blink_mode, NC_BLINK); + TTY_CAPABLE_P_TRY (tty, TTY_CAP_ALT_CHARSET, tty->TS_enter_alt_charset_mode, NC_ALT_CHARSET); /* We can do it! */ return 1; } - /* 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, 1, 0, - doc: /* Return non-nil if TTY can display colors on DISPLAY. */) - (display) - Lisp_Object display; + doc: /* Return non-nil if the display device DEVICE can display colors. +DEVICE must be a tty device. */) + (device) + Lisp_Object device; { - return TN_max_colors > 0 ? Qt : Qnil; + struct device *d = get_tty_device (device); + if (!d) + return Qnil; + else + return d->display_info.tty->TN_max_colors > 0 ? Qt : Qnil; } /* Return the number of supported colors. */ DEFUN ("tty-display-color-cells", Ftty_display_color_cells, Stty_display_color_cells, 0, 1, 0, - doc: /* Return the number of colors supported by TTY on DISPLAY. */) - (display) - Lisp_Object display; + doc: /* Return the number of colors supported by the tty device DEVICE. */) + (device) + Lisp_Object device; { - return make_number (TN_max_colors); + struct device *d = get_tty_device (device); + if (!d) + return make_number (0); + else + return make_number (d->display_info.tty->TN_max_colors); } #ifndef WINDOWSNT @@ -2136,8 +1990,7 @@ DEFUN ("tty-display-color-cells", Ftty_display_color_cells, /* Save or restore the default color-related capabilities of this terminal. */ static void -tty_default_color_capabilities (save) - int save; +tty_default_color_capabilities (struct tty_display_info *tty, int save) { static char *default_orig_pair, *default_set_foreground, *default_set_background; @@ -2147,40 +2000,39 @@ tty_default_color_capabilities (save) { if (default_orig_pair) xfree (default_orig_pair); - default_orig_pair = TS_orig_pair ? xstrdup (TS_orig_pair) : NULL; + default_orig_pair = tty->TS_orig_pair ? xstrdup (tty->TS_orig_pair) : NULL; if (default_set_foreground) xfree (default_set_foreground); - default_set_foreground = TS_set_foreground ? xstrdup (TS_set_foreground) + default_set_foreground = tty->TS_set_foreground ? xstrdup (tty->TS_set_foreground) : NULL; if (default_set_background) xfree (default_set_background); - default_set_background = TS_set_background ? xstrdup (TS_set_background) + default_set_background = tty->TS_set_background ? xstrdup (tty->TS_set_background) : NULL; - default_max_colors = TN_max_colors; - default_max_pairs = TN_max_pairs; - default_no_color_video = TN_no_color_video; + default_max_colors = tty->TN_max_colors; + default_max_pairs = tty->TN_max_pairs; + default_no_color_video = tty->TN_no_color_video; } else { - TS_orig_pair = default_orig_pair; - TS_set_foreground = default_set_foreground; - TS_set_background = default_set_background; - TN_max_colors = default_max_colors; - TN_max_pairs = default_max_pairs; - TN_no_color_video = default_no_color_video; + tty->TS_orig_pair = default_orig_pair; + tty->TS_set_foreground = default_set_foreground; + tty->TS_set_background = default_set_background; + tty->TN_max_colors = default_max_colors; + tty->TN_max_pairs = default_max_pairs; + tty->TN_no_color_video = default_no_color_video; } } /* Setup one of the standard tty color schemes according to MODE. MODE's value is generally the number of colors which we want to support; zero means set up for the default capabilities, the ones - we saw at term_init time; -1 means turn off color support. */ + we saw at init_tty time; -1 means turn off color support. */ void -tty_setup_colors (mode) - int mode; +tty_setup_colors (struct tty_display_info *tty, int mode) { /* Canonicalize all negative values of MODE. */ if (mode < -1) @@ -2189,27 +2041,27 @@ tty_setup_colors (mode) switch (mode) { case -1: /* no colors at all */ - TN_max_colors = 0; - TN_max_pairs = 0; - TN_no_color_video = 0; - TS_set_foreground = TS_set_background = TS_orig_pair = NULL; + tty->TN_max_colors = 0; + tty->TN_max_pairs = 0; + tty->TN_no_color_video = 0; + tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL; break; case 0: /* default colors, if any */ default: - tty_default_color_capabilities (0); + tty_default_color_capabilities (tty, 0); break; case 8: /* 8 standard ANSI colors */ - TS_orig_pair = "\033[0m"; + tty->TS_orig_pair = "\033[0m"; #ifdef TERMINFO - TS_set_foreground = "\033[3%p1%dm"; - TS_set_background = "\033[4%p1%dm"; + tty->TS_set_foreground = "\033[3%p1%dm"; + tty->TS_set_background = "\033[4%p1%dm"; #else - TS_set_foreground = "\033[3%dm"; - TS_set_background = "\033[4%dm"; + tty->TS_set_foreground = "\033[3%dm"; + tty->TS_set_background = "\033[4%dm"; #endif - TN_max_colors = 8; - TN_max_pairs = 64; - TN_no_color_video = 0; + tty->TN_max_colors = 8; + tty->TN_max_pairs = 64; + tty->TN_no_color_video = 0; break; } } @@ -2260,7 +2112,7 @@ set_tty_color_mode (f, val) if (mode != old_mode) { - tty_setup_colors (mode); + tty_setup_colors (FRAME_TTY (f), mode); /* This recomputes all the faces given the new color definitions. */ call0 (intern ("tty-set-up-initial-frame-faces")); @@ -2271,13 +2123,242 @@ set_tty_color_mode (f, val) #endif /* !WINDOWSNT */ + +/* Return the display object specified by DEVICE. DEVICE may be a + display id, a frame, or nil for the display device of the current + frame. If THROW is zero, return NULL for failure, otherwise throw + an error. */ + +struct device * +get_device (Lisp_Object device, int throw) +{ + struct device *result = NULL; + + if (NILP (device)) + device = selected_frame; + + if (INTEGERP (device)) + { + struct device *d; + + for (d = device_list; d; d = d->next_device) + { + if (d->id == XINT (device)) + { + result = d; + break; + } + } + } + else if (FRAMEP (device)) + { + result = FRAME_DEVICE (XFRAME (device)); + } + + if (result == NULL && throw) + wrong_type_argument (Qdisplay_live_p, device); + + return result; +} + +/* Return the tty display object specified by DEVICE. */ + +struct device * +get_tty_device (Lisp_Object terminal) +{ + struct device *d = get_device (terminal, 0); + + if (d && d->type == output_initial) + d = NULL; + + if (d && d->type != output_termcap) + error ("Device %d is not a termcap display device", d->id); + + return d; +} + +/* Return the active termcap device that uses the tty device with the + given name. If NAME is NULL, return the device corresponding to + our controlling terminal. + + This function ignores suspended devices. + + Returns NULL if the named terminal device is not opened. */ + +struct device * +get_named_tty (name) + char *name; +{ + struct device *d; + + for (d = device_list; d; d = d->next_device) { + if (d->type == output_termcap + && ((d->display_info.tty->name == 0 && name == 0) + || (name && d->display_info.tty->name + && !strcmp (d->display_info.tty->name, name))) + && DEVICE_ACTIVE_P (d)) + return d; + }; + + return 0; +} + + + +DEFUN ("display-name", Fdisplay_name, Sdisplay_name, 0, 1, 0, + doc: /* Return the name of the display device DEVICE. +It is not guaranteed that the returned value is unique among opened devices. + +DEVICE may be a display device id, a frame, or nil (meaning the +selected frame's display device). */) + (device) + Lisp_Object device; +{ + struct device *d = get_device (device, 1); + + if (d->name) + return build_string (d->name); + else + return Qnil; +} + +DEFUN ("display-tty-type", Fdisplay_tty_type, Sdisplay_tty_type, 0, 1, 0, + doc: /* Return the type of the tty device that DEVICE uses. + +DEVICE may be a display device id, a frame, or nil (meaning the +selected frame's display device). */) + (device) + Lisp_Object device; +{ + struct device *d = get_device (device, 1); + + if (d->type != output_termcap) + error ("Display %d is not a termcap display", d->id); + + if (d->display_info.tty->type) + return build_string (d->display_info.tty->type); + else + return Qnil; +} + +DEFUN ("display-controlling-tty-p", Fdisplay_controlling_tty_p, Sdisplay_controlling_tty_p, 0, 1, 0, + doc: /* Return non-nil if DEVICE is on the controlling tty of the Emacs process. + +DEVICE may be a display device id, a frame, or nil (meaning the +selected frame's display device). */) + (device) + Lisp_Object device; +{ + struct device *d = get_device (device, 1); + + if (d->type != output_termcap || d->display_info.tty->name) + return Qnil; + else + return Qt; +} + +DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0, + doc: /* Declare that the tty used by DEVICE does not handle underlining. +This is used to override the terminfo data, for certain terminals that +do not really do underlining, but say that they do. This function has +no effect if used on a non-tty display. + +DEVICE may be a display device id, a frame, or nil (meaning the +selected frame's display device). */) + (device) + Lisp_Object device; +{ + struct device *d = get_device (device, 1); + + if (d->type == output_termcap) + d->display_info.tty->TS_enter_underline_mode = 0; + return Qnil; +} + + + /*********************************************************************** Initialization ***********************************************************************/ +/* Create the bootstrap display device for the initial frame. + Returns a device of type output_initial. */ + +struct device * +init_initial_device (void) +{ + if (initialized || device_list || tty_list) + abort (); + + initial_device = create_device (); + initial_device->type = output_initial; + initial_device->name = xstrdup ("initial_device"); + initial_device->kboard = initial_kboard; + + initial_device->delete_device_hook = &delete_initial_device; + /* All other hooks are NULL. */ + + return initial_device; +} + +/* Deletes the bootstrap display device. + Called through delete_device_hook. */ + +void +delete_initial_device (struct device *device) +{ + if (device != initial_device) + abort (); + + delete_device (device); + initial_device = NULL; +} + +/* Drop the controlling terminal if fd is the same device. */ void -term_init (terminal_type) - char *terminal_type; +dissociate_if_controlling_tty (int fd) +{ + int pgid; + EMACS_GET_TTY_PGRP (fd, &pgid); /* If tcgetpgrp succeeds, fd is the ctty. */ + if (pgid != -1) + { +#if defined (USG) && !defined (BSD_PGRPS) + setpgrp (); + no_controlling_tty = 1; +#else +#ifdef TIOCNOTTY /* Try BSD ioctls. */ + sigblock (sigmask (SIGTTOU)); + fd = emacs_open ("/dev/tty", O_RDWR, 0); + if (fd != -1 && ioctl (fd, TIOCNOTTY, 0) != -1) + { + no_controlling_tty = 1; + } + if (fd != -1) + emacs_close (fd); + sigunblock (sigmask (SIGTTOU)); +#else + /* Unknown system. */ + croak (); +#endif /* ! TIOCNOTTY */ +#endif /* ! USG */ + } +} + +static void maybe_fatal(); + +/* Create a termcap display on the tty device with the given name and + type. + + If NAME is NULL, then use the controlling tty, i.e., stdin/stdout. + Otherwise NAME should be a path to the tty device file, + e.g. "/dev/pts/7". + + TERMINAL_TYPE is the termcap type of the device, e.g. "vt100". + + If MUST_SUCCEED is true, then all errors are fatal. */ + +struct device * +init_tty (char *name, char *terminal_type, int must_succeed) { char *area; char **address = &area; @@ -2285,71 +2366,206 @@ term_init (terminal_type) int buffer_size = 4096; register char *p; int status; - struct frame *sf = XFRAME (selected_frame); + struct tty_display_info *tty; + struct device *device; + + if (!terminal_type) + maybe_fatal (must_succeed, 0, 0, + "Unknown terminal type", + "Unknown terminal type"); + + /* If we already have a display on the given device, use that. If + all such displays are suspended, create a new one instead. */ + /* XXX Perhaps this should be made explicit by having init_tty + always create a new display and separating device and frame + creation on Lisp level. */ + device = get_named_tty (name); + if (device) + return device; + + device = create_device (); + tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info)); + bzero (tty, sizeof (struct tty_display_info)); + tty->next = tty_list; + tty_list = tty; + + device->type = output_termcap; + device->display_info.tty = tty; + tty->device = device; + + tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm)); + Wcm_clear (tty); + + device->rif = 0; /* ttys don't support window-based redisplay. */ + + device->cursor_to_hook = &tty_cursor_to; + device->raw_cursor_to_hook = &tty_raw_cursor_to; + + device->clear_to_end_hook = &tty_clear_to_end; + device->clear_frame_hook = &tty_clear_frame; + device->clear_end_of_line_hook = &tty_clear_end_of_line; + + device->ins_del_lines_hook = &tty_ins_del_lines; + + device->insert_glyphs_hook = &tty_insert_glyphs; + device->write_glyphs_hook = &tty_write_glyphs; + device->delete_glyphs_hook = &tty_delete_glyphs; + + device->ring_bell_hook = &tty_ring_bell; + + device->reset_terminal_modes_hook = &tty_reset_terminal_modes; + device->set_terminal_modes_hook = &tty_set_terminal_modes; + device->update_begin_hook = 0; /* Not needed. */ + device->update_end_hook = &tty_update_end; + device->set_terminal_window_hook = &tty_set_terminal_window; + + device->mouse_position_hook = 0; /* Not needed. */ + device->frame_rehighlight_hook = 0; /* Not needed. */ + device->frame_raise_lower_hook = 0; /* Not needed. */ + + device->set_vertical_scroll_bar_hook = 0; /* Not needed. */ + device->condemn_scroll_bars_hook = 0; /* Not needed. */ + device->redeem_scroll_bar_hook = 0; /* Not needed. */ + device->judge_scroll_bars_hook = 0; /* Not needed. */ + + device->read_socket_hook = &tty_read_avail_input; /* keyboard.c */ + device->frame_up_to_date_hook = 0; /* Not needed. */ + + device->delete_frame_hook = &delete_tty_output; + device->delete_device_hook = &delete_tty; + + if (name) + { + int fd; + FILE *file; + +#ifdef O_IGNORE_CTTY + /* Open the terminal device. Don't recognize it as our + controlling terminal, and don't make it the controlling tty + if we don't have one at the moment. */ + fd = emacs_open (name, O_RDWR | O_IGNORE_CTTY | O_NOCTTY, 0); +#else + /* Alas, O_IGNORE_CTTY is a GNU extension that seems to be only + defined on Hurd. On other systems, we need to dissociate + ourselves from the controlling tty when we want to open a + frame on the same terminal. */ + + fd = emacs_open (name, O_RDWR | O_NOCTTY, 0); + +#endif /* O_IGNORE_CTTY */ + + if (fd < 0) + { + delete_tty (device); + error ("Could not open file: %s", name); + } + if (!isatty (fd)) + { + close (fd); + error ("Not a tty device: %s", name); + } + + dissociate_if_controlling_tty (fd); + + file = fdopen (fd, "w+"); + tty->name = xstrdup (name); + device->name = xstrdup (name); + tty->input = file; + tty->output = file; + } + else + { + if (no_controlling_tty) + { + /* Opening a frame on stdout is unsafe if we have + disconnected our controlling terminal. */ + error ("There is no controlling terminal any more"); + } + tty->name = 0; + device->name = xstrdup (ttyname (0)); + tty->input = stdin; + tty->output = stdout; + } + + tty->type = xstrdup (terminal_type); + + add_keyboard_wait_descriptor (fileno (tty->input)); encode_terminal_bufsize = 0; #ifdef WINDOWSNT initialize_w32_display (); - Wcm_clear (); + Wcm_clear (tty); area = (char *) xmalloc (2044); - FrameRows = FRAME_LINES (sf); - FrameCols = FRAME_COLS (sf); - specified_window = FRAME_LINES (sf); - - delete_in_insert_mode = 1; + FrameRows (tty) = FRAME_LINES (f); /* XXX */ + FrameCols (tty) = FRAME_COLS (f); /* XXX */ + tty->specified_window = FRAME_LINES (f); /* XXX */ - UseTabs = 0; - scroll_region_ok = 0; + tty->device->delete_in_insert_mode = 1; - /* 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. */ + UseTabs (tty) = 0; + device->scroll_region_ok = 0; - line_ins_del_ok = 0; - char_ins_del_ok = 1; + /* Seems to insert lines when it's not supposed to, messing up the + device. 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. */ + device->line_ins_del_ok = 0; + device->char_ins_del_ok = 1; baud_rate = 19200; - FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0; - FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none; + FRAME_CAN_HAVE_SCROLL_BARS (f) = 0; /* XXX */ + FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none; /* XXX */ TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */ - return; + return device; #else /* not WINDOWSNT */ - Wcm_clear (); + Wcm_clear (tty); buffer = (char *) xmalloc (buffer_size); + + /* On some systems, tgetent tries to access the controlling + terminal. */ + sigblock (sigmask (SIGTTOU)); status = tgetent (buffer, terminal_type); + sigunblock (sigmask (SIGTTOU)); + if (status < 0) { #ifdef TERMINFO - fatal ("Cannot open terminfo database file"); + maybe_fatal (must_succeed, buffer, device, + "Cannot open terminfo database file", + "Cannot open terminfo database file"); #else - fatal ("Cannot open termcap database file"); + maybe_fatal (must_succeed, buffer, device, + "Cannot open termcap database file", + "Cannot open termcap database file"); #endif } if (status == 0) { #ifdef TERMINFO - fatal ("Terminal type %s is not defined.\n\ + maybe_fatal (must_succeed, buffer, device, + "Terminal type %s is not defined", + "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); + terminal_type); #else - fatal ("Terminal type %s is not defined.\n\ + maybe_fatal (must_succeed, buffer, device, + "Terminal type %s is not defined", + "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); + terminal_type); #endif } @@ -2360,219 +2576,234 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.", #endif area = (char *) xmalloc (buffer_size); - TS_ins_line = tgetstr ("al", address); - TS_ins_multi_lines = tgetstr ("AL", address); - TS_bell = tgetstr ("bl", address); - BackTab = tgetstr ("bt", address); - TS_clr_to_bottom = tgetstr ("cd", address); - TS_clr_line = tgetstr ("ce", address); - TS_clr_frame = tgetstr ("cl", address); - ColPosition = NULL; /* tgetstr ("ch", address); */ - AbsPosition = tgetstr ("cm", address); - CR = tgetstr ("cr", address); - TS_set_scroll_region = tgetstr ("cs", address); - TS_set_scroll_region_1 = tgetstr ("cS", address); - RowPosition = tgetstr ("cv", address); - TS_del_char = tgetstr ("dc", address); - TS_del_multi_chars = tgetstr ("DC", address); - TS_del_line = tgetstr ("dl", address); - TS_del_multi_lines = tgetstr ("DL", address); - TS_delete_mode = tgetstr ("dm", address); - TS_end_delete_mode = tgetstr ("ed", address); - TS_end_insert_mode = tgetstr ("ei", address); - Home = tgetstr ("ho", address); - TS_ins_char = tgetstr ("ic", address); - TS_ins_multi_chars = tgetstr ("IC", address); - TS_insert_mode = tgetstr ("im", address); - TS_pad_inserted_char = tgetstr ("ip", address); - TS_end_keypad_mode = tgetstr ("ke", address); - TS_keypad_mode = tgetstr ("ks", address); - LastLine = tgetstr ("ll", address); - Right = tgetstr ("nd", address); - Down = tgetstr ("do", address); - if (!Down) - Down = tgetstr ("nl", address); /* Obsolete name for "do" */ + tty->TS_ins_line = tgetstr ("al", address); + tty->TS_ins_multi_lines = tgetstr ("AL", address); + tty->TS_bell = tgetstr ("bl", address); + BackTab (tty) = tgetstr ("bt", address); + tty->TS_clr_to_bottom = tgetstr ("cd", address); + tty->TS_clr_line = tgetstr ("ce", address); + tty->TS_clr_frame = tgetstr ("cl", address); + ColPosition (tty) = NULL; /* tgetstr ("ch", address); */ + AbsPosition (tty) = tgetstr ("cm", address); + CR (tty) = tgetstr ("cr", address); + tty->TS_set_scroll_region = tgetstr ("cs", address); + tty->TS_set_scroll_region_1 = tgetstr ("cS", address); + RowPosition (tty) = tgetstr ("cv", address); + tty->TS_del_char = tgetstr ("dc", address); + tty->TS_del_multi_chars = tgetstr ("DC", address); + tty->TS_del_line = tgetstr ("dl", address); + tty->TS_del_multi_lines = tgetstr ("DL", address); + tty->TS_delete_mode = tgetstr ("dm", address); + tty->TS_end_delete_mode = tgetstr ("ed", address); + tty->TS_end_insert_mode = tgetstr ("ei", address); + Home (tty) = tgetstr ("ho", address); + tty->TS_ins_char = tgetstr ("ic", address); + tty->TS_ins_multi_chars = tgetstr ("IC", address); + tty->TS_insert_mode = tgetstr ("im", address); + tty->TS_pad_inserted_char = tgetstr ("ip", address); + tty->TS_end_keypad_mode = tgetstr ("ke", address); + tty->TS_keypad_mode = tgetstr ("ks", address); + LastLine (tty) = tgetstr ("ll", address); + Right (tty) = tgetstr ("nd", address); + Down (tty) = tgetstr ("do", address); + if (!Down (tty)) + Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */ #ifdef VMS /* VMS puts a carriage return before each linefeed, so it is not safe to use linefeeds. */ - if (Down && Down[0] == '\n' && Down[1] == '\0') - Down = 0; + if (Down (tty) && Down (tty)[0] == '\n' && Down (tty)[1] == '\0') + Down (tty) = 0; #endif /* VMS */ if (tgetflag ("bs")) - Left = "\b"; /* can't possibly be longer! */ + Left (tty) = "\b"; /* can't possibly be longer! */ else /* (Actually, "bs" is obsolete...) */ - Left = tgetstr ("le", address); - if (!Left) - Left = tgetstr ("bc", address); /* Obsolete name for "le" */ - TS_pad_char = tgetstr ("pc", address); - TS_repeat = tgetstr ("rp", address); - TS_end_standout_mode = tgetstr ("se", address); - TS_fwd_scroll = tgetstr ("sf", address); - TS_standout_mode = tgetstr ("so", address); - TS_rev_scroll = tgetstr ("sr", address); - Wcm.cm_tab = tgetstr ("ta", address); - TS_end_termcap_modes = tgetstr ("te", address); - TS_termcap_modes = tgetstr ("ti", address); - Up = tgetstr ("up", address); - TS_visible_bell = tgetstr ("vb", 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); - 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); + Left (tty) = tgetstr ("le", address); + if (!Left (tty)) + Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */ + tty->TS_pad_char = tgetstr ("pc", address); + tty->TS_repeat = tgetstr ("rp", address); + tty->TS_end_standout_mode = tgetstr ("se", address); + tty->TS_fwd_scroll = tgetstr ("sf", address); + tty->TS_standout_mode = tgetstr ("so", address); + tty->TS_rev_scroll = tgetstr ("sr", address); + tty->Wcm->cm_tab = tgetstr ("ta", address); + tty->TS_end_termcap_modes = tgetstr ("te", address); + tty->TS_termcap_modes = tgetstr ("ti", address); + Up (tty) = tgetstr ("up", address); + tty->TS_visible_bell = tgetstr ("vb", address); + tty->TS_cursor_normal = tgetstr ("ve", address); + tty->TS_cursor_visible = tgetstr ("vs", address); + tty->TS_cursor_invisible = tgetstr ("vi", address); + tty->TS_set_window = tgetstr ("wi", address); + + tty->TS_enter_underline_mode = tgetstr ("us", address); + tty->TS_exit_underline_mode = tgetstr ("ue", address); + tty->TS_enter_bold_mode = tgetstr ("md", address); + tty->TS_enter_dim_mode = tgetstr ("mh", address); + tty->TS_enter_blink_mode = tgetstr ("mb", address); + tty->TS_enter_reverse_mode = tgetstr ("mr", address); + tty->TS_enter_alt_charset_mode = tgetstr ("as", address); + tty->TS_exit_alt_charset_mode = tgetstr ("ae", address); + tty->TS_exit_attribute_mode = tgetstr ("me", address); + + MultiUp (tty) = tgetstr ("UP", address); + MultiDown (tty) = tgetstr ("DO", address); + MultiLeft (tty) = tgetstr ("LE", address); + MultiRight (tty) = tgetstr ("RI", address); /* 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) + tty->TS_orig_pair = tgetstr ("op", address); + if (tty->TS_orig_pair) { - TS_set_foreground = tgetstr ("AF", address); - TS_set_background = tgetstr ("AB", address); - if (!TS_set_foreground) + tty->TS_set_foreground = tgetstr ("AF", address); + tty->TS_set_background = tgetstr ("AB", address); + if (!tty->TS_set_foreground) { /* SVr4. */ - TS_set_foreground = tgetstr ("Sf", address); - TS_set_background = tgetstr ("Sb", address); + tty->TS_set_foreground = tgetstr ("Sf", address); + tty->TS_set_background = tgetstr ("Sb", address); } - TN_max_colors = tgetnum ("Co"); - TN_max_pairs = tgetnum ("pa"); + tty->TN_max_colors = tgetnum ("Co"); + tty->TN_max_pairs = tgetnum ("pa"); - TN_no_color_video = tgetnum ("NC"); - if (TN_no_color_video == -1) - TN_no_color_video = 0; + tty->TN_no_color_video = tgetnum ("NC"); + if (tty->TN_no_color_video == -1) + tty->TN_no_color_video = 0; } - tty_default_color_capabilities (1); + tty_default_color_capabilities (tty, 1); - MagicWrap = tgetflag ("xn"); + MagicWrap (tty) = 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"); - TF_teleray = tgetflag ("xt"); - - term_get_fkeys (address); + AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am"); + device->memory_below_frame = tgetflag ("db"); + tty->TF_hazeltine = tgetflag ("hz"); + device->must_write_spaces = tgetflag ("in"); + tty->meta_key = tgetflag ("km") || tgetflag ("MT"); + tty->TF_insmode_motion = tgetflag ("mi"); + tty->TF_standout_motion = tgetflag ("ms"); + tty->TF_underscore = tgetflag ("ul"); + tty->TF_teleray = tgetflag ("xt"); + +#ifdef MULTI_KBOARD + device->kboard = (KBOARD *) xmalloc (sizeof (KBOARD)); + init_kboard (device->kboard); + device->kboard->next_kboard = all_kboards; + all_kboards = device->kboard; + device->kboard->reference_count++; + /* Don't let the initial kboard remain current longer than necessary. + That would cause problems if a file loaded on startup tries to + prompt in the mini-buffer. */ + if (current_kboard == initial_kboard) + current_kboard = device->kboard; +#endif + + term_get_fkeys (address, device->kboard); /* Get frame size from system, or else from termcap. */ { int height, width; - get_frame_size (&width, &height); - FRAME_COLS (sf) = width; - FRAME_LINES (sf) = height; + get_tty_size (fileno (tty->input), &width, &height); + FrameCols (tty) = width; + FrameRows (tty) = height; } - if (FRAME_COLS (sf) <= 0) - SET_FRAME_COLS (sf, tgetnum ("co")); - else - /* Keep width and external_width consistent */ - SET_FRAME_COLS (sf, FRAME_COLS (sf)); - if (FRAME_LINES (sf) <= 0) - FRAME_LINES (sf) = tgetnum ("li"); + if (FrameCols (tty) <= 0) + FrameCols (tty) = tgetnum ("co"); + if (FrameRows (tty) <= 0) + FrameRows (tty) = tgetnum ("li"); - if (FRAME_LINES (sf) < 3 || FRAME_COLS (sf) < 3) - fatal ("Screen size %dx%d is too small", - FRAME_LINES (sf), FRAME_COLS (sf)); + if (FrameRows (tty) < 3 || FrameCols (tty) < 3) + maybe_fatal (must_succeed, NULL, device, + "Screen size %dx%d is too small" + "Screen size %dx%d is too small", + FrameCols (tty), FrameRows (tty)); - min_padding_speed = tgetnum ("pb"); - TabWidth = tgetnum ("tw"); +#if 0 /* This is not used anywhere. */ + tty->device->min_padding_speed = tgetnum ("pb"); +#endif + + TabWidth (tty) = tgetnum ("tw"); #ifdef VMS /* These capabilities commonly use ^J. I don't know why, but sending them on VMS does not work; it causes following spaces to be lost, sometimes. For now, the simplest fix is to avoid using these capabilities ever. */ - if (Down && Down[0] == '\n') - Down = 0; + if (Down (tty) && Down (tty)[0] == '\n') + Down (tty) = 0; #endif /* VMS */ - if (!TS_bell) - TS_bell = "\07"; + if (!tty->TS_bell) + tty->TS_bell = "\07"; - if (!TS_fwd_scroll) - TS_fwd_scroll = Down; + if (!tty->TS_fwd_scroll) + tty->TS_fwd_scroll = Down (tty); - PC = TS_pad_char ? *TS_pad_char : 0; + PC = tty->TS_pad_char ? *tty->TS_pad_char : 0; - if (TabWidth < 0) - TabWidth = 8; + if (TabWidth (tty) < 0) + TabWidth (tty) = 8; /* Turned off since /etc/termcap seems to have :ta= for most terminals and newer termcap doc does not seem to say there is a default. - if (!Wcm.cm_tab) - Wcm.cm_tab = "\t"; + if (!tty->Wcm->cm_tab) + tty->Wcm->cm_tab = "\t"; */ /* We don't support standout modes that use `magic cookies', so turn off any that do. */ - if (TS_standout_mode && tgetnum ("sg") >= 0) + if (tty->TS_standout_mode && tgetnum ("sg") >= 0) { - TS_standout_mode = 0; - TS_end_standout_mode = 0; + tty->TS_standout_mode = 0; + tty->TS_end_standout_mode = 0; } - if (TS_enter_underline_mode && tgetnum ("ug") >= 0) + if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0) { - TS_enter_underline_mode = 0; - TS_exit_underline_mode = 0; + tty->TS_enter_underline_mode = 0; + tty->TS_exit_underline_mode = 0; } /* If there's no standout mode, try to use underlining instead. */ - if (TS_standout_mode == 0) + if (tty->TS_standout_mode == 0) { - TS_standout_mode = TS_enter_underline_mode; - TS_end_standout_mode = TS_exit_underline_mode; + tty->TS_standout_mode = tty->TS_enter_underline_mode; + tty->TS_end_standout_mode = tty->TS_exit_underline_mode; } /* 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) + if (tty->TS_end_standout_mode == 0) { char *s = tgetstr ("me", address); if (s != 0) - TS_end_standout_mode = s; + tty->TS_end_standout_mode = s; else - TS_standout_mode = 0; + tty->TS_standout_mode = 0; } - if (TF_teleray) + if (tty->TF_teleray) { - Wcm.cm_tab = 0; + tty->Wcm->cm_tab = 0; /* We can't support standout mode, because it uses magic cookies. */ - TS_standout_mode = 0; + tty->TS_standout_mode = 0; /* But that means we cannot rely on ^M to go to column zero! */ - CR = 0; + CR (tty) = 0; /* LF can't be trusted either -- can alter hpos */ /* if move at column 0 thru a line with TS_standout_mode */ - Down = 0; + Down (tty) = 0; } /* Special handling for certain terminal types known to need it */ if (!strcmp (terminal_type, "supdup")) { - memory_below_frame = 1; - Wcm.cm_losewrap = 1; + device->memory_below_frame = 1; + tty->Wcm->cm_losewrap = 1; } if (!strncmp (terminal_type, "c10", 3) || !strcmp (terminal_type, "perq")) @@ -2589,102 +2820,139 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.", It would be simpler if the :wi string could go in the termcap entry, but it can't because it is not fully valid. If it were in the termcap entry, it would confuse other programs. */ - if (!TS_set_window) + if (!tty->TS_set_window) { - p = TS_termcap_modes; + p = tty->TS_termcap_modes; while (*p && strcmp (p, "\033v ")) p++; if (*p) - TS_set_window = "\033v%C %C %C %C "; + tty->TS_set_window = "\033v%C %C %C %C "; } /* Termcap entry often fails to have :in: flag */ - must_write_spaces = 1; + device->must_write_spaces = 1; /* :ti string typically fails to have \E^G! in it */ /* This limits scope of insert-char to one line. */ - strcpy (area, TS_termcap_modes); + strcpy (area, tty->TS_termcap_modes); strcat (area, "\033\007!"); - TS_termcap_modes = area; + tty->TS_termcap_modes = area; area += strlen (area) + 1; - p = AbsPosition; + p = AbsPosition (tty); /* Change all %+ parameters to %C, to handle - values above 96 correctly for the C100. */ + values above 96 correctly for the C100. */ while (*p) - { - if (p[0] == '%' && p[1] == '+') - p[1] = 'C'; - p++; - } + { + if (p[0] == '%' && p[1] == '+') + p[1] = 'C'; + p++; + } } - FrameRows = FRAME_LINES (sf); - FrameCols = FRAME_COLS (sf); - specified_window = FRAME_LINES (sf); + tty->specified_window = FrameRows (tty); - if (Wcm_init () == -1) /* can't do cursor motion */ + if (Wcm_init (tty) == -1) /* can't do cursor motion */ + { + maybe_fatal (must_succeed, NULL, device, + "Terminal type \"%s\" is not powerful enough to run Emacs", #ifdef VMS - fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\ + "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, use either the\n\ DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\ or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.", - terminal_type); #else /* not VMS */ # ifdef TERMINFO - fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\ + "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 TERMINFO' (C-shell: `unsetenv TERMINFO') as well.", - terminal_type); # else /* TERMCAP */ - fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\ + "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_LINES (sf) <= 0 - || FRAME_COLS (sf) <= 0) - fatal ("The frame size has not been specified"); + terminal_type); + } - delete_in_insert_mode - = TS_delete_mode && TS_insert_mode - && !strcmp (TS_delete_mode, TS_insert_mode); + if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0) + maybe_fatal (must_succeed, NULL, device, + "Could not determine the frame size", + "Could not determine the frame size"); - se_is_so = (TS_standout_mode - && TS_end_standout_mode - && !strcmp (TS_standout_mode, TS_end_standout_mode)); + tty->delete_in_insert_mode + = tty->TS_delete_mode && tty->TS_insert_mode + && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode); - UseTabs = tabs_safe_p () && TabWidth == 8; + tty->se_is_so = (tty->TS_standout_mode + && tty->TS_end_standout_mode + && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode)); - scroll_region_ok - = (Wcm.cm_abs - && (TS_set_window || TS_set_scroll_region || TS_set_scroll_region_1)); + UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8; - line_ins_del_ok = (((TS_ins_line || TS_ins_multi_lines) - && (TS_del_line || TS_del_multi_lines)) - || (scroll_region_ok && TS_fwd_scroll && TS_rev_scroll)); + device->scroll_region_ok + = (tty->Wcm->cm_abs + && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1)); - char_ins_del_ok = ((TS_ins_char || TS_insert_mode - || TS_pad_inserted_char || TS_ins_multi_chars) - && (TS_del_char || TS_del_multi_chars)); + device->line_ins_del_ok + = (((tty->TS_ins_line || tty->TS_ins_multi_lines) + && (tty->TS_del_line || tty->TS_del_multi_lines)) + || (device->scroll_region_ok + && tty->TS_fwd_scroll && tty->TS_rev_scroll)); - fast_clear_end_of_line = TS_clr_line != 0; + device->char_ins_del_ok + = ((tty->TS_ins_char || tty->TS_insert_mode + || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars) + && (tty->TS_del_char || tty->TS_del_multi_chars)); - init_baud_rate (); - if (read_socket_hook) /* Baudrate is somewhat */ - /* meaningless in this case */ - baud_rate = 9600; + device->fast_clear_end_of_line = tty->TS_clr_line != 0; - FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0; - FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none; -#endif /* WINDOWSNT */ + init_baud_rate (fileno (tty->input)); + +#ifdef AIXHFT + /* The HFT system on AIX doesn't optimize for scrolling, so it's + really ugly at times. */ + device->line_ins_del_ok = 0; + device->char_ins_del_ok = 0; +#endif + + /* Don't do this. I think termcap may still need the buffer. */ + /* xfree (buffer); */ + + /* Init system terminal modes (RAW or CBREAK, etc.). */ + init_sys_modes (tty); - xfree (buffer); + return device; +#endif /* not WINDOWSNT */ +} + +/* Auxiliary error-handling function for init_tty. + Free BUFFER and delete DEVICE, then call error or fatal + with str1 or str2, respectively, according to MUST_SUCCEED. */ + +static void +maybe_fatal (must_succeed, buffer, device, str1, str2, arg1, arg2) + int must_succeed; + char *buffer; + struct device *device; + char *str1, *str2, *arg1, *arg2; +{ + if (buffer) + xfree (buffer); + + if (device) + delete_tty (device); + + if (must_succeed) + fatal (str2, arg1, arg2); + else + error (str1, arg1, arg2); + + abort (); } /* VARARGS 1 */ @@ -2699,16 +2967,428 @@ fatal (str, arg1, arg2) exit (1); } -DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 0, 0, - doc: /* Declare that this terminal does not handle underlining. -This is used to override the terminfo data, for certain terminals that -do not really do underlining, but say that they do. */) + + +static int deleting_tty = 0; + + +/* Delete the given terminal device, closing all frames on it. */ + +void +delete_tty (struct device *device) +{ + struct tty_display_info *tty; + Lisp_Object tail, frame; + char *tty_name; + int last_device; + + if (deleting_tty) + /* We get a recursive call when we delete the last frame on this + device. */ + return; + + if (device->type != output_termcap) + abort (); + + tty = device->display_info.tty; + + last_device = 1; + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (FRAME_LIVE_P (f) && (!FRAME_TERMCAP_P (f) || FRAME_TTY (f) != tty)) + { + last_device = 0; + break; + } + } + if (last_device) + error ("Attempt to delete the sole display device with live frames"); + + if (tty == tty_list) + tty_list = tty->next; + else + { + struct tty_display_info *p; + for (p = tty_list; p && p->next != tty; p = p->next) + ; + + if (! p) + /* This should not happen. */ + abort (); + + p->next = tty->next; + tty->next = 0; + } + + deleting_tty = 1; + + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f) && FRAME_TTY (f) == tty) + { + Fdelete_frame (frame, Qt); + } + } + + /* reset_sys_modes needs a valid device, so this call needs to be + before delete_device. */ + reset_sys_modes (tty); + + delete_device (device); + + tty_name = tty->name; + if (tty->type) + xfree (tty->type); + + if (tty->input) + { + delete_keyboard_wait_descriptor (fileno (tty->input)); + if (tty->input != stdin) + fclose (tty->input); + } + if (tty->output && tty->output != stdout && tty->output != tty->input) + fclose (tty->output); + if (tty->termscript) + fclose (tty->termscript); + + if (tty->old_tty) + xfree (tty->old_tty); + + if (tty->Wcm) + xfree (tty->Wcm); + + bzero (tty, sizeof (struct tty_display_info)); + xfree (tty); + deleting_tty = 0; +} + + + +/* Initialize the tty-dependent part of frame F. The frame must + already have its device initialized. */ + +void +create_tty_output (struct frame *f) +{ + struct tty_output *t; + + if (! FRAME_TERMCAP_P (f)) + abort (); + + t = xmalloc (sizeof (struct tty_output)); + bzero (t, sizeof (struct tty_output)); + + t->display_info = FRAME_DEVICE (f)->display_info.tty; + + f->output_data.tty = t; +} + +/* Delete the tty-dependent part of frame F. */ + +void +delete_tty_output (struct frame *f) +{ + if (! FRAME_TERMCAP_P (f)) + abort (); + + xfree (f->output_data.tty); +} + + + + +/* Mark the pointers in the tty_display_info objects. + Called by the Fgarbage_collector. */ + +void +mark_ttys () +{ + struct tty_display_info *tty; + + for (tty = tty_list; tty; tty = tty->next) + { + if (tty->top_frame) + mark_object (tty->top_frame); + } +} + + + +/* Create a new device object and add it to the device list. */ + +struct device * +create_device (void) +{ + struct device *device = (struct device *) xmalloc (sizeof (struct device)); + + bzero (device, sizeof (struct device)); + device->next_device = device_list; + device_list = device; + + device->id = next_device_id++; + + device->keyboard_coding = + (struct coding_system *) xmalloc (sizeof (struct coding_system)); + device->terminal_coding = + (struct coding_system *) xmalloc (sizeof (struct coding_system)); + + setup_coding_system (Qnil, device->keyboard_coding); + setup_coding_system (Qnil, device->terminal_coding); + + return device; +} + +/* Remove a device from the device list and free its memory. */ + +void +delete_device (struct device *device) +{ + struct device **dp; + Lisp_Object tail, frame; + + /* Check for and close live frames that are still on this + device. */ + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (FRAME_LIVE_P (f) && f->device == device) + { + Fdelete_frame (frame, Qt); + } + } + + for (dp = &device_list; *dp != device; dp = &(*dp)->next_device) + if (! *dp) + abort (); + *dp = device->next_device; + + if (device->keyboard_coding) + xfree (device->keyboard_coding); + if (device->terminal_coding) + xfree (device->terminal_coding); + if (device->name) + xfree (device->name); + +#ifdef MULTI_KBOARD + if (device->kboard && --device->kboard->reference_count == 0) + delete_kboard (device->kboard); +#endif + + bzero (device, sizeof (struct device)); + xfree (device); +} + +DEFUN ("delete-display", Fdelete_display, Sdelete_display, 0, 2, 0, + doc: /* Delete DEVICE by deleting all frames on it and closing the device. +DEVICE may be a display device id, a frame, or nil (meaning the +selected frame's display device). + +Normally, you may not delete a display if all other displays are suspended, +but if the second argument FORCE is non-nil, you may do so. */) + (device, force) + Lisp_Object device, force; +{ + struct device *d, *p; + + d = get_device (device, 0); + + if (!d) + return Qnil; + + p = device_list; + while (p && (p == d || !DEVICE_ACTIVE_P (p))) + p = p->next_device; + + if (NILP (force) && !p) + error ("Attempt to delete the sole active display device"); + + if (d->delete_device_hook) + (*d->delete_device_hook) (d); + else + delete_device (d); + + return Qnil; +} + +DEFUN ("display-live-p", Fdisplay_live_p, Sdisplay_live_p, 1, 1, 0, + doc: /* Return non-nil if OBJECT is a device which has not been deleted. +Value is nil if OBJECT is not a live display device. +If object is a live display device, the return value indicates what +sort of output device it uses. See the documentation of `framep' for +possible return values. + +Display devices are represented by their integer identifiers. */) + (object) + Lisp_Object object; +{ + struct device *d; + + if (!INTEGERP (object)) + return Qnil; + + d = get_device (object, 0); + + if (!d) + return Qnil; + + switch (d->type) + { + case output_initial: /* The initial frame is like a termcap frame. */ + case output_termcap: + return Qt; + case output_x_window: + return Qx; + case output_w32: + return Qw32; + case output_msdos_raw: + return Qpc; + case output_mac: + return Qmac; + default: + abort (); + } +} + +DEFUN ("display-list", Fdisplay_list, Sdisplay_list, 0, 0, 0, + doc: /* Return a list of all display devices. +Display devices are represented by their integer identifiers. */) () { - TS_enter_underline_mode = 0; + Lisp_Object devices = Qnil; + struct device *d; + + for (d = device_list; d; d = d->next_device) + devices = Fcons (make_number (d->id), devices); + + return devices; +} + + + + +DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0, + doc: /* Suspend the terminal device TTY. +The terminal is restored to its default state, and Emacs ceases all +access to the terminal device. Frames that use the device are not +deleted, but input is not read from them and if they change, their +display is not updated. + +TTY may be a display id, a frame, or nil for the display device of the +currently selected frame. + +This function runs `suspend-tty-functions' after suspending the +device. The functions are run with one arg, the id of the suspended +display device. + +`suspend-tty' does nothing if it is called on an already suspended +device. + +A suspended terminal device may be resumed by calling `resume-tty' on +it. */) + (tty) + Lisp_Object tty; +{ + struct device *d = get_tty_device (tty); + FILE *f; + + if (!d) + error ("Unknown tty device"); + + f = d->display_info.tty->input; + + if (f) + { + reset_sys_modes (d->display_info.tty); + + delete_keyboard_wait_descriptor (fileno (f)); + + fclose (f); + if (f != d->display_info.tty->output) + fclose (d->display_info.tty->output); + + d->display_info.tty->input = 0; + d->display_info.tty->output = 0; + + if (FRAMEP (d->display_info.tty->top_frame)) + FRAME_SET_VISIBLE (XFRAME (d->display_info.tty->top_frame), 0); + + /* Run `suspend-tty-functions'. */ + if (!NILP (Vrun_hooks)) + { + Lisp_Object args[2]; + args[0] = intern ("suspend-tty-functions"); + args[1] = make_number (d->id); + Frun_hook_with_args (2, args); + } + } + + return Qnil; +} + + +DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0, + doc: /* Resume the previously suspended terminal device TTY. +The terminal is opened and reinitialized. Frames that are on the +suspended display are revived. + +It is an error to resume a display while another display is active on +the same device. + +This function runs `resume-tty-functions' after resuming the device. +The functions are run with one arg, the id of the resumed display +device. + +`resume-tty' does nothing if it is called on a device that is not +suspended. + +TTY may be a display device id, a frame, or nil for the display device +of the currently selected frame. */) + (tty) + Lisp_Object tty; +{ + struct device *d = get_tty_device (tty); + int fd; + + if (!d) + error ("Unknown tty device"); + + if (!d->display_info.tty->input) + { + if (get_named_tty (d->display_info.tty->name)) + error ("Cannot resume display while another display is active on the same device"); + + fd = emacs_open (d->display_info.tty->name, O_RDWR | O_NOCTTY, 0); + + /* XXX What if open fails? */ + + dissociate_if_controlling_tty (fd); + + d->display_info.tty->output = fdopen (fd, "w+"); + d->display_info.tty->input = d->display_info.tty->output; + + add_keyboard_wait_descriptor (fd); + + if (FRAMEP (d->display_info.tty->top_frame)) + FRAME_SET_VISIBLE (XFRAME (d->display_info.tty->top_frame), 1); + + init_sys_modes (d->display_info.tty); + + /* Run `suspend-tty-functions'. */ + if (!NILP (Vrun_hooks)) + { + Lisp_Object args[2]; + args[0] = intern ("resume-tty-functions"); + args[1] = make_number (d->id); + Frun_hook_with_args (2, args); + } + } + return Qnil; } + void syms_of_term () { @@ -2726,10 +3406,36 @@ This variable can be used by terminal emulator packages. */); The function should accept no arguments. */); Vring_bell_function = Qnil; + DEFVAR_LISP ("suspend-tty-functions", &Vsuspend_tty_functions, + doc: /* Functions to be run after suspending a tty. +The functions are run with one argument, the name of the tty to be suspended. +See `suspend-tty'. */); + Vsuspend_tty_functions = Qnil; + + + DEFVAR_LISP ("resume-tty-functions", &Vresume_tty_functions, + doc: /* Functions to be run after resuming a tty. +The functions are run with one argument, the name of the tty that was revived. +See `resume-tty'. */); + Vresume_tty_functions = Qnil; + defsubr (&Stty_display_color_p); defsubr (&Stty_display_color_cells); defsubr (&Stty_no_underline); + defsubr (&Sdisplay_name); + defsubr (&Sdisplay_tty_type); + defsubr (&Sdisplay_controlling_tty_p); + defsubr (&Sdelete_display); + defsubr (&Sdisplay_live_p); + defsubr (&Sdisplay_list); + defsubr (&Ssuspend_tty); + defsubr (&Sresume_tty); + + Fprovide (intern ("multi-tty"), Qnil); + } + + /* arch-tag: 498e7449-6f2e-45e2-91dd-b7d4ca488193 (do not change this comment) */ |