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