X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/af9f81a0de809153d8d39e82417f4cdc72d24f33..65b3d997c854ed75f4557617faeea2e79fc14aac:/src/term.c diff --git a/src/term.c b/src/term.c index d829332f55..78bf77d9d7 100644 --- a/src/term.c +++ b/src/term.c @@ -1,13 +1,14 @@ /* Terminal control module for terminals described by TERMCAP Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1998, 2000, 2001, - 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. This file is part of GNU Emacs. -GNU Emacs is free software; you can redistribute it and/or modify +GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -15,9 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +along with GNU Emacs. If not, see . */ /* New redisplay, TTY faces by Gerd Moellmann . */ @@ -25,12 +24,29 @@ Boston, MA 02110-1301, USA. */ #include #include #include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#if HAVE_TERMIOS_H +#include /* For TIOCNOTTY. */ +#endif + +#include +#include +#include + +#include "lisp.h" #include "termchar.h" #include "termopts.h" -#include "lisp.h" +#include "buffer.h" +#include "character.h" #include "charset.h" #include "coding.h" +#include "composite.h" #include "keyboard.h" #include "frame.h" #include "disptab.h" @@ -39,6 +55,13 @@ Boston, MA 02110-1301, USA. */ #include "window.h" #include "keymap.h" #include "blockinput.h" +#include "syssignal.h" +#include "systty.h" +#include "intervals.h" +#ifdef MSDOS +#include "msdos.h" +static int been_here = -1; +#endif /* For now, don't try to include termcap.h. On some systems, configure finds a non-standard termcap.h that the main build @@ -57,244 +80,76 @@ extern int tgetnum P_ ((char *id)); #ifdef HAVE_X_WINDOWS #include "xterm.h" #endif -#ifdef MAC_OS -#include "macterm.h" + +#ifndef O_RDWR +#define O_RDWR 2 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +/* The name of the default console device. */ +#ifdef WINDOWSNT +#define DEV_TTY "CONOUT$" +#else +#define DEV_TTY "/dev/tty" #endif +static void tty_set_scroll_region P_ ((struct frame *f, int start, int stop)); static void turn_on_face P_ ((struct frame *, int face_id)); static void turn_off_face P_ ((struct frame *, int face_id)); -static void tty_show_cursor P_ ((void)); -static void tty_hide_cursor P_ ((void)); - -#define 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) +static void tty_show_cursor P_ ((struct tty_display_info *)); +static void tty_hide_cursor P_ ((struct tty_display_info *)); +static void tty_background_highlight P_ ((struct tty_display_info *tty)); +static void clear_tty_hooks P_ ((struct terminal *terminal)); +static void set_tty_hooks P_ ((struct terminal *terminal)); +static void dissociate_if_controlling_tty P_ ((int fd)); +static void delete_tty P_ ((struct terminal *)); + +#define OUTPUT(tty, a) \ + emacs_tputs ((tty), a, \ + (int) (FRAME_LINES (XFRAME (selected_frame)) \ + - curY (tty)), \ + cmputc) + +#define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc) +#define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc) + +#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) -#define OUTPUT_IF(a) \ - do { \ - if (a) \ - tputs (a, (int) (FRAME_LINES (XFRAME (selected_frame)) \ - - curY), cmputc); \ - } while (0) +/* If true, use "vs", otherwise use "ve" to make the cursor visible. */ -#define OUTPUT1_IF(a) do { if (a) tputs (a, 1, cmputc); } while (0) +static int visible_cursor; /* Display space properties */ extern Lisp_Object Qspace, QCalign_to, QCwidth; -/* Function to use to ring the bell. */ - -Lisp_Object Vring_bell_function; - -/* If true, use "vs", otherwise use "ve" to make the cursor visible. */ - -static int visible_cursor; - -/* Terminal characteristics that higher levels want to look at. - These are all extern'd in termchar.h */ +/* Functions to call after suspending a tty. */ +Lisp_Object Vsuspend_tty_functions; -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 resuming a tty. */ +Lisp_Object Vresume_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 */ - -/* 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 tty device parameters. */ +struct tty_display_info *tty_list; +/* Nonzero means no need to redraw the entire frame on resuming a + suspended Emacs. This is useful on terminals with multiple + pages, where one page is used for Emacs and another for all + else. */ int no_redraw_on_reenter; -/* Hook functions that you can set to snap out the functions in this file. - These are all extern'd in termhooks.h */ - -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. - - 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)); - -/* If the value of the frame parameter changed, whis hook is called. - For example, if going from fullscreen to not fullscreen this hook - may do something OS dependent, like extended window manager hints on X11. */ -void (*fullscreen_hook) P_ ((struct frame *f)); - -/* 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. */ @@ -311,68 +166,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. */ @@ -383,235 +176,209 @@ 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; - -/* Frame currently being redisplayed; 0 if not currently redisplaying. - (Direct output does not count). */ - -FRAME_PTR updating_frame; +/* Non-zero if we have dropped our controlling tty and therefore + should not open a frame on stdout. */ +static int no_controlling_tty; /* 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 (); -#ifdef WINDOWSNT -/* We aren't X windows, but we aren't termcap either. This makes me - uncertain as to what value to use for frame.output_method. For - this file, we'll define FRAME_TERMCAP_P to be zero so that our - output hooks get called instead of the termcap functions. Probably - the best long-term solution is to define an output_windows_nt... */ +#ifdef HAVE_GPM +#include -#undef FRAME_TERMCAP_P -#define FRAME_TERMCAP_P(_f_) 0 -#endif /* WINDOWSNT */ +static void term_clear_mouse_face (); +static void term_mouse_highlight (struct frame *f, int x, int y); -void -ring_bell () -{ - if (!NILP (Vring_bell_function)) - { - Lisp_Object function; +/* The device for which we have enabled gpm support (or NULL). */ +struct tty_display_info *gpm_tty = NULL; - /* Temporarily set the global variable to nil - so that if we get an error, it stays nil - and we don't call it over and over. +/* These variables describe the range of text currently shown in its + mouse-face, together with the window they apply to. As long as + the mouse stays within this range, we need not redraw anything on + its account. Rows and columns are glyph matrix positions in + MOUSE_FACE_WINDOW. */ +static int mouse_face_beg_row, mouse_face_beg_col; +static int mouse_face_end_row, mouse_face_end_col; +static int mouse_face_past_end; +static Lisp_Object mouse_face_window; +static int mouse_face_face_id; - We don't specbind it, because that would carefully - restore the bad value if there's an error - and make the loop of errors happen anyway. */ +static int pos_x, pos_y; +static int last_mouse_x, last_mouse_y; +#endif /* HAVE_GPM */ - function = Vring_bell_function; - Vring_bell_function = Qnil; +/* Ring the bell on a tty. */ - call0 (function); +static void +tty_ring_bell (struct frame *f) +{ + struct tty_display_info *tty = FRAME_TTY (f); - Vring_bell_function = function; + if (tty->output) + { + OUTPUT (tty, (tty->TS_visible_bell && visible_bell + ? tty->TS_visible_bell + : tty->TS_bell)); + fflush (tty->output); } - else if (!FRAME_TERMCAP_P (XFRAME (selected_frame))) - (*ring_bell_hook) (); - else - OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell); } +/* Set up termcap modes for Emacs. */ + void -set_terminal_modes () +tty_set_terminal_modes (struct terminal *terminal) { - if (FRAME_TERMCAP_P (XFRAME (selected_frame))) + struct tty_display_info *tty = terminal->display_info.tty; + + if (tty->output) { - if (TS_termcap_modes) - OUTPUT (TS_termcap_modes); + 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; - for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++) - putchar ('\n'); - } - - OUTPUT_IF (visible_cursor ? TS_cursor_visible : TS_cursor_normal); - OUTPUT_IF (TS_keypad_mode); - losecursor (); + { + /* 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, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal); + 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 terminal *terminal) { - if (FRAME_TERMCAP_P (XFRAME (selected_frame))) + struct tty_display_info *tty = terminal->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); + tty_turn_off_highlight (tty); + 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; -{ - updating_frame = f; - if (!FRAME_TERMCAP_P (f)) - update_begin_hook (f); -} +/* Flag the end of a display update on a termcap terminal. */ -void -update_end (f) - struct frame *f; +static void +tty_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); + struct tty_display_info *tty = FRAME_TTY (f); - updating_frame = NULL; + if (!XWINDOW (selected_window)->cursor_off_p) + tty_show_cursor (tty); + tty_turn_off_insert (tty); + tty_background_highlight (tty); } -void -set_terminal_window (size) - int size; +/* The implementation of set_terminal_window for termcap frames. */ + +static void +tty_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); + struct tty_display_info *tty = FRAME_TTY (f); + + tty->specified_window = size ? size : FRAME_LINES (f); + if (FRAME_SCROLL_REGION_OK (f)) + tty_set_scroll_region (f, 0, tty->specified_window); } -void -set_scroll_region (start, stop) - int start, stop; +static void +tty_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 () +tty_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 () +tty_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 () +tty_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 () +tty_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 () +tty_toggle_highlight (struct tty_display_info *tty) { - if (standout_mode) - turn_off_highlight (); + if (tty->standout_mode) + tty_turn_off_highlight (tty); else - turn_on_highlight (); + tty_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); } } @@ -619,14 +386,14 @@ 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); + tty->cursor_hidden = 0; + OUTPUT_IF (tty, tty->TS_cursor_normal); if (visible_cursor) - OUTPUT_IF (TS_cursor_visible); + OUTPUT_IF (tty, tty->TS_cursor_visible); } } @@ -635,187 +402,160 @@ tty_show_cursor () empty space inside windows. What this is, depends on the user option inverse-video. */ -void -background_highlight () +static void +tty_background_highlight (struct tty_display_info *tty) { if (inverse_video) - turn_on_highlight (); + tty_turn_on_highlight (tty); else - turn_off_highlight (); + tty_turn_off_highlight (tty); } /* Set standout mode to the mode specified for the text to be output. */ static void -highlight_if_desired () +tty_highlight_if_desired (struct tty_display_info *tty) { if (inverse_video) - turn_on_highlight (); + tty_turn_on_highlight (tty); else - turn_off_highlight (); + tty_turn_off_highlight (tty); } /* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are frame-relative coordinates. */ -void -cursor_to (vpos, hpos) - int vpos, hpos; +static void +tty_cursor_to (struct frame *f, int vpos, int hpos) { - struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame); - - if (! FRAME_TERMCAP_P (f) && cursor_to_hook) - { - (*cursor_to_hook) (vpos, hpos); - return; - } + 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) + tty_background_highlight (tty); + if (!tty->TF_insmode_motion) + tty_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; +static void +tty_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) + 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) + tty_background_highlight (tty); + if (!tty->TF_insmode_motion) + tty_turn_off_insert (tty); + cmgoto (tty, row, col); } /* Erase operations */ -/* clear from cursor to end of frame */ -void -clear_to_end () +/* Clear from cursor to end of frame on a termcap device. */ + +static 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)) - { - (*clear_to_end_hook) (); - return; - } - if (TS_clr_to_bottom) + if (tty->TS_clr_to_bottom) { - background_highlight (); - OUTPUT (TS_clr_to_bottom); + tty_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)); } } } -/* Clear entire frame */ +/* Clear an entire termcap frame. */ -void -clear_frame () +static 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))) + if (tty->TS_clr_frame) { - (*clear_frame_hook) (); - return; - } - if (TS_clr_frame) - { - background_highlight (); - OUTPUT (TS_clr_frame); - cmat (0, 0); + tty_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); } } -/* Clear from cursor to end of line. - Assume that the line is already clear starting at column first_unused_hpos. +/* An implementation of clear_end_of_line for termcap frames. 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; +static void +tty_clear_end_of_line (struct frame *f, int first_unused_hpos) { register int i; - - 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; - } + 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) + tty_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 (); + tty_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)); } } -/* Buffer to store the source and result of code conversion for terminal. */ -static unsigned char *encode_terminal_buf; -/* Allocated size of the above buffer. */ -static int encode_terminal_bufsize; +/* Buffers to store the source and result of code conversion for terminal. */ +static unsigned char *encode_terminal_src; +static unsigned char *encode_terminal_dst; +/* Allocated sizes of the above buffers. */ +static int encode_terminal_src_size; +static int encode_terminal_dst_size; /* Encode SRC_LEN glyphs starting at SRC to terminal output codes. Set CODING->produced to the byte-length of the resulting byte @@ -828,42 +568,106 @@ encode_terminal_code (src, src_len, coding) struct coding_system *coding; { struct glyph *src_end = src + src_len; - register GLYPH g; unsigned char *buf; int nchars, nbytes, required; register int tlen = GLYPH_TABLE_LENGTH; register Lisp_Object *tbase = GLYPH_TABLE_BASE; + Lisp_Object charset_list; /* Allocate sufficient size of buffer to store all characters in multibyte-form. But, it may be enlarged on demand if - Vglyph_table contains a string. */ + Vglyph_table contains a string or a composite glyph is + encountered. */ required = MAX_MULTIBYTE_LENGTH * src_len; - if (encode_terminal_bufsize < required) + if (encode_terminal_src_size < required) { - if (encode_terminal_bufsize == 0) - encode_terminal_buf = xmalloc (required); + if (encode_terminal_src) + encode_terminal_src = xrealloc (encode_terminal_src, required); else - encode_terminal_buf = xrealloc (encode_terminal_buf, required); - encode_terminal_bufsize = required; + encode_terminal_src = xmalloc (required); + encode_terminal_src_size = required; } - buf = encode_terminal_buf; + charset_list = coding_charset_list (coding); + + buf = encode_terminal_src; nchars = 0; while (src < src_end) { + if (src->type == COMPOSITE_GLYPH) + { + struct composition *cmp; + Lisp_Object gstring; + int i; + + nbytes = buf - encode_terminal_src; + if (src->u.cmp.automatic) + { + gstring = composition_gstring_from_id (src->u.cmp.id); + required = src->u.cmp.to + 1 - src->u.cmp.from; + } + else + { + cmp = composition_table[src->u.cmp.id]; + required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len; + } + + if (encode_terminal_src_size < nbytes + required) + { + encode_terminal_src_size = nbytes + required; + encode_terminal_src = xrealloc (encode_terminal_src, + encode_terminal_src_size); + buf = encode_terminal_src + nbytes; + } + + if (src->u.cmp.automatic) + for (i = src->u.cmp.from; i <= src->u.cmp.to; i++) + { + Lisp_Object g = LGSTRING_GLYPH (gstring, i); + int c = LGLYPH_CHAR (g); + + if (! char_charset (c, charset_list, NULL)) + c = '?'; + buf += CHAR_STRING (c, buf); + nchars++; + } + else + for (i = 0; i < cmp->glyph_len; i++) + { + int c = COMPOSITION_GLYPH (cmp, i); + + if (c == '\t') + continue; + if (char_charset (c, charset_list, NULL)) + { + if (CHAR_WIDTH (c) == 0 + && i > 0 && COMPOSITION_GLYPH (cmp, i - 1) == '\t') + /* Should be left-padded */ + { + buf += CHAR_STRING (' ', buf); + nchars++; + } + } + else + c = '?'; + buf += CHAR_STRING (c, buf); + nchars++; + } + } /* We must skip glyphs to be padded for a wide character. */ - if (! CHAR_GLYPH_PADDING_P (*src)) + else if (! CHAR_GLYPH_PADDING_P (*src)) { - g = GLYPH_FROM_CHAR_GLYPH (src[0]); + GLYPH g; + int c; + Lisp_Object string; - if (g < 0 || g >= tlen) + string = Qnil; + SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]); + + if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g)) { - /* This glyph doesn't has an entry in Vglyph_table. */ - if (CHAR_VALID_P (src->u.ch, 0)) - buf += CHAR_STRING (src->u.ch, buf); - else - *buf++ = SPACEGLYPH; - nchars++; + /* This glyph doesn't have an entry in Vglyph_table. */ + c = src->u.ch; } else { @@ -872,101 +676,125 @@ encode_terminal_code (src, src_len, coding) GLYPH_FOLLOW_ALIASES (tbase, tlen, g); if (GLYPH_SIMPLE_P (tbase, tlen, g)) - { - int c = FAST_GLYPH_CHAR (g); + /* We set the multi-byte form of a character in G + (that should be an ASCII character) at WORKBUF. */ + c = GLYPH_CHAR (g); + else + /* We have a string in Vglyph_table. */ + string = tbase[GLYPH_CHAR (g)]; + } - if (CHAR_VALID_P (c, 0)) - buf += CHAR_STRING (c, buf); - else - *buf++ = SPACEGLYPH; + if (NILP (string)) + { + nbytes = buf - encode_terminal_src; + if (encode_terminal_src_size < nbytes + MAX_MULTIBYTE_LENGTH) + { + encode_terminal_src_size = nbytes + MAX_MULTIBYTE_LENGTH; + encode_terminal_src = xrealloc (encode_terminal_src, + encode_terminal_src_size); + buf = encode_terminal_src + nbytes; + } + if (CHAR_BYTE8_P (c) + || char_charset (c, charset_list, NULL)) + { + /* Store the multibyte form of C at BUF. */ + buf += CHAR_STRING (c, buf); nchars++; } else { - /* We have a string in Vglyph_table. */ - Lisp_Object string; - - string = tbase[g]; - if (! STRING_MULTIBYTE (string)) - string = string_to_multibyte (string); - nbytes = buf - encode_terminal_buf; - if (encode_terminal_bufsize < nbytes + SBYTES (string)) + /* C is not encodable. */ + *buf++ = '?'; + nchars++; + while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1])) { - encode_terminal_bufsize = nbytes + SBYTES (string); - encode_terminal_buf = xrealloc (encode_terminal_buf, - encode_terminal_bufsize); - buf = encode_terminal_buf + nbytes; + *buf++ = '?'; + nchars++; + src++; } - bcopy (SDATA (string), buf, SBYTES (string)); - buf += SBYTES (string); - nchars += SCHARS (string); } } + else + { + unsigned char *p = SDATA (string), *pend = p + SBYTES (string); + + if (! STRING_MULTIBYTE (string)) + string = string_to_multibyte (string); + nbytes = buf - encode_terminal_src; + if (encode_terminal_src_size < nbytes + SBYTES (string)) + { + encode_terminal_src_size = nbytes + SBYTES (string); + encode_terminal_src = xrealloc (encode_terminal_src, + encode_terminal_src_size); + buf = encode_terminal_src + nbytes; + } + bcopy (SDATA (string), buf, SBYTES (string)); + buf += SBYTES (string); + nchars += SCHARS (string); + } } src++; } - nbytes = buf - encode_terminal_buf; - coding->src_multibyte = 1; - coding->dst_multibyte = 0; - if (SYMBOLP (coding->pre_write_conversion) - && ! NILP (Ffboundp (coding->pre_write_conversion))) + if (nchars == 0) { - run_pre_write_conversin_on_c_str (&encode_terminal_buf, - &encode_terminal_bufsize, - nchars, nbytes, coding); - nchars = coding->produced_char; - nbytes = coding->produced; + coding->produced = 0; + return NULL; } - required = nbytes + encoding_buffer_size (coding, nbytes); - if (encode_terminal_bufsize < required) + + nbytes = buf - encode_terminal_src; + coding->source = encode_terminal_src; + if (encode_terminal_dst_size == 0) { - encode_terminal_bufsize = required; - encode_terminal_buf = xrealloc (encode_terminal_buf, required); + encode_terminal_dst_size = encode_terminal_src_size; + if (encode_terminal_dst) + encode_terminal_dst = xrealloc (encode_terminal_dst, + encode_terminal_dst_size); + else + encode_terminal_dst = xmalloc (encode_terminal_dst_size); } + coding->destination = encode_terminal_dst; + coding->dst_bytes = encode_terminal_dst_size; + encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil); + /* coding->destination may have been reallocated. */ + encode_terminal_dst = coding->destination; + encode_terminal_dst_size = coding->dst_bytes; - encode_coding (coding, encode_terminal_buf, encode_terminal_buf + nbytes, - nbytes, encode_terminal_bufsize - nbytes); - return encode_terminal_buf + nbytes; + return (encode_terminal_dst); } -void -write_glyphs (string, len) - register struct glyph *string; - register int len; + + +/* An implementation of write_glyphs for termcap frames. */ + +static void +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 (); + tty_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; @@ -982,7 +810,7 @@ write_glyphs (string, len) break; /* Turn appearance modes of the face of the run on. */ - highlight_if_desired (); + tty_highlight_if_desired (tty); turn_on_face (f, face_id); if (n == len) @@ -992,11 +820,11 @@ write_glyphs (string, len) if (coding->produced > 0) { BLOCK_INPUT; - 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); UNBLOCK_INPUT; } len -= n; @@ -1004,50 +832,99 @@ write_glyphs (string, len) /* Turn appearance modes off. */ turn_off_face (f, face_id); - turn_off_highlight (); + tty_turn_off_highlight (tty); } - cmcheckmagic (); + cmcheckmagic (tty); } -/* If start is zero, insert blanks instead of a string at start */ +#ifdef HAVE_GPM /* Only used by GPM code. */ -void -insert_glyphs (start, len) - register struct glyph *start; - register int len; +static void +tty_write_glyphs_with_face (f, string, len, face_id) + register struct frame *f; + register struct glyph *string; + register int len, face_id; { - char *buf; - struct glyph *glyph = NULL; - struct frame *f, *sf; unsigned char *conversion_buffer; - unsigned char space[1]; struct coding_system *coding; + struct tty_display_info *tty = FRAME_TTY (f); + + tty_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 (tty) + && curY (tty) + 1 == FRAME_LINES (f) + && (curX (tty) + len) == FRAME_COLS (f)) + len --; if (len <= 0) return; - if (insert_glyphs_hook) + 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 = (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; + + /* Turn appearance modes of the face. */ + tty_highlight_if_desired (tty); + turn_on_face (f, face_id); + + coding->mode |= CODING_MODE_LAST_BLOCK; + conversion_buffer = encode_terminal_code (string, len, coding); + if (coding->produced > 0) { - (*insert_glyphs_hook) (start, len); - return; + BLOCK_INPUT; + 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); + UNBLOCK_INPUT; } - sf = XFRAME (selected_frame); - f = updating_frame ? updating_frame : sf; + /* Turn appearance modes off. */ + turn_off_face (f, face_id); + tty_turn_off_highlight (tty); + + cmcheckmagic (tty); +} +#endif + +/* An implementation of insert_glyphs for termcap frames. */ + +static void +tty_insert_glyphs (struct frame *f, struct glyph *start, int len) +{ + char *buf; + struct glyph *glyph = NULL; + unsigned char *conversion_buffer; + unsigned char space[1]; + struct coding_system *coding; + + 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); + tty_turn_on_insert (tty); + cmplus (tty, len); if (! start) space[0] = SPACEGLYPH; @@ -1055,15 +932,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; @@ -1071,7 +948,7 @@ insert_glyphs (start, len) } else { - highlight_if_desired (); + tty_highlight_if_desired (tty); turn_on_face (f, start->face_id); glyph = start; ++start; @@ -1079,7 +956,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--; } @@ -1087,89 +964,77 @@ 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) { BLOCK_INPUT; - 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); UNBLOCK_INPUT; } - 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 (); + tty_turn_off_highlight (tty); } } - cmcheckmagic (); + cmcheckmagic (tty); } -void -delete_glyphs (n) - register int n; +/* An implementation of delete_glyphs for termcap frames. */ + +static void +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 (); + tty_turn_on_insert (tty); } else { - turn_off_insert (); - OUTPUT_IF (TS_delete_mode); + tty_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. */ +/* An implementation of ins_del_lines for termcap frames. */ -void -ins_del_lines (vpos, n) - int vpos, n; +static void +tty_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; + 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; register int i = n > 0 ? n : -n; register char *buf; - if (ins_del_lines_hook && ! FRAME_TERMCAP_P (updating_frame)) - { - (*ins_del_lines_hook) (vpos, n); - return; - } - - sf = XFRAME (selected_frame); - /* If the lines below the insertion are being pushed into the end of the window, this is the same as clearing; and we know the lines are already clear, since the matching @@ -1177,45 +1042,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); + tty_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); + tty_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); + tty_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); + tty_background_highlight (tty); while (--i >= 0) - OUTPUTL (scroll, specified_window - vpos); - set_scroll_region (0, specified_window); + OUTPUTL (tty, scroll, tty->specified_window - vpos); + tty_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); } } @@ -1223,8 +1092,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) @@ -1236,8 +1104,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) @@ -1249,8 +1116,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) @@ -1273,26 +1139,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 { @@ -1300,18 +1166,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 { @@ -1320,75 +1186,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 { @@ -1498,16 +1369,18 @@ 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. +/* Find the escape codes sent by the function keys for Vinput_decode_map. This function scans the termcap function key sequence entries, and - adds entries to Vfunction_key_map for each function key it finds. */ + adds entries to Vinput_decode_map for each function key it finds. */ -void -term_get_fkeys (address) +static void +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 @@ -1518,7 +1391,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); } @@ -1527,17 +1401,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); + if (!KEYMAPP (kboard->Vinput_decode_map)) + kboard->Vinput_decode_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->Vinput_decode_map, build_string (sequence), Fmake_vector (make_number (1), intern (keys[i].name))); } @@ -1557,13 +1432,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->Vinput_decode_map, build_string (k0), Fmake_vector (make_number (1), intern ("f0"))); - Fdefine_key (Vfunction_key_map, build_string (k_semi), + Fdefine_key (kboard->Vinput_decode_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->Vinput_decode_map, build_string (k0), Fmake_vector (make_number (1), intern (k0_name))); } @@ -1586,7 +1461,7 @@ term_get_fkeys_1 () if (sequence) { sprintf (fkey, "f%d", i); - Fdefine_key (Vfunction_key_map, build_string (sequence), + Fdefine_key (kboard->Vinput_decode_map, build_string (sequence), Fmake_vector (make_number (1), intern (fkey))); } @@ -1602,10 +1477,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->Vinput_decode_map, build_string (sequence), \ + Fmake_vector (make_number (1), \ + intern (sym))); \ } /* if there's no key_next keycap, map key_npage to `next' keysym */ @@ -1643,11 +1518,14 @@ term_get_fkeys_1 () #ifdef static #define append_glyph append_glyph_term #define produce_stretch_glyph produce_stretch_glyph_term +#define append_composite_glyph append_composite_glyph_term +#define produce_composite_glyph produce_composite_glyph_term #endif static void append_glyph P_ ((struct it *)); static void produce_stretch_glyph P_ ((struct it *)); - +static void append_composite_glyph P_ ((struct it *)); +static void produce_composite_glyph P_ ((struct it *)); /* Append glyphs to IT's glyph_row. Called from produce_glyphs for terminal frames if IT->glyph_row != NULL. IT->char_to_display is @@ -1690,8 +1568,9 @@ append_glyph (it) and where in the glyph matrix we currently are (glyph row and hpos). produce_glyphs fills in output fields of *IT with information such as the pixel width and height of a character, and maybe output actual glyphs at - the same time if IT->glyph_row is non-null. See the explanation of - struct display_iterator in dispextern.h for an overview. + the same time if IT->glyph_row is non-null. For an overview, see + the explanation in dispextern.h, before the definition of the + display_element_type enumeration. produce_glyphs also stores the result of glyph width, ascent etc. computations in *IT. @@ -1708,6 +1587,8 @@ produce_glyphs (it) struct it *it; { /* If a hook is installed, let it do the work. */ + + /* Nothing but characters are supported on terminal frames. */ xassert (it->what == IT_CHARACTER || it->what == IT_COMPOSITION || it->what == IT_STRETCH); @@ -1718,24 +1599,21 @@ produce_glyphs (it) goto done; } - /* Nothing but characters are supported on terminal frames. For a - composition sequence, it->c is the first character of the - sequence. */ - xassert (it->what == IT_CHARACTER - || it->what == IT_COMPOSITION); - - /* Maybe translate single-byte characters to multibyte. */ - it->char_to_display = it->c; + if (it->what == IT_COMPOSITION) + { + produce_composite_glyph (it); + goto done; + } - if (it->c >= 040 && it->c < 0177) + if (it->char_to_display >= 040 && it->char_to_display < 0177) { it->pixel_width = it->nglyphs = 1; if (it->glyph_row) append_glyph (it); } - else if (it->c == '\n') + else if (it->char_to_display == '\n') it->pixel_width = it->nglyphs = 0; - else if (it->c == '\t') + else if (it->char_to_display == '\t') { int absolute_x = (it->current_x + it->continuation_lines_width); @@ -1766,42 +1644,19 @@ produce_glyphs (it) it->pixel_width = nspaces; it->nglyphs = nspaces; } - else if (SINGLE_BYTE_CHAR_P (it->c)) + else if (CHAR_BYTE8_P (it->char_to_display)) { - if (unibyte_display_via_language_environment - && (it->c >= 0240 - || !NILP (Vnonascii_translation_table))) - { - int charset; - - it->char_to_display = unibyte_char_to_multibyte (it->c); - charset = CHAR_CHARSET (it->char_to_display); - it->pixel_width = CHARSET_WIDTH (charset); - it->nglyphs = it->pixel_width; - if (it->glyph_row) - append_glyph (it); - } - else - { - /* Coming here means that it->c is from display table, thus we - must send the code as is to the terminal. Although there's - no way to know how many columns it occupies on a screen, it - is a good assumption that a single byte code has 1-column - width. */ - it->pixel_width = it->nglyphs = 1; - if (it->glyph_row) - append_glyph (it); - } + /* Coming here means that we must send the raw 8-bit byte as is + to the terminal. Although there's no way to know how many + columns it occupies on a screen, it is a good assumption that + a single byte code has 1-column width. */ + it->pixel_width = it->nglyphs = 1; + if (it->glyph_row) + append_glyph (it); } else { - /* A multi-byte character. The display width is fixed for all - characters of the set. Some of the glyphs may have to be - ignored because they are already displayed in a continued - line. */ - int charset = CHAR_CHARSET (it->c); - - it->pixel_width = CHARSET_WIDTH (charset); + it->pixel_width = CHAR_WIDTH (it->char_to_display); it->nglyphs = it->pixel_width; if (it->glyph_row) @@ -1871,6 +1726,10 @@ produce_stretch_glyph (it) if (width <= 0 && (width < 0 || !zero_width_ok_p)) width = 1; + if (width > 0 && it->line_wrap != TRUNCATE + && it->current_x + width > it->last_visible_x) + width = it->last_visible_x - it->current_x - 1; + if (width > 0 && it->glyph_row) { Lisp_Object o_object = it->object; @@ -1891,6 +1750,78 @@ produce_stretch_glyph (it) } +/* Append glyphs to IT's glyph_row for the composition IT->cmp_id. + Called from produce_composite_glyph for terminal frames if + IT->glyph_row != NULL. IT->face_id contains the character's + face. */ + +static void +append_composite_glyph (it) + struct it *it; +{ + struct glyph *glyph; + + xassert (it->glyph_row); + glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area]; + if (glyph < it->glyph_row->glyphs[1 + it->area]) + { + glyph->type = COMPOSITE_GLYPH; + glyph->pixel_width = it->pixel_width; + glyph->u.cmp.id = it->cmp_it.id; + if (it->cmp_it.ch < 0) + { + glyph->u.cmp.automatic = 0; + glyph->u.cmp.id = it->cmp_it.id; + } + else + { + glyph->u.cmp.automatic = 1; + glyph->u.cmp.id = it->cmp_it.id; + glyph->u.cmp.from = it->cmp_it.from; + glyph->u.cmp.to = it->cmp_it.to - 1; + } + + glyph->face_id = it->face_id; + glyph->padding_p = 0; + glyph->charpos = CHARPOS (it->position); + glyph->object = it->object; + + ++it->glyph_row->used[it->area]; + ++glyph; + } +} + + +/* Produce a composite glyph for iterator IT. IT->cmp_id is the ID of + the composition. We simply produces components of the composition + assuming that the terminal has a capability to layout/render it + correctly. */ + +static void +produce_composite_glyph (it) + struct it *it; +{ + int c; + + if (it->cmp_it.ch < 0) + { + struct composition *cmp = composition_table[it->cmp_it.id]; + + it->pixel_width = cmp->width; + } + else + { + Lisp_Object gstring = composition_gstring_from_id (it->cmp_it.id); + + it->pixel_width = composition_gstring_width (gstring, it->cmp_it.from, + it->cmp_it.to, NULL); + } + it->nglyphs = 1; + if (it->glyph_row) + append_composite_glyph (it); +} + + /* Get information about special display element WHAT in an environment described by IT. WHAT is one of IT_TRUNCATION or IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a @@ -1903,6 +1834,7 @@ produce_special_glyphs (it, what) enum display_element_type what; { struct it temp_it; + Lisp_Object gc; GLYPH glyph; temp_it = *it; @@ -1915,34 +1847,32 @@ produce_special_glyphs (it, what) if (what == IT_CONTINUATION) { /* Continuation glyph. */ + SET_GLYPH_FROM_CHAR (glyph, '\\'); if (it->dp - && INTEGERP (DISP_CONTINUE_GLYPH (it->dp)) - && GLYPH_CHAR_VALID_P (XINT (DISP_CONTINUE_GLYPH (it->dp)))) + && (gc = DISP_CONTINUE_GLYPH (it->dp), GLYPH_CODE_P (gc)) + && GLYPH_CODE_CHAR_VALID_P (gc)) { - glyph = XINT (DISP_CONTINUE_GLYPH (it->dp)); - glyph = spec_glyph_lookup_face (XWINDOW (it->window), glyph); + SET_GLYPH_FROM_GLYPH_CODE (glyph, gc); + spec_glyph_lookup_face (XWINDOW (it->window), &glyph); } - else - glyph = '\\'; } else if (what == IT_TRUNCATION) { /* Truncation glyph. */ + SET_GLYPH_FROM_CHAR (glyph, '$'); if (it->dp - && INTEGERP (DISP_TRUNC_GLYPH (it->dp)) - && GLYPH_CHAR_VALID_P (XINT (DISP_TRUNC_GLYPH (it->dp)))) + && (gc = DISP_TRUNC_GLYPH (it->dp), GLYPH_CODE_P (gc)) + && GLYPH_CODE_CHAR_VALID_P (gc)) { - glyph = XINT (DISP_TRUNC_GLYPH (it->dp)); - glyph = spec_glyph_lookup_face (XWINDOW (it->window), glyph); + SET_GLYPH_FROM_GLYPH_CODE (glyph, gc); + spec_glyph_lookup_face (XWINDOW (it->window), &glyph); } - else - glyph = '$'; } else abort (); - temp_it.c = FAST_GLYPH_CHAR (glyph); - temp_it.face_id = FAST_GLYPH_FACE (glyph); + temp_it.c = temp_it.char_to_display = GLYPH_CHAR (glyph); + temp_it.face_id = GLYPH_FACE (glyph); temp_it.len = CHAR_BYTES (temp_it.c); produce_glyphs (&temp_it); @@ -1961,10 +1891,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. */ @@ -1977,12 +1907,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) { @@ -1996,13 +1927,13 @@ turn_on_face (f, face_id) { if (fg == FACE_TTY_DEFAULT_FG_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR) - toggle_highlight (); + tty_toggle_highlight (tty); } else { if (fg == FACE_TTY_DEFAULT_BG_COLOR || bg == FACE_TTY_DEFAULT_FG_COLOR) - toggle_highlight (); + tty_toggle_highlight (tty); } } else @@ -2013,55 +1944,52 @@ turn_on_face (f, face_id) { if (fg == FACE_TTY_DEFAULT_FG_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR) - toggle_highlight (); + tty_toggle_highlight (tty); } else { if (fg == FACE_TTY_DEFAULT_BG_COLOR || bg == FACE_TTY_DEFAULT_FG_COLOR) - toggle_highlight (); + tty_toggle_highlight (tty); } } } - if (face->tty_bold_p) - { - if (MAY_USE_WITH_COLORS_P (NC_BOLD)) - OUTPUT1_IF (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 (face->tty_bold_p && MAY_USE_WITH_COLORS_P (tty, NC_BOLD)) + OUTPUT1_IF (tty, tty->TS_enter_bold_mode); + + if (face->tty_dim_p && 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); } } @@ -2076,10 +2004,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 @@ -2091,32 +2020,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); } @@ -2125,49 +2054,64 @@ 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 tty device TERMINAL can display colors. + +TERMINAL can be a terminal object, a frame, or nil (meaning the +selected frame's terminal). This function always returns nil if +TERMINAL does not refer to a text-only terminal. */) + (terminal) + Lisp_Object terminal; { - return TN_max_colors > 0 ? Qt : Qnil; + struct terminal *t = get_tty_terminal (terminal, 0); + if (!t) + return Qnil; + else + return t->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 TERMINAL. + +TERMINAL can be a terminal object, a frame, or nil (meaning the +selected frame's terminal). This function always returns 0 if +TERMINAL does not refer to a text-only terminal. */) + (terminal) + Lisp_Object terminal; { - return make_number (TN_max_colors); + struct terminal *t = get_tty_terminal (terminal, 0); + if (!t) + return make_number (0); + else + return make_number (t->display_info.tty->TN_max_colors); } -#ifndef WINDOWSNT +#ifndef DOS_NT /* Declare here rather than in the function, as in the rest of Emacs, to work around an HPUX compiler bug (?). See @@ -2182,48 +2126,43 @@ static char *default_set_background; /* 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) { if (save) { - if (default_orig_pair) - xfree (default_orig_pair); - default_orig_pair = TS_orig_pair ? xstrdup (TS_orig_pair) : NULL; + xfree (default_orig_pair); + 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) + xfree (default_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) + xfree (default_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. */ -void -tty_setup_colors (mode) - int mode; + we saw at init_tty time; -1 means turn off color support. */ +static void +tty_setup_colors (struct tty_display_info *tty, int mode) { /* Canonicalize all negative values of MODE. */ if (mode < -1) @@ -2232,390 +2171,1621 @@ 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; } } void -set_tty_color_mode (f, val) +set_tty_color_mode (tty, f) + struct tty_display_info *tty; struct frame *f; - Lisp_Object val; { - Lisp_Object color_mode_spec, current_mode_spec; - Lisp_Object color_mode, current_mode; - int mode, old_mode; + Lisp_Object tem, val, color_mode_spec; + Lisp_Object color_mode; + int mode; extern Lisp_Object Qtty_color_mode; - Lisp_Object tty_color_mode_alist; + Lisp_Object tty_color_mode_alist + = Fintern_soft (build_string ("tty-color-mode-alist"), Qnil); - tty_color_mode_alist = Fintern_soft (build_string ("tty-color-mode-alist"), - Qnil); + tem = assq_no_quit (Qtty_color_mode, f->param_alist); + val = CONSP (tem) ? XCDR (tem) : Qnil; if (INTEGERP (val)) color_mode = val; else { - if (NILP (tty_color_mode_alist)) - color_mode_spec = Qnil; - else - color_mode_spec = Fassq (val, XSYMBOL (tty_color_mode_alist)->value); + tem = (NILP (tty_color_mode_alist) ? Qnil + : Fassq (val, XSYMBOL (tty_color_mode_alist)->value)); + color_mode = CONSP (tem) ? XCDR (tem) : Qnil; + } + + mode = INTEGERP (color_mode) ? XINT (color_mode) : 0; + + if (mode != tty->previous_color_mode) + { + Lisp_Object funsym = intern ("tty-set-up-initial-frame-faces"); + tty->previous_color_mode = mode; + tty_setup_colors (tty , mode); + /* This recomputes all the faces given the new color definitions. */ + safe_call (1, &funsym); + } +} + +#endif /* !DOS_NT */ + + - if (CONSP (color_mode_spec)) - color_mode = XCDR (color_mode_spec); +/* Return the tty display object specified by TERMINAL. */ + +struct terminal * +get_tty_terminal (Lisp_Object terminal, int throw) +{ + struct terminal *t = get_terminal (terminal, throw); + + if (t && t->type != output_termcap && t->type != output_msdos_raw) + { + if (throw) + error ("Device %d is not a termcap terminal device", t->id); else - color_mode = Qnil; + return NULL; } - current_mode_spec = assq_no_quit (Qtty_color_mode, f->param_alist); + return t; +} + +/* Return an active termcap device that uses the tty device with the + given name. + + This function ignores suspended devices. + + Returns NULL if the named terminal device is not opened. */ - if (CONSP (current_mode_spec)) - current_mode = XCDR (current_mode_spec); +struct terminal * +get_named_tty (name) + char *name; +{ + struct terminal *t; + + if (!name) + abort (); + + for (t = terminal_list; t; t = t->next_terminal) + { + if ((t->type == output_termcap || t->type == output_msdos_raw) + && !strcmp (t->display_info.tty->name, name) + && TERMINAL_ACTIVE_P (t)) + return t; + } + + return 0; +} + + +DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0, + doc: /* Return the type of the tty device that TERMINAL uses. +Returns nil if TERMINAL is not on a tty device. + +TERMINAL can be a terminal object, a frame, or nil (meaning the +selected frame's terminal). */) + (terminal) + Lisp_Object terminal; +{ + struct terminal *t = get_terminal (terminal, 1); + + if (t->type != output_termcap && t->type != output_msdos_raw) + return Qnil; + + if (t->display_info.tty->type) + return build_string (t->display_info.tty->type); else - current_mode = Qnil; - if (INTEGERP (color_mode)) - mode = XINT (color_mode); + return Qnil; +} + +DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0, + doc: /* Return non-nil if TERMINAL is the controlling tty of the Emacs process. + +TERMINAL can be a terminal object, a frame, or nil (meaning the +selected frame's terminal). This function always returns nil if +TERMINAL is not on a tty device. */) + (terminal) + Lisp_Object terminal; +{ + struct terminal *t = get_terminal (terminal, 1); + + if ((t->type != output_termcap && t->type != output_msdos_raw) + || strcmp (t->display_info.tty->name, DEV_TTY) != 0) + return Qnil; else - mode = 0; /* meaning default */ - if (INTEGERP (current_mode)) - old_mode = XINT (current_mode); + return Qt; +} + +DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0, + doc: /* Declare that the tty used by 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. This function has +no effect if used on a non-tty terminal. + +TERMINAL can be a terminal object, a frame or nil (meaning the +selected frame's terminal). This function always returns nil if +TERMINAL does not refer to a text-only terminal. */) + (terminal) + Lisp_Object terminal; +{ + struct terminal *t = get_terminal (terminal, 1); + + if (t->type == output_termcap) + t->display_info.tty->TS_enter_underline_mode = 0; + return Qnil; +} + + + +DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0, + doc: /* Suspend the terminal device TTY. + +The device is restored to its default state, and Emacs ceases all +access to the tty 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 terminal object, a frame, or nil for the terminal 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 +terminal device. + +`suspend-tty' does nothing if it is called on a device that is already +suspended. + +A suspended tty may be resumed by calling `resume-tty' on it. */) + (tty) + Lisp_Object tty; +{ + struct terminal *t = get_tty_terminal (tty, 1); + FILE *f; + + if (!t) + error ("Unknown tty device"); + + f = t->display_info.tty->input; + + if (f) + { + /* First run `suspend-tty-functions' and then clean up the tty + state because `suspend-tty-functions' might need to change + the tty state. */ + if (!NILP (Vrun_hooks)) + { + Lisp_Object args[2]; + args[0] = intern ("suspend-tty-functions"); + XSETTERMINAL (args[1], t); + Frun_hook_with_args (2, args); + } + + reset_sys_modes (t->display_info.tty); + +#ifdef subprocesses + delete_keyboard_wait_descriptor (fileno (f)); +#endif + +#ifndef MSDOS + fclose (f); + if (f != t->display_info.tty->output) + fclose (t->display_info.tty->output); +#endif + + t->display_info.tty->input = 0; + t->display_info.tty->output = 0; + + if (FRAMEP (t->display_info.tty->top_frame)) + FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0); + + } + + /* Clear display hooks to prevent further output. */ + clear_tty_hooks (t); + + 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 terminal are revived. + +It is an error to resume a terminal while another terminal is active +on the same device. + +This function runs `resume-tty-functions' after resuming the terminal. +The functions are run with one arg, the id of the resumed terminal +device. + +`resume-tty' does nothing if it is called on a device that is not +suspended. + +TTY may be a terminal object, a frame, or nil (meaning the selected +frame's terminal). */) + (tty) + Lisp_Object tty; +{ + struct terminal *t = get_tty_terminal (tty, 1); + int fd; + + if (!t) + error ("Unknown tty device"); + + if (!t->display_info.tty->input) + { + if (get_named_tty (t->display_info.tty->name)) + error ("Cannot resume display while another display is active on the same device"); + +#ifdef MSDOS + t->display_info.tty->output = stdout; + t->display_info.tty->input = stdin; +#else /* !MSDOS */ + fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0); + + if (fd == -1) + error ("Can not reopen tty device %s: %s", t->display_info.tty->name, strerror (errno)); + + if (strcmp (t->display_info.tty->name, DEV_TTY)) + dissociate_if_controlling_tty (fd); + + t->display_info.tty->output = fdopen (fd, "w+"); + t->display_info.tty->input = t->display_info.tty->output; +#endif + +#ifdef subprocesses + add_keyboard_wait_descriptor (fd); +#endif + + if (FRAMEP (t->display_info.tty->top_frame)) + { + struct frame *f = XFRAME (t->display_info.tty->top_frame); + int width, height; + int old_height = FRAME_COLS (f); + int old_width = FRAME_LINES (f); + + /* Check if terminal/window size has changed while the frame + was suspended. */ + get_tty_size (fileno (t->display_info.tty->input), &width, &height); + if (width != old_width || height != old_height) + change_frame_size (f, height, width, 0, 0, 0); + FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1); + } + + init_sys_modes (t->display_info.tty); + + /* Run `resume-tty-functions'. */ + if (!NILP (Vrun_hooks)) + { + Lisp_Object args[2]; + args[0] = intern ("resume-tty-functions"); + XSETTERMINAL (args[1], t); + Frun_hook_with_args (2, args); + } + } + + set_tty_hooks (t); + + return Qnil; +} + + +/*********************************************************************** + Mouse + ***********************************************************************/ + +#ifdef HAVE_GPM +void +term_mouse_moveto (int x, int y) +{ + /* TODO: how to set mouse position? + const char *name; + int fd; + name = (const char *) ttyname (0); + fd = open (name, O_WRONLY); + SOME_FUNCTION (x, y, fd); + close (fd); + last_mouse_x = x; + last_mouse_y = y; */ +} + +static void +term_show_mouse_face (enum draw_glyphs_face draw) +{ + struct window *w = XWINDOW (mouse_face_window); + int save_x, save_y; + int i; + + struct frame *f = XFRAME (w->frame); + struct tty_display_info *tty = FRAME_TTY (f); + + if (/* If window is in the process of being destroyed, don't bother + to do anything. */ + w->current_matrix != NULL + /* Recognize when we are called to operate on rows that don't exist + anymore. This can happen when a window is split. */ + && mouse_face_end_row < w->current_matrix->nrows) + { + /* write_glyphs writes at cursor position, so we need to + temporarily move cursor coordinates to the beginning of + the highlight region. */ + + /* Save current cursor co-ordinates */ + save_y = curY (tty); + save_x = curX (tty); + + /* Note that mouse_face_beg_row etc. are window relative. */ + for (i = mouse_face_beg_row; i <= mouse_face_end_row; i++) + { + int start_hpos, end_hpos, nglyphs; + struct glyph_row *row = MATRIX_ROW (w->current_matrix, i); + + /* Don't do anything if row doesn't have valid contents. */ + if (!row->enabled_p) + continue; + + /* For all but the first row, the highlight starts at column 0. */ + if (i == mouse_face_beg_row) + start_hpos = mouse_face_beg_col; + else + start_hpos = 0; + + if (i == mouse_face_end_row) + end_hpos = mouse_face_end_col; + else + { + end_hpos = row->used[TEXT_AREA]; + if (draw == DRAW_NORMAL_TEXT) + row->fill_line_p = 1; /* Clear to end of line */ + } + + if (end_hpos <= start_hpos) + continue; + /* Record that some glyphs of this row are displayed in + mouse-face. */ + row->mouse_face_p = draw > 0; + + nglyphs = end_hpos - start_hpos; + + if (end_hpos >= row->used[TEXT_AREA]) + nglyphs = row->used[TEXT_AREA] - start_hpos; + + pos_y = row->y + WINDOW_TOP_EDGE_Y (w); + pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + + WINDOW_LEFT_EDGE_X (w); + + cursor_to (f, pos_y, pos_x); + + if (draw == DRAW_MOUSE_FACE) + { + tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos, + nglyphs, mouse_face_face_id); + } + else /* draw == DRAW_NORMAL_TEXT */ + write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs); + } + cursor_to (f, save_y, save_x); + } +} + +static void +term_clear_mouse_face () +{ + if (!NILP (mouse_face_window)) + term_show_mouse_face (DRAW_NORMAL_TEXT); + + mouse_face_beg_row = mouse_face_beg_col = -1; + mouse_face_end_row = mouse_face_end_col = -1; + mouse_face_window = Qnil; +} + +/* Find the glyph matrix position of buffer position POS in window W. + *HPOS and *VPOS are set to the positions found. W's current glyphs + must be up to date. If POS is above window start return (0, 0). + If POS is after end of W, return end of last line in W. + - taken from msdos.c */ +static int +fast_find_position (struct window *w, int pos, int *hpos, int *vpos) +{ + int i, lastcol, line_start_position, maybe_next_line_p = 0; + int yb = window_text_bottom_y (w); + struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row; + + while (row->y < yb) + { + if (row->used[TEXT_AREA]) + line_start_position = row->glyphs[TEXT_AREA]->charpos; + else + line_start_position = 0; + + if (line_start_position > pos) + break; + /* If the position sought is the end of the buffer, + don't include the blank lines at the bottom of the window. */ + else if (line_start_position == pos + && pos == BUF_ZV (XBUFFER (w->buffer))) + { + maybe_next_line_p = 1; + break; + } + else if (line_start_position > 0) + best_row = row; + + /* Don't overstep the last matrix row, lest we get into the + never-never land... */ + if (row->y + 1 >= yb) + break; + + ++row; + } + + /* Find the right column within BEST_ROW. */ + lastcol = 0; + row = best_row; + for (i = 0; i < row->used[TEXT_AREA]; i++) + { + struct glyph *glyph = row->glyphs[TEXT_AREA] + i; + int charpos; + + charpos = glyph->charpos; + if (charpos == pos) + { + *hpos = i; + *vpos = row->y; + return 1; + } + else if (charpos > pos) + break; + else if (charpos > 0) + lastcol = i; + } + + /* If we're looking for the end of the buffer, + and we didn't find it in the line we scanned, + use the start of the following line. */ + if (maybe_next_line_p) + { + ++row; + lastcol = 0; + } + + *vpos = row->y; + *hpos = lastcol + 1; + return 0; +} + +static void +term_mouse_highlight (struct frame *f, int x, int y) +{ + enum window_part part; + Lisp_Object window; + struct window *w; + struct buffer *b; + + if (NILP (Vmouse_highlight) + || !f->glyphs_initialized_p) + return; + + /* Which window is that in? */ + window = window_from_coordinates (f, x, y, &part, &x, &y, 0); + + /* Not on a window -> return. */ + if (!WINDOWP (window)) + return; + + if (!EQ (window, mouse_face_window)) + term_clear_mouse_face (); + + w = XWINDOW (window); + + /* Are we in a window whose display is up to date? + And verify the buffer's text has not changed. */ + b = XBUFFER (w->buffer); + if (part == ON_TEXT + && EQ (w->window_end_valid, w->buffer) + && XFASTINT (w->last_modified) == BUF_MODIFF (b) + && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b)) + { + int pos, i, nrows = w->current_matrix->nrows; + struct glyph_row *row; + struct glyph *glyph; + + /* Find the glyph under X/Y. */ + glyph = NULL; + if (y >= 0 && y < nrows) + { + row = MATRIX_ROW (w->current_matrix, y); + /* Give up if some row before the one we are looking for is + not enabled. */ + for (i = 0; i <= y; i++) + if (!MATRIX_ROW (w->current_matrix, i)->enabled_p) + break; + if (i > y /* all rows upto and including the one at Y are enabled */ + && row->displays_text_p + && x < window_box_width (w, TEXT_AREA)) + { + glyph = row->glyphs[TEXT_AREA]; + if (x >= row->used[TEXT_AREA]) + glyph = NULL; + else + { + glyph += x; + if (!BUFFERP (glyph->object)) + glyph = NULL; + } + } + } + + /* Clear mouse face if X/Y not over text. */ + if (glyph == NULL) + { + term_clear_mouse_face (); + return; + } + + if (!BUFFERP (glyph->object)) + abort (); + pos = glyph->charpos; + + /* Check for mouse-face. */ + { + extern Lisp_Object Qmouse_face; + Lisp_Object mouse_face, overlay, position, *overlay_vec; + int noverlays, obegv, ozv; + struct buffer *obuf; + + /* If we get an out-of-range value, return now; avoid an error. */ + if (pos > BUF_Z (b)) + return; + + /* Make the window's buffer temporarily current for + overlays_at and compute_char_face. */ + obuf = current_buffer; + current_buffer = b; + obegv = BEGV; + ozv = ZV; + BEGV = BEG; + ZV = Z; + + /* Is this char mouse-active? */ + XSETINT (position, pos); + + /* Put all the overlays we want in a vector in overlay_vec. */ + GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0); + /* Sort overlays into increasing priority order. */ + noverlays = sort_overlays (overlay_vec, noverlays, w); + + /* Check mouse-face highlighting. */ + if (!(EQ (window, mouse_face_window) + && y >= mouse_face_beg_row + && y <= mouse_face_end_row + && (y > mouse_face_beg_row + || x >= mouse_face_beg_col) + && (y < mouse_face_end_row + || x < mouse_face_end_col + || mouse_face_past_end))) + { + /* Clear the display of the old active region, if any. */ + term_clear_mouse_face (); + + /* Find the highest priority overlay that has a mouse-face + property. */ + overlay = Qnil; + for (i = noverlays - 1; i >= 0; --i) + { + mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face); + if (!NILP (mouse_face)) + { + overlay = overlay_vec[i]; + break; + } + } + + /* If no overlay applies, get a text property. */ + if (NILP (overlay)) + mouse_face = Fget_text_property (position, Qmouse_face, + w->buffer); + + /* Handle the overlay case. */ + if (!NILP (overlay)) + { + /* Find the range of text around this char that + should be active. */ + Lisp_Object before, after; + EMACS_INT ignore; + + + before = Foverlay_start (overlay); + after = Foverlay_end (overlay); + /* Record this as the current active region. */ + fast_find_position (w, XFASTINT (before), + &mouse_face_beg_col, + &mouse_face_beg_row); + + mouse_face_past_end + = !fast_find_position (w, XFASTINT (after), + &mouse_face_end_col, + &mouse_face_end_row); + mouse_face_window = window; + + mouse_face_face_id + = face_at_buffer_position (w, pos, 0, 0, + &ignore, pos + 1, 1, -1); + + /* Display it as active. */ + term_show_mouse_face (DRAW_MOUSE_FACE); + } + /* Handle the text property case. */ + else if (!NILP (mouse_face)) + { + /* Find the range of text around this char that + should be active. */ + Lisp_Object before, after, beginning, end; + EMACS_INT ignore; + + beginning = Fmarker_position (w->start); + XSETINT (end, (BUF_Z (b) - XFASTINT (w->window_end_pos))); + before + = Fprevious_single_property_change (make_number (pos + 1), + Qmouse_face, + w->buffer, beginning); + after + = Fnext_single_property_change (position, Qmouse_face, + w->buffer, end); + + /* Record this as the current active region. */ + fast_find_position (w, XFASTINT (before), + &mouse_face_beg_col, + &mouse_face_beg_row); + mouse_face_past_end + = !fast_find_position (w, XFASTINT (after), + &mouse_face_end_col, + &mouse_face_end_row); + mouse_face_window = window; + + mouse_face_face_id + = face_at_buffer_position (w, pos, 0, 0, + &ignore, pos + 1, 1, -1); + + /* Display it as active. */ + term_show_mouse_face (DRAW_MOUSE_FACE); + } + } + + /* Look for a `help-echo' property. */ + { + Lisp_Object help; + extern Lisp_Object Qhelp_echo; + + /* Check overlays first. */ + help = Qnil; + for (i = noverlays - 1; i >= 0 && NILP (help); --i) + { + overlay = overlay_vec[i]; + help = Foverlay_get (overlay, Qhelp_echo); + } + + if (!NILP (help)) + { + help_echo_string = help; + help_echo_window = window; + help_echo_object = overlay; + help_echo_pos = pos; + } + /* Try text properties. */ + else if (NILP (help) + && ((STRINGP (glyph->object) + && glyph->charpos >= 0 + && glyph->charpos < SCHARS (glyph->object)) + || (BUFFERP (glyph->object) + && glyph->charpos >= BEGV + && glyph->charpos < ZV))) + { + help = Fget_text_property (make_number (glyph->charpos), + Qhelp_echo, glyph->object); + if (!NILP (help)) + { + help_echo_string = help; + help_echo_window = window; + help_echo_object = glyph->object; + help_echo_pos = glyph->charpos; + } + } + } + + BEGV = obegv; + ZV = ozv; + current_buffer = obuf; + } + } +} + +static int +term_mouse_movement (FRAME_PTR frame, Gpm_Event *event) +{ + /* Has the mouse moved off the glyph it was on at the last sighting? */ + if (event->x != last_mouse_x || event->y != last_mouse_y) + { + frame->mouse_moved = 1; + term_mouse_highlight (frame, event->x, event->y); + /* Remember which glyph we're now on. */ + last_mouse_x = event->x; + last_mouse_y = event->y; + return 1; + } + return 0; +} + +/* 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. + + 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. + + This clears mouse_moved until the next motion + event arrives. */ +static void +term_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window, + enum scroll_bar_part *part, Lisp_Object *x, + Lisp_Object *y, unsigned long *time) +{ + struct timeval now; + + *fp = SELECTED_FRAME (); + (*fp)->mouse_moved = 0; + + *bar_window = Qnil; + *part = 0; + + XSETINT (*x, last_mouse_x); + XSETINT (*y, last_mouse_y); + gettimeofday(&now, 0); + *time = (now.tv_sec * 1000) + (now.tv_usec / 1000); +} + +/* Prepare a mouse-event in *RESULT for placement in the input queue. + + If the event is a button press, then note that we have grabbed + the mouse. */ + +static Lisp_Object +term_mouse_click (struct input_event *result, Gpm_Event *event, + struct frame *f) +{ + struct timeval now; + int i, j; + + result->kind = GPM_CLICK_EVENT; + for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 ) + { + if (event->buttons & j) { + result->code = i; /* button number */ + break; + } + } + gettimeofday(&now, 0); + result->timestamp = (now.tv_sec * 1000) + (now.tv_usec / 1000); + + if (event->type & GPM_UP) + result->modifiers = up_modifier; + else if (event->type & GPM_DOWN) + result->modifiers = down_modifier; else - old_mode = 0; + result->modifiers = 0; + + if (event->type & GPM_SINGLE) + result->modifiers |= click_modifier; + + if (event->type & GPM_DOUBLE) + result->modifiers |= double_modifier; + + if (event->type & GPM_TRIPLE) + result->modifiers |= triple_modifier; + + if (event->type & GPM_DRAG) + result->modifiers |= drag_modifier; + + if (!(event->type & (GPM_MOVE | GPM_DRAG))) { - if (mode != old_mode) + /* 1 << KG_SHIFT */ + if (event->modifiers & (1 << 0)) + result->modifiers |= shift_modifier; + + /* 1 << KG_CTRL */ + if (event->modifiers & (1 << 2)) + result->modifiers |= ctrl_modifier; + + /* 1 << KG_ALT || KG_ALTGR */ + if (event->modifiers & (1 << 3) + || event->modifiers & (1 << 1)) + result->modifiers |= meta_modifier; + } + + XSETINT (result->x, event->x); + XSETINT (result->y, event->y); + XSETFRAME (result->frame_or_window, f); + result->arg = Qnil; + return Qnil; +} + +int +handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event, struct input_event* hold_quit) +{ + struct frame *f = XFRAME (tty->top_frame); + struct input_event ie; + int do_help = 0; + int count = 0; + + EVENT_INIT (ie); + ie.kind = NO_EVENT; + ie.arg = Qnil; + + if (event->type & (GPM_MOVE | GPM_DRAG)) { + previous_help_echo_string = help_echo_string; + help_echo_string = Qnil; + + Gpm_DrawPointer (event->x, event->y, fileno (tty->output)); + + if (!term_mouse_movement (f, event)) + help_echo_string = previous_help_echo_string; + + /* If the contents of the global variable help_echo_string + has changed, generate a HELP_EVENT. */ + if (!NILP (help_echo_string) + || !NILP (previous_help_echo_string)) + do_help = 1; + + goto done; + } + else { + f->mouse_moved = 0; + term_mouse_click (&ie, event, f); + } + + done: + if (ie.kind != NO_EVENT) + { + kbd_buffer_store_event_hold (&ie, hold_quit); + count++; + } + + if (do_help + && !(hold_quit && hold_quit->kind != NO_EVENT)) + { + Lisp_Object frame; + + if (f) + XSETFRAME (frame, f); + else + frame = Qnil; + + gen_help_event (help_echo_string, frame, help_echo_window, + help_echo_object, help_echo_pos); + count++; + } + + return count; +} + +DEFUN ("gpm-mouse-start", Fgpm_mouse_start, Sgpm_mouse_start, + 0, 0, 0, + doc: /* Open a connection to Gpm. +Gpm-mouse can only be activated for one tty at a time. */) + () +{ + struct frame *f = SELECTED_FRAME (); + struct tty_display_info *tty + = ((f)->output_method == output_termcap + ? (f)->terminal->display_info.tty : NULL); + Gpm_Connect connection; + + if (!tty) + error ("Gpm-mouse only works in the GNU/Linux console"); + if (gpm_tty == tty) + return Qnil; /* Already activated, nothing to do. */ + if (gpm_tty) + error ("Gpm-mouse can only be activated for one tty at a time"); + + connection.eventMask = ~0; + connection.defaultMask = ~GPM_HARD; + connection.maxMod = ~0; + connection.minMod = 0; + gpm_zerobased = 1; + + if (Gpm_Open (&connection, 0) < 0) + error ("Gpm-mouse failed to connect to the gpm daemon"); + else { - tty_setup_colors (mode); - /* This recomputes all the faces given the new color - definitions. */ - call0 (intern ("tty-set-up-initial-frame-faces")); - redraw_frame (f); + gpm_tty = tty; + /* `init_sys_modes' arranges for mouse movements sent through gpm_fd + to generate SIGIOs. Apparently we need to call reset_sys_modes + before calling init_sys_modes. */ + reset_sys_modes (tty); + init_sys_modes (tty); + add_gpm_wait_descriptor (gpm_fd); + return Qnil; } } -#endif /* !WINDOWSNT */ +void +close_gpm (int fd) +{ + if (fd >= 0) + delete_gpm_wait_descriptor (fd); + while (Gpm_Close()); /* close all the stack */ + gpm_tty = NULL; +} + +DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop, + 0, 0, 0, + doc: /* Close a connection to Gpm. */) + () +{ + struct frame *f = SELECTED_FRAME (); + struct tty_display_info *tty + = ((f)->output_method == output_termcap + ? (f)->terminal->display_info.tty : NULL); + + if (!tty || gpm_tty != tty) + return Qnil; /* Not activated on this terminal, nothing to do. */ + + close_gpm (gpm_fd); + return Qnil; +} +#endif /* HAVE_GPM */ +#ifndef MSDOS /*********************************************************************** Initialization ***********************************************************************/ +/* Initialize the tty-dependent part of frame F. The frame must + already have its device initialized. */ + void -term_init (terminal_type) - char *terminal_type; +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_TERMINAL (f)->display_info.tty; + + f->output_data.tty = t; +} + +/* Delete frame F's face cache, and its tty-dependent part. */ + +static void +tty_free_frame_resources (struct frame *f) +{ + if (! FRAME_TERMCAP_P (f)) + abort (); + + if (FRAME_FACE_CACHE (f)) + free_frame_faces (f); + + xfree (f->output_data.tty); +} + +#else /* MSDOS */ + +/* Delete frame F's face cache. */ + +static void +tty_free_frame_resources (struct frame *f) +{ + if (! FRAME_TERMCAP_P (f) && ! FRAME_MSDOS_P (f)) + abort (); + + if (FRAME_FACE_CACHE (f)) + free_frame_faces (f); +} +#endif /* MSDOS */ + +/* Reset the hooks in TERMINAL. */ + +static void +clear_tty_hooks (struct terminal *terminal) +{ + terminal->rif = 0; + terminal->cursor_to_hook = 0; + terminal->raw_cursor_to_hook = 0; + terminal->clear_to_end_hook = 0; + terminal->clear_frame_hook = 0; + terminal->clear_end_of_line_hook = 0; + terminal->ins_del_lines_hook = 0; + terminal->insert_glyphs_hook = 0; + terminal->write_glyphs_hook = 0; + terminal->delete_glyphs_hook = 0; + terminal->ring_bell_hook = 0; + terminal->reset_terminal_modes_hook = 0; + terminal->set_terminal_modes_hook = 0; + terminal->update_begin_hook = 0; + terminal->update_end_hook = 0; + terminal->set_terminal_window_hook = 0; + terminal->mouse_position_hook = 0; + terminal->frame_rehighlight_hook = 0; + terminal->frame_raise_lower_hook = 0; + terminal->fullscreen_hook = 0; + terminal->set_vertical_scroll_bar_hook = 0; + terminal->condemn_scroll_bars_hook = 0; + terminal->redeem_scroll_bar_hook = 0; + terminal->judge_scroll_bars_hook = 0; + terminal->read_socket_hook = 0; + terminal->frame_up_to_date_hook = 0; + + /* Leave these two set, or suspended frames are not deleted + correctly. */ + terminal->delete_frame_hook = &tty_free_frame_resources; + terminal->delete_terminal_hook = &delete_tty; +} + +/* Initialize hooks in TERMINAL with the values needed for a tty. */ + +static void +set_tty_hooks (struct terminal *terminal) +{ + terminal->rif = 0; /* ttys don't support window-based redisplay. */ + + terminal->cursor_to_hook = &tty_cursor_to; + terminal->raw_cursor_to_hook = &tty_raw_cursor_to; + + terminal->clear_to_end_hook = &tty_clear_to_end; + terminal->clear_frame_hook = &tty_clear_frame; + terminal->clear_end_of_line_hook = &tty_clear_end_of_line; + + terminal->ins_del_lines_hook = &tty_ins_del_lines; + + terminal->insert_glyphs_hook = &tty_insert_glyphs; + terminal->write_glyphs_hook = &tty_write_glyphs; + terminal->delete_glyphs_hook = &tty_delete_glyphs; + + terminal->ring_bell_hook = &tty_ring_bell; + + terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes; + terminal->set_terminal_modes_hook = &tty_set_terminal_modes; + terminal->update_begin_hook = 0; /* Not needed. */ + terminal->update_end_hook = &tty_update_end; + terminal->set_terminal_window_hook = &tty_set_terminal_window; + + terminal->mouse_position_hook = 0; /* Not needed. */ + terminal->frame_rehighlight_hook = 0; /* Not needed. */ + terminal->frame_raise_lower_hook = 0; /* Not needed. */ + + terminal->set_vertical_scroll_bar_hook = 0; /* Not needed. */ + terminal->condemn_scroll_bars_hook = 0; /* Not needed. */ + terminal->redeem_scroll_bar_hook = 0; /* Not needed. */ + terminal->judge_scroll_bars_hook = 0; /* Not needed. */ + + terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */ + terminal->frame_up_to_date_hook = 0; /* Not needed. */ + + terminal->delete_frame_hook = &tty_free_frame_resources; + terminal->delete_terminal_hook = &delete_tty; +} + +/* Drop the controlling terminal if fd is the same device. */ +static void +dissociate_if_controlling_tty (int fd) { - char *area; +#ifndef DOS_NT + 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; +#elif defined (CYGWIN) + setsid (); + 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 */ + } +#endif /* !DOS_NT */ +} + +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., "/dev/tty". + 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 terminal * +init_tty (char *name, char *terminal_type, int must_succeed) +{ + char *area = NULL; char **address = &area; - char *buffer = NULL; int buffer_size = 4096; - register char *p; + register char *p = NULL; int status; - struct frame *sf = XFRAME (selected_frame); + struct tty_display_info *tty = NULL; + struct terminal *terminal = NULL; + int ctty = 0; /* 1 if asked to open controlling tty. */ + + if (!terminal_type) + maybe_fatal (must_succeed, 0, + "Unknown terminal type", + "Unknown terminal type"); + + if (name == NULL) + name = DEV_TTY; + if (!strcmp (name, DEV_TTY)) + ctty = 1; + + /* If we already have a terminal on the given device, use that. If + all such terminals are suspended, create a new one instead. */ + /* XXX Perhaps this should be made explicit by having init_tty + always create a new terminal and separating terminal and frame + creation on Lisp level. */ + terminal = get_named_tty (name); + if (terminal) + return terminal; + + terminal = create_terminal (); +#ifdef MSDOS + if (been_here > 0) + maybe_fatal (1, 0, "Attempt to create another terminal %s", "", + name, ""); + been_here = 1; + tty = &the_only_display_info; +#else + tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info)); +#endif + bzero (tty, sizeof (struct tty_display_info)); + tty->next = tty_list; + tty_list = tty; - encode_terminal_bufsize = 0; + terminal->type = output_termcap; + terminal->display_info.tty = tty; + tty->terminal = terminal; -#ifdef WINDOWSNT - initialize_w32_display (); + tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm)); + Wcm_clear (tty); + +#ifndef DOS_NT + set_tty_hooks (terminal); - Wcm_clear (); + { + int fd; + FILE *file; + +#ifdef O_IGNORE_CTTY + if (!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 +#else + /* Alas, O_IGNORE_CTTY is a GNU extension that seems to be only + defined on Hurd. On other systems, we need to explicitly + 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 */ + + tty->name = xstrdup (name); + terminal->name = xstrdup (name); + + if (fd < 0) + maybe_fatal (must_succeed, terminal, + "Could not open file: %s", + "Could not open file: %s", + name); + if (!isatty (fd)) + { + close (fd); + maybe_fatal (must_succeed, terminal, + "Not a tty device: %s", + "Not a tty device: %s", + name); + } - area = (char *) xmalloc (2044); +#ifndef O_IGNORE_CTTY + if (!ctty) + dissociate_if_controlling_tty (fd); +#endif - FrameRows = FRAME_LINES (sf); - FrameCols = FRAME_COLS (sf); - specified_window = FRAME_LINES (sf); + file = fdopen (fd, "w+"); + tty->input = file; + tty->output = file; + } - delete_in_insert_mode = 1; + tty->type = xstrdup (terminal_type); - UseTabs = 0; - scroll_region_ok = 0; + add_keyboard_wait_descriptor (fileno (tty->input)); - /* 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. */ +#endif /* !DOS_NT */ - line_ins_del_ok = 0; - char_ins_del_ok = 1; + encode_terminal_src_size = 0; + encode_terminal_dst_size = 0; + +#ifdef HAVE_GPM + terminal->mouse_position_hook = term_mouse_position; + mouse_face_window = Qnil; +#endif + +#ifdef DOS_NT +#ifdef WINDOWSNT + initialize_w32_display (terminal); +#else /* MSDOS */ + if (strcmp (terminal_type, "internal") == 0) + terminal->type = output_msdos_raw; + initialize_msdos_display (terminal); +#endif /* MSDOS */ + tty->output = stdout; + tty->input = stdin; + /* The following two are inaccessible from w32console.c. */ + terminal->delete_frame_hook = &tty_free_frame_resources; + terminal->delete_terminal_hook = &delete_tty; + + tty->name = xstrdup (name); + terminal->name = xstrdup (name); + tty->type = xstrdup (terminal_type); + +#ifdef subprocesses + add_keyboard_wait_descriptor (0); +#endif + + Wcm_clear (tty); + +#ifdef WINDOWSNT + { + struct frame *f = XFRAME (selected_frame); + + FrameRows (tty) = FRAME_LINES (f); + FrameCols (tty) = FRAME_COLS (f); + tty->specified_window = FRAME_LINES (f); + + FRAME_CAN_HAVE_SCROLL_BARS (f) = 0; + FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none; + } +#else /* MSDOS */ + { + int height, width; + get_tty_size (fileno (tty->input), &width, &height); + FrameCols (tty) = width; + FrameRows (tty) = height; + } +#endif /* MSDOS */ + tty->delete_in_insert_mode = 1; + UseTabs (tty) = 0; + terminal->scroll_region_ok = 0; + + /* Seems to insert lines when it's not supposed to, messing up the + display. In doing a trace, it didn't seem to be called much, so I + don't think we're losing anything by turning it off. */ + terminal->line_ins_del_ok = 0; +#ifdef WINDOWSNT + terminal->char_ins_del_ok = 1; baud_rate = 19200; +#else /* MSDOS */ + terminal->char_ins_del_ok = 0; + init_baud_rate (fileno (tty->input)); +#endif /* MSDOS */ + + tty->TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */ + +#else /* not DOS_NT */ - FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0; - FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none; - TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */ + Wcm_clear (tty); - return; -#else /* not WINDOWSNT */ + tty->termcap_term_buffer = (char *) xmalloc (buffer_size); - Wcm_clear (); + /* On some systems, tgetent tries to access the controlling + terminal. */ + sigblock (sigmask (SIGTTOU)); + status = tgetent (tty->termcap_term_buffer, terminal_type); + sigunblock (sigmask (SIGTTOU)); - buffer = (char *) xmalloc (buffer_size); - status = tgetent (buffer, terminal_type); if (status < 0) { #ifdef TERMINFO - fatal ("Cannot open terminfo database file"); + maybe_fatal (must_succeed, terminal, + "Cannot open terminfo database file", + "Cannot open terminfo database file"); #else - fatal ("Cannot open termcap database file"); + maybe_fatal (must_succeed, terminal, + "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, terminal, + "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, terminal, + "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 } #ifndef TERMINFO - if (strlen (buffer) >= buffer_size) + if (strlen (tty->termcap_term_buffer) >= buffer_size) abort (); - buffer_size = strlen (buffer); + buffer_size = strlen (tty->termcap_term_buffer); #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" */ -#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; -#endif /* VMS */ + tty->termcap_strings_buffer = area = (char *) xmalloc (buffer_size); + 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" */ 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"); + terminal->memory_below_frame = tgetflag ("db"); + tty->TF_hazeltine = tgetflag ("hz"); + terminal->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"); + +#endif /* !DOS_NT */ + terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD)); + init_kboard (terminal->kboard); + terminal->kboard->Vwindow_system = Qnil; + terminal->kboard->next_kboard = all_kboards; + all_kboards = terminal->kboard; + terminal->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 = terminal->kboard; +#ifndef DOS_NT + term_get_fkeys (address, terminal->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 (FRAME_LINES (sf) < 3 || FRAME_COLS (sf) < 3) - fatal ("Screen size %dx%d is too small", - FRAME_LINES (sf), FRAME_COLS (sf)); + if (FrameCols (tty) <= 0) + FrameCols (tty) = tgetnum ("co"); + if (FrameRows (tty) <= 0) + FrameRows (tty) = tgetnum ("li"); - min_padding_speed = tgetnum ("pb"); - TabWidth = tgetnum ("tw"); + if (FrameRows (tty) < 3 || FrameCols (tty) < 3) + maybe_fatal (must_succeed, terminal, + "Screen size %dx%d is too small" + "Screen size %dx%d is too small", + FrameCols (tty), FrameRows (tty)); -#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; -#endif /* VMS */ + TabWidth (tty) = tgetnum ("tw"); - 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; + terminal->memory_below_frame = 1; + tty->Wcm->cm_losewrap = 1; } if (!strncmp (terminal_type, "c10", 3) || !strcmp (terminal_type, "perq")) @@ -2632,126 +3802,216 @@ 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; + terminal->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 */ -#ifdef VMS - fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\ -It lacks the ability to position the cursor.\n\ -If that is not the actual type of terminal you have, 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 */ + if (Wcm_init (tty) == -1) /* can't do cursor motion */ + { + maybe_fatal (must_succeed, terminal, + "Terminal type \"%s\" is not powerful enough to run Emacs", # 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); + } + + if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0) + maybe_fatal (must_succeed, terminal, + "Could not determine the frame size", + "Could not determine the frame size"); - delete_in_insert_mode - = TS_delete_mode && TS_insert_mode - && !strcmp (TS_delete_mode, TS_insert_mode); + tty->delete_in_insert_mode + = tty->TS_delete_mode && tty->TS_insert_mode + && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode); - se_is_so = (TS_standout_mode - && TS_end_standout_mode - && !strcmp (TS_standout_mode, TS_end_standout_mode)); + tty->se_is_so = (tty->TS_standout_mode + && tty->TS_end_standout_mode + && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode)); - UseTabs = tabs_safe_p () && TabWidth == 8; + UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8; - scroll_region_ok - = (Wcm.cm_abs - && (TS_set_window || TS_set_scroll_region || TS_set_scroll_region_1)); + terminal->scroll_region_ok + = (tty->Wcm->cm_abs + && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1)); - 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)); + terminal->line_ins_del_ok + = (((tty->TS_ins_line || tty->TS_ins_multi_lines) + && (tty->TS_del_line || tty->TS_del_multi_lines)) + || (terminal->scroll_region_ok + && tty->TS_fwd_scroll && tty->TS_rev_scroll)); - 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)); + terminal->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)); - fast_clear_end_of_line = TS_clr_line != 0; + terminal->fast_clear_end_of_line = tty->TS_clr_line != 0; - init_baud_rate (); - if (read_socket_hook) /* Baudrate is somewhat */ - /* meaningless in this case */ - baud_rate = 9600; + init_baud_rate (fileno (tty->input)); - FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0; - FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none; -#endif /* WINDOWSNT */ +#endif /* not DOS_NT */ - xfree (buffer); + /* Init system terminal modes (RAW or CBREAK, etc.). */ + init_sys_modes (tty); + + return terminal; +} + +/* Auxiliary error-handling function for init_tty. + Delete TERMINAL, then call error or fatal with str1 or str2, + respectively, according to MUST_SUCCEED. */ + +static void +maybe_fatal (must_succeed, terminal, str1, str2, arg1, arg2) + int must_succeed; + struct terminal *terminal; + char *str1, *str2, *arg1, *arg2; +{ + if (terminal) + delete_tty (terminal); + + if (must_succeed) + fatal (str2, arg1, arg2); + else + error (str1, arg1, arg2); + + abort (); } -/* VARARGS 1 */ void -fatal (str, arg1, arg2) - char *str, *arg1, *arg2; +fatal (const char *str, ...) { + va_list ap; + va_start (ap, str); fprintf (stderr, "emacs: "); - fprintf (stderr, str, arg1, arg2); - fprintf (stderr, "\n"); + vfprintf (stderr, str, ap); + if (!(strlen (str) > 0 && str[strlen (str) - 1] == '\n')) + fprintf (stderr, "\n"); + va_end (ap); fflush (stderr); 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. */) - () + + +/* Delete the given tty terminal, closing all frames on it. */ + +static void +delete_tty (struct terminal *terminal) { - TS_enter_underline_mode = 0; - return Qnil; + struct tty_display_info *tty; + + /* Protect against recursive calls. delete_frame in + delete_terminal calls us back when it deletes our last frame. */ + if (!terminal->name) + return; + + if (terminal->type != output_termcap) + abort (); + + tty = terminal->display_info.tty; + + 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; + } + + /* reset_sys_modes needs a valid device, so this call needs to be + before delete_terminal. */ + reset_sys_modes (tty); + + delete_terminal (terminal); + + xfree (tty->name); + xfree (tty->type); + + if (tty->input) + { +#ifdef subprocesses + delete_keyboard_wait_descriptor (fileno (tty->input)); +#endif + 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); + + xfree (tty->old_tty); + xfree (tty->Wcm); + xfree (tty->termcap_strings_buffer); + xfree (tty->termcap_term_buffer); + + bzero (tty, sizeof (struct tty_display_info)); + xfree (tty); } + + +/* Mark the pointers in the tty_display_info objects. + Called by the Fgarbage_collector. */ + +void +mark_ttys (void) +{ + struct tty_display_info *tty; + + for (tty = tty_list; tty; tty = tty->next) + mark_object (tty->top_frame); +} + + + void syms_of_term () { @@ -2764,10 +4024,18 @@ This variable can be used by terminal emulator packages. */); system_uses_terminfo = 0; #endif - DEFVAR_LISP ("ring-bell-function", &Vring_bell_function, - doc: /* Non-nil means call this function to ring the bell. -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 terminal object 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 terminal object that was revived. +See `resume-tty'. */); + Vresume_tty_functions = Qnil; DEFVAR_BOOL ("visible-cursor", &visible_cursor, doc: /* Non-nil means to make the cursor very visible. @@ -2779,9 +4047,28 @@ bigger, or it may make it blink, or it may do nothing at all. */); defsubr (&Stty_display_color_p); defsubr (&Stty_display_color_cells); defsubr (&Stty_no_underline); - - fullscreen_hook = NULL; + defsubr (&Stty_type); + defsubr (&Scontrolling_tty_p); + defsubr (&Ssuspend_tty); + defsubr (&Sresume_tty); +#ifdef HAVE_GPM + defsubr (&Sgpm_mouse_start); + defsubr (&Sgpm_mouse_stop); + + staticpro (&mouse_face_window); +#endif /* HAVE_GPM */ + +#ifndef DOS_NT + default_orig_pair = NULL; + default_set_foreground = NULL; + default_set_background = NULL; +#endif /* !DOS_NT */ + + encode_terminal_src = NULL; + encode_terminal_dst = NULL; } + + /* arch-tag: 498e7449-6f2e-45e2-91dd-b7d4ca488193 (do not change this comment) */