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