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