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