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