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