(declare-function): Return nil.
[bpt/emacs.git] / src / term.c
CommitLineData
d284f58f 1/* Terminal control module for terminals described by TERMCAP
0b5538bd 2 Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1998, 2000, 2001,
4e6835db 3 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
08a24c47
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
684d6f5b 9the Free Software Foundation; either version 3, or (at your option)
08a24c47
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
4fc5845f
LK
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA. */
08a24c47 21
d284f58f 22/* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>. */
08a24c47 23
565620a5 24#include <config.h>
08a24c47
JB
25#include <stdio.h>
26#include <ctype.h>
a168702a 27#include <string.h>
59b3194c 28#include <errno.h>
28d440ab 29#include <sys/file.h>
7eb1e453 30
d8b18043 31#ifdef HAVE_UNISTD_H
1ec5dc77 32#include <unistd.h>
d8b18043 33#endif
67ad74df
KL
34
35#if HAVE_TERMIOS_H
36#include <termios.h> /* For TIOCNOTTY. */
37#endif
03a1d6bd
KL
38
39#include <signal.h>
0c72d684 40
9628b887 41#include "lisp.h"
08a24c47
JB
42#include "termchar.h"
43#include "termopts.h"
a4decb7f
KH
44#include "charset.h"
45#include "coding.h"
2538fae4 46#include "keyboard.h"
ff11dfa1 47#include "frame.h"
08a24c47
JB
48#include "disptab.h"
49#include "termhooks.h"
dfcf069d 50#include "dispextern.h"
a168702a 51#include "window.h"
8feddab4 52#include "keymap.h"
1a935bfd 53#include "blockinput.h"
03a1d6bd
KL
54#include "syssignal.h"
55#include "systty.h"
c9612b8e 56#include "intervals.h"
a168702a 57
ff23e1dd
GM
58/* For now, don't try to include termcap.h. On some systems,
59 configure finds a non-standard termcap.h that the main build
60 won't find. */
61
62#if defined HAVE_TERMCAP_H && 0
b0f61f15 63#include <termcap.h>
46d1b2bc
DL
64#else
65extern void tputs P_ ((const char *, int, int (*)(int)));
66extern int tgetent P_ ((char *, const char *));
67extern int tgetflag P_ ((char *id));
68extern int tgetnum P_ ((char *id));
b0f61f15
GM
69#endif
70
eccec691 71#include "cm.h"
dfcf069d
AS
72#ifdef HAVE_X_WINDOWS
73#include "xterm.h"
74#endif
e0f712ba 75#ifdef MAC_OS
1a578e9b
AC
76#include "macterm.h"
77#endif
c8951b18 78
28d440ab
KL
79#ifndef O_RDWR
80#define O_RDWR 2
81#endif
82
0c72d684
KL
83#ifndef O_NOCTTY
84#define O_NOCTTY 0
85#endif
86
78048085
EZ
87/* The name of the default console device. */
88#ifdef WINDOWSNT
89#define DEV_TTY "CONOUT$"
90#else
91#define DEV_TTY "/dev/tty"
92#endif
93
ed8dad6b 94static void tty_set_scroll_region P_ ((struct frame *f, int start, int stop));
a168702a
GM
95static void turn_on_face P_ ((struct frame *, int face_id));
96static void turn_off_face P_ ((struct frame *, int face_id));
28d7d09f
KL
97static void tty_show_cursor P_ ((struct tty_display_info *));
98static void tty_hide_cursor P_ ((struct tty_display_info *));
ed8dad6b 99static void tty_background_highlight P_ ((struct tty_display_info *tty));
4a665758
KL
100static void clear_tty_hooks P_ ((struct terminal *terminal));
101static void set_tty_hooks P_ ((struct terminal *terminal));
ed8dad6b 102static void dissociate_if_controlling_tty P_ ((int fd));
6ed8eeff 103static void delete_tty P_ ((struct terminal *));
a168702a 104
6548cf00
KL
105#define OUTPUT(tty, a) \
106 emacs_tputs ((tty), a, \
107 (int) (FRAME_LINES (XFRAME (selected_frame)) \
108 - curY (tty)), \
109 cmputc)
110
28d440ab
KL
111#define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
112#define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
a168702a 113
28d440ab 114#define OUTPUT_IF(tty, a) \
6548cf00
KL
115 do { \
116 if (a) \
117 emacs_tputs ((tty), a, \
118 (int) (FRAME_LINES (XFRAME (selected_frame)) \
119 - curY (tty) ), \
120 cmputc); \
121 } while (0)
177c0ea7 122
28d440ab 123#define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
08a24c47 124
b58cb614 125/* If true, use "vs", otherwise use "ve" to make the cursor visible. */
177c0ea7 126
b58cb614 127static int visible_cursor;
08a24c47 128
f46c2aff
KS
129/* Display space properties */
130
131extern Lisp_Object Qspace, QCalign_to, QCwidth;
132
0b0d3e0b 133/* Functions to call after suspending a tty. */
e4019195 134Lisp_Object Vsuspend_tty_functions;
0b0d3e0b
KL
135
136/* Functions to call after resuming a tty. */
e4019195 137Lisp_Object Vresume_tty_functions;
0b0d3e0b 138
428a555e 139/* Chain of all tty device parameters. */
28d7d09f 140struct tty_display_info *tty_list;
08a24c47 141
fca177d4
KL
142/* Nonzero means no need to redraw the entire frame on resuming a
143 suspended Emacs. This is useful on terminals with multiple
144 pages, where one page is used for Emacs and another for all
145 else. */
08a24c47 146int no_redraw_on_reenter;
819b8f00 147
4e6ba4a4
GM
148/* Meaning of bits in no_color_video. Each bit set means that the
149 corresponding attribute cannot be combined with colors. */
150
151enum no_color_bit
152{
153 NC_STANDOUT = 1 << 0,
154 NC_UNDERLINE = 1 << 1,
155 NC_REVERSE = 1 << 2,
156 NC_BLINK = 1 << 3,
157 NC_DIM = 1 << 4,
158 NC_BOLD = 1 << 5,
159 NC_INVIS = 1 << 6,
160 NC_PROTECT = 1 << 7,
161 NC_ALT_CHARSET = 1 << 8
162};
163
08a24c47
JB
164/* internal state */
165
8dd0c7cb 166/* The largest frame width in any call to calculate_costs. */
a168702a 167
9882535b 168int max_frame_cols;
a168702a 169
8dd0c7cb 170/* The largest frame height in any call to calculate_costs. */
a168702a 171
9882535b 172int max_frame_lines;
8dd0c7cb 173
0c72d684
KL
174/* Non-zero if we have dropped our controlling tty and therefore
175 should not open a frame on stdout. */
176static int no_controlling_tty;
177
07c57952 178/* Provided for lisp packages. */
a168702a 179
07c57952
KH
180static int system_uses_terminfo;
181
08a24c47 182char *tparam ();
e4bfb3b6
RS
183
184extern char *tgetstr ();
08a24c47 185\f
cb28b9c2 186
7e5a23bd 187#ifdef HAVE_GPM
e882229c
NR
188#include <sys/fcntl.h>
189#include "buffer.h"
190
b870aa61
SM
191static void term_clear_mouse_face ();
192static void term_mouse_highlight (struct frame *f, int x, int y);
193
71f44e7a
SM
194/* The device for which we have enabled gpm support (or NULL). */
195struct tty_display_info *gpm_tty = NULL;
7be1c21a 196
e882229c
NR
197/* These variables describe the range of text currently shown in its
198 mouse-face, together with the window they apply to. As long as
199 the mouse stays within this range, we need not redraw anything on
200 its account. Rows and columns are glyph matrix positions in
201 MOUSE_FACE_WINDOW. */
202static int mouse_face_beg_row, mouse_face_beg_col;
203static int mouse_face_end_row, mouse_face_end_col;
204static int mouse_face_past_end;
6178ce5e 205static Lisp_Object mouse_face_window;
e882229c
NR
206static int mouse_face_face_id;
207
e882229c
NR
208static int pos_x, pos_y;
209static int last_mouse_x, last_mouse_y;
7e5a23bd 210#endif /* HAVE_GPM */
08a24c47 211
da8e1115
KL
212/* Ring the bell on a tty. */
213
ed8dad6b 214static void
385ed61f 215tty_ring_bell (struct frame *f)
3224dac1 216{
3224dac1
KL
217 struct tty_display_info *tty = FRAME_TTY (f);
218
b6660415
KL
219 if (tty->output)
220 {
221 OUTPUT (tty, (tty->TS_visible_bell && visible_bell
222 ? tty->TS_visible_bell
223 : tty->TS_bell));
224 fflush (tty->output);
225 }
3224dac1
KL
226}
227
da8e1115
KL
228/* Set up termcap modes for Emacs. */
229
230void
6ed8eeff 231tty_set_terminal_modes (struct terminal *terminal)
fca177d4 232{
6ed8eeff 233 struct tty_display_info *tty = terminal->display_info.tty;
3224dac1 234
0b0d3e0b
KL
235 if (tty->output)
236 {
fbf34973
KL
237 if (tty->TS_termcap_modes)
238 OUTPUT (tty, tty->TS_termcap_modes);
239 else
240 {
241 /* Output enough newlines to scroll all the old screen contents
242 off the screen, so it won't be overwritten and lost. */
243 int i;
a3c07f68 244 current_tty = tty;
fbf34973 245 for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
a3c07f68 246 cmputc ('\n');
fbf34973
KL
247 }
248
0b0d3e0b 249 OUTPUT_IF (tty, tty->TS_termcap_modes);
b58cb614 250 OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
0b0d3e0b
KL
251 OUTPUT_IF (tty, tty->TS_keypad_mode);
252 losecursor (tty);
2f98e6e3 253 fflush (tty->output);
0b0d3e0b 254 }
fca177d4
KL
255}
256
da8e1115
KL
257/* Reset termcap modes before exiting Emacs. */
258
259void
6ed8eeff 260tty_reset_terminal_modes (struct terminal *terminal)
fca177d4 261{
6ed8eeff 262 struct tty_display_info *tty = terminal->display_info.tty;
0b0d3e0b
KL
263
264 if (tty->output)
265 {
ed8dad6b
KL
266 tty_turn_off_highlight (tty);
267 tty_turn_off_insert (tty);
0b0d3e0b
KL
268 OUTPUT_IF (tty, tty->TS_end_keypad_mode);
269 OUTPUT_IF (tty, tty->TS_cursor_normal);
270 OUTPUT_IF (tty, tty->TS_end_termcap_modes);
271 OUTPUT_IF (tty, tty->TS_orig_pair);
272 /* Output raw CR so kernel can track the cursor hpos. */
273 current_tty = tty;
274 cmputc ('\r');
2f98e6e3 275 fflush (tty->output);
0b0d3e0b 276 }
fca177d4
KL
277}
278
6ed8eeff 279/* Flag the end of a display update on a termcap terminal. */
da8e1115 280
ed8dad6b 281static void
3224dac1
KL
282tty_update_end (struct frame *f)
283{
284 struct tty_display_info *tty = FRAME_TTY (f);
285
286 if (!XWINDOW (selected_window)->cursor_off_p)
287 tty_show_cursor (tty);
ed8dad6b
KL
288 tty_turn_off_insert (tty);
289 tty_background_highlight (tty);
3224dac1
KL
290}
291
da8e1115
KL
292/* The implementation of set_terminal_window for termcap frames. */
293
ed8dad6b 294static void
385ed61f 295tty_set_terminal_window (struct frame *f, int size)
3224dac1 296{
3224dac1
KL
297 struct tty_display_info *tty = FRAME_TTY (f);
298
299 tty->specified_window = size ? size : FRAME_LINES (f);
300 if (FRAME_SCROLL_REGION_OK (f))
ed8dad6b 301 tty_set_scroll_region (f, 0, tty->specified_window);
08a24c47
JB
302}
303
ed8dad6b
KL
304static void
305tty_set_scroll_region (struct frame *f, int start, int stop)
08a24c47
JB
306{
307 char *buf;
28d7d09f 308 struct tty_display_info *tty = FRAME_TTY (f);
177c0ea7 309
fca177d4
KL
310 if (tty->TS_set_scroll_region)
311 buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1);
312 else if (tty->TS_set_scroll_region_1)
313 buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
ed02974b
KL
314 FRAME_LINES (f), start,
315 FRAME_LINES (f) - stop,
316 FRAME_LINES (f));
08a24c47 317 else
fca177d4 318 buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
177c0ea7 319
6548cf00 320 OUTPUT (tty, buf);
9ac0d9e0 321 xfree (buf);
6548cf00 322 losecursor (tty);
08a24c47 323}
d284f58f 324
08a24c47 325\f
d284f58f 326static void
ed8dad6b 327tty_turn_on_insert (struct tty_display_info *tty)
08a24c47 328{
fca177d4
KL
329 if (!tty->insert_mode)
330 OUTPUT (tty, tty->TS_insert_mode);
331 tty->insert_mode = 1;
08a24c47
JB
332}
333
dfcf069d 334void
ed8dad6b 335tty_turn_off_insert (struct tty_display_info *tty)
08a24c47 336{
fca177d4
KL
337 if (tty->insert_mode)
338 OUTPUT (tty, tty->TS_end_insert_mode);
339 tty->insert_mode = 0;
08a24c47
JB
340}
341\f
54800acb 342/* Handle highlighting. */
08a24c47 343
dfcf069d 344void
ed8dad6b 345tty_turn_off_highlight (struct tty_display_info *tty)
08a24c47 346{
fca177d4
KL
347 if (tty->standout_mode)
348 OUTPUT_IF (tty, tty->TS_end_standout_mode);
349 tty->standout_mode = 0;
08a24c47
JB
350}
351
d284f58f 352static void
ed8dad6b 353tty_turn_on_highlight (struct tty_display_info *tty)
08a24c47 354{
fca177d4
KL
355 if (!tty->standout_mode)
356 OUTPUT_IF (tty, tty->TS_standout_mode);
357 tty->standout_mode = 1;
08a24c47
JB
358}
359
86a7d192 360static void
ed8dad6b 361tty_toggle_highlight (struct tty_display_info *tty)
86a7d192 362{
fca177d4 363 if (tty->standout_mode)
ed8dad6b 364 tty_turn_off_highlight (tty);
86a7d192 365 else
ed8dad6b 366 tty_turn_on_highlight (tty);
86a7d192
GM
367}
368
a168702a
GM
369
370/* Make cursor invisible. */
371
372static void
28d7d09f 373tty_hide_cursor (struct tty_display_info *tty)
a168702a 374{
fca177d4 375 if (tty->cursor_hidden == 0)
d284f58f 376 {
fca177d4
KL
377 tty->cursor_hidden = 1;
378 OUTPUT_IF (tty, tty->TS_cursor_invisible);
d284f58f 379 }
a168702a
GM
380}
381
382
383/* Ensure that cursor is visible. */
384
385static void
28d7d09f 386tty_show_cursor (struct tty_display_info *tty)
a168702a 387{
fca177d4 388 if (tty->cursor_hidden)
d284f58f 389 {
fca177d4
KL
390 tty->cursor_hidden = 0;
391 OUTPUT_IF (tty, tty->TS_cursor_normal);
0db017c0 392 if (visible_cursor)
b58cb614 393 OUTPUT_IF (tty, tty->TS_cursor_visible);
d284f58f 394 }
a168702a
GM
395}
396
397
08a24c47
JB
398/* Set standout mode to the state it should be in for
399 empty space inside windows. What this is,
400 depends on the user option inverse-video. */
401
ed8dad6b
KL
402static void
403tty_background_highlight (struct tty_display_info *tty)
08a24c47 404{
08a24c47 405 if (inverse_video)
ed8dad6b 406 tty_turn_on_highlight (tty);
08a24c47 407 else
ed8dad6b 408 tty_turn_off_highlight (tty);
08a24c47
JB
409}
410
411/* Set standout mode to the mode specified for the text to be output. */
412
dfcf069d 413static void
ed8dad6b 414tty_highlight_if_desired (struct tty_display_info *tty)
08a24c47 415{
8ede64a5 416 if (inverse_video)
ed8dad6b 417 tty_turn_on_highlight (tty);
8ede64a5 418 else
ed8dad6b 419 tty_turn_off_highlight (tty);
08a24c47
JB
420}
421\f
422
a168702a
GM
423/* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are
424 frame-relative coordinates. */
08a24c47 425
ed8dad6b 426static void
385ed61f 427tty_cursor_to (struct frame *f, int vpos, int hpos)
3224dac1 428{
3224dac1 429 struct tty_display_info *tty = FRAME_TTY (f);
6548cf00 430
36cae867
KH
431 /* Detect the case where we are called from reset_sys_modes
432 and the costs have never been calculated. Do nothing. */
fca177d4 433 if (! tty->costs_set)
36cae867
KH
434 return;
435
6548cf00
KL
436 if (curY (tty) == vpos
437 && curX (tty) == hpos)
08a24c47 438 return;
fca177d4 439 if (!tty->TF_standout_motion)
ed8dad6b 440 tty_background_highlight (tty);
fca177d4 441 if (!tty->TF_insmode_motion)
ed8dad6b 442 tty_turn_off_insert (tty);
6548cf00 443 cmgoto (tty, vpos, hpos);
08a24c47
JB
444}
445
446/* Similar but don't take any account of the wasted characters. */
447
ed8dad6b 448static void
385ed61f 449tty_raw_cursor_to (struct frame *f, int row, int col)
3224dac1 450{
3224dac1
KL
451 struct tty_display_info *tty = FRAME_TTY (f);
452
6548cf00
KL
453 if (curY (tty) == row
454 && curX (tty) == col)
08a24c47 455 return;
fca177d4 456 if (!tty->TF_standout_motion)
ed8dad6b 457 tty_background_highlight (tty);
fca177d4 458 if (!tty->TF_insmode_motion)
ed8dad6b 459 tty_turn_off_insert (tty);
6548cf00 460 cmgoto (tty, row, col);
08a24c47
JB
461}
462\f
463/* Erase operations */
464
da8e1115
KL
465/* Clear from cursor to end of frame on a termcap device. */
466
ed8dad6b 467static void
385ed61f 468tty_clear_to_end (struct frame *f)
3224dac1
KL
469{
470 register int i;
3224dac1
KL
471 struct tty_display_info *tty = FRAME_TTY (f);
472
fca177d4 473 if (tty->TS_clr_to_bottom)
08a24c47 474 {
ed8dad6b 475 tty_background_highlight (tty);
fca177d4 476 OUTPUT (tty, tty->TS_clr_to_bottom);
08a24c47
JB
477 }
478 else
479 {
6548cf00 480 for (i = curY (tty); i < FRAME_LINES (f); i++)
08a24c47 481 {
385ed61f
KL
482 cursor_to (f, i, 0);
483 clear_end_of_line (f, FRAME_COLS (f));
08a24c47
JB
484 }
485 }
486}
487
da8e1115
KL
488/* Clear an entire termcap frame. */
489
ed8dad6b 490static void
385ed61f 491tty_clear_frame (struct frame *f)
3224dac1 492{
3224dac1
KL
493 struct tty_display_info *tty = FRAME_TTY (f);
494
fca177d4 495 if (tty->TS_clr_frame)
08a24c47 496 {
ed8dad6b 497 tty_background_highlight (tty);
fca177d4 498 OUTPUT (tty, tty->TS_clr_frame);
6548cf00 499 cmat (tty, 0, 0);
08a24c47
JB
500 }
501 else
502 {
385ed61f
KL
503 cursor_to (f, 0, 0);
504 clear_to_end (f);
08a24c47
JB
505 }
506}
507
da8e1115
KL
508/* An implementation of clear_end_of_line for termcap frames.
509
510 Note that the cursor may be moved, on terminals lacking a `ce' string. */
511
ed8dad6b 512static void
385ed61f 513tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
0a125897
KL
514{
515 register int i;
3224dac1
KL
516 struct tty_display_info *tty = FRAME_TTY (f);
517
36cae867
KH
518 /* Detect the case where we are called from reset_sys_modes
519 and the costs have never been calculated. Do nothing. */
fca177d4 520 if (! tty->costs_set)
36cae867
KH
521 return;
522
6548cf00 523 if (curX (tty) >= first_unused_hpos)
08a24c47 524 return;
ed8dad6b 525 tty_background_highlight (tty);
fca177d4 526 if (tty->TS_clr_line)
08a24c47 527 {
fca177d4 528 OUTPUT1 (tty, tty->TS_clr_line);
08a24c47
JB
529 }
530 else
531 { /* have to do it the hard way */
ed8dad6b 532 tty_turn_off_insert (tty);
08a24c47 533
a168702a 534 /* Do not write in last row last col with Auto-wrap on. */
6548cf00 535 if (AutoWrap (tty)
0a125897
KL
536 && curY (tty) == FrameRows (tty) - 1
537 && first_unused_hpos == FrameCols (tty))
08a24c47
JB
538 first_unused_hpos--;
539
6548cf00 540 for (i = curX (tty); i < first_unused_hpos; i++)
08a24c47 541 {
0b0d3e0b
KL
542 if (tty->termscript)
543 fputc (' ', tty->termscript);
544 fputc (' ', tty->output);
08a24c47 545 }
6548cf00 546 cmplus (tty, first_unused_hpos - curX (tty));
08a24c47
JB
547 }
548}
549\f
af645abf
KH
550/* Buffer to store the source and result of code conversion for terminal. */
551static unsigned char *encode_terminal_buf;
552/* Allocated size of the above buffer. */
553static int encode_terminal_bufsize;
a4decb7f 554
af645abf
KH
555/* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
556 Set CODING->produced to the byte-length of the resulting byte
557 sequence, and return a pointer to that byte sequence. */
a4decb7f 558
302db699 559unsigned char *
af645abf 560encode_terminal_code (src, src_len, coding)
a168702a 561 struct glyph *src;
a4decb7f 562 int src_len;
af645abf 563 struct coding_system *coding;
a4decb7f 564{
feef4f84 565 struct glyph *src_end = src + src_len;
085d5908 566 register GLYPH g;
af645abf
KH
567 unsigned char *buf;
568 int nchars, nbytes, required;
a4decb7f
KH
569 register int tlen = GLYPH_TABLE_LENGTH;
570 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
6589fd67 571
af645abf
KH
572 /* Allocate sufficient size of buffer to store all characters in
573 multibyte-form. But, it may be enlarged on demand if
574 Vglyph_table contains a string. */
575 required = MAX_MULTIBYTE_LENGTH * src_len;
576 if (encode_terminal_bufsize < required)
577 {
af645abf
KH
578 if (encode_terminal_bufsize == 0)
579 encode_terminal_buf = xmalloc (required);
580 else
581 encode_terminal_buf = xrealloc (encode_terminal_buf, required);
d6d31e57 582 encode_terminal_bufsize = required;
af645abf 583 }
a4decb7f 584
af645abf
KH
585 buf = encode_terminal_buf;
586 nchars = 0;
a4decb7f
KH
587 while (src < src_end)
588 {
a4decb7f 589 /* We must skip glyphs to be padded for a wide character. */
a168702a 590 if (! CHAR_GLYPH_PADDING_P (*src))
a4decb7f 591 {
32de38e4
KH
592 g = GLYPH_FROM_CHAR_GLYPH (src[0]);
593
594 if (g < 0 || g >= tlen)
085d5908 595 {
32de38e4 596 /* This glyph doesn't has an entry in Vglyph_table. */
af645abf
KH
597 if (CHAR_VALID_P (src->u.ch, 0))
598 buf += CHAR_STRING (src->u.ch, buf);
32de38e4 599 else
af645abf
KH
600 *buf++ = SPACEGLYPH;
601 nchars++;
085d5908 602 }
32de38e4 603 else
a4decb7f 604 {
32de38e4 605 /* This glyph has an entry in Vglyph_table,
a4decb7f
KH
606 so process any alias before testing for simpleness. */
607 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
32de38e4
KH
608
609 if (GLYPH_SIMPLE_P (tbase, tlen, g))
610 {
af645abf
KH
611 int c = FAST_GLYPH_CHAR (g);
612
613 if (CHAR_VALID_P (c, 0))
614 buf += CHAR_STRING (c, buf);
615 else
616 *buf++ = SPACEGLYPH;
617 nchars++;
32de38e4
KH
618 }
619 else
620 {
621 /* We have a string in Vglyph_table. */
af645abf
KH
622 Lisp_Object string;
623
624 string = tbase[g];
625 if (! STRING_MULTIBYTE (string))
626 string = string_to_multibyte (string);
627 nbytes = buf - encode_terminal_buf;
fd4a9f8f 628 if (encode_terminal_bufsize < nbytes + SBYTES (string))
af645abf
KH
629 {
630 encode_terminal_bufsize = nbytes + SBYTES (string);
631 encode_terminal_buf = xrealloc (encode_terminal_buf,
632 encode_terminal_bufsize);
633 buf = encode_terminal_buf + nbytes;
634 }
635 bcopy (SDATA (string), buf, SBYTES (string));
636 buf += SBYTES (string);
637 nchars += SCHARS (string);
32de38e4 638 }
171d7f24 639 }
a4decb7f
KH
640 }
641 src++;
642 }
177c0ea7 643
af645abf
KH
644 nbytes = buf - encode_terminal_buf;
645 coding->src_multibyte = 1;
646 coding->dst_multibyte = 0;
647 if (SYMBOLP (coding->pre_write_conversion)
648 && ! NILP (Ffboundp (coding->pre_write_conversion)))
649 {
feef4f84 650 run_pre_write_conversin_on_c_str (&encode_terminal_buf,
af645abf
KH
651 &encode_terminal_bufsize,
652 nchars, nbytes, coding);
653 nchars = coding->produced_char;
654 nbytes = coding->produced;
655 }
656 required = nbytes + encoding_buffer_size (coding, nbytes);
657 if (encode_terminal_bufsize < required)
658 {
659 encode_terminal_bufsize = required;
660 encode_terminal_buf = xrealloc (encode_terminal_buf, required);
661 }
a4decb7f 662
af645abf
KH
663 encode_coding (coding, encode_terminal_buf, encode_terminal_buf + nbytes,
664 nbytes, encode_terminal_bufsize - nbytes);
665 return encode_terminal_buf + nbytes;
a4decb7f
KH
666}
667
08a24c47 668
da8e1115
KL
669/* An implementation of write_glyphs for termcap frames. */
670
ed8dad6b 671static void
385ed61f 672tty_write_glyphs (struct frame *f, struct glyph *string, int len)
08a24c47 673{
af645abf
KH
674 unsigned char *conversion_buffer;
675 struct coding_system *coding;
08a24c47 676
3224dac1 677 struct tty_display_info *tty = FRAME_TTY (f);
6548cf00 678
ed8dad6b 679 tty_turn_off_insert (tty);
fca177d4 680 tty_hide_cursor (tty);
08a24c47 681
a168702a 682 /* Don't dare write in last column of bottom line, if Auto-Wrap,
ff11dfa1 683 since that would scroll the whole frame on some terminals. */
08a24c47 684
6548cf00
KL
685 if (AutoWrap (tty)
686 && curY (tty) + 1 == FRAME_LINES (f)
687 && (curX (tty) + len) == FRAME_COLS (f))
08a24c47 688 len --;
a4decb7f
KH
689 if (len <= 0)
690 return;
08a24c47 691
6548cf00 692 cmplus (tty, len);
177c0ea7 693
af645abf
KH
694 /* If terminal_coding does any conversion, use it, otherwise use
695 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
696 because it always return 1 if the member src_multibyte is 1. */
fad2f685
KL
697 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
698 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
6589fd67
KH
699 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
700 the tail. */
af645abf 701 coding->mode &= ~CODING_MODE_LAST_BLOCK;
177c0ea7 702
a4decb7f 703 while (len > 0)
08a24c47 704 {
a168702a 705 /* Identify a run of glyphs with the same face. */
32de38e4 706 int face_id = string->face_id;
a168702a 707 int n;
177c0ea7 708
a168702a 709 for (n = 1; n < len; ++n)
32de38e4 710 if (string[n].face_id != face_id)
a168702a
GM
711 break;
712
713 /* Turn appearance modes of the face of the run on. */
ed8dad6b 714 tty_highlight_if_desired (tty);
a168702a
GM
715 turn_on_face (f, face_id);
716
af645abf
KH
717 if (n == len)
718 /* This is the last run. */
719 coding->mode |= CODING_MODE_LAST_BLOCK;
720 conversion_buffer = encode_terminal_code (string, n, coding);
721 if (coding->produced > 0)
08a24c47 722 {
1a935bfd 723 BLOCK_INPUT;
fad2f685
KL
724 fwrite (conversion_buffer, 1, coding->produced, tty->output);
725 if (ferror (tty->output))
726 clearerr (tty->output);
727 if (tty->termscript)
728 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
1a935bfd 729 UNBLOCK_INPUT;
08a24c47 730 }
af645abf
KH
731 len -= n;
732 string += n;
a168702a
GM
733
734 /* Turn appearance modes off. */
735 turn_off_face (f, face_id);
ed8dad6b 736 tty_turn_off_highlight (tty);
a4decb7f 737 }
177c0ea7 738
6548cf00 739 cmcheckmagic (tty);
08a24c47
JB
740}
741
b870aa61
SM
742#ifdef HAVE_GPM /* Only used by GPM code. */
743
7be1c21a
MB
744static void
745tty_write_glyphs_with_face (f, string, len, face_id)
746 register struct frame *f;
e882229c
NR
747 register struct glyph *string;
748 register int len, face_id;
749{
e882229c
NR
750 unsigned char *conversion_buffer;
751 struct coding_system *coding;
752
7be1c21a
MB
753 struct tty_display_info *tty = FRAME_TTY (f);
754
755 tty_turn_off_insert (tty);
756 tty_hide_cursor (tty);
e882229c
NR
757
758 /* Don't dare write in last column of bottom line, if Auto-Wrap,
759 since that would scroll the whole frame on some terminals. */
760
7be1c21a
MB
761 if (AutoWrap (tty)
762 && curY (tty) + 1 == FRAME_LINES (f)
763 && (curX (tty) + len) == FRAME_COLS (f))
e882229c
NR
764 len --;
765 if (len <= 0)
766 return;
767
7be1c21a 768 cmplus (tty, len);
e882229c
NR
769
770 /* If terminal_coding does any conversion, use it, otherwise use
771 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
772 because it always return 1 if the member src_multibyte is 1. */
7be1c21a
MB
773 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
774 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
e882229c
NR
775 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
776 the tail. */
777 coding->mode &= ~CODING_MODE_LAST_BLOCK;
778
e882229c 779 /* Turn appearance modes of the face. */
7be1c21a 780 tty_highlight_if_desired (tty);
e882229c
NR
781 turn_on_face (f, face_id);
782
783 coding->mode |= CODING_MODE_LAST_BLOCK;
784 conversion_buffer = encode_terminal_code (string, len, coding);
785 if (coding->produced > 0)
786 {
787 BLOCK_INPUT;
7be1c21a
MB
788 fwrite (conversion_buffer, 1, coding->produced, tty->output);
789 if (ferror (tty->output))
790 clearerr (tty->output);
791 if (tty->termscript)
792 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
e882229c
NR
793 UNBLOCK_INPUT;
794 }
795
796 /* Turn appearance modes off. */
797 turn_off_face (f, face_id);
7be1c21a 798 tty_turn_off_highlight (tty);
e882229c 799
7be1c21a 800 cmcheckmagic (tty);
e882229c 801}
b870aa61 802#endif
177c0ea7 803
da8e1115
KL
804/* An implementation of insert_glyphs for termcap frames. */
805
ed8dad6b 806static void
385ed61f 807tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
3224dac1
KL
808{
809 char *buf;
810 struct glyph *glyph = NULL;
af645abf
KH
811 unsigned char *conversion_buffer;
812 unsigned char space[1];
813 struct coding_system *coding;
3224dac1
KL
814
815 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 816
fca177d4 817 if (tty->TS_ins_multi_chars)
08a24c47 818 {
fca177d4 819 buf = tparam (tty->TS_ins_multi_chars, 0, 0, len);
6548cf00 820 OUTPUT1 (tty, buf);
9ac0d9e0 821 xfree (buf);
08a24c47 822 if (start)
385ed61f 823 write_glyphs (f, start, len);
08a24c47
JB
824 return;
825 }
826
ed8dad6b 827 tty_turn_on_insert (tty);
6548cf00 828 cmplus (tty, len);
af645abf
KH
829
830 if (! start)
831 space[0] = SPACEGLYPH;
832
833 /* If terminal_coding does any conversion, use it, otherwise use
834 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
835 because it always return 1 if the member src_multibyte is 1. */
fad2f685
KL
836 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
837 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
af645abf
KH
838 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
839 the tail. */
840 coding->mode &= ~CODING_MODE_LAST_BLOCK;
841
07109bf9 842 while (len-- > 0)
08a24c47 843 {
fca177d4 844 OUTPUT1_IF (tty, tty->TS_ins_char);
08a24c47 845 if (!start)
32de38e4 846 {
af645abf
KH
847 conversion_buffer = space;
848 coding->produced = 1;
32de38e4 849 }
08a24c47 850 else
08a24c47 851 {
ed8dad6b 852 tty_highlight_if_desired (tty);
32de38e4 853 turn_on_face (f, start->face_id);
816be8b8 854 glyph = start;
a168702a 855 ++start;
a4decb7f
KH
856 /* We must open sufficient space for a character which
857 occupies more than one column. */
a168702a 858 while (len && CHAR_GLYPH_PADDING_P (*start))
a4decb7f 859 {
fca177d4 860 OUTPUT1_IF (tty, tty->TS_ins_char);
a4decb7f
KH
861 start++, len--;
862 }
a4decb7f 863
32de38e4
KH
864 if (len <= 0)
865 /* This is the last glyph. */
af645abf 866 coding->mode |= CODING_MODE_LAST_BLOCK;
32de38e4 867
fad2f685 868 conversion_buffer = encode_terminal_code (glyph, 1, coding);
32de38e4 869 }
a4decb7f 870
af645abf 871 if (coding->produced > 0)
08a24c47 872 {
1a935bfd 873 BLOCK_INPUT;
fad2f685 874 fwrite (conversion_buffer, 1, coding->produced, tty->output);
0b0d3e0b
KL
875 if (ferror (tty->output))
876 clearerr (tty->output);
877 if (tty->termscript)
fad2f685 878 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
1a935bfd 879 UNBLOCK_INPUT;
08a24c47
JB
880 }
881
fca177d4 882 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
32de38e4 883 if (start)
65aa5e85
GM
884 {
885 turn_off_face (f, glyph->face_id);
ed8dad6b 886 tty_turn_off_highlight (tty);
65aa5e85 887 }
9a6b6f92 888 }
177c0ea7 889
6548cf00 890 cmcheckmagic (tty);
08a24c47
JB
891}
892
da8e1115
KL
893/* An implementation of delete_glyphs for termcap frames. */
894
ed8dad6b 895static void
385ed61f 896tty_delete_glyphs (struct frame *f, int n)
3224dac1
KL
897{
898 char *buf;
899 register int i;
3224dac1
KL
900
901 struct tty_display_info *tty = FRAME_TTY (f);
6548cf00 902
fca177d4 903 if (tty->delete_in_insert_mode)
08a24c47 904 {
ed8dad6b 905 tty_turn_on_insert (tty);
08a24c47
JB
906 }
907 else
908 {
ed8dad6b 909 tty_turn_off_insert (tty);
fca177d4 910 OUTPUT_IF (tty, tty->TS_delete_mode);
08a24c47 911 }
daf01701 912
fca177d4 913 if (tty->TS_del_multi_chars)
08a24c47 914 {
fca177d4 915 buf = tparam (tty->TS_del_multi_chars, 0, 0, n);
6548cf00 916 OUTPUT1 (tty, buf);
9ac0d9e0 917 xfree (buf);
08a24c47
JB
918 }
919 else
920 for (i = 0; i < n; i++)
fca177d4
KL
921 OUTPUT1 (tty, tty->TS_del_char);
922 if (!tty->delete_in_insert_mode)
923 OUTPUT_IF (tty, tty->TS_end_delete_mode);
08a24c47
JB
924}
925\f
da8e1115
KL
926/* An implementation of ins_del_lines for termcap frames. */
927
ed8dad6b 928static void
385ed61f 929tty_ins_del_lines (struct frame *f, int vpos, int n)
3224dac1 930{
3224dac1
KL
931 struct tty_display_info *tty = FRAME_TTY (f);
932 char *multi = n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
933 char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
934 char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
935
936 register int i = n > 0 ? n : -n;
937 register char *buf;
938
939 /* If the lines below the insertion are being pushed
940 into the end of the window, this is the same as clearing;
941 and we know the lines are already clear, since the matching
942 deletion has already been done. So can ignore this. */
943 /* If the lines below the deletion are blank lines coming
944 out of the end of the window, don't bother,
945 as there will be a matching inslines later that will flush them. */
946 if (FRAME_SCROLL_REGION_OK (f)
947 && vpos + i >= tty->specified_window)
948 return;
949 if (!FRAME_MEMORY_BELOW_FRAME (f)
950 && vpos + i >= FRAME_LINES (f))
951 return;
952
953 if (multi)
08a24c47 954 {
6839f1e2 955 raw_cursor_to (f, vpos, 0);
ed8dad6b 956 tty_background_highlight (tty);
3224dac1
KL
957 buf = tparam (multi, 0, 0, i);
958 OUTPUT (tty, buf);
959 xfree (buf);
960 }
961 else if (single)
962 {
6839f1e2 963 raw_cursor_to (f, vpos, 0);
ed8dad6b 964 tty_background_highlight (tty);
3224dac1
KL
965 while (--i >= 0)
966 OUTPUT (tty, single);
967 if (tty->TF_teleray)
968 curX (tty) = 0;
08a24c47 969 }
08a24c47
JB
970 else
971 {
ed8dad6b 972 tty_set_scroll_region (f, vpos, tty->specified_window);
3224dac1 973 if (n < 0)
6839f1e2 974 raw_cursor_to (f, tty->specified_window - 1, 0);
08a24c47 975 else
6839f1e2 976 raw_cursor_to (f, vpos, 0);
ed8dad6b 977 tty_background_highlight (tty);
3224dac1
KL
978 while (--i >= 0)
979 OUTPUTL (tty, scroll, tty->specified_window - vpos);
ed8dad6b 980 tty_set_scroll_region (f, 0, tty->specified_window);
3224dac1
KL
981 }
982
983 if (!FRAME_SCROLL_REGION_OK (f)
984 && FRAME_MEMORY_BELOW_FRAME (f)
985 && n < 0)
986 {
385ed61f
KL
987 cursor_to (f, FRAME_LINES (f) + n, 0);
988 clear_to_end (f);
08a24c47
JB
989 }
990}
991\f
992/* Compute cost of sending "str", in characters,
993 not counting any line-dependent padding. */
994
995int
6839f1e2 996string_cost (char *str)
08a24c47
JB
997{
998 cost = 0;
999 if (str)
1000 tputs (str, 0, evalcost);
1001 return cost;
1002}
1003
1004/* Compute cost of sending "str", in characters,
1005 counting any line-dependent padding at one line. */
1006
1007static int
6839f1e2 1008string_cost_one_line (char *str)
08a24c47
JB
1009{
1010 cost = 0;
1011 if (str)
1012 tputs (str, 1, evalcost);
1013 return cost;
1014}
1015
1016/* Compute per line amount of line-dependent padding,
1017 in tenths of characters. */
1018
1019int
6839f1e2 1020per_line_cost (char *str)
08a24c47
JB
1021{
1022 cost = 0;
1023 if (str)
1024 tputs (str, 0, evalcost);
1025 cost = - cost;
1026 if (str)
1027 tputs (str, 10, evalcost);
1028 return cost;
1029}
1030
1031#ifndef old
1032/* char_ins_del_cost[n] is cost of inserting N characters.
8dd0c7cb 1033 char_ins_del_cost[-n] is cost of deleting N characters.
9882535b 1034 The length of this vector is based on max_frame_cols. */
08a24c47
JB
1035
1036int *char_ins_del_vector;
1037
9882535b 1038#define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_COLS ((f))])
08a24c47
JB
1039#endif
1040
1041/* ARGSUSED */
1042static void
6839f1e2 1043calculate_ins_del_char_costs (struct frame *f)
08a24c47 1044{
28d7d09f 1045 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47
JB
1046 int ins_startup_cost, del_startup_cost;
1047 int ins_cost_per_char, del_cost_per_char;
1048 register int i;
1049 register int *p;
1050
fca177d4 1051 if (tty->TS_ins_multi_chars)
08a24c47
JB
1052 {
1053 ins_cost_per_char = 0;
fca177d4 1054 ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars);
08a24c47 1055 }
fca177d4
KL
1056 else if (tty->TS_ins_char || tty->TS_pad_inserted_char
1057 || (tty->TS_insert_mode && tty->TS_end_insert_mode))
08a24c47 1058 {
fca177d4
KL
1059 ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode)
1060 + string_cost (tty->TS_end_insert_mode))) / 100;
1061 ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char)
1062 + string_cost_one_line (tty->TS_pad_inserted_char));
08a24c47
JB
1063 }
1064 else
1065 {
1066 ins_startup_cost = 9999;
1067 ins_cost_per_char = 0;
1068 }
1069
fca177d4 1070 if (tty->TS_del_multi_chars)
08a24c47
JB
1071 {
1072 del_cost_per_char = 0;
fca177d4 1073 del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars);
08a24c47 1074 }
fca177d4 1075 else if (tty->TS_del_char)
08a24c47 1076 {
fca177d4
KL
1077 del_startup_cost = (string_cost (tty->TS_delete_mode)
1078 + string_cost (tty->TS_end_delete_mode));
1079 if (tty->delete_in_insert_mode)
08a24c47 1080 del_startup_cost /= 2;
fca177d4 1081 del_cost_per_char = string_cost_one_line (tty->TS_del_char);
08a24c47
JB
1082 }
1083 else
1084 {
1085 del_startup_cost = 9999;
1086 del_cost_per_char = 0;
1087 }
1088
1089 /* Delete costs are at negative offsets */
fca177d4
KL
1090 p = &char_ins_del_cost (f)[0];
1091 for (i = FRAME_COLS (f); --i >= 0;)
08a24c47
JB
1092 *--p = (del_startup_cost += del_cost_per_char);
1093
1094 /* Doing nothing is free */
fca177d4 1095 p = &char_ins_del_cost (f)[0];
08a24c47
JB
1096 *p++ = 0;
1097
1098 /* Insert costs are at positive offsets */
fca177d4 1099 for (i = FRAME_COLS (f); --i >= 0;)
08a24c47
JB
1100 *p++ = (ins_startup_cost += ins_cost_per_char);
1101}
1102
dfcf069d 1103void
6839f1e2 1104calculate_costs (struct frame *frame)
08a24c47 1105{
9f732a77 1106 FRAME_COST_BAUD_RATE (frame) = baud_rate;
08a24c47 1107
28d440ab 1108 if (FRAME_TERMCAP_P (frame))
daf01701
KL
1109 {
1110 struct tty_display_info *tty = FRAME_TTY (frame);
1111 register char *f = (tty->TS_set_scroll_region
1112 ? tty->TS_set_scroll_region
1113 : tty->TS_set_scroll_region_1);
08a24c47 1114
daf01701 1115 FRAME_SCROLL_REGION_COST (frame) = string_cost (f);
08a24c47 1116
daf01701 1117 tty->costs_set = 1;
08a24c47 1118
daf01701
KL
1119 /* These variables are only used for terminal stuff. They are
1120 allocated once for the terminal frame of X-windows emacs, but not
1121 used afterwards.
8dd0c7cb 1122
daf01701
KL
1123 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1124 X turns off char_ins_del_ok. */
08a24c47 1125
daf01701
KL
1126 max_frame_lines = max (max_frame_lines, FRAME_LINES (frame));
1127 max_frame_cols = max (max_frame_cols, FRAME_COLS (frame));
08a24c47 1128
daf01701
KL
1129 if (char_ins_del_vector != 0)
1130 char_ins_del_vector
1131 = (int *) xrealloc (char_ins_del_vector,
1132 (sizeof (int)
1133 + 2 * max_frame_cols * sizeof (int)));
1134 else
1135 char_ins_del_vector
1136 = (int *) xmalloc (sizeof (int)
1137 + 2 * max_frame_cols * sizeof (int));
08a24c47 1138
daf01701
KL
1139 bzero (char_ins_del_vector, (sizeof (int)
1140 + 2 * max_frame_cols * sizeof (int)));
1141
1142
1143 if (f && (!tty->TS_ins_line && !tty->TS_del_line))
1144 do_line_insertion_deletion_costs (frame,
1145 tty->TS_rev_scroll, tty->TS_ins_multi_lines,
1146 tty->TS_fwd_scroll, tty->TS_del_multi_lines,
1147 f, f, 1);
1148 else
1149 do_line_insertion_deletion_costs (frame,
1150 tty->TS_ins_line, tty->TS_ins_multi_lines,
1151 tty->TS_del_line, tty->TS_del_multi_lines,
1152 0, 0, 1);
1153
1154 calculate_ins_del_char_costs (frame);
1155
1156 /* Don't use TS_repeat if its padding is worse than sending the chars */
1157 if (tty->TS_repeat && per_line_cost (tty->TS_repeat) * baud_rate < 9000)
1158 tty->RPov = string_cost (tty->TS_repeat);
1159 else
1160 tty->RPov = FRAME_COLS (frame) * 2;
08a24c47 1161
daf01701
KL
1162 cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */
1163 }
08a24c47
JB
1164}
1165\f
a796ac82
JB
1166struct fkey_table {
1167 char *cap, *name;
1168};
1169
01d8deb0
ER
1170 /* Termcap capability names that correspond directly to X keysyms.
1171 Some of these (marked "terminfo") aren't supplied by old-style
1172 (Berkeley) termcap entries. They're listed in X keysym order;
1173 except we put the keypad keys first, so that if they clash with
1174 other keys (as on the IBM PC keyboard) they get overridden.
1175 */
1176
a168702a
GM
1177static struct fkey_table keys[] =
1178{
8103ad1a
PJ
1179 {"kh", "home"}, /* termcap */
1180 {"kl", "left"}, /* termcap */
1181 {"ku", "up"}, /* termcap */
1182 {"kr", "right"}, /* termcap */
1183 {"kd", "down"}, /* termcap */
1184 {"%8", "prior"}, /* terminfo */
1185 {"%5", "next"}, /* terminfo */
1186 {"@7", "end"}, /* terminfo */
1187 {"@1", "begin"}, /* terminfo */
1188 {"*6", "select"}, /* terminfo */
1189 {"%9", "print"}, /* terminfo */
1190 {"@4", "execute"}, /* terminfo --- actually the `command' key */
01d8deb0
ER
1191 /*
1192 * "insert" --- see below
1193 */
8103ad1a
PJ
1194 {"&8", "undo"}, /* terminfo */
1195 {"%0", "redo"}, /* terminfo */
1196 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1197 {"@0", "find"}, /* terminfo */
1198 {"@2", "cancel"}, /* terminfo */
1199 {"%1", "help"}, /* terminfo */
01d8deb0
ER
1200 /*
1201 * "break" goes here, but can't be reliably intercepted with termcap
1202 */
8103ad1a 1203 {"&4", "reset"}, /* terminfo --- actually `restart' */
01d8deb0
ER
1204 /*
1205 * "system" and "user" --- no termcaps
1206 */
8103ad1a
PJ
1207 {"kE", "clearline"}, /* terminfo */
1208 {"kA", "insertline"}, /* terminfo */
1209 {"kL", "deleteline"}, /* terminfo */
1210 {"kI", "insertchar"}, /* terminfo */
1211 {"kD", "deletechar"}, /* terminfo */
1212 {"kB", "backtab"}, /* terminfo */
01d8deb0
ER
1213 /*
1214 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1215 */
8103ad1a 1216 {"@8", "kp-enter"}, /* terminfo */
01d8deb0
ER
1217 /*
1218 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1219 * "kp-multiply", "kp-add", "kp-separator",
1220 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1221 * --- no termcaps for any of these.
1222 */
8103ad1a 1223 {"K4", "kp-1"}, /* terminfo */
01d8deb0
ER
1224 /*
1225 * "kp-2" --- no termcap
1226 */
8103ad1a 1227 {"K5", "kp-3"}, /* terminfo */
01d8deb0
ER
1228 /*
1229 * "kp-4" --- no termcap
1230 */
8103ad1a 1231 {"K2", "kp-5"}, /* terminfo */
01d8deb0
ER
1232 /*
1233 * "kp-6" --- no termcap
1234 */
8103ad1a 1235 {"K1", "kp-7"}, /* terminfo */
01d8deb0
ER
1236 /*
1237 * "kp-8" --- no termcap
1238 */
8103ad1a 1239 {"K3", "kp-9"}, /* terminfo */
01d8deb0
ER
1240 /*
1241 * "kp-equal" --- no termcap
1242 */
8103ad1a
PJ
1243 {"k1", "f1"},
1244 {"k2", "f2"},
1245 {"k3", "f3"},
1246 {"k4", "f4"},
1247 {"k5", "f5"},
1248 {"k6", "f6"},
1249 {"k7", "f7"},
1250 {"k8", "f8"},
60ec7b7e
DN
1251 {"k9", "f9"},
1252
1253 {"&0", "S-cancel"}, /*shifted cancel key*/
1254 {"&9", "S-begin"}, /*shifted begin key*/
1255 {"*0", "S-find"}, /*shifted find key*/
1256 {"*1", "S-execute"}, /*shifted execute? actually shifted command key*/
1257 {"*4", "S-delete"}, /*shifted delete-character key*/
1258 {"*7", "S-end"}, /*shifted end key*/
1259 {"*8", "S-clearline"}, /*shifted clear-to end-of-line key*/
1260 {"#1", "S-help"}, /*shifted help key*/
1261 {"#2", "S-home"}, /*shifted home key*/
1262 {"#3", "S-insert"}, /*shifted insert-character key*/
1263 {"#4", "S-left"}, /*shifted left-arrow key*/
1264 {"%d", "S-menu"}, /*shifted menu? actually shifted options key*/
1265 {"%c", "S-next"}, /*shifted next key*/
1266 {"%e", "S-prior"}, /*shifted previous key*/
1267 {"%f", "S-print"}, /*shifted print key*/
1268 {"%g", "S-redo"}, /*shifted redo key*/
1269 {"%i", "S-right"}, /*shifted right-arrow key*/
1270 {"!3", "S-undo"} /*shifted undo key*/
a796ac82
JB
1271 };
1272
e7cf0fa0
KL
1273static char **term_get_fkeys_address;
1274static KBOARD *term_get_fkeys_kboard;
f2a00342 1275static Lisp_Object term_get_fkeys_1 ();
465db27b 1276
4f4a84ec 1277/* Find the escape codes sent by the function keys for Vinput_decode_map.
177c0ea7 1278 This function scans the termcap function key sequence entries, and
4f4a84ec 1279 adds entries to Vinput_decode_map for each function key it finds. */
01d8deb0 1280
ed8dad6b 1281static void
e7cf0fa0 1282term_get_fkeys (address, kboard)
5c2c7893 1283 char **address;
e7cf0fa0 1284 KBOARD *kboard;
f2a00342
RM
1285{
1286 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1287 errors during the call. The only errors should be from Fdefine_key
1288 when given a key sequence containing an invalid prefix key. If the
1289 termcap defines function keys which use a prefix that is already bound
1290 to a command by the default bindings, we should silently ignore that
1291 function key specification, rather than giving the user an error and
1292 refusing to run at all on such a terminal. */
1293
1294 extern Lisp_Object Fidentity ();
e7cf0fa0
KL
1295 term_get_fkeys_address = address;
1296 term_get_fkeys_kboard = kboard;
f2a00342
RM
1297 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1298}
1299
1300static Lisp_Object
1301term_get_fkeys_1 ()
5c2c7893 1302{
5c2c7893
JB
1303 int i;
1304
e7cf0fa0
KL
1305 char **address = term_get_fkeys_address;
1306 KBOARD *kboard = term_get_fkeys_kboard;
1307
3e65092f 1308 /* This can happen if CANNOT_DUMP or with strange options. */
4f4a84ec
SM
1309 if (!KEYMAPP (kboard->Vinput_decode_map))
1310 kboard->Vinput_decode_map = Fmake_sparse_keymap (Qnil);
3e65092f 1311
5c2c7893
JB
1312 for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
1313 {
1314 char *sequence = tgetstr (keys[i].cap, address);
1315 if (sequence)
4f4a84ec 1316 Fdefine_key (kboard->Vinput_decode_map, build_string (sequence),
f2a00342
RM
1317 Fmake_vector (make_number (1),
1318 intern (keys[i].name)));
5c2c7893 1319 }
a796ac82
JB
1320
1321 /* The uses of the "k0" capability are inconsistent; sometimes it
1322 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
eb8c3be9 1323 We will attempt to politely accommodate both systems by testing for
a796ac82
JB
1324 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1325 */
1326 {
1327 char *k_semi = tgetstr ("k;", address);
1328 char *k0 = tgetstr ("k0", address);
1329 char *k0_name = "f10";
1330
1331 if (k_semi)
1332 {
95c11956
SM
1333 if (k0)
1334 /* Define f0 first, so that f10 takes precedence in case the
1335 key sequences happens to be the same. */
4f4a84ec 1336 Fdefine_key (kboard->Vinput_decode_map, build_string (k0),
95c11956 1337 Fmake_vector (make_number (1), intern ("f0")));
4f4a84ec 1338 Fdefine_key (kboard->Vinput_decode_map, build_string (k_semi),
f2a00342 1339 Fmake_vector (make_number (1), intern ("f10")));
a796ac82 1340 }
95c11956 1341 else if (k0)
4f4a84ec 1342 Fdefine_key (kboard->Vinput_decode_map, build_string (k0),
f2a00342 1343 Fmake_vector (make_number (1), intern (k0_name)));
a796ac82 1344 }
01d8deb0
ER
1345
1346 /* Set up cookies for numbered function keys above f10. */
1347 {
1348 char fcap[3], fkey[4];
1349
fc4f24da 1350 fcap[0] = 'F'; fcap[2] = '\0';
01d8deb0
ER
1351 for (i = 11; i < 64; i++)
1352 {
1353 if (i <= 19)
1354 fcap[1] = '1' + i - 11;
1355 else if (i <= 45)
b59ab95c 1356 fcap[1] = 'A' + i - 20;
01d8deb0 1357 else
b59ab95c 1358 fcap[1] = 'a' + i - 46;
01d8deb0 1359
fc4f24da
RS
1360 {
1361 char *sequence = tgetstr (fcap, address);
1362 if (sequence)
1363 {
465db27b 1364 sprintf (fkey, "f%d", i);
4f4a84ec 1365 Fdefine_key (kboard->Vinput_decode_map, build_string (sequence),
f2a00342
RM
1366 Fmake_vector (make_number (1),
1367 intern (fkey)));
fc4f24da
RS
1368 }
1369 }
01d8deb0
ER
1370 }
1371 }
1372
1373 /*
1374 * Various mappings to try and get a better fit.
1375 */
1376 {
fc4f24da
RS
1377#define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1378 if (!tgetstr (cap1, address)) \
1379 { \
1380 char *sequence = tgetstr (cap2, address); \
e7cf0fa0 1381 if (sequence) \
4f4a84ec 1382 Fdefine_key (kboard->Vinput_decode_map, build_string (sequence), \
e7cf0fa0
KL
1383 Fmake_vector (make_number (1), \
1384 intern (sym))); \
fc4f24da 1385 }
177c0ea7 1386
01d8deb0 1387 /* if there's no key_next keycap, map key_npage to `next' keysym */
27b61785 1388 CONDITIONAL_REASSIGN ("%5", "kN", "next");
01d8deb0 1389 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
381d11a1 1390 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
01d8deb0 1391 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
27b61785 1392 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
403c995b
RS
1393 /* if there's no key_end keycap, map key_ll to 'end' keysym */
1394 CONDITIONAL_REASSIGN ("@7", "kH", "end");
0a7f697a
KH
1395
1396 /* IBM has their own non-standard dialect of terminfo.
1397 If the standard name isn't found, try the IBM name. */
1398 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1399 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1400 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1401 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1402 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1403 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1404 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1405 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1406 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1dd40212 1407#undef CONDITIONAL_REASSIGN
01d8deb0 1408 }
a168702a
GM
1409
1410 return Qnil;
5c2c7893
JB
1411}
1412
1413\f
a168702a
GM
1414/***********************************************************************
1415 Character Display Information
1416 ***********************************************************************/
1417
47021b11
KS
1418/* Avoid name clash with functions defined in xterm.c */
1419#ifdef static
1420#define append_glyph append_glyph_term
1421#define produce_stretch_glyph produce_stretch_glyph_term
1422#endif
1423
a168702a 1424static void append_glyph P_ ((struct it *));
f46c2aff 1425static void produce_stretch_glyph P_ ((struct it *));
a168702a
GM
1426
1427
1428/* Append glyphs to IT's glyph_row. Called from produce_glyphs for
d2b4c17d
KH
1429 terminal frames if IT->glyph_row != NULL. IT->char_to_display is
1430 the character for which to produce glyphs; IT->face_id contains the
1431 character's face. Padding glyphs are appended if IT->c has a
1432 IT->pixel_width > 1. */
177c0ea7 1433
a168702a
GM
1434static void
1435append_glyph (it)
1436 struct it *it;
1437{
1438 struct glyph *glyph, *end;
1439 int i;
1440
1441 xassert (it->glyph_row);
1442 glyph = (it->glyph_row->glyphs[it->area]
1443 + it->glyph_row->used[it->area]);
1444 end = it->glyph_row->glyphs[1 + it->area];
1445
177c0ea7
JB
1446 for (i = 0;
1447 i < it->pixel_width && glyph < end;
a168702a
GM
1448 ++i)
1449 {
1450 glyph->type = CHAR_GLYPH;
d13f3e2e 1451 glyph->pixel_width = 1;
d2b4c17d 1452 glyph->u.ch = it->char_to_display;
32de38e4
KH
1453 glyph->face_id = it->face_id;
1454 glyph->padding_p = i > 0;
a168702a
GM
1455 glyph->charpos = CHARPOS (it->position);
1456 glyph->object = it->object;
177c0ea7 1457
a168702a
GM
1458 ++it->glyph_row->used[it->area];
1459 ++glyph;
1460 }
1461}
1462
1463
b50fe468
RS
1464/* Produce glyphs for the display element described by IT. *IT
1465 specifies what we want to produce a glyph for (character, image, ...),
1466 and where in the glyph matrix we currently are (glyph row and hpos).
1467 produce_glyphs fills in output fields of *IT with information such as the
1468 pixel width and height of a character, and maybe output actual glyphs at
a168702a 1469 the same time if IT->glyph_row is non-null. See the explanation of
b50fe468
RS
1470 struct display_iterator in dispextern.h for an overview.
1471
1472 produce_glyphs also stores the result of glyph width, ascent
1473 etc. computations in *IT.
1474
1475 IT->glyph_row may be null, in which case produce_glyphs does not
1476 actually fill in the glyphs. This is used in the move_* functions
1477 in xdisp.c for text width and height computations.
1478
1479 Callers usually don't call produce_glyphs directly;
1480 instead they use the macro PRODUCE_GLYPHS. */
a168702a 1481
177c0ea7 1482void
a168702a
GM
1483produce_glyphs (it)
1484 struct it *it;
1485{
1486 /* If a hook is installed, let it do the work. */
1487 xassert (it->what == IT_CHARACTER
c7cba11d 1488 || it->what == IT_COMPOSITION
a168702a 1489 || it->what == IT_STRETCH);
177c0ea7 1490
f46c2aff
KS
1491 if (it->what == IT_STRETCH)
1492 {
1493 produce_stretch_glyph (it);
1494 goto done;
1495 }
1496
c7cba11d
KH
1497 /* Nothing but characters are supported on terminal frames. For a
1498 composition sequence, it->c is the first character of the
1499 sequence. */
1500 xassert (it->what == IT_CHARACTER
1501 || it->what == IT_COMPOSITION);
a168702a 1502
d2b4c17d
KH
1503 /* Maybe translate single-byte characters to multibyte. */
1504 it->char_to_display = it->c;
1505
a168702a
GM
1506 if (it->c >= 040 && it->c < 0177)
1507 {
1508 it->pixel_width = it->nglyphs = 1;
1509 if (it->glyph_row)
1510 append_glyph (it);
1511 }
1512 else if (it->c == '\n')
1513 it->pixel_width = it->nglyphs = 0;
1514 else if (it->c == '\t')
1515 {
2efdbcdd 1516 int absolute_x = (it->current_x
a168702a 1517 + it->continuation_lines_width);
177c0ea7
JB
1518 int next_tab_x
1519 = (((1 + absolute_x + it->tab_width - 1)
a168702a
GM
1520 / it->tab_width)
1521 * it->tab_width);
1522 int nspaces;
1523
1524 /* If part of the TAB has been displayed on the previous line
1525 which is continued now, continuation_lines_width will have
1526 been incremented already by the part that fitted on the
1527 continued line. So, we will get the right number of spaces
1528 here. */
1529 nspaces = next_tab_x - absolute_x;
177c0ea7 1530
a168702a
GM
1531 if (it->glyph_row)
1532 {
1533 int n = nspaces;
177c0ea7 1534
d2b4c17d 1535 it->char_to_display = ' ';
a168702a 1536 it->pixel_width = it->len = 1;
177c0ea7 1537
a168702a
GM
1538 while (n--)
1539 append_glyph (it);
a168702a
GM
1540 }
1541
1542 it->pixel_width = nspaces;
1543 it->nglyphs = nspaces;
1544 }
add44890
EZ
1545 else if (SINGLE_BYTE_CHAR_P (it->c))
1546 {
d2b4c17d
KH
1547 if (unibyte_display_via_language_environment
1548 && (it->c >= 0240
1549 || !NILP (Vnonascii_translation_table)))
1550 {
1551 int charset;
1552
1553 it->char_to_display = unibyte_char_to_multibyte (it->c);
1554 charset = CHAR_CHARSET (it->char_to_display);
1555 it->pixel_width = CHARSET_WIDTH (charset);
1556 it->nglyphs = it->pixel_width;
1557 if (it->glyph_row)
1558 append_glyph (it);
1559 }
1560 else
1561 {
1562 /* Coming here means that it->c is from display table, thus we
1563 must send the code as is to the terminal. Although there's
1564 no way to know how many columns it occupies on a screen, it
1565 is a good assumption that a single byte code has 1-column
1566 width. */
1567 it->pixel_width = it->nglyphs = 1;
1568 if (it->glyph_row)
1569 append_glyph (it);
1570 }
add44890 1571 }
a168702a
GM
1572 else
1573 {
c7cba11d
KH
1574 /* A multi-byte character. The display width is fixed for all
1575 characters of the set. Some of the glyphs may have to be
1576 ignored because they are already displayed in a continued
1577 line. */
a168702a
GM
1578 int charset = CHAR_CHARSET (it->c);
1579
c7cba11d 1580 it->pixel_width = CHARSET_WIDTH (charset);
a168702a 1581 it->nglyphs = it->pixel_width;
177c0ea7 1582
a168702a
GM
1583 if (it->glyph_row)
1584 append_glyph (it);
1585 }
1586
f46c2aff 1587 done:
177c0ea7 1588 /* Advance current_x by the pixel width as a convenience for
a168702a
GM
1589 the caller. */
1590 if (it->area == TEXT_AREA)
1591 it->current_x += it->pixel_width;
cfe8a05e
GM
1592 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1593 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
a168702a
GM
1594}
1595
1596
f46c2aff
KS
1597/* Produce a stretch glyph for iterator IT. IT->object is the value
1598 of the glyph property displayed. The value must be a list
1599 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1600 being recognized:
1601
1602 1. `:width WIDTH' specifies that the space should be WIDTH *
1603 canonical char width wide. WIDTH may be an integer or floating
1604 point number.
1605
1606 2. `:align-to HPOS' specifies that the space should be wide enough
1607 to reach HPOS, a value in canonical character units. */
1608
1609static void
1610produce_stretch_glyph (it)
1611 struct it *it;
1612{
1613 /* (space :width WIDTH ...) */
1614 Lisp_Object prop, plist;
1615 int width = 0, align_to = -1;
1616 int zero_width_ok_p = 0;
1617 double tem;
1618
1619 /* List should start with `space'. */
1620 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1621 plist = XCDR (it->object);
1622
1623 /* Compute the width of the stretch. */
1624 if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
1625 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, 0))
1626 {
1627 /* Absolute width `:width WIDTH' specified and valid. */
1628 zero_width_ok_p = 1;
1629 width = (int)(tem + 0.5);
1630 }
1631 else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
1632 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, &align_to))
1633 {
1634 if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
feef4f84 1635 align_to = (align_to < 0
f46c2aff
KS
1636 ? 0
1637 : align_to - window_box_left_offset (it->w, TEXT_AREA));
1638 else if (align_to < 0)
1639 align_to = window_box_left_offset (it->w, TEXT_AREA);
1640 width = max (0, (int)(tem + 0.5) + align_to - it->current_x);
1641 zero_width_ok_p = 1;
1642 }
1643 else
1644 /* Nothing specified -> width defaults to canonical char width. */
1645 width = FRAME_COLUMN_WIDTH (it->f);
1646
1647 if (width <= 0 && (width < 0 || !zero_width_ok_p))
1648 width = 1;
1649
1650 if (width > 0 && it->glyph_row)
1651 {
1652 Lisp_Object o_object = it->object;
1653 Lisp_Object object = it->stack[it->sp - 1].string;
1654 int n = width;
f46c2aff
KS
1655
1656 if (!STRINGP (object))
1657 object = it->w->buffer;
1658 it->object = object;
d2b4c17d 1659 it->char_to_display = ' ';
f46c2aff
KS
1660 it->pixel_width = it->len = 1;
1661 while (n--)
1662 append_glyph (it);
1663 it->object = o_object;
f46c2aff
KS
1664 }
1665 it->pixel_width = width;
1666 it->nglyphs = width;
1667}
1668
1669
a168702a
GM
1670/* Get information about special display element WHAT in an
1671 environment described by IT. WHAT is one of IT_TRUNCATION or
1672 IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a
1673 non-null glyph_row member. This function ensures that fields like
1674 face_id, c, len of IT are left untouched. */
1675
1676void
1677produce_special_glyphs (it, what)
1678 struct it *it;
1679 enum display_element_type what;
1680{
1681 struct it temp_it;
072d84a6 1682 GLYPH glyph;
177c0ea7 1683
a168702a
GM
1684 temp_it = *it;
1685 temp_it.dp = NULL;
1686 temp_it.what = IT_CHARACTER;
1687 temp_it.len = 1;
7c752c80 1688 temp_it.object = make_number (0);
a168702a
GM
1689 bzero (&temp_it.current, sizeof temp_it.current);
1690
1691 if (what == IT_CONTINUATION)
1692 {
1693 /* Continuation glyph. */
1694 if (it->dp
1695 && INTEGERP (DISP_CONTINUE_GLYPH (it->dp))
1696 && GLYPH_CHAR_VALID_P (XINT (DISP_CONTINUE_GLYPH (it->dp))))
1697 {
072d84a6
RS
1698 glyph = XINT (DISP_CONTINUE_GLYPH (it->dp));
1699 glyph = spec_glyph_lookup_face (XWINDOW (it->window), glyph);
a168702a
GM
1700 }
1701 else
072d84a6 1702 glyph = '\\';
a168702a
GM
1703 }
1704 else if (what == IT_TRUNCATION)
1705 {
1706 /* Truncation glyph. */
1707 if (it->dp
1708 && INTEGERP (DISP_TRUNC_GLYPH (it->dp))
1709 && GLYPH_CHAR_VALID_P (XINT (DISP_TRUNC_GLYPH (it->dp))))
1710 {
072d84a6
RS
1711 glyph = XINT (DISP_TRUNC_GLYPH (it->dp));
1712 glyph = spec_glyph_lookup_face (XWINDOW (it->window), glyph);
a168702a
GM
1713 }
1714 else
072d84a6 1715 glyph = '$';
a168702a
GM
1716 }
1717 else
1718 abort ();
072d84a6
RS
1719
1720 temp_it.c = FAST_GLYPH_CHAR (glyph);
1721 temp_it.face_id = FAST_GLYPH_FACE (glyph);
1722 temp_it.len = CHAR_BYTES (temp_it.c);
1723
1724 produce_glyphs (&temp_it);
1725 it->pixel_width = temp_it.pixel_width;
1726 it->nglyphs = temp_it.pixel_width;
a168702a
GM
1727}
1728
1729
a168702a
GM
1730\f
1731/***********************************************************************
1732 Faces
1733 ***********************************************************************/
1734
4e6ba4a4
GM
1735/* Value is non-zero if attribute ATTR may be used. ATTR should be
1736 one of the enumerators from enum no_color_bit, or a bit set built
1737 from them. Some display attributes may not be used together with
1738 color; the termcap capability `NC' specifies which ones. */
1739
fca177d4
KL
1740#define MAY_USE_WITH_COLORS_P(tty, ATTR) \
1741 (tty->TN_max_colors > 0 \
1742 ? (tty->TN_no_color_video & (ATTR)) == 0 \
1743 : 1)
a168702a 1744
072d84a6
RS
1745/* Turn appearances of face FACE_ID on tty frame F on.
1746 FACE_ID is a realized face ID number, in the face cache. */
a168702a
GM
1747
1748static void
1749turn_on_face (f, face_id)
1750 struct frame *f;
1751 int face_id;
1752{
1753 struct face *face = FACE_FROM_ID (f, face_id);
86a7d192
GM
1754 long fg = face->foreground;
1755 long bg = face->background;
28d7d09f 1756 struct tty_display_info *tty = FRAME_TTY (f);
a168702a 1757
86a7d192
GM
1758 /* Do this first because TS_end_standout_mode may be the same
1759 as TS_exit_attribute_mode, which turns all appearances off. */
fca177d4 1760 if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE))
86a7d192 1761 {
fca177d4 1762 if (tty->TN_max_colors > 0)
86a7d192
GM
1763 {
1764 if (fg >= 0 && bg >= 0)
1765 {
1766 /* If the terminal supports colors, we can set them
1767 below without using reverse video. The face's fg
1768 and bg colors are set as they should appear on
1769 the screen, i.e. they take the inverse-video'ness
1770 of the face already into account. */
1771 }
1772 else if (inverse_video)
1773 {
1774 if (fg == FACE_TTY_DEFAULT_FG_COLOR
1775 || bg == FACE_TTY_DEFAULT_BG_COLOR)
ed8dad6b 1776 tty_toggle_highlight (tty);
86a7d192
GM
1777 }
1778 else
1779 {
1780 if (fg == FACE_TTY_DEFAULT_BG_COLOR
1781 || bg == FACE_TTY_DEFAULT_FG_COLOR)
ed8dad6b 1782 tty_toggle_highlight (tty);
86a7d192
GM
1783 }
1784 }
1785 else
1786 {
1787 /* If we can't display colors, use reverse video
1788 if the face specifies that. */
37526b42
GM
1789 if (inverse_video)
1790 {
1791 if (fg == FACE_TTY_DEFAULT_FG_COLOR
1792 || bg == FACE_TTY_DEFAULT_BG_COLOR)
ed8dad6b 1793 tty_toggle_highlight (tty);
37526b42
GM
1794 }
1795 else
1796 {
1797 if (fg == FACE_TTY_DEFAULT_BG_COLOR
1798 || bg == FACE_TTY_DEFAULT_FG_COLOR)
ed8dad6b 1799 tty_toggle_highlight (tty);
37526b42 1800 }
86a7d192
GM
1801 }
1802 }
a168702a
GM
1803
1804 if (face->tty_bold_p)
4e6ba4a4 1805 {
fca177d4
KL
1806 if (MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
1807 OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
4e6ba4a4 1808 }
a168702a 1809 else if (face->tty_dim_p)
fca177d4
KL
1810 if (MAY_USE_WITH_COLORS_P (tty, NC_DIM))
1811 OUTPUT1_IF (tty, tty->TS_enter_dim_mode);
a168702a
GM
1812
1813 /* Alternate charset and blinking not yet used. */
4e6ba4a4 1814 if (face->tty_alt_charset_p
fca177d4
KL
1815 && MAY_USE_WITH_COLORS_P (tty, NC_ALT_CHARSET))
1816 OUTPUT1_IF (tty, tty->TS_enter_alt_charset_mode);
a168702a 1817
4e6ba4a4 1818 if (face->tty_blinking_p
fca177d4
KL
1819 && MAY_USE_WITH_COLORS_P (tty, NC_BLINK))
1820 OUTPUT1_IF (tty, tty->TS_enter_blink_mode);
a168702a 1821
fca177d4
KL
1822 if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
1823 OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
a168702a 1824
fca177d4 1825 if (tty->TN_max_colors > 0)
a168702a 1826 {
753d161b 1827 char *ts, *p;
177c0ea7 1828
fbf34973 1829 ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
753d161b 1830 if (fg >= 0 && ts)
a168702a 1831 {
fbf34973 1832 p = tparam (ts, NULL, 0, (int) fg);
6548cf00 1833 OUTPUT (tty, p);
a168702a
GM
1834 xfree (p);
1835 }
1836
fbf34973 1837 ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
753d161b 1838 if (bg >= 0 && ts)
a168702a 1839 {
fbf34973 1840 p = tparam (ts, NULL, 0, (int) bg);
6548cf00 1841 OUTPUT (tty, p);
a168702a
GM
1842 xfree (p);
1843 }
1844 }
1845}
177c0ea7 1846
a168702a
GM
1847
1848/* Turn off appearances of face FACE_ID on tty frame F. */
1849
1850static void
1851turn_off_face (f, face_id)
1852 struct frame *f;
1853 int face_id;
1854{
1855 struct face *face = FACE_FROM_ID (f, face_id);
28d7d09f 1856 struct tty_display_info *tty = FRAME_TTY (f);
a168702a
GM
1857
1858 xassert (face != NULL);
1859
fca177d4 1860 if (tty->TS_exit_attribute_mode)
a168702a
GM
1861 {
1862 /* Capability "me" will turn off appearance modes double-bright,
1863 half-bright, reverse-video, standout, underline. It may or
1864 may not turn off alt-char-mode. */
1865 if (face->tty_bold_p
1866 || face->tty_dim_p
1867 || face->tty_reverse_p
1868 || face->tty_alt_charset_p
1869 || face->tty_blinking_p
1870 || face->tty_underline_p)
65aa5e85 1871 {
fca177d4
KL
1872 OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
1873 if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0)
1874 tty->standout_mode = 0;
65aa5e85 1875 }
a168702a
GM
1876
1877 if (face->tty_alt_charset_p)
fca177d4 1878 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
a168702a
GM
1879 }
1880 else
1881 {
1882 /* If we don't have "me" we can only have those appearances
1883 that have exit sequences defined. */
1884 if (face->tty_alt_charset_p)
fca177d4 1885 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
a168702a 1886
54800acb 1887 if (face->tty_underline_p)
fca177d4 1888 OUTPUT_IF (tty, tty->TS_exit_underline_mode);
a168702a
GM
1889 }
1890
1891 /* Switch back to default colors. */
fca177d4 1892 if (tty->TN_max_colors > 0
f9d2fdc4
EZ
1893 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
1894 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
1895 || (face->background != FACE_TTY_DEFAULT_COLOR
1896 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
fca177d4 1897 OUTPUT1_IF (tty, tty->TS_orig_pair);
a168702a 1898}
177c0ea7
JB
1899
1900
b63a55ac
MB
1901/* Return non-zero if the terminal on frame F supports all of the
1902 capabilities in CAPS simultaneously, with foreground and background
1903 colors FG and BG. */
1904
4a8130f2 1905int
fca177d4 1906tty_capable_p (tty, caps, fg, bg)
28d7d09f 1907 struct tty_display_info *tty;
b63a55ac
MB
1908 unsigned caps;
1909 unsigned long fg, bg;
1910{
fca177d4
KL
1911#define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
1912 if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
b63a55ac
MB
1913 return 0;
1914
fca177d4
KL
1915 TTY_CAPABLE_P_TRY (tty, TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE);
1916 TTY_CAPABLE_P_TRY (tty, TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode, NC_UNDERLINE);
1917 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
1918 TTY_CAPABLE_P_TRY (tty, TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM);
1919 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BLINK, tty->TS_enter_blink_mode, NC_BLINK);
1920 TTY_CAPABLE_P_TRY (tty, TTY_CAP_ALT_CHARSET, tty->TS_enter_alt_charset_mode, NC_ALT_CHARSET);
b63a55ac
MB
1921
1922 /* We can do it! */
1923 return 1;
1924}
1925
a168702a
GM
1926/* Return non-zero if the terminal is capable to display colors. */
1927
1928DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
981e4297 1929 0, 1, 0,
6ed8eeff
KL
1930 doc: /* Return non-nil if the tty device TERMINAL can display colors.
1931
1932TERMINAL can be a terminal id, a frame or nil (meaning the selected
1933frame's terminal). This function always returns nil if TERMINAL
1934is not on a tty device. */)
1935 (terminal)
1936 Lisp_Object terminal;
a168702a 1937{
717a00ef 1938 struct terminal *t = get_tty_terminal (terminal, 0);
6ed8eeff 1939 if (!t)
428a555e 1940 return Qnil;
3224dac1 1941 else
6ed8eeff 1942 return t->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
a168702a
GM
1943}
1944
bfa62f96
EZ
1945/* Return the number of supported colors. */
1946DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
1947 Stty_display_color_cells, 0, 1, 0,
6ed8eeff
KL
1948 doc: /* Return the number of colors supported by the tty device TERMINAL.
1949
1950TERMINAL can be a terminal id, a frame or nil (meaning the selected
717a00ef 1951frame's terminal). This function always returns 0 if TERMINAL
6ed8eeff
KL
1952is not on a tty device. */)
1953 (terminal)
1954 Lisp_Object terminal;
bfa62f96 1955{
717a00ef 1956 struct terminal *t = get_tty_terminal (terminal, 0);
6ed8eeff 1957 if (!t)
8c8d5f35 1958 return make_number (0);
3224dac1 1959 else
6ed8eeff 1960 return make_number (t->display_info.tty->TN_max_colors);
bfa62f96
EZ
1961}
1962
ace28297 1963#ifndef WINDOWSNT
a168702a 1964
5205ee62
GM
1965/* Declare here rather than in the function, as in the rest of Emacs,
1966 to work around an HPUX compiler bug (?). See
57407fb4 1967 http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00410.html */
5205ee62
GM
1968static int default_max_colors;
1969static int default_max_pairs;
1970static int default_no_color_video;
1971static char *default_orig_pair;
1972static char *default_set_foreground;
1973static char *default_set_background;
fcf8ff2e 1974
ace28297
EZ
1975/* Save or restore the default color-related capabilities of this
1976 terminal. */
1977static void
28d7d09f 1978tty_default_color_capabilities (struct tty_display_info *tty, int save)
ace28297 1979{
ace28297
EZ
1980
1981 if (save)
1982 {
1983 if (default_orig_pair)
1984 xfree (default_orig_pair);
fca177d4 1985 default_orig_pair = tty->TS_orig_pair ? xstrdup (tty->TS_orig_pair) : NULL;
ace28297
EZ
1986
1987 if (default_set_foreground)
1988 xfree (default_set_foreground);
fca177d4 1989 default_set_foreground = tty->TS_set_foreground ? xstrdup (tty->TS_set_foreground)
ace28297
EZ
1990 : NULL;
1991
1992 if (default_set_background)
1993 xfree (default_set_background);
fca177d4 1994 default_set_background = tty->TS_set_background ? xstrdup (tty->TS_set_background)
ace28297
EZ
1995 : NULL;
1996
fca177d4
KL
1997 default_max_colors = tty->TN_max_colors;
1998 default_max_pairs = tty->TN_max_pairs;
1999 default_no_color_video = tty->TN_no_color_video;
ace28297
EZ
2000 }
2001 else
2002 {
fca177d4
KL
2003 tty->TS_orig_pair = default_orig_pair;
2004 tty->TS_set_foreground = default_set_foreground;
2005 tty->TS_set_background = default_set_background;
2006 tty->TN_max_colors = default_max_colors;
2007 tty->TN_max_pairs = default_max_pairs;
2008 tty->TN_no_color_video = default_no_color_video;
ace28297
EZ
2009 }
2010}
2011
2012/* Setup one of the standard tty color schemes according to MODE.
2013 MODE's value is generally the number of colors which we want to
2014 support; zero means set up for the default capabilities, the ones
a4c6993d 2015 we saw at init_tty time; -1 means turn off color support. */
ed8dad6b 2016static void
28d7d09f 2017tty_setup_colors (struct tty_display_info *tty, int mode)
ace28297 2018{
40409f05
EZ
2019 /* Canonicalize all negative values of MODE. */
2020 if (mode < -1)
2021 mode = -1;
2022
ace28297
EZ
2023 switch (mode)
2024 {
2025 case -1: /* no colors at all */
fca177d4
KL
2026 tty->TN_max_colors = 0;
2027 tty->TN_max_pairs = 0;
2028 tty->TN_no_color_video = 0;
2029 tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL;
ace28297
EZ
2030 break;
2031 case 0: /* default colors, if any */
2032 default:
fca177d4 2033 tty_default_color_capabilities (tty, 0);
ace28297
EZ
2034 break;
2035 case 8: /* 8 standard ANSI colors */
fca177d4 2036 tty->TS_orig_pair = "\033[0m";
ace28297 2037#ifdef TERMINFO
fca177d4
KL
2038 tty->TS_set_foreground = "\033[3%p1%dm";
2039 tty->TS_set_background = "\033[4%p1%dm";
ace28297 2040#else
fca177d4
KL
2041 tty->TS_set_foreground = "\033[3%dm";
2042 tty->TS_set_background = "\033[4%dm";
ace28297 2043#endif
fca177d4
KL
2044 tty->TN_max_colors = 8;
2045 tty->TN_max_pairs = 64;
2046 tty->TN_no_color_video = 0;
ace28297
EZ
2047 break;
2048 }
2049}
2050
2051void
2052set_tty_color_mode (f, val)
2053 struct frame *f;
2054 Lisp_Object val;
2055{
dfc7a077 2056 Lisp_Object color_mode_spec, current_mode_spec;
ace28297
EZ
2057 Lisp_Object color_mode, current_mode;
2058 int mode, old_mode;
2059 extern Lisp_Object Qtty_color_mode;
2060 Lisp_Object tty_color_mode_alist;
2061
2062 tty_color_mode_alist = Fintern_soft (build_string ("tty-color-mode-alist"),
2063 Qnil);
2064
9ac61a89 2065 if (INTEGERP (val))
ace28297
EZ
2066 color_mode = val;
2067 else
2068 {
2069 if (NILP (tty_color_mode_alist))
2070 color_mode_spec = Qnil;
2071 else
2072 color_mode_spec = Fassq (val, XSYMBOL (tty_color_mode_alist)->value);
ace28297
EZ
2073
2074 if (CONSP (color_mode_spec))
2075 color_mode = XCDR (color_mode_spec);
2076 else
2077 color_mode = Qnil;
2078 }
545d91d5
RS
2079
2080 current_mode_spec = assq_no_quit (Qtty_color_mode, f->param_alist);
2081
ace28297
EZ
2082 if (CONSP (current_mode_spec))
2083 current_mode = XCDR (current_mode_spec);
2084 else
2085 current_mode = Qnil;
9ac61a89 2086 if (INTEGERP (color_mode))
ace28297
EZ
2087 mode = XINT (color_mode);
2088 else
2089 mode = 0; /* meaning default */
9ac61a89 2090 if (INTEGERP (current_mode))
ace28297
EZ
2091 old_mode = XINT (current_mode);
2092 else
2093 old_mode = 0;
2094
2095 if (mode != old_mode)
2096 {
fca177d4 2097 tty_setup_colors (FRAME_TTY (f), mode);
ace28297
EZ
2098 /* This recomputes all the faces given the new color
2099 definitions. */
2100 call0 (intern ("tty-set-up-initial-frame-faces"));
2101 redraw_frame (f);
2102 }
2103}
2104
2105#endif /* !WINDOWSNT */
a168702a
GM
2106
2107\f
28d440ab 2108
6ed8eeff 2109/* Return the tty display object specified by TERMINAL. */
b6660415 2110
6ed8eeff 2111struct terminal *
717a00ef 2112get_tty_terminal (Lisp_Object terminal, int throw)
b6660415 2113{
717a00ef 2114 struct terminal *t = get_terminal (terminal, throw);
62af879c 2115
6ed8eeff 2116 if (t && t->type != output_termcap)
717a00ef
KL
2117 {
2118 if (throw)
2119 error ("Device %d is not a termcap terminal device", t->id);
2120 else
2121 return NULL;
2122 }
b6660415 2123
6ed8eeff 2124 return t;
b6660415
KL
2125}
2126
ab797f65
KL
2127/* Return an active termcap device that uses the tty device with the
2128 given name.
b6660415 2129
7e59217d 2130 This function ignores suspended devices.
da8e1115
KL
2131
2132 Returns NULL if the named terminal device is not opened. */
2133
6ed8eeff 2134struct terminal *
7e59217d 2135get_named_tty (name)
28d440ab
KL
2136 char *name;
2137{
6ed8eeff
KL
2138 struct terminal *t;
2139
ab797f65
KL
2140 if (!name)
2141 abort ();
2142
2143 for (t = terminal_list; t; t = t->next_terminal)
2144 {
2145 if (t->type == output_termcap
2146 && !strcmp (t->display_info.tty->name, name)
2147 && TERMINAL_ACTIVE_P (t))
2148 return t;
2149 }
28d440ab
KL
2150
2151 return 0;
2152}
2153
2154\f
6ed8eeff
KL
2155DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
2156 doc: /* Return the type of the tty device that TERMINAL uses.
ab797f65 2157Returns nil if TERMINAL is not on a tty device.
a3fbb897 2158
6ed8eeff
KL
2159TERMINAL can be a terminal id, a frame or nil (meaning the selected
2160frame's terminal). */)
2161 (terminal)
2162 Lisp_Object terminal;
b6660415 2163{
6ed8eeff 2164 struct terminal *t = get_terminal (terminal, 1);
819b8f00 2165
6ed8eeff 2166 if (t->type != output_termcap)
ab797f65
KL
2167 return Qnil;
2168
6ed8eeff
KL
2169 if (t->display_info.tty->type)
2170 return build_string (t->display_info.tty->type);
819b8f00
KL
2171 else
2172 return Qnil;
2173}
2174
6ed8eeff
KL
2175DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
2176 doc: /* Return non-nil if TERMINAL is on the controlling tty of the Emacs process.
a3fbb897 2177
6ed8eeff
KL
2178TERMINAL can be a terminal id, a frame or nil (meaning the selected
2179frame's terminal). This function always returns nil if TERMINAL
2180is not on a tty device. */)
2181 (terminal)
2182 Lisp_Object terminal;
4a933ef8 2183{
6ed8eeff 2184 struct terminal *t = get_terminal (terminal, 1);
4a933ef8 2185
78048085 2186 if (t->type != output_termcap || strcmp (t->display_info.tty->name, DEV_TTY))
4a933ef8
KL
2187 return Qnil;
2188 else
2189 return Qt;
2190}
2191
a3fbb897 2192DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
6ed8eeff 2193 doc: /* Declare that the tty used by TERMINAL does not handle underlining.
a3fbb897
KL
2194This is used to override the terminfo data, for certain terminals that
2195do not really do underlining, but say that they do. This function has
6ed8eeff 2196no effect if used on a non-tty terminal.
a3fbb897 2197
6ed8eeff
KL
2198TERMINAL can be a terminal id, a frame or nil (meaning the selected
2199frame's terminal). This function always returns nil if TERMINAL
2200is not on a tty device. */)
2201 (terminal)
2202 Lisp_Object terminal;
a3fbb897 2203{
6ed8eeff 2204 struct terminal *t = get_terminal (terminal, 1);
a3fbb897 2205
6ed8eeff
KL
2206 if (t->type == output_termcap)
2207 t->display_info.tty->TS_enter_underline_mode = 0;
a3fbb897
KL
2208 return Qnil;
2209}
2210
ed8dad6b
KL
2211\f
2212
2213DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
2214 doc: /* Suspend the terminal device TTY.
2215
2216The device is restored to its default state, and Emacs ceases all
2217access to the tty device. Frames that use the device are not deleted,
2218but input is not read from them and if they change, their display is
2219not updated.
2220
2221TTY may be a terminal id, a frame, or nil for the terminal device of
2222the currently selected frame.
2223
e4019195 2224This function runs `suspend-tty-functions' after suspending the
ed8dad6b
KL
2225device. The functions are run with one arg, the id of the suspended
2226terminal device.
2227
2228`suspend-tty' does nothing if it is called on a device that is already
2229suspended.
2230
2231A suspended tty may be resumed by calling `resume-tty' on it. */)
2232 (tty)
2233 Lisp_Object tty;
2234{
717a00ef 2235 struct terminal *t = get_tty_terminal (tty, 1);
ed8dad6b
KL
2236 FILE *f;
2237
6ed8eeff 2238 if (!t)
ed8dad6b
KL
2239 error ("Unknown tty device");
2240
6ed8eeff 2241 f = t->display_info.tty->input;
ed8dad6b
KL
2242
2243 if (f)
2244 {
23d4cba5
DN
2245 /* First run `suspend-tty-functions' and then clean up the tty
2246 state because `suspend-tty-functions' might need to change
2247 the tty state. */
2248 if (!NILP (Vrun_hooks))
2249 {
2250 Lisp_Object args[2];
2251 args[0] = intern ("suspend-tty-functions");
2252 XSETTERMINAL (args[1], t);
2253 Frun_hook_with_args (2, args);
2254 }
2255
6ed8eeff 2256 reset_sys_modes (t->display_info.tty);
ed8dad6b
KL
2257
2258 delete_keyboard_wait_descriptor (fileno (f));
2259
2260 fclose (f);
6ed8eeff
KL
2261 if (f != t->display_info.tty->output)
2262 fclose (t->display_info.tty->output);
ed8dad6b 2263
6ed8eeff
KL
2264 t->display_info.tty->input = 0;
2265 t->display_info.tty->output = 0;
ed8dad6b 2266
6ed8eeff
KL
2267 if (FRAMEP (t->display_info.tty->top_frame))
2268 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
ed8dad6b 2269
ed8dad6b
KL
2270 }
2271
4a665758
KL
2272 /* Clear display hooks to prevent further output. */
2273 clear_tty_hooks (t);
2274
ed8dad6b
KL
2275 return Qnil;
2276}
2277
2278DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
2279 doc: /* Resume the previously suspended terminal device TTY.
2280The terminal is opened and reinitialized. Frames that are on the
6ed8eeff 2281suspended terminal are revived.
ed8dad6b 2282
6ed8eeff
KL
2283It is an error to resume a terminal while another terminal is active
2284on the same device.
ed8dad6b 2285
e4019195 2286This function runs `resume-tty-functions' after resuming the terminal.
6ed8eeff 2287The functions are run with one arg, the id of the resumed terminal
ed8dad6b
KL
2288device.
2289
2290`resume-tty' does nothing if it is called on a device that is not
2291suspended.
2292
6ed8eeff
KL
2293TTY may be a terminal id, a frame, or nil for the terminal device of
2294the currently selected frame. */)
ed8dad6b
KL
2295 (tty)
2296 Lisp_Object tty;
2297{
717a00ef 2298 struct terminal *t = get_tty_terminal (tty, 1);
ed8dad6b
KL
2299 int fd;
2300
6ed8eeff 2301 if (!t)
ed8dad6b
KL
2302 error ("Unknown tty device");
2303
6ed8eeff 2304 if (!t->display_info.tty->input)
ed8dad6b 2305 {
6ed8eeff 2306 if (get_named_tty (t->display_info.tty->name))
ed8dad6b
KL
2307 error ("Cannot resume display while another display is active on the same device");
2308
6ed8eeff 2309 fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
ed8dad6b 2310
59b3194c
KL
2311 if (fd == -1)
2312 error ("Can not reopen tty device %s: %s", t->display_info.tty->name, strerror (errno));
ed8dad6b 2313
78048085 2314 if (strcmp (t->display_info.tty->name, DEV_TTY))
59b3194c 2315 dissociate_if_controlling_tty (fd);
78048085 2316
6ed8eeff
KL
2317 t->display_info.tty->output = fdopen (fd, "w+");
2318 t->display_info.tty->input = t->display_info.tty->output;
78048085 2319
ed8dad6b
KL
2320 add_keyboard_wait_descriptor (fd);
2321
6ed8eeff
KL
2322 if (FRAMEP (t->display_info.tty->top_frame))
2323 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
ed8dad6b 2324
6ed8eeff 2325 init_sys_modes (t->display_info.tty);
ed8dad6b 2326
e4019195 2327 /* Run `resume-tty-functions'. */
ed8dad6b
KL
2328 if (!NILP (Vrun_hooks))
2329 {
2330 Lisp_Object args[2];
e4019195 2331 args[0] = intern ("resume-tty-functions");
59a7bc63 2332 XSETTERMINAL (args[1], t);
ed8dad6b
KL
2333 Frun_hook_with_args (2, args);
2334 }
2335 }
2336
4a665758
KL
2337 set_tty_hooks (t);
2338
ed8dad6b
KL
2339 return Qnil;
2340}
a3fbb897 2341
819b8f00 2342\f
e882229c
NR
2343/***********************************************************************
2344 Mouse
2345 ***********************************************************************/
2346
7e5a23bd 2347#ifdef HAVE_GPM
5faa03ba
RS
2348void
2349term_mouse_moveto (int x, int y)
94da14a0 2350{
1ec5dc77 2351 /* TODO: how to set mouse position?
94da14a0
NR
2352 const char *name;
2353 int fd;
2354 name = (const char *) ttyname (0);
2355 fd = open (name, O_WRONLY);
80fb2ce0 2356 SOME_FUNCTION (x, y, fd);
94da14a0
NR
2357 close (fd);
2358 last_mouse_x = x;
80fb2ce0 2359 last_mouse_y = y; */
94da14a0
NR
2360}
2361
e882229c
NR
2362static void
2363term_show_mouse_face (enum draw_glyphs_face draw)
2364{
6178ce5e 2365 struct window *w = XWINDOW (mouse_face_window);
e882229c 2366 int save_x, save_y;
1ec5dc77 2367 int i;
e882229c 2368
7be1c21a
MB
2369 struct frame *f = XFRAME (w->frame);
2370 struct tty_display_info *tty = FRAME_TTY (f);
2371
e882229c
NR
2372 if (/* If window is in the process of being destroyed, don't bother
2373 to do anything. */
2374 w->current_matrix != NULL
2375 /* Recognize when we are called to operate on rows that don't exist
2376 anymore. This can happen when a window is split. */
2377 && mouse_face_end_row < w->current_matrix->nrows)
2378 {
2379 /* write_glyphs writes at cursor position, so we need to
2380 temporarily move cursor coordinates to the beginning of
2381 the highlight region. */
2382
2383 /* Save current cursor co-ordinates */
7be1c21a
MB
2384 save_y = curY (tty);
2385 save_x = curX (tty);
e882229c
NR
2386
2387 /* Note that mouse_face_beg_row etc. are window relative. */
2388 for (i = mouse_face_beg_row; i <= mouse_face_end_row; i++)
2389 {
2390 int start_hpos, end_hpos, nglyphs;
2391 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
2392
2393 /* Don't do anything if row doesn't have valid contents. */
2394 if (!row->enabled_p)
2395 continue;
2396
2397 /* For all but the first row, the highlight starts at column 0. */
2398 if (i == mouse_face_beg_row)
2399 start_hpos = mouse_face_beg_col;
2400 else
2401 start_hpos = 0;
2402
2403 if (i == mouse_face_end_row)
2404 end_hpos = mouse_face_end_col;
2405 else
2406 {
2407 end_hpos = row->used[TEXT_AREA];
2408 if (draw == DRAW_NORMAL_TEXT)
2409 row->fill_line_p = 1; /* Clear to end of line */
2410 }
2411
2412 if (end_hpos <= start_hpos)
2413 continue;
2414 /* Record that some glyphs of this row are displayed in
2415 mouse-face. */
2416 row->mouse_face_p = draw > 0;
2417
2418 nglyphs = end_hpos - start_hpos;
2419
2420 if (end_hpos >= row->used[TEXT_AREA])
2421 nglyphs = row->used[TEXT_AREA] - start_hpos;
2422
2423 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
2424 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos
2425 + WINDOW_LEFT_EDGE_X (w);
2426
7be1c21a 2427 cursor_to (f, pos_y, pos_x);
e882229c
NR
2428
2429 if (draw == DRAW_MOUSE_FACE)
2430 {
7be1c21a 2431 tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
e882229c
NR
2432 nglyphs, mouse_face_face_id);
2433 }
2434 else /* draw == DRAW_NORMAL_TEXT */
7be1c21a 2435 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
e882229c 2436 }
7be1c21a 2437 cursor_to (f, save_y, save_x);
e882229c
NR
2438 }
2439}
2440
2441static void
2442term_clear_mouse_face ()
2443{
6178ce5e 2444 if (!NILP (mouse_face_window))
e882229c
NR
2445 term_show_mouse_face (DRAW_NORMAL_TEXT);
2446
2447 mouse_face_beg_row = mouse_face_beg_col = -1;
2448 mouse_face_end_row = mouse_face_end_col = -1;
6178ce5e 2449 mouse_face_window = Qnil;
e882229c
NR
2450}
2451
2452/* Find the glyph matrix position of buffer position POS in window W.
2453 *HPOS and *VPOS are set to the positions found. W's current glyphs
2454 must be up to date. If POS is above window start return (0, 0).
2455 If POS is after end of W, return end of last line in W.
2456 - taken from msdos.c */
2457static int
2458fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
2459{
2460 int i, lastcol, line_start_position, maybe_next_line_p = 0;
2461 int yb = window_text_bottom_y (w);
2462 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
2463
2464 while (row->y < yb)
2465 {
2466 if (row->used[TEXT_AREA])
2467 line_start_position = row->glyphs[TEXT_AREA]->charpos;
2468 else
2469 line_start_position = 0;
2470
2471 if (line_start_position > pos)
2472 break;
2473 /* If the position sought is the end of the buffer,
2474 don't include the blank lines at the bottom of the window. */
2475 else if (line_start_position == pos
2476 && pos == BUF_ZV (XBUFFER (w->buffer)))
2477 {
2478 maybe_next_line_p = 1;
2479 break;
2480 }
2481 else if (line_start_position > 0)
2482 best_row = row;
2483
2484 /* Don't overstep the last matrix row, lest we get into the
2485 never-never land... */
2486 if (row->y + 1 >= yb)
2487 break;
2488
2489 ++row;
2490 }
2491
2492 /* Find the right column within BEST_ROW. */
2493 lastcol = 0;
2494 row = best_row;
2495 for (i = 0; i < row->used[TEXT_AREA]; i++)
2496 {
2497 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
2498 int charpos;
2499
2500 charpos = glyph->charpos;
2501 if (charpos == pos)
2502 {
2503 *hpos = i;
2504 *vpos = row->y;
2505 return 1;
2506 }
2507 else if (charpos > pos)
2508 break;
2509 else if (charpos > 0)
2510 lastcol = i;
2511 }
2512
2513 /* If we're looking for the end of the buffer,
2514 and we didn't find it in the line we scanned,
2515 use the start of the following line. */
2516 if (maybe_next_line_p)
2517 {
2518 ++row;
2519 lastcol = 0;
2520 }
2521
2522 *vpos = row->y;
2523 *hpos = lastcol + 1;
2524 return 0;
2525}
2526
2527static void
2528term_mouse_highlight (struct frame *f, int x, int y)
2529{
2530 enum window_part part;
2531 Lisp_Object window;
2532 struct window *w;
2533 struct buffer *b;
2534
2535 if (NILP (Vmouse_highlight)
2536 || !f->glyphs_initialized_p)
2537 return;
2538
e882229c
NR
2539 /* Which window is that in? */
2540 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
2541
2542 /* Not on a window -> return. */
2543 if (!WINDOWP (window))
2544 return;
2545
6178ce5e 2546 if (!EQ (window, mouse_face_window))
e882229c
NR
2547 term_clear_mouse_face ();
2548
2549 w = XWINDOW (window);
2550
2551 /* Are we in a window whose display is up to date?
2552 And verify the buffer's text has not changed. */
2553 b = XBUFFER (w->buffer);
2554 if (part == ON_TEXT
2555 && EQ (w->window_end_valid, w->buffer)
2556 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
2557 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
2558 {
2559 int pos, i, nrows = w->current_matrix->nrows;
2560 struct glyph_row *row;
2561 struct glyph *glyph;
2562
2563 /* Find the glyph under X/Y. */
2564 glyph = NULL;
2565 if (y >= 0 && y < nrows)
2566 {
2567 row = MATRIX_ROW (w->current_matrix, y);
2568 /* Give up if some row before the one we are looking for is
2569 not enabled. */
2570 for (i = 0; i <= y; i++)
2571 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
2572 break;
2573 if (i > y /* all rows upto and including the one at Y are enabled */
2574 && row->displays_text_p
2575 && x < window_box_width (w, TEXT_AREA))
2576 {
2577 glyph = row->glyphs[TEXT_AREA];
2578 if (x >= row->used[TEXT_AREA])
2579 glyph = NULL;
2580 else
2581 {
2582 glyph += x;
2583 if (!BUFFERP (glyph->object))
2584 glyph = NULL;
2585 }
2586 }
2587 }
2588
2589 /* Clear mouse face if X/Y not over text. */
2590 if (glyph == NULL)
2591 {
2592 term_clear_mouse_face ();
2593 return;
2594 }
2595
2596 if (!BUFFERP (glyph->object))
2597 abort ();
2598 pos = glyph->charpos;
2599
2600 /* Check for mouse-face. */
2601 {
2602 extern Lisp_Object Qmouse_face;
2603 Lisp_Object mouse_face, overlay, position, *overlay_vec;
3b8c0c70 2604 int noverlays, obegv, ozv;
e882229c
NR
2605 struct buffer *obuf;
2606
2607 /* If we get an out-of-range value, return now; avoid an error. */
2608 if (pos > BUF_Z (b))
2609 return;
2610
2611 /* Make the window's buffer temporarily current for
2612 overlays_at and compute_char_face. */
2613 obuf = current_buffer;
2614 current_buffer = b;
2615 obegv = BEGV;
2616 ozv = ZV;
2617 BEGV = BEG;
2618 ZV = Z;
2619
2620 /* Is this char mouse-active? */
2621 XSETINT (position, pos);
2622
2623 /* Put all the overlays we want in a vector in overlay_vec. */
2624 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
2625 /* Sort overlays into increasing priority order. */
2626 noverlays = sort_overlays (overlay_vec, noverlays, w);
2627
2628 /* Check mouse-face highlighting. */
6178ce5e 2629 if (!(EQ (window, mouse_face_window)
e882229c
NR
2630 && y >= mouse_face_beg_row
2631 && y <= mouse_face_end_row
2632 && (y > mouse_face_beg_row
2633 || x >= mouse_face_beg_col)
2634 && (y < mouse_face_end_row
2635 || x < mouse_face_end_col
2636 || mouse_face_past_end)))
2637 {
2638 /* Clear the display of the old active region, if any. */
2639 term_clear_mouse_face ();
2640
2641 /* Find the highest priority overlay that has a mouse-face
2642 property. */
2643 overlay = Qnil;
2644 for (i = noverlays - 1; i >= 0; --i)
2645 {
2646 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
2647 if (!NILP (mouse_face))
2648 {
2649 overlay = overlay_vec[i];
2650 break;
2651 }
2652 }
2653
2654 /* If no overlay applies, get a text property. */
2655 if (NILP (overlay))
2656 mouse_face = Fget_text_property (position, Qmouse_face,
2657 w->buffer);
2658
2659 /* Handle the overlay case. */
2660 if (!NILP (overlay))
2661 {
2662 /* Find the range of text around this char that
2663 should be active. */
2664 Lisp_Object before, after;
2665 int ignore;
2666
2667
2668 before = Foverlay_start (overlay);
2669 after = Foverlay_end (overlay);
2670 /* Record this as the current active region. */
2671 fast_find_position (w, XFASTINT (before),
2672 &mouse_face_beg_col,
2673 &mouse_face_beg_row);
2674
2675 mouse_face_past_end
2676 = !fast_find_position (w, XFASTINT (after),
2677 &mouse_face_end_col,
2678 &mouse_face_end_row);
6178ce5e 2679 mouse_face_window = window;
e882229c
NR
2680
2681 mouse_face_face_id
2682 = face_at_buffer_position (w, pos, 0, 0,
2683 &ignore, pos + 1, 1);
2684
2685 /* Display it as active. */
2686 term_show_mouse_face (DRAW_MOUSE_FACE);
2687 }
2688 /* Handle the text property case. */
2689 else if (!NILP (mouse_face))
2690 {
2691 /* Find the range of text around this char that
2692 should be active. */
2693 Lisp_Object before, after, beginning, end;
2694 int ignore;
2695
2696 beginning = Fmarker_position (w->start);
2697 XSETINT (end, (BUF_Z (b) - XFASTINT (w->window_end_pos)));
2698 before
2699 = Fprevious_single_property_change (make_number (pos + 1),
2700 Qmouse_face,
2701 w->buffer, beginning);
2702 after
2703 = Fnext_single_property_change (position, Qmouse_face,
2704 w->buffer, end);
2705
2706 /* Record this as the current active region. */
2707 fast_find_position (w, XFASTINT (before),
2708 &mouse_face_beg_col,
2709 &mouse_face_beg_row);
2710 mouse_face_past_end
2711 = !fast_find_position (w, XFASTINT (after),
2712 &mouse_face_end_col,
2713 &mouse_face_end_row);
6178ce5e 2714 mouse_face_window = window;
e882229c
NR
2715
2716 mouse_face_face_id
2717 = face_at_buffer_position (w, pos, 0, 0,
2718 &ignore, pos + 1, 1);
2719
2720 /* Display it as active. */
2721 term_show_mouse_face (DRAW_MOUSE_FACE);
2722 }
2723 }
2724
2725 /* Look for a `help-echo' property. */
2726 {
2727 Lisp_Object help;
2728 extern Lisp_Object Qhelp_echo;
2729
2730 /* Check overlays first. */
2731 help = Qnil;
2732 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
2733 {
2734 overlay = overlay_vec[i];
2735 help = Foverlay_get (overlay, Qhelp_echo);
2736 }
2737
2738 if (!NILP (help))
2739 {
2740 help_echo_string = help;
2741 help_echo_window = window;
2742 help_echo_object = overlay;
2743 help_echo_pos = pos;
2744 }
2745 /* Try text properties. */
2746 else if (NILP (help)
2747 && ((STRINGP (glyph->object)
2748 && glyph->charpos >= 0
2749 && glyph->charpos < SCHARS (glyph->object))
2750 || (BUFFERP (glyph->object)
2751 && glyph->charpos >= BEGV
2752 && glyph->charpos < ZV)))
2753 {
2754 help = Fget_text_property (make_number (glyph->charpos),
2755 Qhelp_echo, glyph->object);
2756 if (!NILP (help))
2757 {
2758 help_echo_string = help;
2759 help_echo_window = window;
2760 help_echo_object = glyph->object;
2761 help_echo_pos = glyph->charpos;
2762 }
2763 }
2764 }
2765
2766 BEGV = obegv;
2767 ZV = ozv;
2768 current_buffer = obuf;
2769 }
2770 }
2771}
2772
2773static int
2774term_mouse_movement (FRAME_PTR frame, Gpm_Event *event)
2775{
2776 /* Has the mouse moved off the glyph it was on at the last sighting? */
2777 if (event->x != last_mouse_x || event->y != last_mouse_y)
2778 {
2779 frame->mouse_moved = 1;
80fb2ce0 2780 term_mouse_highlight (frame, event->x, event->y);
e882229c
NR
2781 /* Remember which glyph we're now on. */
2782 last_mouse_x = event->x;
2783 last_mouse_y = event->y;
2784 return 1;
2785 }
2786 return 0;
2787}
2788
2789/* Return the current position of the mouse.
2790
2791 Set *f to the frame the mouse is in, or zero if the mouse is in no
2792 Emacs frame. If it is set to zero, all the other arguments are
2793 garbage.
2794
2795 Set *bar_window to Qnil, and *x and *y to the column and
2796 row of the character cell the mouse is over.
2797
2798 Set *time to the time the mouse was at the returned position.
2799
80fb2ce0 2800 This clears mouse_moved until the next motion
94da14a0 2801 event arrives. */
e882229c
NR
2802static void
2803term_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window,
2804 enum scroll_bar_part *part, Lisp_Object *x,
2805 Lisp_Object *y, unsigned long *time)
2806{
e882229c 2807 struct timeval now;
e882229c
NR
2808
2809 *fp = SELECTED_FRAME ();
94da14a0 2810 (*fp)->mouse_moved = 0;
e882229c
NR
2811
2812 *bar_window = Qnil;
2813 *part = 0;
2814
80fb2ce0 2815 XSETINT (*x, last_mouse_x);
94da14a0 2816 XSETINT (*y, last_mouse_y);
e882229c
NR
2817 gettimeofday(&now, 0);
2818 *time = (now.tv_sec * 1000) + (now.tv_usec / 1000);
e882229c
NR
2819}
2820
2821/* Prepare a mouse-event in *RESULT for placement in the input queue.
2822
2823 If the event is a button press, then note that we have grabbed
2824 the mouse. */
2825
2826static Lisp_Object
2827term_mouse_click (struct input_event *result, Gpm_Event *event,
2828 struct frame *f)
2829{
2830 struct timeval now;
2831 int i, j;
2832
2833 result->kind = GPM_CLICK_EVENT;
2834 for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
2835 {
2836 if (event->buttons & j) {
2837 result->code = i; /* button number */
2838 break;
2839 }
2840 }
2841 gettimeofday(&now, 0);
2842 result->timestamp = (now.tv_sec * 1000) + (now.tv_usec / 1000);
2843
2844 if (event->type & GPM_UP)
2845 result->modifiers = up_modifier;
2846 else if (event->type & GPM_DOWN)
2847 result->modifiers = down_modifier;
2848 else
2849 result->modifiers = 0;
2850
2851 if (event->type & GPM_SINGLE)
2852 result->modifiers |= click_modifier;
2853
2854 if (event->type & GPM_DOUBLE)
2855 result->modifiers |= double_modifier;
2856
2857 if (event->type & GPM_TRIPLE)
2858 result->modifiers |= triple_modifier;
2859
2860 if (event->type & GPM_DRAG)
2861 result->modifiers |= drag_modifier;
2862
80fb2ce0 2863 if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
e882229c
NR
2864
2865 /* 1 << KG_SHIFT */
2866 if (event->modifiers & (1 << 0))
2867 result->modifiers |= shift_modifier;
2868
2869 /* 1 << KG_CTRL */
2870 if (event->modifiers & (1 << 2))
2871 result->modifiers |= ctrl_modifier;
2872
2873 /* 1 << KG_ALT || KG_ALTGR */
2874 if (event->modifiers & (1 << 3)
2875 || event->modifiers & (1 << 1))
2876 result->modifiers |= meta_modifier;
2877 }
2878
80fb2ce0
NR
2879 XSETINT (result->x, event->x);
2880 XSETINT (result->y, event->y);
e882229c
NR
2881 XSETFRAME (result->frame_or_window, f);
2882 result->arg = Qnil;
2883 return Qnil;
2884}
2885
2886int
7be1c21a 2887handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event, struct input_event* hold_quit)
e882229c 2888{
7be1c21a 2889 struct frame *f = XFRAME (tty->top_frame);
e882229c
NR
2890 struct input_event ie;
2891 int do_help = 0;
2892 int count = 0;
2893
2894 EVENT_INIT (ie);
2895 ie.kind = NO_EVENT;
2896 ie.arg = Qnil;
2897
80fb2ce0 2898 if (event->type & (GPM_MOVE | GPM_DRAG)) {
e882229c
NR
2899 previous_help_echo_string = help_echo_string;
2900 help_echo_string = Qnil;
2901
6178ce5e 2902 Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
e882229c 2903
80fb2ce0
NR
2904 if (!term_mouse_movement (f, event))
2905 help_echo_string = previous_help_echo_string;
e882229c
NR
2906
2907 /* If the contents of the global variable help_echo_string
2908 has changed, generate a HELP_EVENT. */
2909 if (!NILP (help_echo_string)
2910 || !NILP (previous_help_echo_string))
2911 do_help = 1;
2912
2913 goto done;
2914 }
2915 else {
2916 f->mouse_moved = 0;
2917 term_mouse_click (&ie, event, f);
e882229c
NR
2918 }
2919
2920 done:
2921 if (ie.kind != NO_EVENT)
2922 {
2923 kbd_buffer_store_event_hold (&ie, hold_quit);
2924 count++;
2925 }
2926
2927 if (do_help
2928 && !(hold_quit && hold_quit->kind != NO_EVENT))
2929 {
2930 Lisp_Object frame;
2931
2932 if (f)
2933 XSETFRAME (frame, f);
2934 else
2935 frame = Qnil;
2936
2937 gen_help_event (help_echo_string, frame, help_echo_window,
2938 help_echo_object, help_echo_pos);
2939 count++;
2940 }
2941
2942 return count;
2943}
2944
6178ce5e 2945DEFUN ("gpm-mouse-start", Fgpm_mouse_start, Sgpm_mouse_start,
e882229c 2946 0, 0, 0,
71f44e7a 2947 doc: /* Open a connection to Gpm.
6178ce5e 2948Gpm-mouse can only be activated for one tty at a time. */)
e882229c
NR
2949 ()
2950{
71f44e7a
SM
2951 struct frame *f = SELECTED_FRAME ();
2952 struct tty_display_info *tty
2953 = ((f)->output_method == output_termcap
2954 ? (f)->terminal->display_info.tty : NULL);
e882229c
NR
2955 Gpm_Connect connection;
2956
6178ce5e
SM
2957 if (!tty)
2958 error ("Gpm-mouse only works in the GNU/Linux console");
4ce5ab77
SM
2959 if (gpm_tty == tty)
2960 return Qnil; /* Already activated, nothing to do. */
2961 if (gpm_tty)
2962 error ("Gpm-mouse can only be activated for one tty at a time");
71f44e7a 2963
e882229c
NR
2964 connection.eventMask = ~0;
2965 connection.defaultMask = ~GPM_HARD;
2966 connection.maxMod = ~0;
2967 connection.minMod = 0;
80fb2ce0 2968 gpm_zerobased = 1;
e882229c 2969
71f44e7a 2970 if (Gpm_Open (&connection, 0) < 0)
6178ce5e 2971 error ("Gpm-mouse failed to connect to the gpm daemon");
e882229c
NR
2972 else
2973 {
71f44e7a 2974 gpm_tty = tty;
1023cbed
SM
2975 /* `init_sys_modes' arranges for mouse movements sent through gpm_fd
2976 to generate SIGIOs. Apparently we need to call reset_sys_modes
2977 before calling init_sys_modes. */
7be1c21a
MB
2978 reset_sys_modes (tty);
2979 init_sys_modes (tty);
e882229c 2980 add_gpm_wait_descriptor (gpm_fd);
6178ce5e 2981 return Qnil;
e882229c
NR
2982 }
2983}
2984
6178ce5e 2985DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
e882229c
NR
2986 0, 0, 0,
2987 doc: /* Close a connection to Gpm. */)
2988 ()
2989{
4ce5ab77
SM
2990 struct frame *f = SELECTED_FRAME ();
2991 struct tty_display_info *tty
2992 = ((f)->output_method == output_termcap
2993 ? (f)->terminal->display_info.tty : NULL);
2994
2995 if (!tty || gpm_tty != tty)
2996 return Qnil; /* Not activated on this terminal, nothing to do. */
2997
6178ce5e
SM
2998 if (gpm_fd >= 0)
2999 delete_gpm_wait_descriptor (gpm_fd);
3000 while (Gpm_Close()); /* close all the stack */
3001 gpm_tty = NULL;
3002 return Qnil;
e882229c 3003}
7e5a23bd 3004#endif /* HAVE_GPM */
e882229c
NR
3005
3006\f
a168702a
GM
3007/***********************************************************************
3008 Initialization
3009 ***********************************************************************/
3010
ed8dad6b
KL
3011/* Initialize the tty-dependent part of frame F. The frame must
3012 already have its device initialized. */
3224dac1 3013
ed8dad6b
KL
3014void
3015create_tty_output (struct frame *f)
28d440ab 3016{
ed8dad6b
KL
3017 struct tty_output *t;
3018
3019 if (! FRAME_TERMCAP_P (f))
428a555e
KL
3020 abort ();
3021
ed8dad6b
KL
3022 t = xmalloc (sizeof (struct tty_output));
3023 bzero (t, sizeof (struct tty_output));
b6660415 3024
6ed8eeff 3025 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
bedb9c0e 3026
ed8dad6b 3027 f->output_data.tty = t;
3224dac1
KL
3028}
3029
ed8dad6b 3030/* Delete the tty-dependent part of frame F. */
da8e1115 3031
ed8dad6b
KL
3032static void
3033delete_tty_output (struct frame *f)
3224dac1 3034{
ed8dad6b 3035 if (! FRAME_TERMCAP_P (f))
3224dac1
KL
3036 abort ();
3037
ed8dad6b 3038 xfree (f->output_data.tty);
28d440ab
KL
3039}
3040
ed8dad6b 3041\f
47cc8819 3042/* Reset the hooks in TERMINAL. */
ed8dad6b 3043
4a665758
KL
3044static void
3045clear_tty_hooks (struct terminal *terminal)
3046{
3047 terminal->rif = 0;
3048 terminal->cursor_to_hook = 0;
3049 terminal->raw_cursor_to_hook = 0;
3050 terminal->clear_to_end_hook = 0;
3051 terminal->clear_frame_hook = 0;
3052 terminal->clear_end_of_line_hook = 0;
3053 terminal->ins_del_lines_hook = 0;
3054 terminal->insert_glyphs_hook = 0;
3055 terminal->write_glyphs_hook = 0;
3056 terminal->delete_glyphs_hook = 0;
3057 terminal->ring_bell_hook = 0;
3058 terminal->reset_terminal_modes_hook = 0;
3059 terminal->set_terminal_modes_hook = 0;
3060 terminal->update_begin_hook = 0;
3061 terminal->update_end_hook = 0;
3062 terminal->set_terminal_window_hook = 0;
3063 terminal->mouse_position_hook = 0;
3064 terminal->frame_rehighlight_hook = 0;
3065 terminal->frame_raise_lower_hook = 0;
974b73e8 3066 terminal->fullscreen_hook = 0;
4a665758
KL
3067 terminal->set_vertical_scroll_bar_hook = 0;
3068 terminal->condemn_scroll_bars_hook = 0;
3069 terminal->redeem_scroll_bar_hook = 0;
3070 terminal->judge_scroll_bars_hook = 0;
3071 terminal->read_socket_hook = 0;
3072 terminal->frame_up_to_date_hook = 0;
3073
3074 /* Leave these two set, or suspended frames are not deleted
3075 correctly. */
3076 terminal->delete_frame_hook = &delete_tty_output;
3077 terminal->delete_terminal_hook = &delete_tty;
3078}
3079
47cc8819
DN
3080/* Initialize hooks in TERMINAL with the values needed for a tty. */
3081
4a665758
KL
3082static void
3083set_tty_hooks (struct terminal *terminal)
3084{
3085 terminal->rif = 0; /* ttys don't support window-based redisplay. */
3086
3087 terminal->cursor_to_hook = &tty_cursor_to;
3088 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
3089
3090 terminal->clear_to_end_hook = &tty_clear_to_end;
3091 terminal->clear_frame_hook = &tty_clear_frame;
3092 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
3093
3094 terminal->ins_del_lines_hook = &tty_ins_del_lines;
3095
3096 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3097 terminal->write_glyphs_hook = &tty_write_glyphs;
3098 terminal->delete_glyphs_hook = &tty_delete_glyphs;
3099
3100 terminal->ring_bell_hook = &tty_ring_bell;
3101
3102 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3103 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
3104 terminal->update_begin_hook = 0; /* Not needed. */
3105 terminal->update_end_hook = &tty_update_end;
3106 terminal->set_terminal_window_hook = &tty_set_terminal_window;
3107
3108 terminal->mouse_position_hook = 0; /* Not needed. */
3109 terminal->frame_rehighlight_hook = 0; /* Not needed. */
3110 terminal->frame_raise_lower_hook = 0; /* Not needed. */
3111
3112 terminal->set_vertical_scroll_bar_hook = 0; /* Not needed. */
3113 terminal->condemn_scroll_bars_hook = 0; /* Not needed. */
3114 terminal->redeem_scroll_bar_hook = 0; /* Not needed. */
3115 terminal->judge_scroll_bars_hook = 0; /* Not needed. */
3116
3117 terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
3118 terminal->frame_up_to_date_hook = 0; /* Not needed. */
3119
3120 terminal->delete_frame_hook = &delete_tty_output;
3121 terminal->delete_terminal_hook = &delete_tty;
3122}
3123
03a1d6bd 3124/* Drop the controlling terminal if fd is the same device. */
ed8dad6b 3125static void
03a1d6bd
KL
3126dissociate_if_controlling_tty (int fd)
3127{
5d333979 3128#ifndef WINDOWSNT
03a1d6bd 3129 int pgid;
8516815b 3130 EMACS_GET_TTY_PGRP (fd, &pgid); /* If tcgetpgrp succeeds, fd is the ctty. */
03a1d6bd
KL
3131 if (pgid != -1)
3132 {
8516815b 3133#if defined (USG) && !defined (BSD_PGRPS)
03a1d6bd
KL
3134 setpgrp ();
3135 no_controlling_tty = 1;
de52dcbb
DN
3136#elif defined (CYGWIN)
3137 setsid ();
3138 no_controlling_tty = 1;
03a1d6bd
KL
3139#else
3140#ifdef TIOCNOTTY /* Try BSD ioctls. */
8516815b 3141 sigblock (sigmask (SIGTTOU));
78048085 3142 fd = emacs_open (DEV_TTY, O_RDWR, 0);
8516815b
KL
3143 if (fd != -1 && ioctl (fd, TIOCNOTTY, 0) != -1)
3144 {
3145 no_controlling_tty = 1;
3146 }
3147 if (fd != -1)
3148 emacs_close (fd);
3149 sigunblock (sigmask (SIGTTOU));
03a1d6bd 3150#else
8516815b
KL
3151 /* Unknown system. */
3152 croak ();
03a1d6bd
KL
3153#endif /* ! TIOCNOTTY */
3154#endif /* ! USG */
71a96040 3155 }
78048085 3156#endif /* !WINDOWSNT */
03a1d6bd
KL
3157}
3158
520c4dfd
KL
3159static void maybe_fatal();
3160
3224dac1
KL
3161/* Create a termcap display on the tty device with the given name and
3162 type.
3163
ab797f65 3164 If NAME is NULL, then use the controlling tty, i.e., "/dev/tty".
3224dac1
KL
3165 Otherwise NAME should be a path to the tty device file,
3166 e.g. "/dev/pts/7".
28d440ab 3167
3224dac1
KL
3168 TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
3169
3170 If MUST_SUCCEED is true, then all errors are fatal. */
da8e1115 3171
6ed8eeff 3172struct terminal *
a4c6993d 3173init_tty (char *name, char *terminal_type, int must_succeed)
08a24c47 3174{
59b3194c 3175 char *area = NULL;
08a24c47 3176 char **address = &area;
3a06a6d9 3177 char *buffer = NULL;
5846981b 3178 int buffer_size = 4096;
59b3194c 3179 register char *p = NULL;
08a24c47 3180 int status;
59b3194c
KL
3181 struct tty_display_info *tty = NULL;
3182 struct terminal *terminal = NULL;
3183 int ctty = 0; /* 1 if asked to open controlling tty. */
28d440ab 3184
3224dac1
KL
3185 if (!terminal_type)
3186 maybe_fatal (must_succeed, 0, 0,
3187 "Unknown terminal type",
3188 "Unknown terminal type");
b6660415 3189
ab797f65 3190 if (name == NULL)
78048085
EZ
3191 name = DEV_TTY;
3192 if (!strcmp (name, DEV_TTY))
ab797f65
KL
3193 ctty = 1;
3194
6ed8eeff
KL
3195 /* If we already have a terminal on the given device, use that. If
3196 all such terminals are suspended, create a new one instead. */
a4c6993d 3197 /* XXX Perhaps this should be made explicit by having init_tty
6ed8eeff 3198 always create a new terminal and separating terminal and frame
b6660415 3199 creation on Lisp level. */
6ed8eeff
KL
3200 terminal = get_named_tty (name);
3201 if (terminal)
3202 return terminal;
78048085 3203
6ed8eeff 3204 terminal = create_terminal ();
3224dac1
KL
3205 tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info));
3206 bzero (tty, sizeof (struct tty_display_info));
3207 tty->next = tty_list;
3208 tty_list = tty;
428a555e 3209
6ed8eeff
KL
3210 terminal->type = output_termcap;
3211 terminal->display_info.tty = tty;
3212 tty->terminal = terminal;
28d440ab 3213
7b00d185
KL
3214 tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
3215 Wcm_clear (tty);
daf01701 3216
55d5acfa 3217#ifndef WINDOWSNT
4a665758 3218 set_tty_hooks (terminal);
78048085 3219
59b3194c
KL
3220 {
3221 int fd;
3222 FILE *file;
0c72d684
KL
3223
3224#ifdef O_IGNORE_CTTY
59b3194c 3225 if (!ctty)
0c72d684
KL
3226 /* Open the terminal device. Don't recognize it as our
3227 controlling terminal, and don't make it the controlling tty
3228 if we don't have one at the moment. */
3229 fd = emacs_open (name, O_RDWR | O_IGNORE_CTTY | O_NOCTTY, 0);
59b3194c 3230 else
0c72d684 3231#else
2666355c 3232 /* Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
59b3194c
KL
3233 defined on Hurd. On other systems, we need to explicitly
3234 dissociate ourselves from the controlling tty when we want to
3235 open a frame on the same terminal. */
0c72d684 3236 fd = emacs_open (name, O_RDWR | O_NOCTTY, 0);
0c72d684
KL
3237#endif /* O_IGNORE_CTTY */
3238
59b3194c
KL
3239 if (fd < 0)
3240 maybe_fatal (must_succeed, buffer, terminal,
3241 "Could not open file: %s",
3242 "Could not open file: %s",
3243 name);
3244 if (!isatty (fd))
3245 {
3246 close (fd);
3247 maybe_fatal (must_succeed, buffer, terminal,
3248 "Not a tty device: %s",
3249 "Not a tty device: %s",
3250 name);
3251 }
0c72d684 3252
59b3194c
KL
3253#ifndef O_IGNORE_CTTY
3254 if (!ctty)
03a1d6bd 3255 dissociate_if_controlling_tty (fd);
59b3194c
KL
3256#endif
3257
3258 file = fdopen (fd, "w+");
3259 tty->name = xstrdup (name);
3260 terminal->name = xstrdup (name);
3261 tty->input = file;
3262 tty->output = file;
3263 }
78048085 3264
28d7d09f 3265 tty->type = xstrdup (terminal_type);
28d440ab 3266
819b8f00 3267 add_keyboard_wait_descriptor (fileno (tty->input));
daf01701 3268
55d5acfa
DN
3269#endif
3270
af645abf
KH
3271 encode_terminal_bufsize = 0;
3272
7e5a23bd 3273#ifdef HAVE_GPM
88acaaf2 3274 terminal->mouse_position_hook = term_mouse_position;
6178ce5e 3275 mouse_face_window = Qnil;
e882229c
NR
3276#endif
3277
cb28b9c2 3278#ifdef WINDOWSNT
953bf0dc 3279 initialize_w32_display (terminal);
a0236551
JR
3280 /* The following two are inaccessible from w32console.c. */
3281 terminal->delete_frame_hook = &delete_tty_output;
3282 terminal->delete_terminal_hook = &delete_tty;
cb28b9c2 3283
78048085
EZ
3284 tty->name = xstrdup (name);
3285 terminal->name = xstrdup (name);
3286 tty->type = xstrdup (terminal_type);
55d5acfa 3287
55d5acfa 3288 tty->output = stdout;
a0236551
JR
3289 tty->input = stdin;
3290 add_keyboard_wait_descriptor (0);
cb28b9c2 3291
a0236551 3292 Wcm_clear (tty);
cb28b9c2 3293
5d333979
JR
3294 {
3295 struct frame *f = XFRAME (selected_frame);
cb28b9c2 3296
a0236551
JR
3297 FrameRows (tty) = FRAME_LINES (f);
3298 FrameCols (tty) = FRAME_COLS (f);
3299 tty->specified_window = FRAME_LINES (f);
5d333979 3300
a0236551
JR
3301 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
3302 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
5d333979
JR
3303 }
3304 tty->delete_in_insert_mode = 1;
cb28b9c2 3305
daf01701 3306 UseTabs (tty) = 0;
6ed8eeff 3307 terminal->scroll_region_ok = 0;
cb28b9c2 3308
7e59217d 3309 /* Seems to insert lines when it's not supposed to, messing up the
6ed8eeff 3310 display. In doing a trace, it didn't seem to be called much, so I
7e59217d 3311 don't think we're losing anything by turning it off. */
6ed8eeff
KL
3312 terminal->line_ins_del_ok = 0;
3313 terminal->char_ins_del_ok = 1;
cb28b9c2
RS
3314
3315 baud_rate = 19200;
3316
5d333979 3317 tty->TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */
cb28b9c2 3318
eccec691 3319#else /* not WINDOWSNT */
cb28b9c2 3320
6548cf00 3321 Wcm_clear (tty);
08a24c47 3322
3a06a6d9 3323 buffer = (char *) xmalloc (buffer_size);
78048085 3324
03a1d6bd
KL
3325 /* On some systems, tgetent tries to access the controlling
3326 terminal. */
3327 sigblock (sigmask (SIGTTOU));
08a24c47 3328 status = tgetent (buffer, terminal_type);
03a1d6bd 3329 sigunblock (sigmask (SIGTTOU));
78048085 3330
08a24c47 3331 if (status < 0)
b0347178
KH
3332 {
3333#ifdef TERMINFO
6ed8eeff 3334 maybe_fatal (must_succeed, buffer, terminal,
3224dac1
KL
3335 "Cannot open terminfo database file",
3336 "Cannot open terminfo database file");
b0347178 3337#else
6ed8eeff 3338 maybe_fatal (must_succeed, buffer, terminal,
3224dac1
KL
3339 "Cannot open termcap database file",
3340 "Cannot open termcap database file");
b0347178
KH
3341#endif
3342 }
08a24c47 3343 if (status == 0)
b0347178
KH
3344 {
3345#ifdef TERMINFO
6ed8eeff 3346 maybe_fatal (must_succeed, buffer, terminal,
3224dac1
KL
3347 "Terminal type %s is not defined",
3348 "Terminal type %s is not defined.\n\
0a125897 3349If that is not the actual type of terminal you have,\n\
b0347178
KH
3350use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3351`setenv TERM ...') to specify the correct type. It may be necessary\n\
e12c1054 3352to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
3224dac1 3353 terminal_type);
b0347178 3354#else
6ed8eeff 3355 maybe_fatal (must_succeed, buffer, terminal,
3224dac1
KL
3356 "Terminal type %s is not defined",
3357 "Terminal type %s is not defined.\n\
0a125897 3358If that is not the actual type of terminal you have,\n\
c5a9c3e6
RS
3359use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3360`setenv TERM ...') to specify the correct type. It may be necessary\n\
e12c1054 3361to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
3224dac1 3362 terminal_type);
b0347178
KH
3363#endif
3364 }
3a06a6d9 3365
f730033e 3366#ifndef TERMINFO
3a06a6d9 3367 if (strlen (buffer) >= buffer_size)
08a24c47 3368 abort ();
f730033e 3369 buffer_size = strlen (buffer);
3dd3a502 3370#endif
f730033e 3371 area = (char *) xmalloc (buffer_size);
08a24c47 3372
fca177d4
KL
3373 tty->TS_ins_line = tgetstr ("al", address);
3374 tty->TS_ins_multi_lines = tgetstr ("AL", address);
3375 tty->TS_bell = tgetstr ("bl", address);
6548cf00 3376 BackTab (tty) = tgetstr ("bt", address);
fca177d4
KL
3377 tty->TS_clr_to_bottom = tgetstr ("cd", address);
3378 tty->TS_clr_line = tgetstr ("ce", address);
3379 tty->TS_clr_frame = tgetstr ("cl", address);
6548cf00
KL
3380 ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
3381 AbsPosition (tty) = tgetstr ("cm", address);
3382 CR (tty) = tgetstr ("cr", address);
fca177d4
KL
3383 tty->TS_set_scroll_region = tgetstr ("cs", address);
3384 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
6548cf00 3385 RowPosition (tty) = tgetstr ("cv", address);
fca177d4
KL
3386 tty->TS_del_char = tgetstr ("dc", address);
3387 tty->TS_del_multi_chars = tgetstr ("DC", address);
3388 tty->TS_del_line = tgetstr ("dl", address);
3389 tty->TS_del_multi_lines = tgetstr ("DL", address);
3390 tty->TS_delete_mode = tgetstr ("dm", address);
3391 tty->TS_end_delete_mode = tgetstr ("ed", address);
3392 tty->TS_end_insert_mode = tgetstr ("ei", address);
6548cf00 3393 Home (tty) = tgetstr ("ho", address);
fca177d4
KL
3394 tty->TS_ins_char = tgetstr ("ic", address);
3395 tty->TS_ins_multi_chars = tgetstr ("IC", address);
3396 tty->TS_insert_mode = tgetstr ("im", address);
3397 tty->TS_pad_inserted_char = tgetstr ("ip", address);
3398 tty->TS_end_keypad_mode = tgetstr ("ke", address);
3399 tty->TS_keypad_mode = tgetstr ("ks", address);
6548cf00
KL
3400 LastLine (tty) = tgetstr ("ll", address);
3401 Right (tty) = tgetstr ("nd", address);
3402 Down (tty) = tgetstr ("do", address);
3403 if (!Down (tty))
3404 Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */
08a24c47
JB
3405#ifdef VMS
3406 /* VMS puts a carriage return before each linefeed,
3407 so it is not safe to use linefeeds. */
6548cf00
KL
3408 if (Down (tty) && Down (tty)[0] == '\n' && Down (tty)[1] == '\0')
3409 Down (tty) = 0;
08a24c47
JB
3410#endif /* VMS */
3411 if (tgetflag ("bs"))
6548cf00 3412 Left (tty) = "\b"; /* can't possibly be longer! */
08a24c47 3413 else /* (Actually, "bs" is obsolete...) */
6548cf00
KL
3414 Left (tty) = tgetstr ("le", address);
3415 if (!Left (tty))
3416 Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */
fca177d4
KL
3417 tty->TS_pad_char = tgetstr ("pc", address);
3418 tty->TS_repeat = tgetstr ("rp", address);
3419 tty->TS_end_standout_mode = tgetstr ("se", address);
3420 tty->TS_fwd_scroll = tgetstr ("sf", address);
3421 tty->TS_standout_mode = tgetstr ("so", address);
3422 tty->TS_rev_scroll = tgetstr ("sr", address);
6548cf00 3423 tty->Wcm->cm_tab = tgetstr ("ta", address);
fca177d4
KL
3424 tty->TS_end_termcap_modes = tgetstr ("te", address);
3425 tty->TS_termcap_modes = tgetstr ("ti", address);
6548cf00 3426 Up (tty) = tgetstr ("up", address);
fca177d4
KL
3427 tty->TS_visible_bell = tgetstr ("vb", address);
3428 tty->TS_cursor_normal = tgetstr ("ve", address);
3429 tty->TS_cursor_visible = tgetstr ("vs", address);
3430 tty->TS_cursor_invisible = tgetstr ("vi", address);
3431 tty->TS_set_window = tgetstr ("wi", address);
3432
3433 tty->TS_enter_underline_mode = tgetstr ("us", address);
3434 tty->TS_exit_underline_mode = tgetstr ("ue", address);
3435 tty->TS_enter_bold_mode = tgetstr ("md", address);
3436 tty->TS_enter_dim_mode = tgetstr ("mh", address);
3437 tty->TS_enter_blink_mode = tgetstr ("mb", address);
3438 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
3439 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
3440 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
3441 tty->TS_exit_attribute_mode = tgetstr ("me", address);
177c0ea7 3442
6548cf00
KL
3443 MultiUp (tty) = tgetstr ("UP", address);
3444 MultiDown (tty) = tgetstr ("DO", address);
3445 MultiLeft (tty) = tgetstr ("LE", address);
3446 MultiRight (tty) = tgetstr ("RI", address);
08a24c47 3447
e7f90eab
GM
3448 /* SVr4/ANSI color suppert. If "op" isn't available, don't support
3449 color because we can't switch back to the default foreground and
3450 background. */
fca177d4
KL
3451 tty->TS_orig_pair = tgetstr ("op", address);
3452 if (tty->TS_orig_pair)
a168702a 3453 {
fca177d4
KL
3454 tty->TS_set_foreground = tgetstr ("AF", address);
3455 tty->TS_set_background = tgetstr ("AB", address);
3456 if (!tty->TS_set_foreground)
e7f90eab
GM
3457 {
3458 /* SVr4. */
fca177d4
KL
3459 tty->TS_set_foreground = tgetstr ("Sf", address);
3460 tty->TS_set_background = tgetstr ("Sb", address);
e7f90eab 3461 }
177c0ea7 3462
fca177d4
KL
3463 tty->TN_max_colors = tgetnum ("Co");
3464 tty->TN_max_pairs = tgetnum ("pa");
177c0ea7 3465
fca177d4
KL
3466 tty->TN_no_color_video = tgetnum ("NC");
3467 if (tty->TN_no_color_video == -1)
3468 tty->TN_no_color_video = 0;
a168702a 3469 }
a168702a 3470
fca177d4 3471 tty_default_color_capabilities (tty, 1);
ace28297 3472
6548cf00 3473 MagicWrap (tty) = tgetflag ("xn");
e4058338
KH
3474 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
3475 the former flag imply the latter. */
6548cf00 3476 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
6ed8eeff 3477 terminal->memory_below_frame = tgetflag ("db");
fca177d4 3478 tty->TF_hazeltine = tgetflag ("hz");
6ed8eeff 3479 terminal->must_write_spaces = tgetflag ("in");
fca177d4
KL
3480 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
3481 tty->TF_insmode_motion = tgetflag ("mi");
3482 tty->TF_standout_motion = tgetflag ("ms");
3483 tty->TF_underscore = tgetflag ("ul");
3484 tty->TF_teleray = tgetflag ("xt");
08a24c47 3485
953bf0dc 3486#endif /* !WINDOWSNT */
e7cf0fa0 3487#ifdef MULTI_KBOARD
6ed8eeff
KL
3488 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3489 init_kboard (terminal->kboard);
70b8d0a4 3490 terminal->kboard->Vwindow_system = Qnil;
6ed8eeff
KL
3491 terminal->kboard->next_kboard = all_kboards;
3492 all_kboards = terminal->kboard;
3493 terminal->kboard->reference_count++;
e7cf0fa0
KL
3494 /* Don't let the initial kboard remain current longer than necessary.
3495 That would cause problems if a file loaded on startup tries to
3496 prompt in the mini-buffer. */
3497 if (current_kboard == initial_kboard)
6ed8eeff 3498 current_kboard = terminal->kboard;
953bf0dc 3499#ifndef WINDOWSNT
6ed8eeff 3500 term_get_fkeys (address, terminal->kboard);
80ca7302 3501#endif
953bf0dc 3502#endif
5c2c7893 3503
953bf0dc 3504#ifndef WINDOWSNT
ff11dfa1 3505 /* Get frame size from system, or else from termcap. */
3b12ce12
RS
3506 {
3507 int height, width;
0b0d3e0b 3508 get_tty_size (fileno (tty->input), &width, &height);
0a125897
KL
3509 FrameCols (tty) = width;
3510 FrameRows (tty) = height;
3b12ce12
RS
3511 }
3512
0a125897
KL
3513 if (FrameCols (tty) <= 0)
3514 FrameCols (tty) = tgetnum ("co");
3515 if (FrameRows (tty) <= 0)
3516 FrameRows (tty) = tgetnum ("li");
177c0ea7 3517
0a125897 3518 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
6ed8eeff 3519 maybe_fatal (must_succeed, NULL, terminal,
3224dac1
KL
3520 "Screen size %dx%d is too small"
3521 "Screen size %dx%d is too small",
0a125897 3522 FrameCols (tty), FrameRows (tty));
ee7a2de4 3523
8a56675d 3524#if 0 /* This is not used anywhere. */
6ed8eeff 3525 tty->terminal->min_padding_speed = tgetnum ("pb");
8a56675d 3526#endif
28d440ab 3527
6548cf00 3528 TabWidth (tty) = tgetnum ("tw");
08a24c47
JB
3529
3530#ifdef VMS
3531 /* These capabilities commonly use ^J.
3532 I don't know why, but sending them on VMS does not work;
3533 it causes following spaces to be lost, sometimes.
3534 For now, the simplest fix is to avoid using these capabilities ever. */
6548cf00
KL
3535 if (Down (tty) && Down (tty)[0] == '\n')
3536 Down (tty) = 0;
08a24c47
JB
3537#endif /* VMS */
3538
fca177d4
KL
3539 if (!tty->TS_bell)
3540 tty->TS_bell = "\07";
08a24c47 3541
fca177d4
KL
3542 if (!tty->TS_fwd_scroll)
3543 tty->TS_fwd_scroll = Down (tty);
08a24c47 3544
fca177d4 3545 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
08a24c47 3546
6548cf00
KL
3547 if (TabWidth (tty) < 0)
3548 TabWidth (tty) = 8;
177c0ea7 3549
08a24c47
JB
3550/* Turned off since /etc/termcap seems to have :ta= for most terminals
3551 and newer termcap doc does not seem to say there is a default.
6548cf00
KL
3552 if (!tty->Wcm->cm_tab)
3553 tty->Wcm->cm_tab = "\t";
08a24c47
JB
3554*/
3555
54800acb
MB
3556 /* We don't support standout modes that use `magic cookies', so
3557 turn off any that do. */
fca177d4 3558 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
54800acb 3559 {
fca177d4
KL
3560 tty->TS_standout_mode = 0;
3561 tty->TS_end_standout_mode = 0;
54800acb 3562 }
fca177d4 3563 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
54800acb 3564 {
fca177d4
KL
3565 tty->TS_enter_underline_mode = 0;
3566 tty->TS_exit_underline_mode = 0;
54800acb
MB
3567 }
3568
3569 /* If there's no standout mode, try to use underlining instead. */
fca177d4 3570 if (tty->TS_standout_mode == 0)
08a24c47 3571 {
fca177d4
KL
3572 tty->TS_standout_mode = tty->TS_enter_underline_mode;
3573 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
08a24c47
JB
3574 }
3575
afd359c4
RS
3576 /* If no `se' string, try using a `me' string instead.
3577 If that fails, we can't use standout mode at all. */
fca177d4 3578 if (tty->TS_end_standout_mode == 0)
afd359c4 3579 {
e4bfb3b6 3580 char *s = tgetstr ("me", address);
afd359c4 3581 if (s != 0)
fca177d4 3582 tty->TS_end_standout_mode = s;
afd359c4 3583 else
fca177d4 3584 tty->TS_standout_mode = 0;
afd359c4
RS
3585 }
3586
fca177d4 3587 if (tty->TF_teleray)
08a24c47 3588 {
6548cf00 3589 tty->Wcm->cm_tab = 0;
54800acb 3590 /* We can't support standout mode, because it uses magic cookies. */
fca177d4 3591 tty->TS_standout_mode = 0;
08a24c47 3592 /* But that means we cannot rely on ^M to go to column zero! */
6548cf00 3593 CR (tty) = 0;
08a24c47
JB
3594 /* LF can't be trusted either -- can alter hpos */
3595 /* if move at column 0 thru a line with TS_standout_mode */
6548cf00 3596 Down (tty) = 0;
08a24c47
JB
3597 }
3598
3599 /* Special handling for certain terminal types known to need it */
3600
3601 if (!strcmp (terminal_type, "supdup"))
3602 {
6ed8eeff 3603 terminal->memory_below_frame = 1;
6548cf00 3604 tty->Wcm->cm_losewrap = 1;
08a24c47
JB
3605 }
3606 if (!strncmp (terminal_type, "c10", 3)
3607 || !strcmp (terminal_type, "perq"))
3608 {
3609 /* Supply a makeshift :wi string.
3610 This string is not valid in general since it works only
3611 for windows starting at the upper left corner;
3612 but that is all Emacs uses.
daf01701 3613
ff11dfa1 3614 This string works only if the frame is using
08a24c47
JB
3615 the top of the video memory, because addressing is memory-relative.
3616 So first check the :ti string to see if that is true.
3617
3618 It would be simpler if the :wi string could go in the termcap
3619 entry, but it can't because it is not fully valid.
3620 If it were in the termcap entry, it would confuse other programs. */
fca177d4 3621 if (!tty->TS_set_window)
08a24c47 3622 {
fca177d4 3623 p = tty->TS_termcap_modes;
08a24c47
JB
3624 while (*p && strcmp (p, "\033v "))
3625 p++;
3626 if (*p)
fca177d4 3627 tty->TS_set_window = "\033v%C %C %C %C ";
08a24c47
JB
3628 }
3629 /* Termcap entry often fails to have :in: flag */
6ed8eeff 3630 terminal->must_write_spaces = 1;
08a24c47
JB
3631 /* :ti string typically fails to have \E^G! in it */
3632 /* This limits scope of insert-char to one line. */
fca177d4 3633 strcpy (area, tty->TS_termcap_modes);
08a24c47 3634 strcat (area, "\033\007!");
fca177d4 3635 tty->TS_termcap_modes = area;
08a24c47 3636 area += strlen (area) + 1;
6548cf00 3637 p = AbsPosition (tty);
08a24c47 3638 /* Change all %+ parameters to %C, to handle
28d440ab 3639 values above 96 correctly for the C100. */
08a24c47 3640 while (*p)
28d440ab
KL
3641 {
3642 if (p[0] == '%' && p[1] == '+')
3643 p[1] = 'C';
3644 p++;
3645 }
08a24c47
JB
3646 }
3647
0a125897 3648 tty->specified_window = FrameRows (tty);
08a24c47 3649
6548cf00 3650 if (Wcm_init (tty) == -1) /* can't do cursor motion */
3224dac1 3651 {
6ed8eeff 3652 maybe_fatal (must_succeed, NULL, terminal,
3224dac1 3653 "Terminal type \"%s\" is not powerful enough to run Emacs",
08a24c47 3654#ifdef VMS
3224dac1 3655 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
08a24c47
JB
3656It lacks the ability to position the cursor.\n\
3657If that is not the actual type of terminal you have, use either the\n\
3658DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
e12c1054 3659or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.",
37dad45a
RS
3660#else /* not VMS */
3661# ifdef TERMINFO
3224dac1 3662 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
0a125897
KL
3663It lacks the ability to position the cursor.\n\
3664If that is not the actual type of terminal you have,\n\
37dad45a
RS
3665use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3666`setenv TERM ...') to specify the correct type. It may be necessary\n\
e12c1054 3667to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
37dad45a 3668# else /* TERMCAP */
3224dac1 3669 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
0a125897 3670It lacks the ability to position the cursor.\n\
08a24c47 3671If that is not the actual type of terminal you have,\n\
c5a9c3e6
RS
3672use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3673`setenv TERM ...') to specify the correct type. It may be necessary\n\
e12c1054 3674to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
37dad45a
RS
3675# endif /* TERMINFO */
3676#endif /*VMS */
3224dac1 3677 terminal_type);
fca177d4 3678 }
daf01701 3679
0a125897 3680 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
6ed8eeff 3681 maybe_fatal (must_succeed, NULL, terminal,
3224dac1
KL
3682 "Could not determine the frame size",
3683 "Could not determine the frame size");
08a24c47 3684
fca177d4
KL
3685 tty->delete_in_insert_mode
3686 = tty->TS_delete_mode && tty->TS_insert_mode
3687 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
08a24c47 3688
fca177d4
KL
3689 tty->se_is_so = (tty->TS_standout_mode
3690 && tty->TS_end_standout_mode
3691 && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode));
08a24c47 3692
0b0d3e0b 3693 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
08a24c47 3694
6ed8eeff 3695 terminal->scroll_region_ok
6548cf00 3696 = (tty->Wcm->cm_abs
fca177d4 3697 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
08a24c47 3698
6ed8eeff 3699 terminal->line_ins_del_ok
fca177d4
KL
3700 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
3701 && (tty->TS_del_line || tty->TS_del_multi_lines))
6ed8eeff 3702 || (terminal->scroll_region_ok
fca177d4 3703 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
28d440ab 3704
6ed8eeff 3705 terminal->char_ins_del_ok
fca177d4
KL
3706 = ((tty->TS_ins_char || tty->TS_insert_mode
3707 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
3708 && (tty->TS_del_char || tty->TS_del_multi_chars));
8a56675d 3709
6ed8eeff 3710 terminal->fast_clear_end_of_line = tty->TS_clr_line != 0;
08a24c47 3711
0b0d3e0b 3712 init_baud_rate (fileno (tty->input));
20a558dc 3713
daf01701
KL
3714#ifdef AIXHFT
3715 /* The HFT system on AIX doesn't optimize for scrolling, so it's
3716 really ugly at times. */
6ed8eeff
KL
3717 terminal->line_ins_del_ok = 0;
3718 terminal->char_ins_del_ok = 0;
daf01701
KL
3719#endif
3720
0a125897
KL
3721 /* Don't do this. I think termcap may still need the buffer. */
3722 /* xfree (buffer); */
28d440ab 3723
635e3b29
JR
3724#endif /* not WINDOWSNT */
3725
0a125897
KL
3726 /* Init system terminal modes (RAW or CBREAK, etc.). */
3727 init_sys_modes (tty);
daf01701 3728
6ed8eeff 3729 return terminal;
08a24c47
JB
3730}
3731
a4c6993d 3732/* Auxiliary error-handling function for init_tty.
6ed8eeff 3733 Free BUFFER and delete TERMINAL, then call error or fatal
da8e1115
KL
3734 with str1 or str2, respectively, according to MUST_SUCCEED. */
3735
3224dac1 3736static void
6ed8eeff 3737maybe_fatal (must_succeed, buffer, terminal, str1, str2, arg1, arg2)
3224dac1
KL
3738 int must_succeed;
3739 char *buffer;
6ed8eeff 3740 struct terminal *terminal;
3224dac1
KL
3741 char *str1, *str2, *arg1, *arg2;
3742{
3743 if (buffer)
3744 xfree (buffer);
3745
6ed8eeff
KL
3746 if (terminal)
3747 delete_tty (terminal);
3224dac1
KL
3748
3749 if (must_succeed)
3750 fatal (str2, arg1, arg2);
3751 else
3752 error (str1, arg1, arg2);
3753
3754 abort ();
3755}
3756
08a24c47 3757/* VARARGS 1 */
dfcf069d 3758void
08a24c47 3759fatal (str, arg1, arg2)
4746118a 3760 char *str, *arg1, *arg2;
08a24c47
JB
3761{
3762 fprintf (stderr, "emacs: ");
3763 fprintf (stderr, str, arg1, arg2);
e12c1054 3764 fprintf (stderr, "\n");
08a24c47
JB
3765 fflush (stderr);
3766 exit (1);
3767}
07c57952 3768
819b8f00
KL
3769\f
3770
6ed8eeff 3771/* Delete the given tty terminal, closing all frames on it. */
da8e1115 3772
ed8dad6b 3773static void
6ed8eeff 3774delete_tty (struct terminal *terminal)
fca177d4 3775{
428a555e 3776 struct tty_display_info *tty;
fca177d4 3777 Lisp_Object tail, frame;
6ed8eeff 3778 int last_terminal;
4d553a13 3779
ab797f65
KL
3780 /* Protect against recursive calls. Fdelete_frame in
3781 delete_terminal calls us back when it deletes our last frame. */
59a7bc63 3782 if (!terminal->name)
0a125897 3783 return;
fca177d4 3784
6ed8eeff 3785 if (terminal->type != output_termcap)
428a555e
KL
3786 abort ();
3787
6ed8eeff 3788 tty = terminal->display_info.tty;
428a555e 3789
6ed8eeff 3790 last_terminal = 1;
81be1a93
KL
3791 FOR_EACH_FRAME (tail, frame)
3792 {
3793 struct frame *f = XFRAME (frame);
3794 if (FRAME_LIVE_P (f) && (!FRAME_TERMCAP_P (f) || FRAME_TTY (f) != tty))
3795 {
6ed8eeff 3796 last_terminal = 0;
81be1a93
KL
3797 break;
3798 }
3799 }
6ed8eeff
KL
3800 if (last_terminal)
3801 error ("Attempt to delete the sole terminal device with live frames");
81be1a93 3802
fca177d4
KL
3803 if (tty == tty_list)
3804 tty_list = tty->next;
3805 else
3806 {
28d7d09f 3807 struct tty_display_info *p;
fca177d4
KL
3808 for (p = tty_list; p && p->next != tty; p = p->next)
3809 ;
3810
3811 if (! p)
3812 /* This should not happen. */
3813 abort ();
3814
0a125897
KL
3815 p->next = tty->next;
3816 tty->next = 0;
fca177d4
KL
3817 }
3818
7e59217d 3819 /* reset_sys_modes needs a valid device, so this call needs to be
6ed8eeff 3820 before delete_terminal. */
04c3243c 3821 reset_sys_modes (tty);
fca177d4 3822
6ed8eeff 3823 delete_terminal (terminal);
3224dac1 3824
ab797f65
KL
3825 if (tty->name)
3826 xfree (tty->name);
3827
fca177d4
KL
3828 if (tty->type)
3829 xfree (tty->type);
daf01701 3830
fca177d4 3831 if (tty->input)
819b8f00
KL
3832 {
3833 delete_keyboard_wait_descriptor (fileno (tty->input));
3834 if (tty->input != stdin)
3835 fclose (tty->input);
3836 }
3837 if (tty->output && tty->output != stdout && tty->output != tty->input)
fca177d4
KL
3838 fclose (tty->output);
3839 if (tty->termscript)
3840 fclose (tty->termscript);
daf01701 3841
fca177d4 3842 if (tty->old_tty)
0a125897 3843 xfree (tty->old_tty);
fca177d4 3844
0a125897 3845 if (tty->Wcm)
daf01701
KL
3846 xfree (tty->Wcm);
3847
28d7d09f 3848 bzero (tty, sizeof (struct tty_display_info));
fca177d4 3849 xfree (tty);
fca177d4
KL
3850}
3851
428a555e
KL
3852\f
3853
28d7d09f 3854/* Mark the pointers in the tty_display_info objects.
819b8f00 3855 Called by the Fgarbage_collector. */
da8e1115 3856
fca177d4 3857void
ed8dad6b 3858mark_ttys (void)
fca177d4 3859{
28d7d09f 3860 struct tty_display_info *tty;
0c72d684 3861
819b8f00 3862 for (tty = tty_list; tty; tty = tty->next)
3b6fc48f 3863 mark_object (tty->top_frame);
fca177d4
KL
3864}
3865
428a555e
KL
3866\f
3867
819b8f00
KL
3868void
3869syms_of_term ()
3870{
3871 DEFVAR_BOOL ("system-uses-terminfo", &system_uses_terminfo,
3872 doc: /* Non-nil means the system uses terminfo rather than termcap.
3873This variable can be used by terminal emulator packages. */);
3874#ifdef TERMINFO
3875 system_uses_terminfo = 1;
3876#else
3877 system_uses_terminfo = 0;
3878#endif
3879
e4019195
DN
3880 DEFVAR_LISP ("suspend-tty-functions", &Vsuspend_tty_functions,
3881 doc: /* Functions to be run after suspending a tty.
ab797f65 3882The functions are run with one argument, the terminal id to be suspended.
0b0d3e0b 3883See `suspend-tty'. */);
e4019195 3884 Vsuspend_tty_functions = Qnil;
0b0d3e0b
KL
3885
3886
e4019195
DN
3887 DEFVAR_LISP ("resume-tty-functions", &Vresume_tty_functions,
3888 doc: /* Functions to be run after resuming a tty.
ab797f65 3889The functions are run with one argument, the terminal id that was revived.
0b0d3e0b 3890See `resume-tty'. */);
e4019195 3891 Vresume_tty_functions = Qnil;
0b0d3e0b 3892
0db017c0
SM
3893 DEFVAR_BOOL ("visible-cursor", &visible_cursor,
3894 doc: /* Non-nil means to make the cursor very visible.
3895This only has an effect when running in a text terminal.
3896What means \"very visible\" is up to your terminal. It may make the cursor
3897bigger, or it may make it blink, or it may do nothing at all. */);
3898 visible_cursor = 1;
3899
819b8f00
KL
3900 defsubr (&Stty_display_color_p);
3901 defsubr (&Stty_display_color_cells);
072d84a6 3902 defsubr (&Stty_no_underline);
6ed8eeff
KL
3903 defsubr (&Stty_type);
3904 defsubr (&Scontrolling_tty_p);
0b0d3e0b
KL
3905 defsubr (&Ssuspend_tty);
3906 defsubr (&Sresume_tty);
7e5a23bd 3907#ifdef HAVE_GPM
6178ce5e
SM
3908 defsubr (&Sgpm_mouse_start);
3909 defsubr (&Sgpm_mouse_stop);
94da14a0 3910
6178ce5e 3911 staticpro (&mouse_face_window);
7e5a23bd 3912#endif /* HAVE_GPM */
819b8f00
KL
3913}
3914
3915
3916
ab5796a9
MB
3917/* arch-tag: 498e7449-6f2e-45e2-91dd-b7d4ca488193
3918 (do not change this comment) */