* termhooks.h (FRAME_MUST_WRITE_SPACES, FRAME_LINE_INS_DEL_OK)
[bpt/emacs.git] / src / term.c
CommitLineData
d284f58f 1/* Terminal control module for terminals described by TERMCAP
ab422c4d
PE
2 Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2013 Free Software
3 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>
59b3194c 23#include <errno.h>
49cdacda
PE
24#include <fcntl.h>
25#include <stdio.h>
28d440ab 26#include <sys/file.h>
d35af63c 27#include <sys/time.h>
1ec5dc77 28#include <unistd.h>
0c72d684 29
9628b887 30#include "lisp.h"
08a24c47 31#include "termchar.h"
50938595 32#include "tparam.h"
9332ea03 33#include "character.h"
e5560ff7 34#include "buffer.h"
a4decb7f
KH
35#include "charset.h"
36#include "coding.h"
4c12d738 37#include "composite.h"
2538fae4 38#include "keyboard.h"
ff11dfa1 39#include "frame.h"
08a24c47
JB
40#include "disptab.h"
41#include "termhooks.h"
dfcf069d 42#include "dispextern.h"
a168702a 43#include "window.h"
8feddab4 44#include "keymap.h"
1a935bfd 45#include "blockinput.h"
03a1d6bd
KL
46#include "syssignal.h"
47#include "systty.h"
c9612b8e 48#include "intervals.h"
84704c5c
EZ
49#ifdef MSDOS
50#include "msdos.h"
51static int been_here = -1;
52#endif
a168702a 53
c7a7f318
EZ
54#ifdef USE_X_TOOLKIT
55#include "../lwlib/lwlib.h"
56#endif
57
eccec691 58#include "cm.h"
dfcf069d
AS
59#ifdef HAVE_X_WINDOWS
60#include "xterm.h"
61#endif
c8951b18 62
b5e9cbb6 63#include "menu.h"
6b61353c 64
78048085
EZ
65/* The name of the default console device. */
66#ifdef WINDOWSNT
67#define DEV_TTY "CONOUT$"
a68089e4 68#include "w32term.h"
78048085
EZ
69#else
70#define DEV_TTY "/dev/tty"
71#endif
a168702a 72
f57e2426
J
73static void tty_set_scroll_region (struct frame *f, int start, int stop);
74static void turn_on_face (struct frame *, int face_id);
75static void turn_off_face (struct frame *, int face_id);
64520e5c 76static void tty_turn_off_highlight (struct tty_display_info *);
f57e2426
J
77static void tty_show_cursor (struct tty_display_info *);
78static void tty_hide_cursor (struct tty_display_info *);
79static void tty_background_highlight (struct tty_display_info *tty);
653d4f43 80static struct terminal *get_tty_terminal (Lisp_Object, bool);
f57e2426
J
81static void clear_tty_hooks (struct terminal *terminal);
82static void set_tty_hooks (struct terminal *terminal);
83static void dissociate_if_controlling_tty (int fd);
84static void delete_tty (struct terminal *);
653d4f43
PE
85static _Noreturn void maybe_fatal (bool, struct terminal *,
86 const char *, const char *, ...)
845ca893
PE
87 ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5);
88static _Noreturn void vfatal (const char *str, va_list ap)
89 ATTRIBUTE_FORMAT_PRINTF (1, 0);
b3ffc17c 90
a168702a 91
6548cf00
KL
92#define OUTPUT(tty, a) \
93 emacs_tputs ((tty), a, \
653d4f43 94 FRAME_LINES (XFRAME (selected_frame)) - curY (tty), \
6548cf00
KL
95 cmputc)
96
28d440ab
KL
97#define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
98#define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
a168702a 99
28d440ab 100#define OUTPUT_IF(tty, a) \
6548cf00
KL
101 do { \
102 if (a) \
b286858c 103 OUTPUT (tty, a); \
6548cf00 104 } while (0)
177c0ea7 105
28d440ab 106#define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
c291d9ef 107
f46c2aff 108/* Display space properties */
08a24c47 109
428a555e 110/* Chain of all tty device parameters. */
28d7d09f 111struct tty_display_info *tty_list;
08a24c47 112
4e6ba4a4
GM
113/* Meaning of bits in no_color_video. Each bit set means that the
114 corresponding attribute cannot be combined with colors. */
115
116enum no_color_bit
117{
118 NC_STANDOUT = 1 << 0,
119 NC_UNDERLINE = 1 << 1,
120 NC_REVERSE = 1 << 2,
cd4eb164 121 NC_ITALIC = 1 << 3,
4e6ba4a4
GM
122 NC_DIM = 1 << 4,
123 NC_BOLD = 1 << 5,
124 NC_INVIS = 1 << 6,
cd4eb164 125 NC_PROTECT = 1 << 7
4e6ba4a4
GM
126};
127
08a24c47
JB
128/* internal state */
129
8dd0c7cb 130/* The largest frame width in any call to calculate_costs. */
a168702a 131
64520e5c 132static int max_frame_cols;
a168702a 133
08a24c47 134\f
cb28b9c2 135
7e5a23bd 136#ifdef HAVE_GPM
e882229c 137#include <sys/fcntl.h>
e882229c 138
71f44e7a
SM
139/* The device for which we have enabled gpm support (or NULL). */
140struct tty_display_info *gpm_tty = NULL;
e882229c 141
cf482c50 142/* Last recorded mouse coordinates. */
e882229c 143static int last_mouse_x, last_mouse_y;
7e5a23bd 144#endif /* HAVE_GPM */
e882229c 145
da8e1115 146/* Ring the bell on a tty. */
c291d9ef 147
ed8dad6b 148static void
385ed61f 149tty_ring_bell (struct frame *f)
3224dac1 150{
3224dac1 151 struct tty_display_info *tty = FRAME_TTY (f);
c291d9ef 152
b6660415
KL
153 if (tty->output)
154 {
155 OUTPUT (tty, (tty->TS_visible_bell && visible_bell
156 ? tty->TS_visible_bell
157 : tty->TS_bell));
158 fflush (tty->output);
08a24c47 159 }
08a24c47
JB
160}
161
da8e1115
KL
162/* Set up termcap modes for Emacs. */
163
64520e5c 164static void
6ed8eeff 165tty_set_terminal_modes (struct terminal *terminal)
08a24c47 166{
6ed8eeff 167 struct tty_display_info *tty = terminal->display_info.tty;
f4d953fc 168
0b0d3e0b 169 if (tty->output)
08a24c47 170 {
fbf34973
KL
171 if (tty->TS_termcap_modes)
172 OUTPUT (tty, tty->TS_termcap_modes);
3ae9c96a 173 else
fbf34973
KL
174 {
175 /* Output enough newlines to scroll all the old screen contents
176 off the screen, so it won't be overwritten and lost. */
177 int i;
a3c07f68 178 current_tty = tty;
fbf34973 179 for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
a3c07f68 180 cmputc ('\n');
fbf34973
KL
181 }
182
b58cb614 183 OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
0b0d3e0b
KL
184 OUTPUT_IF (tty, tty->TS_keypad_mode);
185 losecursor (tty);
2f98e6e3 186 fflush (tty->output);
08a24c47 187 }
08a24c47
JB
188}
189
da8e1115
KL
190/* Reset termcap modes before exiting Emacs. */
191
64520e5c 192static void
6ed8eeff 193tty_reset_terminal_modes (struct terminal *terminal)
08a24c47 194{
6ed8eeff 195 struct tty_display_info *tty = terminal->display_info.tty;
0b0d3e0b
KL
196
197 if (tty->output)
08a24c47 198 {
ed8dad6b
KL
199 tty_turn_off_highlight (tty);
200 tty_turn_off_insert (tty);
0b0d3e0b
KL
201 OUTPUT_IF (tty, tty->TS_end_keypad_mode);
202 OUTPUT_IF (tty, tty->TS_cursor_normal);
203 OUTPUT_IF (tty, tty->TS_end_termcap_modes);
204 OUTPUT_IF (tty, tty->TS_orig_pair);
d284f58f 205 /* Output raw CR so kernel can track the cursor hpos. */
0b0d3e0b 206 current_tty = tty;
d284f58f 207 cmputc ('\r');
2f98e6e3 208 fflush (tty->output);
08a24c47 209 }
08a24c47
JB
210}
211
6ed8eeff 212/* Flag the end of a display update on a termcap terminal. */
08a24c47 213
ed8dad6b 214static void
3224dac1 215tty_update_end (struct frame *f)
08a24c47 216{
3224dac1 217 struct tty_display_info *tty = FRAME_TTY (f);
177c0ea7 218
3224dac1
KL
219 if (!XWINDOW (selected_window)->cursor_off_p)
220 tty_show_cursor (tty);
ed8dad6b
KL
221 tty_turn_off_insert (tty);
222 tty_background_highlight (tty);
7d563e36 223 fflush (tty->output);
08a24c47
JB
224}
225
da8e1115
KL
226/* The implementation of set_terminal_window for termcap frames. */
227
ed8dad6b 228static void
385ed61f 229tty_set_terminal_window (struct frame *f, int size)
08a24c47 230{
3224dac1
KL
231 struct tty_display_info *tty = FRAME_TTY (f);
232
233 tty->specified_window = size ? size : FRAME_LINES (f);
234 if (FRAME_SCROLL_REGION_OK (f))
ed8dad6b 235 tty_set_scroll_region (f, 0, tty->specified_window);
08a24c47
JB
236}
237
ed8dad6b
KL
238static void
239tty_set_scroll_region (struct frame *f, int start, int stop)
08a24c47
JB
240{
241 char *buf;
28d7d09f 242 struct tty_display_info *tty = FRAME_TTY (f);
177c0ea7 243
fca177d4 244 if (tty->TS_set_scroll_region)
50938595 245 buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1, 0, 0);
fca177d4
KL
246 else if (tty->TS_set_scroll_region_1)
247 buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
ed02974b
KL
248 FRAME_LINES (f), start,
249 FRAME_LINES (f) - stop,
250 FRAME_LINES (f));
08a24c47 251 else
fca177d4 252 buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
177c0ea7 253
6548cf00 254 OUTPUT (tty, buf);
9ac0d9e0 255 xfree (buf);
6548cf00 256 losecursor (tty);
08a24c47 257}
d284f58f 258
08a24c47 259\f
d284f58f 260static void
ed8dad6b 261tty_turn_on_insert (struct tty_display_info *tty)
08a24c47 262{
fca177d4
KL
263 if (!tty->insert_mode)
264 OUTPUT (tty, tty->TS_insert_mode);
265 tty->insert_mode = 1;
08a24c47
JB
266}
267
dfcf069d 268void
ed8dad6b 269tty_turn_off_insert (struct tty_display_info *tty)
08a24c47 270{
fca177d4
KL
271 if (tty->insert_mode)
272 OUTPUT (tty, tty->TS_end_insert_mode);
273 tty->insert_mode = 0;
08a24c47
JB
274}
275\f
54800acb 276/* Handle highlighting. */
08a24c47 277
64520e5c 278static void
ed8dad6b 279tty_turn_off_highlight (struct tty_display_info *tty)
08a24c47 280{
fca177d4
KL
281 if (tty->standout_mode)
282 OUTPUT_IF (tty, tty->TS_end_standout_mode);
283 tty->standout_mode = 0;
08a24c47
JB
284}
285
d284f58f 286static void
ed8dad6b 287tty_turn_on_highlight (struct tty_display_info *tty)
08a24c47 288{
fca177d4
KL
289 if (!tty->standout_mode)
290 OUTPUT_IF (tty, tty->TS_standout_mode);
291 tty->standout_mode = 1;
08a24c47
JB
292}
293
86a7d192 294static void
ed8dad6b 295tty_toggle_highlight (struct tty_display_info *tty)
86a7d192 296{
fca177d4 297 if (tty->standout_mode)
ed8dad6b 298 tty_turn_off_highlight (tty);
86a7d192 299 else
ed8dad6b 300 tty_turn_on_highlight (tty);
86a7d192
GM
301}
302
a168702a
GM
303
304/* Make cursor invisible. */
305
306static void
28d7d09f 307tty_hide_cursor (struct tty_display_info *tty)
a168702a 308{
fca177d4 309 if (tty->cursor_hidden == 0)
d284f58f 310 {
fca177d4 311 tty->cursor_hidden = 1;
28a16449
EZ
312#ifdef WINDOWSNT
313 w32con_hide_cursor ();
314#else
fca177d4 315 OUTPUT_IF (tty, tty->TS_cursor_invisible);
28a16449 316#endif
d284f58f 317 }
a168702a
GM
318}
319
320
321/* Ensure that cursor is visible. */
322
323static void
28d7d09f 324tty_show_cursor (struct tty_display_info *tty)
a168702a 325{
fca177d4 326 if (tty->cursor_hidden)
d284f58f 327 {
fca177d4 328 tty->cursor_hidden = 0;
28a16449
EZ
329#ifdef WINDOWSNT
330 w32con_show_cursor ();
331#else
fca177d4 332 OUTPUT_IF (tty, tty->TS_cursor_normal);
0db017c0 333 if (visible_cursor)
b58cb614 334 OUTPUT_IF (tty, tty->TS_cursor_visible);
28a16449 335#endif
d284f58f 336 }
a168702a
GM
337}
338
339
08a24c47
JB
340/* Set standout mode to the state it should be in for
341 empty space inside windows. What this is,
342 depends on the user option inverse-video. */
343
ed8dad6b
KL
344static void
345tty_background_highlight (struct tty_display_info *tty)
08a24c47 346{
08a24c47 347 if (inverse_video)
ed8dad6b 348 tty_turn_on_highlight (tty);
08a24c47 349 else
ed8dad6b 350 tty_turn_off_highlight (tty);
08a24c47
JB
351}
352
353/* Set standout mode to the mode specified for the text to be output. */
354
dfcf069d 355static void
ed8dad6b 356tty_highlight_if_desired (struct tty_display_info *tty)
08a24c47 357{
8ede64a5 358 if (inverse_video)
ed8dad6b 359 tty_turn_on_highlight (tty);
8ede64a5 360 else
ed8dad6b 361 tty_turn_off_highlight (tty);
08a24c47
JB
362}
363\f
364
a168702a
GM
365/* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are
366 frame-relative coordinates. */
08a24c47 367
ed8dad6b 368static void
385ed61f 369tty_cursor_to (struct frame *f, int vpos, int hpos)
08a24c47 370{
3224dac1 371 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 372
36cae867
KH
373 /* Detect the case where we are called from reset_sys_modes
374 and the costs have never been calculated. Do nothing. */
fca177d4 375 if (! tty->costs_set)
36cae867
KH
376 return;
377
6548cf00
KL
378 if (curY (tty) == vpos
379 && curX (tty) == hpos)
08a24c47 380 return;
fca177d4 381 if (!tty->TF_standout_motion)
ed8dad6b 382 tty_background_highlight (tty);
fca177d4 383 if (!tty->TF_insmode_motion)
ed8dad6b 384 tty_turn_off_insert (tty);
6548cf00 385 cmgoto (tty, vpos, hpos);
08a24c47
JB
386}
387
388/* Similar but don't take any account of the wasted characters. */
389
ed8dad6b 390static void
385ed61f 391tty_raw_cursor_to (struct frame *f, int row, int col)
08a24c47 392{
3224dac1
KL
393 struct tty_display_info *tty = FRAME_TTY (f);
394
6548cf00
KL
395 if (curY (tty) == row
396 && curX (tty) == col)
08a24c47 397 return;
fca177d4 398 if (!tty->TF_standout_motion)
ed8dad6b 399 tty_background_highlight (tty);
fca177d4 400 if (!tty->TF_insmode_motion)
ed8dad6b 401 tty_turn_off_insert (tty);
6548cf00 402 cmgoto (tty, row, col);
08a24c47
JB
403}
404\f
405/* Erase operations */
406
da8e1115
KL
407/* Clear from cursor to end of frame on a termcap device. */
408
ed8dad6b 409static void
385ed61f 410tty_clear_to_end (struct frame *f)
08a24c47
JB
411{
412 register int i;
3224dac1 413 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 414
fca177d4 415 if (tty->TS_clr_to_bottom)
08a24c47 416 {
ed8dad6b 417 tty_background_highlight (tty);
fca177d4 418 OUTPUT (tty, tty->TS_clr_to_bottom);
08a24c47
JB
419 }
420 else
421 {
6548cf00 422 for (i = curY (tty); i < FRAME_LINES (f); i++)
08a24c47 423 {
385ed61f
KL
424 cursor_to (f, i, 0);
425 clear_end_of_line (f, FRAME_COLS (f));
08a24c47
JB
426 }
427 }
428}
429
da8e1115 430/* Clear an entire termcap frame. */
08a24c47 431
ed8dad6b 432static void
385ed61f 433tty_clear_frame (struct frame *f)
08a24c47 434{
3224dac1 435 struct tty_display_info *tty = FRAME_TTY (f);
177c0ea7 436
fca177d4 437 if (tty->TS_clr_frame)
08a24c47 438 {
ed8dad6b 439 tty_background_highlight (tty);
fca177d4 440 OUTPUT (tty, tty->TS_clr_frame);
6548cf00 441 cmat (tty, 0, 0);
08a24c47
JB
442 }
443 else
444 {
385ed61f
KL
445 cursor_to (f, 0, 0);
446 clear_to_end (f);
08a24c47
JB
447 }
448}
449
da8e1115 450/* An implementation of clear_end_of_line for termcap frames.
08a24c47
JB
451
452 Note that the cursor may be moved, on terminals lacking a `ce' string. */
453
ed8dad6b 454static void
385ed61f 455tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
08a24c47
JB
456{
457 register int i;
3224dac1 458 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 459
36cae867
KH
460 /* Detect the case where we are called from reset_sys_modes
461 and the costs have never been calculated. Do nothing. */
fca177d4 462 if (! tty->costs_set)
36cae867
KH
463 return;
464
6548cf00 465 if (curX (tty) >= first_unused_hpos)
08a24c47 466 return;
ed8dad6b 467 tty_background_highlight (tty);
fca177d4 468 if (tty->TS_clr_line)
08a24c47 469 {
fca177d4 470 OUTPUT1 (tty, tty->TS_clr_line);
08a24c47
JB
471 }
472 else
473 { /* have to do it the hard way */
ed8dad6b 474 tty_turn_off_insert (tty);
08a24c47 475
a168702a 476 /* Do not write in last row last col with Auto-wrap on. */
6548cf00 477 if (AutoWrap (tty)
0a125897
KL
478 && curY (tty) == FrameRows (tty) - 1
479 && first_unused_hpos == FrameCols (tty))
08a24c47
JB
480 first_unused_hpos--;
481
6548cf00 482 for (i = curX (tty); i < first_unused_hpos; i++)
08a24c47 483 {
0b0d3e0b
KL
484 if (tty->termscript)
485 fputc (' ', tty->termscript);
486 fputc (' ', tty->output);
08a24c47 487 }
6548cf00 488 cmplus (tty, first_unused_hpos - curX (tty));
08a24c47
JB
489 }
490}
491\f
288d5132
KH
492/* Buffers to store the source and result of code conversion for terminal. */
493static unsigned char *encode_terminal_src;
494static unsigned char *encode_terminal_dst;
495/* Allocated sizes of the above buffers. */
fee31f82
PE
496static ptrdiff_t encode_terminal_src_size;
497static ptrdiff_t encode_terminal_dst_size;
288d5132
KH
498
499/* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
500 Set CODING->produced to the byte-length of the resulting byte
501 sequence, and return a pointer to that byte sequence. */
502
7ef4b50c 503unsigned char *
d3da34e0 504encode_terminal_code (struct glyph *src, int src_len, struct coding_system *coding)
a4decb7f 505{
feef4f84 506 struct glyph *src_end = src + src_len;
288d5132 507 unsigned char *buf;
fee31f82
PE
508 ptrdiff_t nchars, nbytes, required;
509 ptrdiff_t tlen = GLYPH_TABLE_LENGTH;
a4decb7f 510 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
288d5132 511 Lisp_Object charset_list;
c5a518df 512
288d5132
KH
513 /* Allocate sufficient size of buffer to store all characters in
514 multibyte-form. But, it may be enlarged on demand if
4c12d738
KH
515 Vglyph_table contains a string or a composite glyph is
516 encountered. */
fee31f82
PE
517 if (min (PTRDIFF_MAX, SIZE_MAX) / MAX_MULTIBYTE_LENGTH < src_len)
518 memory_full (SIZE_MAX);
519 required = src_len;
520 required *= MAX_MULTIBYTE_LENGTH;
288d5132
KH
521 if (encode_terminal_src_size < required)
522 {
fee31f82 523 encode_terminal_src = xrealloc (encode_terminal_src, required);
288d5132
KH
524 encode_terminal_src_size = required;
525 }
6589fd67 526
288d5132 527 charset_list = coding_charset_list (coding);
a4decb7f 528
288d5132
KH
529 buf = encode_terminal_src;
530 nchars = 0;
531 while (src < src_end)
a4decb7f 532 {
4c12d738
KH
533 if (src->type == COMPOSITE_GLYPH)
534 {
c2ed9c8b
PE
535 struct composition *cmp IF_LINT (= NULL);
536 Lisp_Object gstring IF_LINT (= Qnil);
4c12d738
KH
537 int i;
538
539 nbytes = buf - encode_terminal_src;
75a10786
KH
540 if (src->u.cmp.automatic)
541 {
542 gstring = composition_gstring_from_id (src->u.cmp.id);
fee31f82 543 required = src->slice.cmp.to - src->slice.cmp.from + 1;
75a10786
KH
544 }
545 else
546 {
547 cmp = composition_table[src->u.cmp.id];
fee31f82
PE
548 required = cmp->glyph_len;
549 required *= MAX_MULTIBYTE_LENGTH;
75a10786 550 }
4c12d738 551
fee31f82 552 if (encode_terminal_src_size - nbytes < required)
4c12d738 553 {
0065d054
PE
554 encode_terminal_src =
555 xpalloc (encode_terminal_src, &encode_terminal_src_size,
556 required - (encode_terminal_src_size - nbytes),
557 -1, 1);
4c12d738
KH
558 buf = encode_terminal_src + nbytes;
559 }
560
75a10786 561 if (src->u.cmp.automatic)
4be9765d 562 for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
75a10786
KH
563 {
564 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
565 int c = LGLYPH_CHAR (g);
566
567 if (! char_charset (c, charset_list, NULL))
d0984aff 568 c = '?';
75a10786
KH
569 buf += CHAR_STRING (c, buf);
570 nchars++;
571 }
572 else
573 for (i = 0; i < cmp->glyph_len; i++)
574 {
575 int c = COMPOSITION_GLYPH (cmp, i);
576
bd01620e
EZ
577 /* TAB in a composition means display glyphs with
578 padding space on the left or right. */
d0984aff
KH
579 if (c == '\t')
580 continue;
581 if (char_charset (c, charset_list, NULL))
582 {
583 if (CHAR_WIDTH (c) == 0
584 && i > 0 && COMPOSITION_GLYPH (cmp, i - 1) == '\t')
585 /* Should be left-padded */
586 {
587 buf += CHAR_STRING (' ', buf);
588 nchars++;
589 }
590 }
591 else
592 c = '?';
75a10786
KH
593 buf += CHAR_STRING (c, buf);
594 nchars++;
595 }
4c12d738 596 }
a4decb7f 597 /* We must skip glyphs to be padded for a wide character. */
4c12d738 598 else if (! CHAR_GLYPH_PADDING_P (*src))
a4decb7f 599 {
f4d953fc 600 GLYPH g;
c2ed9c8b 601 int c IF_LINT (= 0);
288d5132
KH
602 Lisp_Object string;
603
4ae0a2c0 604 string = Qnil;
f4d953fc 605 SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
32de38e4 606
f4d953fc 607 if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
288d5132 608 {
f185a758 609 /* This glyph doesn't have an entry in Vglyph_table. */
288d5132
KH
610 c = src->u.ch;
611 }
32de38e4 612 else
a4decb7f 613 {
32de38e4 614 /* This glyph has an entry in Vglyph_table,
a4decb7f
KH
615 so process any alias before testing for simpleness. */
616 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
32de38e4
KH
617
618 if (GLYPH_SIMPLE_P (tbase, tlen, g))
4ae0a2c0
KH
619 /* We set the multi-byte form of a character in G
620 (that should be an ASCII character) at WORKBUF. */
f4d953fc 621 c = GLYPH_CHAR (g);
32de38e4 622 else
4ae0a2c0 623 /* We have a string in Vglyph_table. */
f4d953fc 624 string = tbase[GLYPH_CHAR (g)];
171d7f24 625 }
177c0ea7 626
4ae0a2c0 627 if (NILP (string))
c42869c4 628 {
4c12d738 629 nbytes = buf - encode_terminal_src;
fee31f82 630 if (encode_terminal_src_size - nbytes < MAX_MULTIBYTE_LENGTH)
4c12d738 631 {
0065d054
PE
632 encode_terminal_src =
633 xpalloc (encode_terminal_src, &encode_terminal_src_size,
634 MAX_MULTIBYTE_LENGTH, -1, 1);
4c12d738
KH
635 buf = encode_terminal_src + nbytes;
636 }
d419e1d9
KH
637 if (CHAR_BYTE8_P (c)
638 || char_charset (c, charset_list, NULL))
c5a518df 639 {
288d5132
KH
640 /* Store the multibyte form of C at BUF. */
641 buf += CHAR_STRING (c, buf);
642 nchars++;
c5a518df
KH
643 }
644 else
645 {
288d5132
KH
646 /* C is not encodable. */
647 *buf++ = '?';
c5a518df 648 nchars++;
288d5132
KH
649 while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
650 {
651 *buf++ = '?';
652 nchars++;
653 src++;
654 }
c5a518df 655 }
4ae0a2c0
KH
656 }
657 else
658 {
288d5132
KH
659 if (! STRING_MULTIBYTE (string))
660 string = string_to_multibyte (string);
661 nbytes = buf - encode_terminal_src;
fee31f82 662 if (encode_terminal_src_size - nbytes < SBYTES (string))
4ae0a2c0 663 {
0065d054
PE
664 encode_terminal_src =
665 xpalloc (encode_terminal_src, &encode_terminal_src_size,
666 (SBYTES (string)
667 - (encode_terminal_src_size - nbytes)),
668 -1, 1);
288d5132 669 buf = encode_terminal_src + nbytes;
4ae0a2c0 670 }
72af86bd 671 memcpy (buf, SDATA (string), SBYTES (string));
288d5132
KH
672 buf += SBYTES (string);
673 nchars += SCHARS (string);
c42869c4 674 }
a4decb7f 675 }
288d5132
KH
676 src++;
677 }
678
679 if (nchars == 0)
680 {
681 coding->produced = 0;
682 return NULL;
a4decb7f 683 }
177c0ea7 684
288d5132
KH
685 nbytes = buf - encode_terminal_src;
686 coding->source = encode_terminal_src;
687 if (encode_terminal_dst_size == 0)
4ae0a2c0 688 {
fee31f82
PE
689 encode_terminal_dst = xrealloc (encode_terminal_dst,
690 encode_terminal_src_size);
288d5132 691 encode_terminal_dst_size = encode_terminal_src_size;
4ae0a2c0 692 }
288d5132
KH
693 coding->destination = encode_terminal_dst;
694 coding->dst_bytes = encode_terminal_dst_size;
695 encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
c5a518df 696 /* coding->destination may have been reallocated. */
288d5132
KH
697 encode_terminal_dst = coding->destination;
698 encode_terminal_dst_size = coding->dst_bytes;
4ae0a2c0 699
288d5132 700 return (encode_terminal_dst);
a4decb7f
KH
701}
702
08a24c47 703
c73bd236 704
da8e1115
KL
705/* An implementation of write_glyphs for termcap frames. */
706
ed8dad6b 707static void
385ed61f 708tty_write_glyphs (struct frame *f, struct glyph *string, int len)
08a24c47 709{
288d5132
KH
710 unsigned char *conversion_buffer;
711 struct coding_system *coding;
653d4f43 712 int n, stringlen;
08a24c47 713
3224dac1 714 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 715
ed8dad6b 716 tty_turn_off_insert (tty);
fca177d4 717 tty_hide_cursor (tty);
08a24c47 718
a168702a 719 /* Don't dare write in last column of bottom line, if Auto-Wrap,
ff11dfa1 720 since that would scroll the whole frame on some terminals. */
08a24c47 721
6548cf00
KL
722 if (AutoWrap (tty)
723 && curY (tty) + 1 == FRAME_LINES (f)
724 && (curX (tty) + len) == FRAME_COLS (f))
08a24c47 725 len --;
a4decb7f
KH
726 if (len <= 0)
727 return;
08a24c47 728
6548cf00 729 cmplus (tty, len);
177c0ea7 730
af645abf
KH
731 /* If terminal_coding does any conversion, use it, otherwise use
732 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
733 because it always return 1 if the member src_multibyte is 1. */
fad2f685
KL
734 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
735 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
6589fd67
KH
736 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
737 the tail. */
af645abf 738 coding->mode &= ~CODING_MODE_LAST_BLOCK;
177c0ea7 739
5c5cdd39 740 for (stringlen = len; stringlen != 0; stringlen -= n)
08a24c47 741 {
a168702a 742 /* Identify a run of glyphs with the same face. */
32de38e4 743 int face_id = string->face_id;
177c0ea7 744
5c5cdd39 745 for (n = 1; n < stringlen; ++n)
32de38e4 746 if (string[n].face_id != face_id)
a168702a
GM
747 break;
748
749 /* Turn appearance modes of the face of the run on. */
ed8dad6b 750 tty_highlight_if_desired (tty);
a168702a
GM
751 turn_on_face (f, face_id);
752
5c5cdd39 753 if (n == stringlen)
288d5132
KH
754 /* This is the last run. */
755 coding->mode |= CODING_MODE_LAST_BLOCK;
756 conversion_buffer = encode_terminal_code (string, n, coding);
757 if (coding->produced > 0)
08a24c47 758 {
4d7e6e51 759 block_input ();
fad2f685
KL
760 fwrite (conversion_buffer, 1, coding->produced, tty->output);
761 if (ferror (tty->output))
762 clearerr (tty->output);
763 if (tty->termscript)
764 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
4d7e6e51 765 unblock_input ();
08a24c47 766 }
288d5132 767 string += n;
a168702a
GM
768
769 /* Turn appearance modes off. */
770 turn_off_face (f, face_id);
ed8dad6b 771 tty_turn_off_highlight (tty);
a4decb7f 772 }
177c0ea7 773
6548cf00 774 cmcheckmagic (tty);
08a24c47
JB
775}
776
b870aa61
SM
777#ifdef HAVE_GPM /* Only used by GPM code. */
778
7be1c21a 779static void
d3da34e0
JB
780tty_write_glyphs_with_face (register struct frame *f, register struct glyph *string,
781 register int len, register int face_id)
e882229c 782{
e882229c
NR
783 unsigned char *conversion_buffer;
784 struct coding_system *coding;
785
7be1c21a
MB
786 struct tty_display_info *tty = FRAME_TTY (f);
787
788 tty_turn_off_insert (tty);
789 tty_hide_cursor (tty);
e882229c
NR
790
791 /* Don't dare write in last column of bottom line, if Auto-Wrap,
792 since that would scroll the whole frame on some terminals. */
793
7be1c21a
MB
794 if (AutoWrap (tty)
795 && curY (tty) + 1 == FRAME_LINES (f)
796 && (curX (tty) + len) == FRAME_COLS (f))
e882229c
NR
797 len --;
798 if (len <= 0)
799 return;
800
7be1c21a 801 cmplus (tty, len);
e882229c
NR
802
803 /* If terminal_coding does any conversion, use it, otherwise use
804 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
805 because it always return 1 if the member src_multibyte is 1. */
7be1c21a
MB
806 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
807 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
e882229c
NR
808 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
809 the tail. */
810 coding->mode &= ~CODING_MODE_LAST_BLOCK;
811
e882229c 812 /* Turn appearance modes of the face. */
7be1c21a 813 tty_highlight_if_desired (tty);
e882229c
NR
814 turn_on_face (f, face_id);
815
816 coding->mode |= CODING_MODE_LAST_BLOCK;
817 conversion_buffer = encode_terminal_code (string, len, coding);
818 if (coding->produced > 0)
819 {
4d7e6e51 820 block_input ();
7be1c21a
MB
821 fwrite (conversion_buffer, 1, coding->produced, tty->output);
822 if (ferror (tty->output))
823 clearerr (tty->output);
824 if (tty->termscript)
825 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
4d7e6e51 826 unblock_input ();
e882229c
NR
827 }
828
829 /* Turn appearance modes off. */
830 turn_off_face (f, face_id);
7be1c21a 831 tty_turn_off_highlight (tty);
e882229c 832
7be1c21a 833 cmcheckmagic (tty);
e882229c 834}
b870aa61 835#endif
e882229c 836
da8e1115 837/* An implementation of insert_glyphs for termcap frames. */
177c0ea7 838
ed8dad6b 839static void
385ed61f 840tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
08a24c47
JB
841{
842 char *buf;
6bbd7a29 843 struct glyph *glyph = NULL;
af645abf
KH
844 unsigned char *conversion_buffer;
845 unsigned char space[1];
846 struct coding_system *coding;
08a24c47 847
3224dac1 848 struct tty_display_info *tty = FRAME_TTY (f);
a168702a 849
fca177d4 850 if (tty->TS_ins_multi_chars)
08a24c47 851 {
50938595 852 buf = tparam (tty->TS_ins_multi_chars, 0, 0, len, 0, 0, 0);
6548cf00 853 OUTPUT1 (tty, buf);
9ac0d9e0 854 xfree (buf);
08a24c47 855 if (start)
385ed61f 856 write_glyphs (f, start, len);
08a24c47
JB
857 return;
858 }
859
ed8dad6b 860 tty_turn_on_insert (tty);
6548cf00 861 cmplus (tty, len);
288d5132
KH
862
863 if (! start)
864 space[0] = SPACEGLYPH;
865
866 /* If terminal_coding does any conversion, use it, otherwise use
867 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
868 because it always return 1 if the member src_multibyte is 1. */
fad2f685
KL
869 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
870 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
288d5132
KH
871 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
872 the tail. */
873 coding->mode &= ~CODING_MODE_LAST_BLOCK;
874
07109bf9 875 while (len-- > 0)
08a24c47 876 {
fca177d4 877 OUTPUT1_IF (tty, tty->TS_ins_char);
08a24c47 878 if (!start)
32de38e4 879 {
288d5132
KH
880 conversion_buffer = space;
881 coding->produced = 1;
32de38e4 882 }
08a24c47 883 else
08a24c47 884 {
ed8dad6b 885 tty_highlight_if_desired (tty);
32de38e4 886 turn_on_face (f, start->face_id);
816be8b8 887 glyph = start;
a168702a 888 ++start;
a4decb7f
KH
889 /* We must open sufficient space for a character which
890 occupies more than one column. */
a168702a 891 while (len && CHAR_GLYPH_PADDING_P (*start))
a4decb7f 892 {
fca177d4 893 OUTPUT1_IF (tty, tty->TS_ins_char);
a4decb7f
KH
894 start++, len--;
895 }
288d5132
KH
896
897 if (len <= 0)
898 /* This is the last glyph. */
899 coding->mode |= CODING_MODE_LAST_BLOCK;
900
fad2f685 901 conversion_buffer = encode_terminal_code (glyph, 1, coding);
32de38e4 902 }
a4decb7f 903
288d5132 904 if (coding->produced > 0)
08a24c47 905 {
4d7e6e51 906 block_input ();
fad2f685 907 fwrite (conversion_buffer, 1, coding->produced, tty->output);
0b0d3e0b
KL
908 if (ferror (tty->output))
909 clearerr (tty->output);
910 if (tty->termscript)
fad2f685 911 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
4d7e6e51 912 unblock_input ();
08a24c47
JB
913 }
914
fca177d4 915 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
32de38e4 916 if (start)
65aa5e85
GM
917 {
918 turn_off_face (f, glyph->face_id);
ed8dad6b 919 tty_turn_off_highlight (tty);
65aa5e85 920 }
9a6b6f92 921 }
177c0ea7 922
6548cf00 923 cmcheckmagic (tty);
08a24c47
JB
924}
925
da8e1115
KL
926/* An implementation of delete_glyphs for termcap frames. */
927
ed8dad6b 928static void
385ed61f 929tty_delete_glyphs (struct frame *f, int n)
08a24c47
JB
930{
931 char *buf;
932 register int i;
933
3224dac1 934 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 935
fca177d4 936 if (tty->delete_in_insert_mode)
08a24c47 937 {
ed8dad6b 938 tty_turn_on_insert (tty);
08a24c47
JB
939 }
940 else
941 {
ed8dad6b 942 tty_turn_off_insert (tty);
fca177d4 943 OUTPUT_IF (tty, tty->TS_delete_mode);
08a24c47
JB
944 }
945
fca177d4 946 if (tty->TS_del_multi_chars)
08a24c47 947 {
50938595 948 buf = tparam (tty->TS_del_multi_chars, 0, 0, n, 0, 0, 0);
6548cf00 949 OUTPUT1 (tty, buf);
9ac0d9e0 950 xfree (buf);
08a24c47
JB
951 }
952 else
953 for (i = 0; i < n; i++)
fca177d4
KL
954 OUTPUT1 (tty, tty->TS_del_char);
955 if (!tty->delete_in_insert_mode)
956 OUTPUT_IF (tty, tty->TS_end_delete_mode);
08a24c47
JB
957}
958\f
da8e1115 959/* An implementation of ins_del_lines for termcap frames. */
08a24c47 960
ed8dad6b 961static void
385ed61f 962tty_ins_del_lines (struct frame *f, int vpos, int n)
08a24c47 963{
3224dac1 964 struct tty_display_info *tty = FRAME_TTY (f);
fbceeba2
PE
965 const char *multi =
966 n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
967 const char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
968 const char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
08a24c47 969
71376d4b
PE
970 int i = eabs (n);
971 char *buf;
08a24c47 972
08a24c47
JB
973 /* If the lines below the insertion are being pushed
974 into the end of the window, this is the same as clearing;
975 and we know the lines are already clear, since the matching
976 deletion has already been done. So can ignore this. */
977 /* If the lines below the deletion are blank lines coming
978 out of the end of the window, don't bother,
979 as there will be a matching inslines later that will flush them. */
3224dac1
KL
980 if (FRAME_SCROLL_REGION_OK (f)
981 && vpos + i >= tty->specified_window)
08a24c47 982 return;
3224dac1
KL
983 if (!FRAME_MEMORY_BELOW_FRAME (f)
984 && vpos + i >= FRAME_LINES (f))
08a24c47 985 return;
f4d953fc 986
08a24c47
JB
987 if (multi)
988 {
6839f1e2 989 raw_cursor_to (f, vpos, 0);
ed8dad6b 990 tty_background_highlight (tty);
50938595 991 buf = tparam (multi, 0, 0, i, 0, 0, 0);
3224dac1 992 OUTPUT (tty, buf);
9ac0d9e0 993 xfree (buf);
08a24c47
JB
994 }
995 else if (single)
996 {
6839f1e2 997 raw_cursor_to (f, vpos, 0);
ed8dad6b 998 tty_background_highlight (tty);
08a24c47 999 while (--i >= 0)
3224dac1
KL
1000 OUTPUT (tty, single);
1001 if (tty->TF_teleray)
1002 curX (tty) = 0;
08a24c47
JB
1003 }
1004 else
1005 {
ed8dad6b 1006 tty_set_scroll_region (f, vpos, tty->specified_window);
08a24c47 1007 if (n < 0)
6839f1e2 1008 raw_cursor_to (f, tty->specified_window - 1, 0);
08a24c47 1009 else
6839f1e2 1010 raw_cursor_to (f, vpos, 0);
ed8dad6b 1011 tty_background_highlight (tty);
08a24c47 1012 while (--i >= 0)
3224dac1 1013 OUTPUTL (tty, scroll, tty->specified_window - vpos);
ed8dad6b 1014 tty_set_scroll_region (f, 0, tty->specified_window);
08a24c47 1015 }
f4d953fc 1016
3224dac1
KL
1017 if (!FRAME_SCROLL_REGION_OK (f)
1018 && FRAME_MEMORY_BELOW_FRAME (f)
1019 && n < 0)
08a24c47 1020 {
385ed61f
KL
1021 cursor_to (f, FRAME_LINES (f) + n, 0);
1022 clear_to_end (f);
08a24c47
JB
1023 }
1024}
1025\f
1026/* Compute cost of sending "str", in characters,
1027 not counting any line-dependent padding. */
1028
1029int
8ea90aa3 1030string_cost (const char *str)
08a24c47
JB
1031{
1032 cost = 0;
1033 if (str)
1034 tputs (str, 0, evalcost);
1035 return cost;
1036}
1037
1038/* Compute cost of sending "str", in characters,
1039 counting any line-dependent padding at one line. */
1040
1041static int
8ea90aa3 1042string_cost_one_line (const char *str)
08a24c47
JB
1043{
1044 cost = 0;
1045 if (str)
1046 tputs (str, 1, evalcost);
1047 return cost;
1048}
1049
1050/* Compute per line amount of line-dependent padding,
1051 in tenths of characters. */
1052
1053int
8ea90aa3 1054per_line_cost (const char *str)
08a24c47
JB
1055{
1056 cost = 0;
1057 if (str)
1058 tputs (str, 0, evalcost);
1059 cost = - cost;
1060 if (str)
1061 tputs (str, 10, evalcost);
1062 return cost;
1063}
1064
08a24c47 1065/* char_ins_del_cost[n] is cost of inserting N characters.
8dd0c7cb 1066 char_ins_del_cost[-n] is cost of deleting N characters.
9882535b 1067 The length of this vector is based on max_frame_cols. */
08a24c47
JB
1068
1069int *char_ins_del_vector;
1070
9882535b 1071#define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_COLS ((f))])
08a24c47
JB
1072
1073/* ARGSUSED */
1074static void
6839f1e2 1075calculate_ins_del_char_costs (struct frame *f)
08a24c47 1076{
28d7d09f 1077 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47
JB
1078 int ins_startup_cost, del_startup_cost;
1079 int ins_cost_per_char, del_cost_per_char;
1080 register int i;
1081 register int *p;
1082
fca177d4 1083 if (tty->TS_ins_multi_chars)
08a24c47
JB
1084 {
1085 ins_cost_per_char = 0;
fca177d4 1086 ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars);
08a24c47 1087 }
fca177d4
KL
1088 else if (tty->TS_ins_char || tty->TS_pad_inserted_char
1089 || (tty->TS_insert_mode && tty->TS_end_insert_mode))
08a24c47 1090 {
fca177d4
KL
1091 ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode)
1092 + string_cost (tty->TS_end_insert_mode))) / 100;
1093 ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char)
1094 + string_cost_one_line (tty->TS_pad_inserted_char));
08a24c47
JB
1095 }
1096 else
1097 {
1098 ins_startup_cost = 9999;
1099 ins_cost_per_char = 0;
1100 }
1101
fca177d4 1102 if (tty->TS_del_multi_chars)
08a24c47
JB
1103 {
1104 del_cost_per_char = 0;
fca177d4 1105 del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars);
08a24c47 1106 }
fca177d4 1107 else if (tty->TS_del_char)
08a24c47 1108 {
fca177d4
KL
1109 del_startup_cost = (string_cost (tty->TS_delete_mode)
1110 + string_cost (tty->TS_end_delete_mode));
1111 if (tty->delete_in_insert_mode)
08a24c47 1112 del_startup_cost /= 2;
fca177d4 1113 del_cost_per_char = string_cost_one_line (tty->TS_del_char);
08a24c47
JB
1114 }
1115 else
1116 {
1117 del_startup_cost = 9999;
1118 del_cost_per_char = 0;
1119 }
1120
1121 /* Delete costs are at negative offsets */
fca177d4
KL
1122 p = &char_ins_del_cost (f)[0];
1123 for (i = FRAME_COLS (f); --i >= 0;)
08a24c47
JB
1124 *--p = (del_startup_cost += del_cost_per_char);
1125
1126 /* Doing nothing is free */
fca177d4 1127 p = &char_ins_del_cost (f)[0];
08a24c47
JB
1128 *p++ = 0;
1129
1130 /* Insert costs are at positive offsets */
fca177d4 1131 for (i = FRAME_COLS (f); --i >= 0;)
08a24c47
JB
1132 *p++ = (ins_startup_cost += ins_cost_per_char);
1133}
1134
dfcf069d 1135void
6839f1e2 1136calculate_costs (struct frame *frame)
08a24c47 1137{
9f732a77 1138 FRAME_COST_BAUD_RATE (frame) = baud_rate;
08a24c47 1139
28d440ab 1140 if (FRAME_TERMCAP_P (frame))
daf01701
KL
1141 {
1142 struct tty_display_info *tty = FRAME_TTY (frame);
fbceeba2
PE
1143 register const char *f = (tty->TS_set_scroll_region
1144 ? tty->TS_set_scroll_region
1145 : tty->TS_set_scroll_region_1);
08a24c47 1146
daf01701 1147 FRAME_SCROLL_REGION_COST (frame) = string_cost (f);
08a24c47 1148
daf01701 1149 tty->costs_set = 1;
08a24c47 1150
daf01701
KL
1151 /* These variables are only used for terminal stuff. They are
1152 allocated once for the terminal frame of X-windows emacs, but not
1153 used afterwards.
8dd0c7cb 1154
daf01701
KL
1155 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1156 X turns off char_ins_del_ok. */
08a24c47 1157
daf01701 1158 max_frame_cols = max (max_frame_cols, FRAME_COLS (frame));
0065d054
PE
1159 if ((min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) - 1) / 2
1160 < max_frame_cols)
fee31f82 1161 memory_full (SIZE_MAX);
08a24c47 1162
0065d054
PE
1163 char_ins_del_vector =
1164 xrealloc (char_ins_del_vector,
1165 (sizeof (int) + 2 * sizeof (int) * max_frame_cols));
08a24c47 1166
72af86bd 1167 memset (char_ins_del_vector, 0,
0065d054 1168 (sizeof (int) + 2 * sizeof (int) * max_frame_cols));
08a24c47 1169
daf01701
KL
1170
1171 if (f && (!tty->TS_ins_line && !tty->TS_del_line))
1172 do_line_insertion_deletion_costs (frame,
1173 tty->TS_rev_scroll, tty->TS_ins_multi_lines,
1174 tty->TS_fwd_scroll, tty->TS_del_multi_lines,
1175 f, f, 1);
1176 else
1177 do_line_insertion_deletion_costs (frame,
1178 tty->TS_ins_line, tty->TS_ins_multi_lines,
1179 tty->TS_del_line, tty->TS_del_multi_lines,
1180 0, 0, 1);
1181
1182 calculate_ins_del_char_costs (frame);
1183
1184 /* Don't use TS_repeat if its padding is worse than sending the chars */
1185 if (tty->TS_repeat && per_line_cost (tty->TS_repeat) * baud_rate < 9000)
1186 tty->RPov = string_cost (tty->TS_repeat);
1187 else
1188 tty->RPov = FRAME_COLS (frame) * 2;
08a24c47 1189
daf01701
KL
1190 cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */
1191 }
08a24c47
JB
1192}
1193\f
a796ac82 1194struct fkey_table {
fbceeba2 1195 const char *cap, *name;
a796ac82
JB
1196};
1197
01d8deb0
ER
1198 /* Termcap capability names that correspond directly to X keysyms.
1199 Some of these (marked "terminfo") aren't supplied by old-style
1200 (Berkeley) termcap entries. They're listed in X keysym order;
1201 except we put the keypad keys first, so that if they clash with
1202 other keys (as on the IBM PC keyboard) they get overridden.
1203 */
1204
648801d1 1205static const struct fkey_table keys[] =
a168702a 1206{
8103ad1a
PJ
1207 {"kh", "home"}, /* termcap */
1208 {"kl", "left"}, /* termcap */
1209 {"ku", "up"}, /* termcap */
1210 {"kr", "right"}, /* termcap */
1211 {"kd", "down"}, /* termcap */
1212 {"%8", "prior"}, /* terminfo */
1213 {"%5", "next"}, /* terminfo */
1214 {"@7", "end"}, /* terminfo */
1215 {"@1", "begin"}, /* terminfo */
1216 {"*6", "select"}, /* terminfo */
1217 {"%9", "print"}, /* terminfo */
1218 {"@4", "execute"}, /* terminfo --- actually the `command' key */
01d8deb0
ER
1219 /*
1220 * "insert" --- see below
1221 */
8103ad1a
PJ
1222 {"&8", "undo"}, /* terminfo */
1223 {"%0", "redo"}, /* terminfo */
1224 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1225 {"@0", "find"}, /* terminfo */
1226 {"@2", "cancel"}, /* terminfo */
1227 {"%1", "help"}, /* terminfo */
01d8deb0
ER
1228 /*
1229 * "break" goes here, but can't be reliably intercepted with termcap
1230 */
8103ad1a 1231 {"&4", "reset"}, /* terminfo --- actually `restart' */
01d8deb0
ER
1232 /*
1233 * "system" and "user" --- no termcaps
1234 */
8103ad1a
PJ
1235 {"kE", "clearline"}, /* terminfo */
1236 {"kA", "insertline"}, /* terminfo */
1237 {"kL", "deleteline"}, /* terminfo */
1238 {"kI", "insertchar"}, /* terminfo */
1239 {"kD", "deletechar"}, /* terminfo */
1240 {"kB", "backtab"}, /* terminfo */
01d8deb0
ER
1241 /*
1242 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1243 */
8103ad1a 1244 {"@8", "kp-enter"}, /* terminfo */
01d8deb0
ER
1245 /*
1246 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1247 * "kp-multiply", "kp-add", "kp-separator",
1248 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1249 * --- no termcaps for any of these.
1250 */
8103ad1a 1251 {"K4", "kp-1"}, /* terminfo */
01d8deb0
ER
1252 /*
1253 * "kp-2" --- no termcap
1254 */
8103ad1a 1255 {"K5", "kp-3"}, /* terminfo */
01d8deb0
ER
1256 /*
1257 * "kp-4" --- no termcap
1258 */
8103ad1a 1259 {"K2", "kp-5"}, /* terminfo */
01d8deb0
ER
1260 /*
1261 * "kp-6" --- no termcap
1262 */
8103ad1a 1263 {"K1", "kp-7"}, /* terminfo */
01d8deb0
ER
1264 /*
1265 * "kp-8" --- no termcap
1266 */
8103ad1a 1267 {"K3", "kp-9"}, /* terminfo */
01d8deb0
ER
1268 /*
1269 * "kp-equal" --- no termcap
1270 */
8103ad1a
PJ
1271 {"k1", "f1"},
1272 {"k2", "f2"},
1273 {"k3", "f3"},
1274 {"k4", "f4"},
1275 {"k5", "f5"},
1276 {"k6", "f6"},
1277 {"k7", "f7"},
1278 {"k8", "f8"},
60ec7b7e
DN
1279 {"k9", "f9"},
1280
1281 {"&0", "S-cancel"}, /*shifted cancel key*/
1282 {"&9", "S-begin"}, /*shifted begin key*/
1283 {"*0", "S-find"}, /*shifted find key*/
1284 {"*1", "S-execute"}, /*shifted execute? actually shifted command key*/
1285 {"*4", "S-delete"}, /*shifted delete-character key*/
1286 {"*7", "S-end"}, /*shifted end key*/
1287 {"*8", "S-clearline"}, /*shifted clear-to end-of-line key*/
1288 {"#1", "S-help"}, /*shifted help key*/
1289 {"#2", "S-home"}, /*shifted home key*/
1290 {"#3", "S-insert"}, /*shifted insert-character key*/
1291 {"#4", "S-left"}, /*shifted left-arrow key*/
1292 {"%d", "S-menu"}, /*shifted menu? actually shifted options key*/
1293 {"%c", "S-next"}, /*shifted next key*/
1294 {"%e", "S-prior"}, /*shifted previous key*/
1295 {"%f", "S-print"}, /*shifted print key*/
1296 {"%g", "S-redo"}, /*shifted redo key*/
1297 {"%i", "S-right"}, /*shifted right-arrow key*/
1298 {"!3", "S-undo"} /*shifted undo key*/
a796ac82
JB
1299 };
1300
361358ea 1301#ifndef DOS_NT
e7cf0fa0
KL
1302static char **term_get_fkeys_address;
1303static KBOARD *term_get_fkeys_kboard;
d3da34e0 1304static Lisp_Object term_get_fkeys_1 (void);
465db27b 1305
4f4a84ec 1306/* Find the escape codes sent by the function keys for Vinput_decode_map.
177c0ea7 1307 This function scans the termcap function key sequence entries, and
4f4a84ec 1308 adds entries to Vinput_decode_map for each function key it finds. */
01d8deb0 1309
ed8dad6b 1310static void
d3da34e0 1311term_get_fkeys (char **address, KBOARD *kboard)
f2a00342
RM
1312{
1313 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1314 errors during the call. The only errors should be from Fdefine_key
1315 when given a key sequence containing an invalid prefix key. If the
1316 termcap defines function keys which use a prefix that is already bound
1317 to a command by the default bindings, we should silently ignore that
1318 function key specification, rather than giving the user an error and
1319 refusing to run at all on such a terminal. */
1320
e7cf0fa0
KL
1321 term_get_fkeys_address = address;
1322 term_get_fkeys_kboard = kboard;
f2a00342
RM
1323 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1324}
1325
1326static Lisp_Object
d3da34e0 1327term_get_fkeys_1 (void)
5c2c7893 1328{
5c2c7893
JB
1329 int i;
1330
e7cf0fa0
KL
1331 char **address = term_get_fkeys_address;
1332 KBOARD *kboard = term_get_fkeys_kboard;
f4d953fc 1333
3e65092f 1334 /* This can happen if CANNOT_DUMP or with strange options. */
1344aad4 1335 if (!KEYMAPP (KVAR (kboard, Vinput_decode_map)))
15dbb4d6 1336 kset_input_decode_map (kboard, Fmake_sparse_keymap (Qnil));
3e65092f 1337
cbae07d5 1338 for (i = 0; i < (sizeof (keys) / sizeof (keys[0])); i++)
5c2c7893
JB
1339 {
1340 char *sequence = tgetstr (keys[i].cap, address);
1341 if (sequence)
1344aad4 1342 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
f2a00342
RM
1343 Fmake_vector (make_number (1),
1344 intern (keys[i].name)));
5c2c7893 1345 }
a796ac82
JB
1346
1347 /* The uses of the "k0" capability are inconsistent; sometimes it
1348 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
eb8c3be9 1349 We will attempt to politely accommodate both systems by testing for
a796ac82
JB
1350 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1351 */
1352 {
fbceeba2
PE
1353 const char *k_semi = tgetstr ("k;", address);
1354 const char *k0 = tgetstr ("k0", address);
1355 const char *k0_name = "f10";
a796ac82
JB
1356
1357 if (k_semi)
1358 {
95c11956
SM
1359 if (k0)
1360 /* Define f0 first, so that f10 takes precedence in case the
1361 key sequences happens to be the same. */
1344aad4 1362 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
95c11956 1363 Fmake_vector (make_number (1), intern ("f0")));
1344aad4 1364 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k_semi),
f2a00342 1365 Fmake_vector (make_number (1), intern ("f10")));
a796ac82 1366 }
95c11956 1367 else if (k0)
1344aad4 1368 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
f2a00342 1369 Fmake_vector (make_number (1), intern (k0_name)));
a796ac82 1370 }
01d8deb0
ER
1371
1372 /* Set up cookies for numbered function keys above f10. */
1373 {
1374 char fcap[3], fkey[4];
1375
fc4f24da 1376 fcap[0] = 'F'; fcap[2] = '\0';
01d8deb0
ER
1377 for (i = 11; i < 64; i++)
1378 {
1379 if (i <= 19)
1380 fcap[1] = '1' + i - 11;
1381 else if (i <= 45)
b59ab95c 1382 fcap[1] = 'A' + i - 20;
01d8deb0 1383 else
b59ab95c 1384 fcap[1] = 'a' + i - 46;
01d8deb0 1385
fc4f24da
RS
1386 {
1387 char *sequence = tgetstr (fcap, address);
1388 if (sequence)
1389 {
465db27b 1390 sprintf (fkey, "f%d", i);
1344aad4 1391 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
f2a00342
RM
1392 Fmake_vector (make_number (1),
1393 intern (fkey)));
fc4f24da
RS
1394 }
1395 }
01d8deb0
ER
1396 }
1397 }
1398
1399 /*
1400 * Various mappings to try and get a better fit.
1401 */
1402 {
fc4f24da
RS
1403#define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1404 if (!tgetstr (cap1, address)) \
1405 { \
1406 char *sequence = tgetstr (cap2, address); \
e7cf0fa0 1407 if (sequence) \
1344aad4 1408 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence), \
e7cf0fa0
KL
1409 Fmake_vector (make_number (1), \
1410 intern (sym))); \
fc4f24da 1411 }
177c0ea7 1412
01d8deb0 1413 /* if there's no key_next keycap, map key_npage to `next' keysym */
27b61785 1414 CONDITIONAL_REASSIGN ("%5", "kN", "next");
01d8deb0 1415 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
381d11a1 1416 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
01d8deb0 1417 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
27b61785 1418 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
403c995b
RS
1419 /* if there's no key_end keycap, map key_ll to 'end' keysym */
1420 CONDITIONAL_REASSIGN ("@7", "kH", "end");
0a7f697a
KH
1421
1422 /* IBM has their own non-standard dialect of terminfo.
1423 If the standard name isn't found, try the IBM name. */
1424 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1425 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1426 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1427 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1428 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1429 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1430 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1431 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1432 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1dd40212 1433#undef CONDITIONAL_REASSIGN
01d8deb0 1434 }
a168702a
GM
1435
1436 return Qnil;
5c2c7893 1437}
361358ea 1438#endif /* not DOS_NT */
5c2c7893
JB
1439
1440\f
a168702a
GM
1441/***********************************************************************
1442 Character Display Information
1443 ***********************************************************************/
f57e2426 1444static void append_glyph (struct it *);
f57e2426
J
1445static void append_composite_glyph (struct it *);
1446static void produce_composite_glyph (struct it *);
fbceeba2 1447static void append_glyphless_glyph (struct it *, int, const char *);
653d4f43 1448static void produce_glyphless_glyph (struct it *, Lisp_Object);
a168702a
GM
1449
1450/* Append glyphs to IT's glyph_row. Called from produce_glyphs for
d2b4c17d
KH
1451 terminal frames if IT->glyph_row != NULL. IT->char_to_display is
1452 the character for which to produce glyphs; IT->face_id contains the
1453 character's face. Padding glyphs are appended if IT->c has a
1454 IT->pixel_width > 1. */
177c0ea7 1455
a168702a 1456static void
d3da34e0 1457append_glyph (struct it *it)
a168702a
GM
1458{
1459 struct glyph *glyph, *end;
1460 int i;
1461
a54e2c05 1462 eassert (it->glyph_row);
a168702a
GM
1463 glyph = (it->glyph_row->glyphs[it->area]
1464 + it->glyph_row->used[it->area]);
1465 end = it->glyph_row->glyphs[1 + it->area];
1466
5e65aec0
EZ
1467 /* If the glyph row is reversed, we need to prepend the glyph rather
1468 than append it. */
1469 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1470 {
1471 struct glyph *g;
1472 int move_by = it->pixel_width;
1473
1474 /* Make room for the new glyphs. */
1475 if (move_by > end - glyph) /* don't overstep end of this area */
1476 move_by = end - glyph;
1477 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1478 g[move_by] = *g;
1479 glyph = it->glyph_row->glyphs[it->area];
1480 end = glyph + move_by;
1481 }
1482
1483 /* BIDI Note: we put the glyphs of a "multi-pixel" character left to
1484 right, even in the REVERSED_P case, since (a) all of its u.ch are
1485 identical, and (b) the PADDING_P flag needs to be set for the
1486 leftmost one, because we write to the terminal left-to-right. */
177c0ea7
JB
1487 for (i = 0;
1488 i < it->pixel_width && glyph < end;
a168702a
GM
1489 ++i)
1490 {
1491 glyph->type = CHAR_GLYPH;
d13f3e2e 1492 glyph->pixel_width = 1;
d2b4c17d 1493 glyph->u.ch = it->char_to_display;
32de38e4
KH
1494 glyph->face_id = it->face_id;
1495 glyph->padding_p = i > 0;
a168702a
GM
1496 glyph->charpos = CHARPOS (it->position);
1497 glyph->object = it->object;
5e65aec0
EZ
1498 if (it->bidi_p)
1499 {
1500 glyph->resolved_level = it->bidi_it.resolved_level;
9443b3c7 1501 if ((it->bidi_it.type & 7) != it->bidi_it.type)
1088b922 1502 emacs_abort ();
5e65aec0
EZ
1503 glyph->bidi_type = it->bidi_it.type;
1504 }
9443b3c7
EZ
1505 else
1506 {
1507 glyph->resolved_level = 0;
1508 glyph->bidi_type = UNKNOWN_BT;
1509 }
177c0ea7 1510
a168702a
GM
1511 ++it->glyph_row->used[it->area];
1512 ++glyph;
1513 }
1514}
1515
148ae00e
EZ
1516/* For external use. */
1517void
1518tty_append_glyph (struct it *it)
1519{
1520 append_glyph (it);
1521}
1522
1523
b50fe468
RS
1524/* Produce glyphs for the display element described by IT. *IT
1525 specifies what we want to produce a glyph for (character, image, ...),
1526 and where in the glyph matrix we currently are (glyph row and hpos).
1527 produce_glyphs fills in output fields of *IT with information such as the
1528 pixel width and height of a character, and maybe output actual glyphs at
e3670e00
EZ
1529 the same time if IT->glyph_row is non-null. For an overview, see
1530 the explanation in dispextern.h, before the definition of the
1531 display_element_type enumeration.
b50fe468
RS
1532
1533 produce_glyphs also stores the result of glyph width, ascent
1534 etc. computations in *IT.
1535
1536 IT->glyph_row may be null, in which case produce_glyphs does not
1537 actually fill in the glyphs. This is used in the move_* functions
1538 in xdisp.c for text width and height computations.
1539
1540 Callers usually don't call produce_glyphs directly;
1541 instead they use the macro PRODUCE_GLYPHS. */
a168702a 1542
177c0ea7 1543void
d3da34e0 1544produce_glyphs (struct it *it)
a168702a
GM
1545{
1546 /* If a hook is installed, let it do the work. */
4c12d738
KH
1547
1548 /* Nothing but characters are supported on terminal frames. */
a54e2c05 1549 eassert (it->what == IT_CHARACTER
c7cba11d 1550 || it->what == IT_COMPOSITION
a8815b00
EZ
1551 || it->what == IT_STRETCH
1552 || it->what == IT_GLYPHLESS);
177c0ea7 1553
6b61353c
KH
1554 if (it->what == IT_STRETCH)
1555 {
1556 produce_stretch_glyph (it);
1557 goto done;
1558 }
1559
4c12d738
KH
1560 if (it->what == IT_COMPOSITION)
1561 {
1562 produce_composite_glyph (it);
1563 goto done;
1564 }
a168702a 1565
b18fad6d
KH
1566 if (it->what == IT_GLYPHLESS)
1567 {
653d4f43 1568 produce_glyphless_glyph (it, Qnil);
b18fad6d
KH
1569 goto done;
1570 }
1571
d419e1d9 1572 if (it->char_to_display >= 040 && it->char_to_display < 0177)
a168702a
GM
1573 {
1574 it->pixel_width = it->nglyphs = 1;
1575 if (it->glyph_row)
1576 append_glyph (it);
1577 }
d419e1d9 1578 else if (it->char_to_display == '\n')
a168702a 1579 it->pixel_width = it->nglyphs = 0;
d419e1d9 1580 else if (it->char_to_display == '\t')
a168702a 1581 {
2efdbcdd 1582 int absolute_x = (it->current_x
a168702a 1583 + it->continuation_lines_width);
177c0ea7
JB
1584 int next_tab_x
1585 = (((1 + absolute_x + it->tab_width - 1)
a168702a
GM
1586 / it->tab_width)
1587 * it->tab_width);
1588 int nspaces;
1589
1590 /* If part of the TAB has been displayed on the previous line
1591 which is continued now, continuation_lines_width will have
1592 been incremented already by the part that fitted on the
1593 continued line. So, we will get the right number of spaces
1594 here. */
1595 nspaces = next_tab_x - absolute_x;
177c0ea7 1596
a168702a
GM
1597 if (it->glyph_row)
1598 {
1599 int n = nspaces;
177c0ea7 1600
d2b4c17d 1601 it->char_to_display = ' ';
a168702a 1602 it->pixel_width = it->len = 1;
177c0ea7 1603
a168702a
GM
1604 while (n--)
1605 append_glyph (it);
a168702a
GM
1606 }
1607
1608 it->pixel_width = nspaces;
1609 it->nglyphs = nspaces;
1610 }
d419e1d9 1611 else if (CHAR_BYTE8_P (it->char_to_display))
add44890 1612 {
d419e1d9
KH
1613 /* Coming here means that we must send the raw 8-bit byte as is
1614 to the terminal. Although there's no way to know how many
1615 columns it occupies on a screen, it is a good assumption that
1616 a single byte code has 1-column width. */
1617 it->pixel_width = it->nglyphs = 1;
1618 if (it->glyph_row)
1619 append_glyph (it);
add44890 1620 }
a168702a
GM
1621 else
1622 {
b18fad6d 1623 Lisp_Object charset_list = FRAME_TERMINAL (it->f)->charset_list;
177c0ea7 1624
b18fad6d
KH
1625 if (char_charset (it->char_to_display, charset_list, NULL))
1626 {
1627 it->pixel_width = CHAR_WIDTH (it->char_to_display);
1628 it->nglyphs = it->pixel_width;
1629 if (it->glyph_row)
1630 append_glyph (it);
1631 }
1632 else
1633 {
1634 Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
1635
a54e2c05 1636 eassert (it->what == IT_GLYPHLESS);
653d4f43 1637 produce_glyphless_glyph (it, acronym);
b18fad6d 1638 }
a168702a
GM
1639 }
1640
6b61353c 1641 done:
177c0ea7 1642 /* Advance current_x by the pixel width as a convenience for
a168702a
GM
1643 the caller. */
1644 if (it->area == TEXT_AREA)
1645 it->current_x += it->pixel_width;
cfe8a05e
GM
1646 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1647 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
a168702a
GM
1648}
1649
4c12d738
KH
1650/* Append glyphs to IT's glyph_row for the composition IT->cmp_id.
1651 Called from produce_composite_glyph for terminal frames if
1652 IT->glyph_row != NULL. IT->face_id contains the character's
1653 face. */
1654
1655static void
d3da34e0 1656append_composite_glyph (struct it *it)
4c12d738
KH
1657{
1658 struct glyph *glyph;
1659
a54e2c05 1660 eassert (it->glyph_row);
4c12d738
KH
1661 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1662 if (glyph < it->glyph_row->glyphs[1 + it->area])
1663 {
93d68d0c
EZ
1664 /* If the glyph row is reversed, we need to prepend the glyph
1665 rather than append it. */
1666 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1667 {
1668 struct glyph *g;
1669
1670 /* Make room for the new glyph. */
1671 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1672 g[1] = *g;
1673 glyph = it->glyph_row->glyphs[it->area];
1674 }
4c12d738
KH
1675 glyph->type = COMPOSITE_GLYPH;
1676 glyph->pixel_width = it->pixel_width;
75a10786
KH
1677 glyph->u.cmp.id = it->cmp_it.id;
1678 if (it->cmp_it.ch < 0)
1679 {
1680 glyph->u.cmp.automatic = 0;
1681 glyph->u.cmp.id = it->cmp_it.id;
1682 }
1683 else
1684 {
1685 glyph->u.cmp.automatic = 1;
1686 glyph->u.cmp.id = it->cmp_it.id;
4be9765d
KH
1687 glyph->slice.cmp.from = it->cmp_it.from;
1688 glyph->slice.cmp.to = it->cmp_it.to - 1;
75a10786
KH
1689 }
1690
4c12d738
KH
1691 glyph->face_id = it->face_id;
1692 glyph->padding_p = 0;
1693 glyph->charpos = CHARPOS (it->position);
1694 glyph->object = it->object;
93d68d0c
EZ
1695 if (it->bidi_p)
1696 {
1697 glyph->resolved_level = it->bidi_it.resolved_level;
1698 if ((it->bidi_it.type & 7) != it->bidi_it.type)
1088b922 1699 emacs_abort ();
93d68d0c
EZ
1700 glyph->bidi_type = it->bidi_it.type;
1701 }
1702 else
1703 {
1704 glyph->resolved_level = 0;
1705 glyph->bidi_type = UNKNOWN_BT;
1706 }
4c12d738
KH
1707
1708 ++it->glyph_row->used[it->area];
1709 ++glyph;
1710 }
1711}
1712
1713
1714/* Produce a composite glyph for iterator IT. IT->cmp_id is the ID of
1715 the composition. We simply produces components of the composition
2b34df4e
JB
1716 assuming that the terminal has a capability to layout/render it
1717 correctly. */
4c12d738
KH
1718
1719static void
d3da34e0 1720produce_composite_glyph (struct it *it)
4c12d738 1721{
75a10786
KH
1722 if (it->cmp_it.ch < 0)
1723 {
1724 struct composition *cmp = composition_table[it->cmp_it.id];
1725
d0984aff 1726 it->pixel_width = cmp->width;
75a10786
KH
1727 }
1728 else
1729 {
1730 Lisp_Object gstring = composition_gstring_from_id (it->cmp_it.id);
4c12d738 1731
75a10786
KH
1732 it->pixel_width = composition_gstring_width (gstring, it->cmp_it.from,
1733 it->cmp_it.to, NULL);
1734 }
1735 it->nglyphs = 1;
4c12d738
KH
1736 if (it->glyph_row)
1737 append_composite_glyph (it);
1738}
1739
1740
b18fad6d 1741/* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID
0eb025fb
EZ
1742 is a face ID to be used for the glyph. What is actually appended
1743 are glyphs of type CHAR_GLYPH whose characters are in STR (which
1744 comes from it->nglyphs bytes). */
b18fad6d
KH
1745
1746static void
fbceeba2 1747append_glyphless_glyph (struct it *it, int face_id, const char *str)
b18fad6d
KH
1748{
1749 struct glyph *glyph, *end;
b18fad6d
KH
1750 int i;
1751
a54e2c05 1752 eassert (it->glyph_row);
b18fad6d
KH
1753 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1754 end = it->glyph_row->glyphs[1 + it->area];
1755
1756 /* If the glyph row is reversed, we need to prepend the glyph rather
1757 than append it. */
1758 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1759 {
1760 struct glyph *g;
1761 int move_by = it->pixel_width;
1762
1763 /* Make room for the new glyphs. */
1764 if (move_by > end - glyph) /* don't overstep end of this area */
1765 move_by = end - glyph;
1766 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1767 g[move_by] = *g;
1768 glyph = it->glyph_row->glyphs[it->area];
1769 end = glyph + move_by;
1770 }
1771
1772 if (glyph >= end)
1773 return;
1774 glyph->type = CHAR_GLYPH;
1775 glyph->pixel_width = 1;
1776 glyph->face_id = face_id;
1777 glyph->padding_p = 0;
1778 glyph->charpos = CHARPOS (it->position);
1779 glyph->object = it->object;
1780 if (it->bidi_p)
1781 {
1782 glyph->resolved_level = it->bidi_it.resolved_level;
1783 if ((it->bidi_it.type & 7) != it->bidi_it.type)
1088b922 1784 emacs_abort ();
b18fad6d
KH
1785 glyph->bidi_type = it->bidi_it.type;
1786 }
1787 else
1788 {
1789 glyph->resolved_level = 0;
1790 glyph->bidi_type = UNKNOWN_BT;
1791 }
1792
1793 /* BIDI Note: we put the glyphs of characters left to right, even in
1794 the REVERSED_P case because we write to the terminal
1795 left-to-right. */
1796 for (i = 0; i < it->nglyphs && glyph < end; ++i)
1797 {
1798 if (i > 0)
1799 glyph[0] = glyph[-1];
1800 glyph->u.ch = str[i];
1801 ++it->glyph_row->used[it->area];
1802 ++glyph;
1803 }
1804}
1805
b18fad6d
KH
1806/* Produce glyphs for a glyphless character for iterator IT.
1807 IT->glyphless_method specifies which method to use for displaying
1808 the character. See the description of enum
0eb025fb 1809 glyphless_display_method in dispextern.h for the details.
b18fad6d 1810
653d4f43 1811 ACRONYM, if non-nil, is an acronym string for the character.
b18fad6d
KH
1812
1813 The glyphs actually produced are of type CHAR_GLYPH. */
1814
1815static void
653d4f43 1816produce_glyphless_glyph (struct it *it, Lisp_Object acronym)
b18fad6d 1817{
77394d40 1818 int len, face_id = merge_glyphless_glyph_face (it);
80f2e268 1819 char buf[sizeof "\\x" + max (6, (sizeof it->c * CHAR_BIT + 3) / 4)];
fbceeba2 1820 char const *str = " ";
b18fad6d 1821
b18fad6d
KH
1822 if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
1823 {
0eb025fb
EZ
1824 /* As there's no way to produce a thin space, we produce a space
1825 of canonical width. */
b18fad6d
KH
1826 len = 1;
1827 }
1828 else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
1829 {
1830 len = CHAR_WIDTH (it->c);
1831 if (len == 0)
1832 len = 1;
0eb025fb 1833 else if (len > 4)
b18fad6d 1834 len = 4;
99027bdd 1835 len = sprintf (buf, "[%.*s]", len, str);
0eb025fb 1836 str = buf;
b18fad6d
KH
1837 }
1838 else
1839 {
1840 if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
1841 {
b18fad6d
KH
1842 if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
1843 acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
16a43933
CY
1844 if (CONSP (acronym))
1845 acronym = XCDR (acronym);
b18fad6d 1846 buf[0] = '[';
51b59d79 1847 str = STRINGP (acronym) ? SSDATA (acronym) : "";
b18fad6d
KH
1848 for (len = 0; len < 6 && str[len] && ASCII_BYTE_P (str[len]); len++)
1849 buf[1 + len] = str[len];
1850 buf[1 + len] = ']';
1851 len += 2;
1852 }
1853 else
1854 {
a54e2c05 1855 eassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEX_CODE);
7c2d713b
EZ
1856 len = (it->c < 0x10000 ? sprintf (buf, "\\u%04X", it->c)
1857 : it->c <= MAX_UNICODE_CHAR ? sprintf (buf, "\\U%06X", it->c)
1858 : sprintf (buf, "\\x%06X", it->c));
b18fad6d
KH
1859 }
1860 str = buf;
1861 }
1862
1863 it->pixel_width = len;
1864 it->nglyphs = len;
d284567f 1865 if (it->glyph_row)
b18fad6d
KH
1866 append_glyphless_glyph (it, face_id, str);
1867}
1868
a168702a
GM
1869\f
1870/***********************************************************************
1871 Faces
1872 ***********************************************************************/
1873
4e6ba4a4
GM
1874/* Value is non-zero if attribute ATTR may be used. ATTR should be
1875 one of the enumerators from enum no_color_bit, or a bit set built
1876 from them. Some display attributes may not be used together with
1877 color; the termcap capability `NC' specifies which ones. */
1878
fca177d4
KL
1879#define MAY_USE_WITH_COLORS_P(tty, ATTR) \
1880 (tty->TN_max_colors > 0 \
1881 ? (tty->TN_no_color_video & (ATTR)) == 0 \
1882 : 1)
a168702a 1883
072d84a6
RS
1884/* Turn appearances of face FACE_ID on tty frame F on.
1885 FACE_ID is a realized face ID number, in the face cache. */
a168702a
GM
1886
1887static void
d3da34e0 1888turn_on_face (struct frame *f, int face_id)
a168702a
GM
1889{
1890 struct face *face = FACE_FROM_ID (f, face_id);
86a7d192
GM
1891 long fg = face->foreground;
1892 long bg = face->background;
28d7d09f 1893 struct tty_display_info *tty = FRAME_TTY (f);
a168702a 1894
86a7d192
GM
1895 /* Do this first because TS_end_standout_mode may be the same
1896 as TS_exit_attribute_mode, which turns all appearances off. */
fca177d4 1897 if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE))
86a7d192 1898 {
fca177d4 1899 if (tty->TN_max_colors > 0)
86a7d192
GM
1900 {
1901 if (fg >= 0 && bg >= 0)
1902 {
1903 /* If the terminal supports colors, we can set them
1904 below without using reverse video. The face's fg
1905 and bg colors are set as they should appear on
1906 the screen, i.e. they take the inverse-video'ness
1907 of the face already into account. */
1908 }
1909 else if (inverse_video)
1910 {
1911 if (fg == FACE_TTY_DEFAULT_FG_COLOR
1912 || bg == FACE_TTY_DEFAULT_BG_COLOR)
ed8dad6b 1913 tty_toggle_highlight (tty);
86a7d192
GM
1914 }
1915 else
1916 {
1917 if (fg == FACE_TTY_DEFAULT_BG_COLOR
1918 || bg == FACE_TTY_DEFAULT_FG_COLOR)
ed8dad6b 1919 tty_toggle_highlight (tty);
86a7d192
GM
1920 }
1921 }
1922 else
1923 {
1924 /* If we can't display colors, use reverse video
1925 if the face specifies that. */
37526b42
GM
1926 if (inverse_video)
1927 {
1928 if (fg == FACE_TTY_DEFAULT_FG_COLOR
1929 || bg == FACE_TTY_DEFAULT_BG_COLOR)
ed8dad6b 1930 tty_toggle_highlight (tty);
37526b42
GM
1931 }
1932 else
1933 {
1934 if (fg == FACE_TTY_DEFAULT_BG_COLOR
1935 || bg == FACE_TTY_DEFAULT_FG_COLOR)
ed8dad6b 1936 tty_toggle_highlight (tty);
37526b42 1937 }
86a7d192
GM
1938 }
1939 }
a168702a 1940
4189ed40
CY
1941 if (face->tty_bold_p && MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
1942 OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
1943
cd4eb164
CY
1944 if (face->tty_italic_p && MAY_USE_WITH_COLORS_P (tty, NC_ITALIC))
1945 {
1946 if (tty->TS_enter_italic_mode)
1947 OUTPUT1 (tty, tty->TS_enter_italic_mode);
1948 else
1949 /* Italics mode is unavailable on many terminals. In that
1950 case, map slant to dimmed text; we want italic text to
1951 appear different and dimming is not otherwise used. */
1952 OUTPUT1 (tty, tty->TS_enter_dim_mode);
1953 }
a168702a 1954
fca177d4
KL
1955 if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
1956 OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
a168702a 1957
fca177d4 1958 if (tty->TN_max_colors > 0)
a168702a 1959 {
fbceeba2
PE
1960 const char *ts;
1961 char *p;
177c0ea7 1962
fbf34973 1963 ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
753d161b 1964 if (fg >= 0 && ts)
a168702a 1965 {
653d4f43 1966 p = tparam (ts, NULL, 0, fg, 0, 0, 0);
6548cf00 1967 OUTPUT (tty, p);
a168702a
GM
1968 xfree (p);
1969 }
1970
fbf34973 1971 ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
753d161b 1972 if (bg >= 0 && ts)
a168702a 1973 {
653d4f43 1974 p = tparam (ts, NULL, 0, bg, 0, 0, 0);
6548cf00 1975 OUTPUT (tty, p);
a168702a
GM
1976 xfree (p);
1977 }
1978 }
1979}
177c0ea7 1980
a168702a
GM
1981
1982/* Turn off appearances of face FACE_ID on tty frame F. */
1983
1984static void
d3da34e0 1985turn_off_face (struct frame *f, int face_id)
a168702a
GM
1986{
1987 struct face *face = FACE_FROM_ID (f, face_id);
28d7d09f 1988 struct tty_display_info *tty = FRAME_TTY (f);
a168702a 1989
a54e2c05 1990 eassert (face != NULL);
a168702a 1991
fca177d4 1992 if (tty->TS_exit_attribute_mode)
a168702a
GM
1993 {
1994 /* Capability "me" will turn off appearance modes double-bright,
1995 half-bright, reverse-video, standout, underline. It may or
1996 may not turn off alt-char-mode. */
1997 if (face->tty_bold_p
cd4eb164 1998 || face->tty_italic_p
a168702a 1999 || face->tty_reverse_p
a168702a 2000 || face->tty_underline_p)
65aa5e85 2001 {
fca177d4
KL
2002 OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
2003 if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0)
2004 tty->standout_mode = 0;
65aa5e85 2005 }
a168702a
GM
2006 }
2007 else
2008 {
2009 /* If we don't have "me" we can only have those appearances
2010 that have exit sequences defined. */
54800acb 2011 if (face->tty_underline_p)
fca177d4 2012 OUTPUT_IF (tty, tty->TS_exit_underline_mode);
a168702a
GM
2013 }
2014
2015 /* Switch back to default colors. */
fca177d4 2016 if (tty->TN_max_colors > 0
f9d2fdc4
EZ
2017 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
2018 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
2019 || (face->background != FACE_TTY_DEFAULT_COLOR
2020 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
fca177d4 2021 OUTPUT1_IF (tty, tty->TS_orig_pair);
a168702a 2022}
177c0ea7
JB
2023
2024
653d4f43 2025/* Return true if the terminal on frame F supports all of the
b63a55ac
MB
2026 capabilities in CAPS simultaneously, with foreground and background
2027 colors FG and BG. */
2028
653d4f43 2029bool
d3da34e0
JB
2030tty_capable_p (struct tty_display_info *tty, unsigned int caps,
2031 unsigned long fg, unsigned long bg)
b63a55ac 2032{
fca177d4
KL
2033#define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
2034 if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
b63a55ac
MB
2035 return 0;
2036
fca177d4
KL
2037 TTY_CAPABLE_P_TRY (tty, TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE);
2038 TTY_CAPABLE_P_TRY (tty, TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode, NC_UNDERLINE);
2039 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
2040 TTY_CAPABLE_P_TRY (tty, TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM);
cd4eb164 2041 TTY_CAPABLE_P_TRY (tty, TTY_CAP_ITALIC, tty->TS_enter_italic_mode, NC_ITALIC);
b63a55ac
MB
2042
2043 /* We can do it! */
2044 return 1;
2045}
2046
a168702a
GM
2047/* Return non-zero if the terminal is capable to display colors. */
2048
2049DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
981e4297 2050 0, 1, 0,
6ed8eeff
KL
2051 doc: /* Return non-nil if the tty device TERMINAL can display colors.
2052
401e9e57
CY
2053TERMINAL can be a terminal object, a frame, or nil (meaning the
2054selected frame's terminal). This function always returns nil if
c6bf3022 2055TERMINAL does not refer to a text terminal. */)
5842a27b 2056 (Lisp_Object terminal)
a168702a 2057{
717a00ef 2058 struct terminal *t = get_tty_terminal (terminal, 0);
6ed8eeff 2059 if (!t)
428a555e 2060 return Qnil;
3224dac1 2061 else
6ed8eeff 2062 return t->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
a168702a
GM
2063}
2064
bfa62f96
EZ
2065/* Return the number of supported colors. */
2066DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
2067 Stty_display_color_cells, 0, 1, 0,
6ed8eeff
KL
2068 doc: /* Return the number of colors supported by the tty device TERMINAL.
2069
401e9e57
CY
2070TERMINAL can be a terminal object, a frame, or nil (meaning the
2071selected frame's terminal). This function always returns 0 if
c6bf3022 2072TERMINAL does not refer to a text terminal. */)
5842a27b 2073 (Lisp_Object terminal)
bfa62f96 2074{
717a00ef 2075 struct terminal *t = get_tty_terminal (terminal, 0);
6ed8eeff 2076 if (!t)
8c8d5f35 2077 return make_number (0);
3224dac1 2078 else
6ed8eeff 2079 return make_number (t->display_info.tty->TN_max_colors);
bfa62f96
EZ
2080}
2081
84704c5c 2082#ifndef DOS_NT
a168702a 2083
5205ee62
GM
2084/* Declare here rather than in the function, as in the rest of Emacs,
2085 to work around an HPUX compiler bug (?). See
57407fb4 2086 http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00410.html */
5205ee62
GM
2087static int default_max_colors;
2088static int default_max_pairs;
2089static int default_no_color_video;
2090static char *default_orig_pair;
2091static char *default_set_foreground;
2092static char *default_set_background;
fcf8ff2e 2093
ace28297
EZ
2094/* Save or restore the default color-related capabilities of this
2095 terminal. */
2096static void
653d4f43 2097tty_default_color_capabilities (struct tty_display_info *tty, bool save)
ace28297 2098{
ace28297
EZ
2099
2100 if (save)
2101 {
70fdbb46 2102 xfree (default_orig_pair);
fca177d4 2103 default_orig_pair = tty->TS_orig_pair ? xstrdup (tty->TS_orig_pair) : NULL;
ace28297 2104
70fdbb46 2105 xfree (default_set_foreground);
fca177d4 2106 default_set_foreground = tty->TS_set_foreground ? xstrdup (tty->TS_set_foreground)
ace28297
EZ
2107 : NULL;
2108
70fdbb46 2109 xfree (default_set_background);
fca177d4 2110 default_set_background = tty->TS_set_background ? xstrdup (tty->TS_set_background)
ace28297
EZ
2111 : NULL;
2112
fca177d4
KL
2113 default_max_colors = tty->TN_max_colors;
2114 default_max_pairs = tty->TN_max_pairs;
2115 default_no_color_video = tty->TN_no_color_video;
ace28297
EZ
2116 }
2117 else
2118 {
fca177d4
KL
2119 tty->TS_orig_pair = default_orig_pair;
2120 tty->TS_set_foreground = default_set_foreground;
2121 tty->TS_set_background = default_set_background;
2122 tty->TN_max_colors = default_max_colors;
2123 tty->TN_max_pairs = default_max_pairs;
2124 tty->TN_no_color_video = default_no_color_video;
ace28297
EZ
2125 }
2126}
2127
2128/* Setup one of the standard tty color schemes according to MODE.
2129 MODE's value is generally the number of colors which we want to
2130 support; zero means set up for the default capabilities, the ones
a4c6993d 2131 we saw at init_tty time; -1 means turn off color support. */
ed8dad6b 2132static void
28d7d09f 2133tty_setup_colors (struct tty_display_info *tty, int mode)
ace28297 2134{
6b61353c
KH
2135 /* Canonicalize all negative values of MODE. */
2136 if (mode < -1)
2137 mode = -1;
2138
ace28297
EZ
2139 switch (mode)
2140 {
2141 case -1: /* no colors at all */
fca177d4
KL
2142 tty->TN_max_colors = 0;
2143 tty->TN_max_pairs = 0;
2144 tty->TN_no_color_video = 0;
2145 tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL;
ace28297
EZ
2146 break;
2147 case 0: /* default colors, if any */
2148 default:
fca177d4 2149 tty_default_color_capabilities (tty, 0);
ace28297
EZ
2150 break;
2151 case 8: /* 8 standard ANSI colors */
fca177d4 2152 tty->TS_orig_pair = "\033[0m";
ace28297 2153#ifdef TERMINFO
fca177d4
KL
2154 tty->TS_set_foreground = "\033[3%p1%dm";
2155 tty->TS_set_background = "\033[4%p1%dm";
ace28297 2156#else
fca177d4
KL
2157 tty->TS_set_foreground = "\033[3%dm";
2158 tty->TS_set_background = "\033[4%dm";
ace28297 2159#endif
fca177d4
KL
2160 tty->TN_max_colors = 8;
2161 tty->TN_max_pairs = 64;
2162 tty->TN_no_color_video = 0;
ace28297
EZ
2163 break;
2164 }
2165}
2166
2167void
d3da34e0 2168set_tty_color_mode (struct tty_display_info *tty, struct frame *f)
ace28297 2169{
ce5b453a 2170 Lisp_Object tem, val;
9b2cd403
SM
2171 Lisp_Object color_mode;
2172 int mode;
9b2cd403
SM
2173 Lisp_Object tty_color_mode_alist
2174 = Fintern_soft (build_string ("tty-color-mode-alist"), Qnil);
ace28297 2175
e69b0960 2176 tem = assq_no_quit (Qtty_color_mode, f->param_alist);
9b2cd403 2177 val = CONSP (tem) ? XCDR (tem) : Qnil;
ace28297 2178
6b61353c 2179 if (INTEGERP (val))
ace28297 2180 color_mode = val;
ce5b453a 2181 else if (SYMBOLP (tty_color_mode_alist))
ace28297 2182 {
ce5b453a 2183 tem = Fassq (val, Fsymbol_value (tty_color_mode_alist));
9b2cd403 2184 color_mode = CONSP (tem) ? XCDR (tem) : Qnil;
ace28297 2185 }
ce5b453a
SM
2186 else
2187 color_mode = Qnil;
6b61353c 2188
d311d28c 2189 mode = TYPE_RANGED_INTEGERP (int, color_mode) ? XINT (color_mode) : 0;
ace28297 2190
9b2cd403 2191 if (mode != tty->previous_color_mode)
ace28297 2192 {
9b2cd403
SM
2193 tty->previous_color_mode = mode;
2194 tty_setup_colors (tty , mode);
2195 /* This recomputes all the faces given the new color definitions. */
6cd7a139 2196 safe_call (1, intern ("tty-set-up-initial-frame-faces"));
ace28297
EZ
2197 }
2198}
2199
84704c5c 2200#endif /* !DOS_NT */
a168702a
GM
2201
2202\f
28d440ab 2203
6ed8eeff 2204/* Return the tty display object specified by TERMINAL. */
b6660415 2205
64520e5c 2206static struct terminal *
653d4f43 2207get_tty_terminal (Lisp_Object terminal, bool throw)
b6660415 2208{
717a00ef 2209 struct terminal *t = get_terminal (terminal, throw);
62af879c 2210
84704c5c 2211 if (t && t->type != output_termcap && t->type != output_msdos_raw)
717a00ef
KL
2212 {
2213 if (throw)
2214 error ("Device %d is not a termcap terminal device", t->id);
2215 else
2216 return NULL;
2217 }
b6660415 2218
6ed8eeff 2219 return t;
b6660415
KL
2220}
2221
ab797f65
KL
2222/* Return an active termcap device that uses the tty device with the
2223 given name.
b6660415 2224
7e59217d 2225 This function ignores suspended devices.
da8e1115
KL
2226
2227 Returns NULL if the named terminal device is not opened. */
f4d953fc 2228
6ed8eeff 2229struct terminal *
8ea90aa3 2230get_named_tty (const char *name)
28d440ab 2231{
6ed8eeff
KL
2232 struct terminal *t;
2233
9c253307 2234 eassert (name);
ab797f65
KL
2235
2236 for (t = terminal_list; t; t = t->next_terminal)
2237 {
5cc67f65 2238 if ((t->type == output_termcap || t->type == output_msdos_raw)
ab797f65
KL
2239 && !strcmp (t->display_info.tty->name, name)
2240 && TERMINAL_ACTIVE_P (t))
2241 return t;
2242 }
28d440ab
KL
2243
2244 return 0;
2245}
2246
2247\f
a7ca3326 2248DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
6ed8eeff 2249 doc: /* Return the type of the tty device that TERMINAL uses.
ab797f65 2250Returns nil if TERMINAL is not on a tty device.
a3fbb897 2251
401e9e57
CY
2252TERMINAL can be a terminal object, a frame, or nil (meaning the
2253selected frame's terminal). */)
5842a27b 2254 (Lisp_Object terminal)
b6660415 2255{
6ed8eeff 2256 struct terminal *t = get_terminal (terminal, 1);
819b8f00 2257
84704c5c 2258 if (t->type != output_termcap && t->type != output_msdos_raw)
ab797f65
KL
2259 return Qnil;
2260
6ed8eeff
KL
2261 if (t->display_info.tty->type)
2262 return build_string (t->display_info.tty->type);
819b8f00
KL
2263 else
2264 return Qnil;
2265}
2266
6ed8eeff 2267DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
84704c5c 2268 doc: /* Return non-nil if TERMINAL is the controlling tty of the Emacs process.
a3fbb897 2269
401e9e57
CY
2270TERMINAL can be a terminal object, a frame, or nil (meaning the
2271selected frame's terminal). This function always returns nil if
2272TERMINAL is not on a tty device. */)
5842a27b 2273 (Lisp_Object terminal)
4a933ef8 2274{
6ed8eeff 2275 struct terminal *t = get_terminal (terminal, 1);
4a933ef8 2276
84704c5c
EZ
2277 if ((t->type != output_termcap && t->type != output_msdos_raw)
2278 || strcmp (t->display_info.tty->name, DEV_TTY) != 0)
4a933ef8
KL
2279 return Qnil;
2280 else
2281 return Qt;
2282}
2283
a3fbb897 2284DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
6ed8eeff 2285 doc: /* Declare that the tty used by TERMINAL does not handle underlining.
a3fbb897
KL
2286This is used to override the terminfo data, for certain terminals that
2287do not really do underlining, but say that they do. This function has
6ed8eeff 2288no effect if used on a non-tty terminal.
a3fbb897 2289
401e9e57
CY
2290TERMINAL can be a terminal object, a frame or nil (meaning the
2291selected frame's terminal). This function always returns nil if
c6bf3022 2292TERMINAL does not refer to a text terminal. */)
5842a27b 2293 (Lisp_Object terminal)
a3fbb897 2294{
6ed8eeff 2295 struct terminal *t = get_terminal (terminal, 1);
a3fbb897 2296
6ed8eeff
KL
2297 if (t->type == output_termcap)
2298 t->display_info.tty->TS_enter_underline_mode = 0;
a3fbb897
KL
2299 return Qnil;
2300}
2301
c6bf3022
CY
2302DEFUN ("tty-top-frame", Ftty_top_frame, Stty_top_frame, 0, 1, 0,
2303 doc: /* Return the topmost terminal frame on TERMINAL.
2304TERMINAL can be a terminal object, a frame or nil (meaning the
2305selected frame's terminal). This function returns nil if TERMINAL
2306does not refer to a text terminal. Otherwise, it returns the
2307top-most frame on the text terminal. */)
2308 (Lisp_Object terminal)
2309{
2310 struct terminal *t = get_terminal (terminal, 1);
2311
2312 if (t->type == output_termcap)
2313 return t->display_info.tty->top_frame;
2314 return Qnil;
2315}
2316
ed8dad6b
KL
2317\f
2318
2319DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
2320 doc: /* Suspend the terminal device TTY.
2321
2322The device is restored to its default state, and Emacs ceases all
2323access to the tty device. Frames that use the device are not deleted,
2324but input is not read from them and if they change, their display is
2325not updated.
2326
401e9e57
CY
2327TTY may be a terminal object, a frame, or nil for the terminal device
2328of the currently selected frame.
ed8dad6b 2329
e4019195 2330This function runs `suspend-tty-functions' after suspending the
ed8dad6b
KL
2331device. The functions are run with one arg, the id of the suspended
2332terminal device.
2333
2334`suspend-tty' does nothing if it is called on a device that is already
2335suspended.
2336
2337A suspended tty may be resumed by calling `resume-tty' on it. */)
5842a27b 2338 (Lisp_Object tty)
ed8dad6b 2339{
717a00ef 2340 struct terminal *t = get_tty_terminal (tty, 1);
ed8dad6b 2341 FILE *f;
f4d953fc 2342
6ed8eeff 2343 if (!t)
ed8dad6b
KL
2344 error ("Unknown tty device");
2345
6ed8eeff 2346 f = t->display_info.tty->input;
f4d953fc 2347
ed8dad6b
KL
2348 if (f)
2349 {
23d4cba5
DN
2350 /* First run `suspend-tty-functions' and then clean up the tty
2351 state because `suspend-tty-functions' might need to change
2352 the tty state. */
dee091a3
JD
2353 Lisp_Object args[2];
2354 args[0] = intern ("suspend-tty-functions");
2355 XSETTERMINAL (args[1], t);
2356 Frun_hook_with_args (2, args);
23d4cba5 2357
6ed8eeff 2358 reset_sys_modes (t->display_info.tty);
ed8dad6b 2359 delete_keyboard_wait_descriptor (fileno (f));
f4d953fc 2360
84704c5c 2361#ifndef MSDOS
ed8dad6b 2362 fclose (f);
6ed8eeff
KL
2363 if (f != t->display_info.tty->output)
2364 fclose (t->display_info.tty->output);
84704c5c 2365#endif
f4d953fc 2366
6ed8eeff
KL
2367 t->display_info.tty->input = 0;
2368 t->display_info.tty->output = 0;
ed8dad6b 2369
6ed8eeff 2370 if (FRAMEP (t->display_info.tty->top_frame))
edfa7fa0 2371 SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
f4d953fc 2372
ed8dad6b
KL
2373 }
2374
4a665758
KL
2375 /* Clear display hooks to prevent further output. */
2376 clear_tty_hooks (t);
2377
ed8dad6b
KL
2378 return Qnil;
2379}
2380
2381DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
2382 doc: /* Resume the previously suspended terminal device TTY.
2383The terminal is opened and reinitialized. Frames that are on the
6ed8eeff 2384suspended terminal are revived.
ed8dad6b 2385
6ed8eeff
KL
2386It is an error to resume a terminal while another terminal is active
2387on the same device.
ed8dad6b 2388
e4019195 2389This function runs `resume-tty-functions' after resuming the terminal.
6ed8eeff 2390The functions are run with one arg, the id of the resumed terminal
ed8dad6b
KL
2391device.
2392
2393`resume-tty' does nothing if it is called on a device that is not
2394suspended.
2395
401e9e57
CY
2396TTY may be a terminal object, a frame, or nil (meaning the selected
2397frame's terminal). */)
5842a27b 2398 (Lisp_Object tty)
ed8dad6b 2399{
717a00ef 2400 struct terminal *t = get_tty_terminal (tty, 1);
ed8dad6b
KL
2401 int fd;
2402
6ed8eeff 2403 if (!t)
ed8dad6b
KL
2404 error ("Unknown tty device");
2405
6ed8eeff 2406 if (!t->display_info.tty->input)
ed8dad6b 2407 {
6ed8eeff 2408 if (get_named_tty (t->display_info.tty->name))
ed8dad6b
KL
2409 error ("Cannot resume display while another display is active on the same device");
2410
84704c5c
EZ
2411#ifdef MSDOS
2412 t->display_info.tty->output = stdout;
2413 t->display_info.tty->input = stdin;
2414#else /* !MSDOS */
6ed8eeff 2415 fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
ef30e638
PE
2416 t->display_info.tty->input = t->display_info.tty->output
2417 = fd < 0 ? 0 : fdopen (fd, "w+");
ed8dad6b 2418
ef30e638
PE
2419 if (! t->display_info.tty->input)
2420 {
2421 int open_errno = errno;
2422 emacs_close (fd);
2423 report_file_errno ("Cannot reopen tty device",
2424 build_string (t->display_info.tty->name),
2425 open_errno);
2426 }
ed8dad6b 2427
b8956427 2428 if (!O_IGNORE_CTTY && strcmp (t->display_info.tty->name, DEV_TTY) != 0)
59b3194c 2429 dissociate_if_controlling_tty (fd);
84704c5c 2430#endif
78048085 2431
ed8dad6b
KL
2432 add_keyboard_wait_descriptor (fd);
2433
6ed8eeff 2434 if (FRAMEP (t->display_info.tty->top_frame))
db878925
DN
2435 {
2436 struct frame *f = XFRAME (t->display_info.tty->top_frame);
2437 int width, height;
2438 int old_height = FRAME_COLS (f);
2439 int old_width = FRAME_LINES (f);
2440
2441 /* Check if terminal/window size has changed while the frame
2442 was suspended. */
2443 get_tty_size (fileno (t->display_info.tty->input), &width, &height);
2444 if (width != old_width || height != old_height)
2445 change_frame_size (f, height, width, 0, 0, 0);
edfa7fa0 2446 SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
db878925 2447 }
ed8dad6b 2448
04f2d78b 2449 set_tty_hooks (t);
6ed8eeff 2450 init_sys_modes (t->display_info.tty);
ed8dad6b 2451
dee091a3
JD
2452 {
2453 /* Run `resume-tty-functions'. */
2454 Lisp_Object args[2];
2455 args[0] = intern ("resume-tty-functions");
2456 XSETTERMINAL (args[1], t);
2457 Frun_hook_with_args (2, args);
2458 }
ed8dad6b
KL
2459 }
2460
4a665758
KL
2461 set_tty_hooks (t);
2462
ed8dad6b
KL
2463 return Qnil;
2464}
a3fbb897 2465
819b8f00 2466\f
e882229c
NR
2467/***********************************************************************
2468 Mouse
2469 ***********************************************************************/
2470
7e5a23bd 2471#ifdef HAVE_GPM
64520e5c
PE
2472
2473#ifndef HAVE_WINDOW_SYSTEM
5faa03ba
RS
2474void
2475term_mouse_moveto (int x, int y)
94da14a0 2476{
1ec5dc77 2477 /* TODO: how to set mouse position?
94da14a0
NR
2478 const char *name;
2479 int fd;
2480 name = (const char *) ttyname (0);
406af475 2481 fd = emacs_open (name, O_WRONLY, 0);
80fb2ce0 2482 SOME_FUNCTION (x, y, fd);
bacba3c2 2483 emacs_close (fd);
94da14a0 2484 last_mouse_x = x;
80fb2ce0 2485 last_mouse_y = y; */
94da14a0 2486}
64520e5c 2487#endif /* HAVE_WINDOW_SYSTEM */
94da14a0 2488
cf482c50
EZ
2489/* Implementation of draw_row_with_mouse_face for TTY/GPM. */
2490void
2491tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
2492 int start_hpos, int end_hpos,
2493 enum draw_glyphs_face draw)
e882229c 2494{
cf482c50
EZ
2495 int nglyphs = end_hpos - start_hpos;
2496 struct frame *f = XFRAME (WINDOW_FRAME (w));
7be1c21a 2497 struct tty_display_info *tty = FRAME_TTY (f);
cf482c50
EZ
2498 int face_id = tty->mouse_highlight.mouse_face_face_id;
2499 int save_x, save_y, pos_x, pos_y;
7be1c21a 2500
cf482c50
EZ
2501 if (end_hpos >= row->used[TEXT_AREA])
2502 nglyphs = row->used[TEXT_AREA] - start_hpos;
e882229c 2503
cf482c50
EZ
2504 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
2505 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w);
e882229c 2506
cf482c50
EZ
2507 /* Save current cursor co-ordinates. */
2508 save_y = curY (tty);
2509 save_x = curX (tty);
2510 cursor_to (f, pos_y, pos_x);
e882229c 2511
cf482c50
EZ
2512 if (draw == DRAW_MOUSE_FACE)
2513 tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
2514 nglyphs, face_id);
2515 else if (draw == DRAW_NORMAL_TEXT)
2516 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
e882229c 2517
cf482c50 2518 cursor_to (f, save_y, save_x);
e882229c
NR
2519}
2520
653d4f43 2521static bool
a10c8269 2522term_mouse_movement (struct frame *frame, Gpm_Event *event)
e882229c
NR
2523{
2524 /* Has the mouse moved off the glyph it was on at the last sighting? */
2525 if (event->x != last_mouse_x || event->y != last_mouse_y)
2526 {
2527 frame->mouse_moved = 1;
cf482c50 2528 note_mouse_highlight (frame, event->x, event->y);
e882229c
NR
2529 /* Remember which glyph we're now on. */
2530 last_mouse_x = event->x;
2531 last_mouse_y = event->y;
2532 return 1;
2533 }
2534 return 0;
2535}
2536
d35af63c
PE
2537/* Return the Time that corresponds to T. Wrap around on overflow. */
2538static Time
2539timeval_to_Time (struct timeval const *t)
2540{
2541 Time s_1000, ms;
2542
2543 s_1000 = t->tv_sec;
2544 s_1000 *= 1000;
2545 ms = t->tv_usec / 1000;
2546 return s_1000 + ms;
2547}
2548
e882229c
NR
2549/* Return the current position of the mouse.
2550
2551 Set *f to the frame the mouse is in, or zero if the mouse is in no
2552 Emacs frame. If it is set to zero, all the other arguments are
2553 garbage.
2554
2555 Set *bar_window to Qnil, and *x and *y to the column and
2556 row of the character cell the mouse is over.
2557
7f3f1250 2558 Set *timeptr to the time the mouse was at the returned position.
e882229c 2559
80fb2ce0 2560 This clears mouse_moved until the next motion
94da14a0 2561 event arrives. */
e882229c 2562static void
a10c8269 2563term_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
e882229c 2564 enum scroll_bar_part *part, Lisp_Object *x,
08dc5ae6 2565 Lisp_Object *y, Time *timeptr)
e882229c 2566{
e882229c 2567 struct timeval now;
e882229c
NR
2568
2569 *fp = SELECTED_FRAME ();
94da14a0 2570 (*fp)->mouse_moved = 0;
e882229c
NR
2571
2572 *bar_window = Qnil;
2573 *part = 0;
2574
80fb2ce0 2575 XSETINT (*x, last_mouse_x);
94da14a0 2576 XSETINT (*y, last_mouse_y);
e882229c 2577 gettimeofday(&now, 0);
d35af63c 2578 *timeptr = timeval_to_Time (&now);
e882229c
NR
2579}
2580
2581/* Prepare a mouse-event in *RESULT for placement in the input queue.
2582
2583 If the event is a button press, then note that we have grabbed
2584 the mouse. */
2585
2586static Lisp_Object
2587term_mouse_click (struct input_event *result, Gpm_Event *event,
2588 struct frame *f)
2589{
2590 struct timeval now;
2591 int i, j;
2592
2593 result->kind = GPM_CLICK_EVENT;
2594 for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
2595 {
2596 if (event->buttons & j) {
2597 result->code = i; /* button number */
2598 break;
2599 }
2600 }
2601 gettimeofday(&now, 0);
d35af63c 2602 result->timestamp = timeval_to_Time (&now);
e882229c
NR
2603
2604 if (event->type & GPM_UP)
2605 result->modifiers = up_modifier;
2606 else if (event->type & GPM_DOWN)
2607 result->modifiers = down_modifier;
2608 else
2609 result->modifiers = 0;
f4d953fc 2610
e882229c
NR
2611 if (event->type & GPM_SINGLE)
2612 result->modifiers |= click_modifier;
f4d953fc 2613
e882229c
NR
2614 if (event->type & GPM_DOUBLE)
2615 result->modifiers |= double_modifier;
2616
2617 if (event->type & GPM_TRIPLE)
2618 result->modifiers |= triple_modifier;
2619
2620 if (event->type & GPM_DRAG)
2621 result->modifiers |= drag_modifier;
2622
80fb2ce0 2623 if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
e882229c
NR
2624
2625 /* 1 << KG_SHIFT */
2626 if (event->modifiers & (1 << 0))
2627 result->modifiers |= shift_modifier;
2628
2629 /* 1 << KG_CTRL */
2630 if (event->modifiers & (1 << 2))
2631 result->modifiers |= ctrl_modifier;
2632
2633 /* 1 << KG_ALT || KG_ALTGR */
2634 if (event->modifiers & (1 << 3)
2635 || event->modifiers & (1 << 1))
2636 result->modifiers |= meta_modifier;
2637 }
2638
80fb2ce0
NR
2639 XSETINT (result->x, event->x);
2640 XSETINT (result->y, event->y);
e882229c
NR
2641 XSETFRAME (result->frame_or_window, f);
2642 result->arg = Qnil;
2643 return Qnil;
2644}
2645
f4d953fc 2646int
7be1c21a 2647handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event, struct input_event* hold_quit)
e882229c 2648{
7be1c21a 2649 struct frame *f = XFRAME (tty->top_frame);
e882229c 2650 struct input_event ie;
653d4f43 2651 bool do_help = 0;
e882229c
NR
2652 int count = 0;
2653
2654 EVENT_INIT (ie);
2655 ie.kind = NO_EVENT;
2656 ie.arg = Qnil;
2657
80fb2ce0 2658 if (event->type & (GPM_MOVE | GPM_DRAG)) {
e882229c
NR
2659 previous_help_echo_string = help_echo_string;
2660 help_echo_string = Qnil;
2661
6178ce5e 2662 Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
e882229c 2663
80fb2ce0
NR
2664 if (!term_mouse_movement (f, event))
2665 help_echo_string = previous_help_echo_string;
e882229c
NR
2666
2667 /* If the contents of the global variable help_echo_string
2668 has changed, generate a HELP_EVENT. */
2669 if (!NILP (help_echo_string)
2670 || !NILP (previous_help_echo_string))
2671 do_help = 1;
2672
2673 goto done;
2674 }
2675 else {
2676 f->mouse_moved = 0;
2677 term_mouse_click (&ie, event, f);
e882229c
NR
2678 }
2679
2680 done:
2681 if (ie.kind != NO_EVENT)
2682 {
2683 kbd_buffer_store_event_hold (&ie, hold_quit);
2684 count++;
2685 }
2686
2687 if (do_help
2688 && !(hold_quit && hold_quit->kind != NO_EVENT))
2689 {
2690 Lisp_Object frame;
2691
2692 if (f)
2693 XSETFRAME (frame, f);
2694 else
2695 frame = Qnil;
2696
2697 gen_help_event (help_echo_string, frame, help_echo_window,
2698 help_echo_object, help_echo_pos);
2699 count++;
2700 }
2701
2702 return count;
2703}
2704
6178ce5e 2705DEFUN ("gpm-mouse-start", Fgpm_mouse_start, Sgpm_mouse_start,
e882229c 2706 0, 0, 0,
71f44e7a 2707 doc: /* Open a connection to Gpm.
6178ce5e 2708Gpm-mouse can only be activated for one tty at a time. */)
5842a27b 2709 (void)
e882229c 2710{
71f44e7a
SM
2711 struct frame *f = SELECTED_FRAME ();
2712 struct tty_display_info *tty
2713 = ((f)->output_method == output_termcap
2714 ? (f)->terminal->display_info.tty : NULL);
e882229c
NR
2715 Gpm_Connect connection;
2716
6178ce5e
SM
2717 if (!tty)
2718 error ("Gpm-mouse only works in the GNU/Linux console");
4ce5ab77
SM
2719 if (gpm_tty == tty)
2720 return Qnil; /* Already activated, nothing to do. */
2721 if (gpm_tty)
2722 error ("Gpm-mouse can only be activated for one tty at a time");
71f44e7a 2723
e882229c
NR
2724 connection.eventMask = ~0;
2725 connection.defaultMask = ~GPM_HARD;
2726 connection.maxMod = ~0;
2727 connection.minMod = 0;
80fb2ce0 2728 gpm_zerobased = 1;
e882229c
NR
2729
2730 if (Gpm_Open (&connection, 0) < 0)
6178ce5e 2731 error ("Gpm-mouse failed to connect to the gpm daemon");
e882229c
NR
2732 else
2733 {
71f44e7a 2734 gpm_tty = tty;
1023cbed
SM
2735 /* `init_sys_modes' arranges for mouse movements sent through gpm_fd
2736 to generate SIGIOs. Apparently we need to call reset_sys_modes
2737 before calling init_sys_modes. */
7be1c21a
MB
2738 reset_sys_modes (tty);
2739 init_sys_modes (tty);
e882229c 2740 add_gpm_wait_descriptor (gpm_fd);
6178ce5e 2741 return Qnil;
e882229c
NR
2742 }
2743}
2744
ed5ff21d 2745void
d347e494 2746close_gpm (int fd)
ed5ff21d 2747{
d347e494
SM
2748 if (fd >= 0)
2749 delete_gpm_wait_descriptor (fd);
ed5ff21d
SM
2750 while (Gpm_Close()); /* close all the stack */
2751 gpm_tty = NULL;
2752}
2753
6178ce5e 2754DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
e882229c
NR
2755 0, 0, 0,
2756 doc: /* Close a connection to Gpm. */)
5842a27b 2757 (void)
e882229c 2758{
4ce5ab77
SM
2759 struct frame *f = SELECTED_FRAME ();
2760 struct tty_display_info *tty
2761 = ((f)->output_method == output_termcap
2762 ? (f)->terminal->display_info.tty : NULL);
2763
2764 if (!tty || gpm_tty != tty)
2765 return Qnil; /* Not activated on this terminal, nothing to do. */
f4d953fc 2766
d347e494 2767 close_gpm (gpm_fd);
6178ce5e 2768 return Qnil;
e882229c 2769}
7e5a23bd 2770#endif /* HAVE_GPM */
e882229c
NR
2771
2772\f
b5e9cbb6
EZ
2773/***********************************************************************
2774 Menus
2775 ***********************************************************************/
2776
2777#if defined (HAVE_MENUS) && !defined (MSDOS)
2778
2779/* TTY menu implementation and main ideas are borrowed from msdos.c.
2780
2781 However, unlike on MSDOS, where the menu text is drawn directly to
fa93733d
EZ
2782 the display video memory, on a TTY we use display_string (see
2783 display_tty_menu_item in xdisp.c) to put the glyphs produced from
2784 the menu items directly into the frame's 'desired_matrix' glyph
2785 matrix, and then call update_frame_with_menu to deliver the results
2786 to the glass. The previous contents of the screen, in the form of
2787 the current_matrix, is stashed away, and used to restore screen
b5e9cbb6
EZ
2788 contents when the menu selection changes or when the final
2789 selection is made and the menu should be popped down.
2790
141f1ff7 2791 The idea of this implementation was suggested by Gerd Moellmann. */
b5e9cbb6
EZ
2792
2793#define TTYM_FAILURE -1
2794#define TTYM_SUCCESS 1
2795#define TTYM_NO_SELECT 2
2796#define TTYM_IA_SELECT 3
4a48e94d
EZ
2797#define TTYM_NEXT 4
2798#define TTYM_PREV 5
b5e9cbb6
EZ
2799
2800/* These hold text of the current and the previous menu help messages. */
2801static const char *menu_help_message, *prev_menu_help_message;
2802/* Pane number and item number of the menu item which generated the
2803 last menu help message. */
2804static int menu_help_paneno, menu_help_itemno;
2805
df782309
EZ
2806static Lisp_Object Qtty_menu_navigation_map, Qtty_menu_exit;
2807static Lisp_Object Qtty_menu_prev_item, Qtty_menu_next_item;
2808static Lisp_Object Qtty_menu_next_menu, Qtty_menu_prev_menu;
2809static Lisp_Object Qtty_menu_select, Qtty_menu_ignore;
e648f699 2810static Lisp_Object Qtty_menu_mouse_movement;
f0177f86 2811
b5e9cbb6
EZ
2812typedef struct tty_menu_struct
2813{
2814 int count;
2815 char **text;
2816 struct tty_menu_struct **submenu;
5cbcc455 2817 int *panenumber; /* Also used as enabled flag. */
3b158d11 2818 ptrdiff_t allocated;
b5e9cbb6
EZ
2819 int panecount;
2820 int width;
2821 const char **help_text;
2822} tty_menu;
2823
2824/* Create a brand new menu structure. */
2825
2826static tty_menu *
2827tty_menu_create (void)
2828{
3b158d11 2829 return xzalloc (sizeof *tty_menu_create ());
b5e9cbb6
EZ
2830}
2831
2832/* Allocate some (more) memory for MENU ensuring that there is room for one
3b158d11 2833 more item. */
b5e9cbb6
EZ
2834
2835static void
2836tty_menu_make_room (tty_menu *menu)
2837{
3b158d11 2838 if (menu->allocated == menu->count)
b5e9cbb6 2839 {
3b158d11
PE
2840 ptrdiff_t allocated = menu->allocated;
2841 menu->text = xpalloc (menu->text, &allocated, 1, -1, sizeof *menu->text);
2842 menu->text = xrealloc (menu->text, allocated * sizeof *menu->text);
2843 menu->submenu = xrealloc (menu->submenu,
2844 allocated * sizeof *menu->submenu);
2845 menu->panenumber = xrealloc (menu->panenumber,
2846 allocated * sizeof *menu->panenumber);
2847 menu->help_text = xrealloc (menu->help_text,
2848 allocated * sizeof *menu->help_text);
2849 menu->allocated = allocated;
b5e9cbb6
EZ
2850 }
2851}
2852
2853/* Search the given menu structure for a given pane number. */
2854
2855static tty_menu *
2856tty_menu_search_pane (tty_menu *menu, int pane)
2857{
2858 int i;
2859 tty_menu *try;
2860
2861 for (i = 0; i < menu->count; i++)
2862 if (menu->submenu[i])
2863 {
2864 if (pane == menu->panenumber[i])
2865 return menu->submenu[i];
2866 if ((try = tty_menu_search_pane (menu->submenu[i], pane)))
2867 return try;
2868 }
2869 return (tty_menu *) 0;
2870}
2871
2872/* Determine how much screen space a given menu needs. */
2873
2874static void
2875tty_menu_calc_size (tty_menu *menu, int *width, int *height)
2876{
2877 int i, h2, w2, maxsubwidth, maxheight;
2878
9e30f0e1 2879 maxsubwidth = menu->width;
b5e9cbb6
EZ
2880 maxheight = menu->count;
2881 for (i = 0; i < menu->count; i++)
2882 {
2883 if (menu->submenu[i])
2884 {
2885 tty_menu_calc_size (menu->submenu[i], &w2, &h2);
2886 if (w2 > maxsubwidth) maxsubwidth = w2;
2887 if (i + h2 > maxheight) maxheight = i + h2;
2888 }
2889 }
9e30f0e1 2890 *width = maxsubwidth;
b5e9cbb6
EZ
2891 *height = maxheight;
2892}
2893
e648f699
EZ
2894static void
2895mouse_get_xy (int *x, int *y)
2896{
2897 struct frame *sf = SELECTED_FRAME ();
5cbcc455 2898 Lisp_Object lmx = Qnil, lmy = Qnil, lisp_dummy;
e648f699
EZ
2899 enum scroll_bar_part part_dummy;
2900 Time time_dummy;
2901
2902 if (FRAME_TERMINAL (sf)->mouse_position_hook)
2903 (*FRAME_TERMINAL (sf)->mouse_position_hook) (&sf, -1,
2904 &lisp_dummy, &part_dummy,
2905 &lmx, &lmy,
2906 &time_dummy);
2907 if (!NILP (lmx))
2908 {
2909 *x = XINT (lmx);
2910 *y = XINT (lmy);
2911 }
2912}
2913
b5e9cbb6
EZ
2914/* Display MENU at (X,Y) using FACES. */
2915
b5e9cbb6 2916static void
ffc3882f 2917tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
bbc10837 2918 int mx, int my, int disp_help)
b5e9cbb6 2919{
bbc10837 2920 int i, face, width, enabled, mousehere, row, col;
b5e9cbb6
EZ
2921 struct frame *sf = SELECTED_FRAME ();
2922 struct tty_display_info *tty = FRAME_TTY (sf);
48621e69
EZ
2923 /* Don't try to display more menu items than the console can display
2924 using the available screen lines. Exclude the echo area line, as
2925 it will be overwritten by the help-echo anyway. */
2926 int max_items = min (menu->count, FRAME_LINES (sf) - 1);
b5e9cbb6
EZ
2927
2928 menu_help_message = NULL;
2929
2930 width = menu->width;
e7873136
EZ
2931 col = cursorX (tty);
2932 row = cursorY (tty);
48621e69 2933 for (i = 0; i < max_items; i++)
b5e9cbb6 2934 {
342cf494 2935 int max_width = width + 2; /* +2 for padding blanks on each side */
b5e9cbb6 2936
342cf494
EZ
2937 if (menu->submenu[i])
2938 max_width += 2; /* for displaying " >" after the item */
b5e9cbb6
EZ
2939 enabled
2940 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2941 mousehere = (y + i == my && x <= mx && mx < x + max_width);
2942 face = faces[enabled + mousehere * 2];
2943 /* Display the menu help string for the i-th menu item even if
2944 the menu item is currently disabled. That's what the GUI
2945 code does. */
2946 if (disp_help && enabled + mousehere * 2 >= 2)
2947 {
2948 menu_help_message = menu->help_text[i];
2949 menu_help_paneno = pn - 1;
2950 menu_help_itemno = i;
2951 }
342cf494 2952 display_tty_menu_item (menu->text[i], max_width, face, x, y + i,
b5e9cbb6
EZ
2953 menu->submenu[i] != NULL);
2954 }
2955 update_frame_with_menu (sf);
2956 cursor_to (sf, row, col);
2957}
2958
2959/* --------------------------- X Menu emulation ---------------------- */
2960
b5e9cbb6
EZ
2961/* Create a new pane and place it on the outer-most level. */
2962
e7873136
EZ
2963static int
2964tty_menu_add_pane (tty_menu *menu, const char *txt)
b5e9cbb6
EZ
2965{
2966 int len;
3b158d11 2967 const unsigned char *p;
b5e9cbb6
EZ
2968
2969 tty_menu_make_room (menu);
2970 menu->submenu[menu->count] = tty_menu_create ();
2971 menu->text[menu->count] = (char *)txt;
2972 menu->panenumber[menu->count] = ++menu->panecount;
2973 menu->help_text[menu->count] = NULL;
2974 menu->count++;
2975
2976 /* Update the menu width, if necessary. */
3b158d11 2977 for (len = 0, p = (unsigned char *) txt; *p; )
b5e9cbb6
EZ
2978 {
2979 int ch_len;
2980 int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
2981
2982 len += CHAR_WIDTH (ch);
2983 p += ch_len;
2984 }
2985
2986 if (len > menu->width)
2987 menu->width = len;
2988
2989 return menu->panecount;
2990}
2991
2992/* Create a new item in a menu pane. */
2993
3b158d11 2994static int
b5e9cbb6
EZ
2995tty_menu_add_selection (tty_menu *menu, int pane,
2996 char *txt, int enable, char const *help_text)
2997{
2998 int len;
3b158d11 2999 unsigned char *p;
b5e9cbb6
EZ
3000
3001 if (pane)
3002 if (!(menu = tty_menu_search_pane (menu, pane)))
3003 return TTYM_FAILURE;
3004 tty_menu_make_room (menu);
3005 menu->submenu[menu->count] = (tty_menu *) 0;
3006 menu->text[menu->count] = txt;
3007 menu->panenumber[menu->count] = enable;
3008 menu->help_text[menu->count] = help_text;
3009 menu->count++;
3010
3011 /* Update the menu width, if necessary. */
3b158d11 3012 for (len = 0, p = (unsigned char *) txt; *p; )
b5e9cbb6
EZ
3013 {
3014 int ch_len;
3015 int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
3016
3017 len += CHAR_WIDTH (ch);
3018 p += ch_len;
3019 }
3020
3021 if (len > menu->width)
3022 menu->width = len;
3023
3024 return TTYM_SUCCESS;
3025}
3026
3027/* Decide where the menu would be placed if requested at (X,Y). */
3028
3b158d11 3029static void
b5e9cbb6
EZ
3030tty_menu_locate (tty_menu *menu, int x, int y,
3031 int *ulx, int *uly, int *width, int *height)
3032{
3033 tty_menu_calc_size (menu, width, height);
3034 *ulx = x + 1;
3035 *uly = y;
3036 *width += 2;
3037}
3038
3039struct tty_menu_state
3040{
141f1ff7 3041 struct glyph_matrix *screen_behind;
b5e9cbb6
EZ
3042 tty_menu *menu;
3043 int pane;
3044 int x, y;
3045};
3046
f34729ea
EZ
3047/* Save away the contents of frame F's current frame matrix, and
3048 enable all its rows. Value is a glyph matrix holding the contents
3049 of F's current frame matrix with all its glyph rows enabled. */
3050
4ed77415 3051static struct glyph_matrix *
f34729ea
EZ
3052save_and_enable_current_matrix (struct frame *f)
3053{
3054 int i;
3055 struct glyph_matrix *saved = xzalloc (sizeof *saved);
3056 saved->nrows = f->current_matrix->nrows;
3057 saved->rows = xzalloc (saved->nrows * sizeof *saved->rows);
3058
3059 for (i = 0; i < saved->nrows; ++i)
3060 {
3061 struct glyph_row *from = f->current_matrix->rows + i;
3062 struct glyph_row *to = saved->rows + i;
3063 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
3064
3065 to->glyphs[TEXT_AREA] = xmalloc (nbytes);
3066 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
3067 to->used[TEXT_AREA] = from->used[TEXT_AREA];
3068 /* Make sure every row is enabled, or else update_frame will not
3069 redraw them. (Rows that are identical to what is already on
3070 screen will not be redrawn anyway.) */
3071 to->enabled_p = 1;
3072 to->hash = from->hash;
f34729ea
EZ
3073 }
3074
3075 return saved;
3076}
3077
141f1ff7
EZ
3078/* Restore the contents of frame F's desired frame matrix from SAVED,
3079 and free memory associated with SAVED. */
b5e9cbb6 3080
141f1ff7
EZ
3081static void
3082restore_desired_matrix (struct frame *f, struct glyph_matrix *saved)
3083{
3084 int i;
3085
3086 for (i = 0; i < saved->nrows; ++i)
3087 {
3088 struct glyph_row *from = saved->rows + i;
3089 struct glyph_row *to = f->desired_matrix->rows + i;
3090 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
3091
96114a30 3092 eassert (to->glyphs[TEXT_AREA] != from->glyphs[TEXT_AREA]);
141f1ff7
EZ
3093 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
3094 to->used[TEXT_AREA] = from->used[TEXT_AREA];
fa93733d
EZ
3095 to->enabled_p = from->enabled_p;
3096 to->hash = from->hash;
141f1ff7 3097 }
141f1ff7
EZ
3098}
3099
3100static void
3101free_saved_screen (struct glyph_matrix *saved)
3102{
3103 int i;
3104
3105 if (!saved)
3106 return; /* already freed */
3107
3108 for (i = 0; i < saved->nrows; ++i)
3109 {
3110 struct glyph_row *from = saved->rows + i;
3111
3112 xfree (from->glyphs[TEXT_AREA]);
141f1ff7
EZ
3113 }
3114
3115 xfree (saved->rows);
3116 xfree (saved);
3117}
3118
3119/* Update the display of frame F from its saved contents. */
3120static void
3121screen_update (struct frame *f, struct glyph_matrix *mtx)
3122{
3123 restore_desired_matrix (f, mtx);
3124 update_frame_with_menu (f);
3125}
3126
3127/* Read user input and return X and Y coordinates where that input
3128 puts us. We only consider mouse movement and click events and
0de83597
EZ
3129 keyboard movement commands; the rest are ignored.
3130
4a48e94d
EZ
3131 Value is -1 if C-g was pressed, 1 if an item was selected, 2 or 3
3132 if we need to move to the next or previous menu-bar menu, zero
e648f699 3133 otherwise. */
0de83597 3134static int
df782309
EZ
3135read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
3136 bool *first_time)
141f1ff7 3137{
ffc3882f
EZ
3138 if (*first_time)
3139 {
3140 *first_time = false;
3141 sf->mouse_moved = 1;
ffc3882f 3142 }
afd8eb2c 3143 else
141f1ff7 3144 {
7ace9265 3145 Lisp_Object cmd;
f0177f86
EZ
3146 int usable_input = 1;
3147 int st = 0;
f34729ea 3148 struct tty_display_info *tty = FRAME_TTY (sf);
e648f699 3149 Lisp_Object saved_mouse_tracking = do_mouse_tracking;
f0177f86 3150
f34729ea
EZ
3151 /* Signal the keyboard reading routines we are displaying a menu
3152 on this terminal. */
3153 tty->showing_menu = 1;
e648f699
EZ
3154 /* We want mouse movements be reported by read_menu_command. */
3155 do_mouse_tracking = Qt;
7ace9265
EZ
3156 do {
3157 cmd = read_menu_command ();
e648f699 3158 } while (NILP (cmd));
f34729ea 3159 tty->showing_menu = 0;
e648f699 3160 do_mouse_tracking = saved_mouse_tracking;
7ace9265 3161
df782309 3162 if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit))
f0177f86 3163 return -1;
e648f699 3164 if (EQ (cmd, Qtty_menu_mouse_movement))
3b158d11 3165 mouse_get_xy (x, y);
e648f699 3166 else if (EQ (cmd, Qtty_menu_next_menu))
4a48e94d
EZ
3167 {
3168 usable_input = 0;
3169 st = 2;
3170 }
df782309 3171 else if (EQ (cmd, Qtty_menu_prev_menu))
4a48e94d
EZ
3172 {
3173 usable_input = 0;
3174 st = 3;
3175 }
df782309
EZ
3176 else if (EQ (cmd, Qtty_menu_next_item))
3177 {
3178 if (*y < max_y)
3179 *y += 1;
052bac0b
EZ
3180 else
3181 *y = min_y;
df782309
EZ
3182 }
3183 else if (EQ (cmd, Qtty_menu_prev_item))
3184 {
3185 if (*y > min_y)
3186 *y -= 1;
052bac0b
EZ
3187 else
3188 *y = max_y;
df782309
EZ
3189 }
3190 else if (EQ (cmd, Qtty_menu_select))
f0177f86 3191 st = 1;
df782309 3192 else if (!EQ (cmd, Qtty_menu_ignore))
e648f699 3193 usable_input = 0;
f0177f86
EZ
3194 if (usable_input)
3195 sf->mouse_moved = 1;
0de83597 3196 return st;
141f1ff7 3197 }
0de83597 3198 return 0;
141f1ff7
EZ
3199}
3200
3201/* Display menu, wait for user's response, and return that response. */
4a48e94d 3202static int
b5e9cbb6
EZ
3203tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
3204 int x0, int y0, char **txt,
4a48e94d
EZ
3205 void (*help_callback)(char const *, int, int),
3206 int kbd_navigation)
b5e9cbb6
EZ
3207{
3208 struct tty_menu_state *state;
3b158d11
PE
3209 int statecount, x, y, i, leave, onepane;
3210 int result IF_LINT (= 0);
b5e9cbb6
EZ
3211 int title_faces[4]; /* face to display the menu title */
3212 int faces[4], buffers_num_deleted = 0;
3213 struct frame *sf = SELECTED_FRAME ();
28a16449 3214 struct tty_display_info *tty = FRAME_TTY (sf);
ffc3882f 3215 bool first_time;
3b158d11 3216 Lisp_Object selectface;
b5e9cbb6
EZ
3217
3218 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3219 around the display. */
3220 if (x0 <= 0)
3221 x0 = 1;
3222 if (y0 <= 0)
3223 y0 = 1;
3224
b5e9cbb6 3225 state = alloca (menu->panecount * sizeof (struct tty_menu_state));
141f1ff7 3226 memset (state, 0, sizeof (*state));
b5e9cbb6
EZ
3227 faces[0]
3228 = lookup_derived_face (sf, intern ("tty-menu-disabled-face"),
3229 DEFAULT_FACE_ID, 1);
3230 faces[1]
3231 = lookup_derived_face (sf, intern ("tty-menu-enabled-face"),
3232 DEFAULT_FACE_ID, 1);
3233 selectface = intern ("tty-menu-selected-face");
3234 faces[2] = lookup_derived_face (sf, selectface,
3235 faces[0], 1);
3236 faces[3] = lookup_derived_face (sf, selectface,
3237 faces[1], 1);
3238
3239 /* Make sure the menu title is always displayed with
50a5f95e 3240 `tty-menu-selected-face', no matter where the mouse pointer is. */
b5e9cbb6
EZ
3241 for (i = 0; i < 4; i++)
3242 title_faces[i] = faces[3];
3243
3244 statecount = 1;
3245
3246 /* Don't let the title for the "Buffers" popup menu include a
3247 digit (which is ugly).
3248
3249 This is a terrible kludge, but I think the "Buffers" case is
3250 the only one where the title includes a number, so it doesn't
3251 seem to be necessary to make this more general. */
3252 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3253 {
3254 menu->text[0][7] = '\0';
3255 buffers_num_deleted = 1;
3256 }
3257
141f1ff7
EZ
3258 /* Force update of the current frame, so that the desired and the
3259 current matrices are identical. */
3260 update_frame_with_menu (sf);
b5e9cbb6 3261 state[0].menu = menu;
f34729ea 3262 state[0].screen_behind = save_and_enable_current_matrix (sf);
b5e9cbb6 3263
ffc3882f
EZ
3264 /* Display the menu title. We subtract 1 from x0 and y0 because we
3265 want to interpret them as zero-based column and row coordinates,
3266 and also because we want the first item of the menu, not its
3267 title, to appear at x0,y0. */
bbc10837 3268 tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0);
6270e29e
EZ
3269
3270 /* Turn off the cursor. Otherwise it shows through the menu
3271 panes, which is ugly. */
3272 tty_hide_cursor (tty);
b5e9cbb6
EZ
3273 if (buffers_num_deleted)
3274 menu->text[0][7] = ' ';
3275 if ((onepane = menu->count == 1 && menu->submenu[0]))
3276 {
3277 menu->width = menu->submenu[0]->width;
3278 state[0].menu = menu->submenu[0];
3279 }
3280 else
3281 {
3282 state[0].menu = menu;
3283 }
3284 state[0].x = x0 - 1;
3285 state[0].y = y0;
3286 state[0].pane = onepane;
3287
141f1ff7
EZ
3288 x = state[0].x;
3289 y = state[0].y;
ffc3882f 3290 first_time = true;
141f1ff7 3291
b5e9cbb6
EZ
3292 leave = 0;
3293 while (!leave)
3294 {
f0177f86 3295 int input_status;
48621e69 3296 int min_y = state[0].y;
052bac0b 3297 int max_y = min (min_y + state[0].menu->count, FRAME_LINES (sf) - 1) - 1;
e7873136 3298
df782309 3299 input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
f0177f86
EZ
3300 if (input_status)
3301 {
4a48e94d 3302 leave = 1;
f0177f86 3303 if (input_status == -1)
824682ea
EZ
3304 {
3305 /* Remove the last help-echo, so that it doesn't
3306 re-appear after "Quit". */
3307 show_help_echo (Qnil, Qnil, Qnil, Qnil);
3308 result = TTYM_NO_SELECT;
3309 }
4a48e94d
EZ
3310 else if (input_status == 2)
3311 {
3312 if (kbd_navigation)
3313 result = TTYM_NEXT;
3314 else
3315 leave = 0;
3316 }
3317 else if (input_status == 3)
3318 {
3319 if (kbd_navigation)
3320 result = TTYM_PREV;
3321 else
3322 leave = 0;
3323 }
f0177f86 3324 }
f34729ea 3325 if (sf->mouse_moved && input_status != -1)
b5e9cbb6
EZ
3326 {
3327 sf->mouse_moved = 0;
3328 result = TTYM_IA_SELECT;
b5e9cbb6
EZ
3329 for (i = 0; i < statecount; i++)
3330 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3331 {
3332 int dy = y - state[i].y;
3333 if (0 <= dy && dy < state[i].menu->count)
3334 {
3335 if (!state[i].menu->submenu[dy])
3336 {
3337 if (state[i].menu->panenumber[dy])
3338 result = TTYM_SUCCESS;
3339 else
3340 result = TTYM_IA_SELECT;
3341 }
3342 *pane = state[i].pane - 1;
3343 *selidx = dy;
3344 /* We hit some part of a menu, so drop extra menus that
3345 have been opened. That does not include an open and
3346 active submenu. */
3347 if (i != statecount - 2
3348 || state[i].menu->submenu[dy] != state[i+1].menu)
3349 while (i != statecount - 1)
3350 {
3351 statecount--;
e7873136 3352 screen_update (sf, state[statecount].screen_behind);
141f1ff7 3353 state[statecount].screen_behind = NULL;
b5e9cbb6
EZ
3354 }
3355 if (i == statecount - 1 && state[i].menu->submenu[dy])
3356 {
3357 tty_menu_display (state[i].menu,
b5e9cbb6 3358 state[i].x,
ffc3882f 3359 state[i].y,
b5e9cbb6 3360 state[i].pane,
bbc10837 3361 faces, x, y, 1);
b5e9cbb6
EZ
3362 state[statecount].menu = state[i].menu->submenu[dy];
3363 state[statecount].pane = state[i].menu->panenumber[dy];
141f1ff7 3364 state[statecount].screen_behind
f34729ea 3365 = save_and_enable_current_matrix (sf);
b5e9cbb6
EZ
3366 state[statecount].x
3367 = state[i].x + state[i].menu->width + 2;
3368 state[statecount].y = y;
3369 statecount++;
3370 }
3371 }
3372 }
3373 tty_menu_display (state[statecount - 1].menu,
b5e9cbb6 3374 state[statecount - 1].x,
ffc3882f 3375 state[statecount - 1].y,
b5e9cbb6 3376 state[statecount - 1].pane,
bbc10837 3377 faces, x, y, 1);
6270e29e
EZ
3378 tty_hide_cursor (tty);
3379 fflush (tty->output);
b5e9cbb6 3380 }
824682ea
EZ
3381
3382 /* Display the help-echo message for the currently-selected menu
3383 item. */
3384 if ((menu_help_message || prev_menu_help_message)
3385 && menu_help_message != prev_menu_help_message)
b5e9cbb6 3386 {
824682ea
EZ
3387 help_callback (menu_help_message,
3388 menu_help_paneno, menu_help_itemno);
3389 tty_hide_cursor (tty);
6270e29e 3390 fflush (tty->output);
824682ea 3391 prev_menu_help_message = menu_help_message;
b5e9cbb6 3392 }
b5e9cbb6
EZ
3393 }
3394
ffc3882f 3395 sf->mouse_moved = 0;
141f1ff7 3396 screen_update (sf, state[0].screen_behind);
b5e9cbb6 3397 while (statecount--)
141f1ff7 3398 free_saved_screen (state[statecount].screen_behind);
28a16449 3399 tty_show_cursor (tty); /* turn cursor back on */
9f6a18d2 3400 fflush (tty->output);
28a16449
EZ
3401
3402/* Clean up any mouse events that are waiting inside Emacs event queue.
b5e9cbb6
EZ
3403 These events are likely to be generated before the menu was even
3404 displayed, probably because the user pressed and released the button
3405 (which invoked the menu) too quickly. If we don't remove these events,
3406 Emacs will process them after we return and surprise the user. */
3407 discard_mouse_events ();
e7873136 3408 if (!kbd_buffer_events_waiting ())
b5e9cbb6 3409 clear_input_pending ();
b5e9cbb6
EZ
3410 return result;
3411}
3412
3413/* Dispose of a menu. */
3414
3b158d11 3415static void
b5e9cbb6
EZ
3416tty_menu_destroy (tty_menu *menu)
3417{
3418 int i;
3419 if (menu->allocated)
3420 {
3421 for (i = 0; i < menu->count; i++)
3422 if (menu->submenu[i])
3423 tty_menu_destroy (menu->submenu[i]);
3424 xfree (menu->text);
3425 xfree (menu->submenu);
3426 xfree (menu->panenumber);
3427 xfree (menu->help_text);
3428 }
3429 xfree (menu);
3430 menu_help_message = prev_menu_help_message = NULL;
3431}
3432
e7873136
EZ
3433/* Show help HELP_STRING, or clear help if HELP_STRING is null.
3434
3435 PANE is the pane number, and ITEM is the menu item number in
5cbcc455 3436 the menu (currently not used). */
e7873136
EZ
3437
3438static void
3439tty_menu_help_callback (char const *help_string, int pane, int item)
3440{
3441 Lisp_Object *first_item;
3442 Lisp_Object pane_name;
3443 Lisp_Object menu_object;
3444
f573ac33 3445 first_item = XVECTOR (menu_items)->u.contents;
e7873136
EZ
3446 if (EQ (first_item[0], Qt))
3447 pane_name = first_item[MENU_ITEMS_PANE_NAME];
3448 else if (EQ (first_item[0], Qquote))
3449 /* This shouldn't happen, see xmenu_show. */
3450 pane_name = empty_unibyte_string;
3451 else
3452 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
3453
3454 /* (menu-item MENU-NAME PANE-NUMBER) */
3455 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
3456 show_help_echo (help_string ? build_string (help_string) : Qnil,
3457 Qnil, menu_object, make_number (item));
3458}
3459
3460static void
3461tty_pop_down_menu (Lisp_Object arg)
3462{
3463 tty_menu *menu = XSAVE_POINTER (arg, 0);
3464
3465 block_input ();
3466 tty_menu_destroy (menu);
3467 unblock_input ();
3468}
3469
4a48e94d
EZ
3470/* Return the zero-based index of the last menu-bar item on frame F. */
3471static int
3472tty_menu_last_menubar_item (struct frame *f)
3473{
3474 int i = 0;
3475
3476 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3477 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3478 {
3479 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3480
3481 while (i < ASIZE (items))
3482 {
3483 Lisp_Object str;
3484
3485 str = AREF (items, i + 1);
3486 if (NILP (str))
3487 break;
3488 i += 4;
3489 }
3490 i -= 4; /* went one too far */
3491 }
3492 return i;
3493}
3494
3495/* Find in frame F's menu bar the menu item that is next or previous
3496 to the item at X/Y, and return that item's position in X/Y. WHICH
3497 says which one--next or previous--item to look for. X and Y are
3498 measured in character cells. This should only be called on TTY
3499 frames. */
3500static void
3501tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
3502{
3503 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3504 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3505 {
3506 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3507 int last_i = tty_menu_last_menubar_item (f);
3508 int i, prev_x;
3509
3510 /* This loop assumes a single menu-bar line, and will fail to
3511 find an item if it is not in the first line. Note that
3512 make_lispy_event in keyboard.c makes the same assumption. */
3513 for (i = 0, prev_x = -1; i < ASIZE (items); i += 4)
3514 {
3515 Lisp_Object pos, str;
3516 int ix;
3517
3518 str = AREF (items, i + 1);
3519 pos = AREF (items, i + 3);
3520 if (NILP (str))
3521 return;
3522 ix = XINT (pos);
3523 if (ix <= *x
3524 /* We use <= so the blank between 2 items on a TTY is
3525 considered part of the previous item. */
3b158d11 3526 && *x <= ix + menu_item_width (SDATA (str)))
4a48e94d
EZ
3527 {
3528 /* Found current item. Now compute the X coordinate of
3529 the previous or next item. */
3530 if (which == TTYM_NEXT)
3531 {
3532 if (i < last_i)
3533 *x = XINT (AREF (items, i + 4 + 3));
3534 else
3535 *x = 0; /* wrap around to the first item */
3536 }
3537 else if (prev_x < 0)
3538 {
3539 /* Wrap around to the last item. */
3540 *x = XINT (AREF (items, last_i + 3));
3541 }
3542 else
3543 *x = prev_x;
3544 return;
3545 }
3546 prev_x = ix;
3547 }
3548 }
3549}
3550
b5e9cbb6 3551Lisp_Object
e7873136 3552tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
4a48e94d 3553 Lisp_Object title, int kbd_navigation, const char **error_name)
b5e9cbb6
EZ
3554{
3555 tty_menu *menu;
3556 int pane, selidx, lpane, status;
3557 Lisp_Object entry, pane_prefix;
3558 char *datap;
3559 int ulx, uly, width, height;
4a48e94d 3560 int item_x, item_y;
b5e9cbb6
EZ
3561 int dispwidth, dispheight;
3562 int i, j, lines, maxlines;
3563 int maxwidth;
9428abbf 3564 ptrdiff_t specpdl_count;
b5e9cbb6 3565
9428abbf 3566 eassert (FRAME_TERMCAP_P (f));
b5e9cbb6
EZ
3567
3568 *error_name = 0;
3569 if (menu_items_n_panes == 0)
3570 return Qnil;
3571
3572 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
3573 {
3574 *error_name = "Empty menu";
3575 return Qnil;
3576 }
3577
3578 /* Make the menu on that window. */
3579 menu = tty_menu_create ();
3580 if (menu == NULL)
3581 {
3582 *error_name = "Can't create menu";
3583 return Qnil;
3584 }
3585
3586 /* Don't GC while we prepare and show the menu, because we give the
3587 menu functions pointers to the contents of strings. */
9428abbf 3588 specpdl_count = inhibit_garbage_collection ();
b5e9cbb6
EZ
3589
3590 /* Adjust coordinates to be root-window-relative. */
4a48e94d
EZ
3591 item_x = x += f->left_pos;
3592 item_y = y += f->top_pos;
b5e9cbb6
EZ
3593
3594 /* Create all the necessary panes and their items. */
3595 maxwidth = maxlines = lines = i = 0;
3596 lpane = TTYM_FAILURE;
3597 while (i < menu_items_used)
3598 {
dfe3ac02 3599 if (EQ (AREF (menu_items, i), Qt))
b5e9cbb6
EZ
3600 {
3601 /* Create a new pane. */
3602 Lisp_Object pane_name, prefix;
3603 const char *pane_string;
3604
3605 maxlines = max (maxlines, lines);
3606 lines = 0;
dfe3ac02
EZ
3607 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
3608 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
b5e9cbb6
EZ
3609 pane_string = (NILP (pane_name)
3610 ? "" : SSDATA (pane_name));
3611 if (keymaps && !NILP (prefix))
3612 pane_string++;
3613
3614 lpane = tty_menu_add_pane (menu, pane_string);
3615 if (lpane == TTYM_FAILURE)
3616 {
3617 tty_menu_destroy (menu);
3618 *error_name = "Can't create pane";
9428abbf
DA
3619 entry = Qnil;
3620 goto tty_menu_end;
b5e9cbb6
EZ
3621 }
3622 i += MENU_ITEMS_PANE_LENGTH;
3623
3624 /* Find the width of the widest item in this pane. */
3625 j = i;
3626 while (j < menu_items_used)
3627 {
3628 Lisp_Object item;
dfe3ac02 3629 item = AREF (menu_items, j);
b5e9cbb6
EZ
3630 if (EQ (item, Qt))
3631 break;
3632 if (NILP (item))
3633 {
3634 j++;
3635 continue;
3636 }
3637 width = SBYTES (item);
3638 if (width > maxwidth)
3639 maxwidth = width;
3640
3641 j += MENU_ITEMS_ITEM_LENGTH;
3642 }
3643 }
3644 /* Ignore a nil in the item list.
3645 It's meaningful only for dialog boxes. */
dfe3ac02 3646 else if (EQ (AREF (menu_items, i), Qquote))
b5e9cbb6
EZ
3647 i += 1;
3648 else
3649 {
3650 /* Create a new item within current pane. */
3651 Lisp_Object item_name, enable, descrip, help;
3652 char *item_data;
3653 char const *help_string;
3654
dfe3ac02
EZ
3655 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
3656 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
3657 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
3658 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
b5e9cbb6
EZ
3659 help_string = STRINGP (help) ? SSDATA (help) : NULL;
3660
3661 if (!NILP (descrip))
3662 {
3663 /* if alloca is fast, use that to make the space,
3664 to reduce gc needs. */
3665 item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1);
3666 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
3667 for (j = SCHARS (item_name); j < maxwidth; j++)
3668 item_data[j] = ' ';
3669 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
3670 item_data[j + SBYTES (descrip)] = 0;
3671 }
3672 else
3673 item_data = SSDATA (item_name);
3674
3675 if (lpane == TTYM_FAILURE
3676 || (tty_menu_add_selection (menu, lpane, item_data,
3677 !NILP (enable), help_string)
3678 == TTYM_FAILURE))
3679 {
3680 tty_menu_destroy (menu);
3681 *error_name = "Can't add selection to menu";
9428abbf
DA
3682 entry = Qnil;
3683 goto tty_menu_end;
b5e9cbb6
EZ
3684 }
3685 i += MENU_ITEMS_ITEM_LENGTH;
3686 lines++;
3687 }
3688 }
3689
3690 maxlines = max (maxlines, lines);
3691
3692 /* All set and ready to fly. */
3693 dispwidth = f->text_cols;
3694 dispheight = f->text_lines;
3695 x = min (x, dispwidth);
3696 y = min (y, dispheight);
3697 x = max (x, 1);
3698 y = max (y, 1);
3699 tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
9428abbf 3700 if (ulx + width > dispwidth)
b5e9cbb6
EZ
3701 {
3702 x -= (ulx + width) - dispwidth;
3703 ulx = dispwidth - width;
3704 }
9428abbf 3705 if (uly + height > dispheight)
b5e9cbb6
EZ
3706 {
3707 y -= (uly + height) - dispheight;
3708 uly = dispheight - height;
3709 }
3710
df782309 3711 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 2)
b5e9cbb6
EZ
3712 {
3713 /* Move the menu away of the echo area, to avoid overwriting the
3714 menu with help echo messages or vice versa. */
3715 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
3716 {
df782309
EZ
3717 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
3718 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
b5e9cbb6
EZ
3719 }
3720 else
3721 {
df782309
EZ
3722 y -= 2;
3723 uly -= 2;
b5e9cbb6
EZ
3724 }
3725 }
3726
3727 if (ulx < 0) x -= ulx;
3728 if (uly < 0) y -= uly;
3729
a01f89af
EZ
3730#if 0
3731 /* This code doesn't make sense on a TTY, since it can easily annul
3732 the adjustments above that carefully avoid truncation of the menu
5cbcc455
EZ
3733 items. I think it was written to fix some problem that only
3734 happens on X11. */
b5e9cbb6
EZ
3735 if (! for_click)
3736 {
3737 /* If position was not given by a mouse click, adjust so upper left
3738 corner of the menu as a whole ends up at given coordinates. This
3739 is what x-popup-menu says in its documentation. */
3740 x += width/2;
3741 y += 1.5*height/(maxlines+2);
3742 }
a01f89af 3743#endif
b5e9cbb6
EZ
3744
3745 pane = selidx = 0;
3746
e7873136 3747 record_unwind_protect (tty_pop_down_menu, make_save_ptr (menu));
b5e9cbb6 3748
df782309
EZ
3749 specbind (Qoverriding_terminal_local_map,
3750 Fsymbol_value (Qtty_menu_navigation_map));
b5e9cbb6 3751 status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
4a48e94d 3752 tty_menu_help_callback, kbd_navigation);
b5e9cbb6
EZ
3753 entry = pane_prefix = Qnil;
3754
3755 switch (status)
3756 {
3757 case TTYM_SUCCESS:
3758 /* Find the item number SELIDX in pane number PANE. */
3759 i = 0;
3760 while (i < menu_items_used)
3761 {
dfe3ac02 3762 if (EQ (AREF (menu_items, i), Qt))
b5e9cbb6
EZ
3763 {
3764 if (pane == 0)
3765 pane_prefix
dfe3ac02 3766 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
b5e9cbb6
EZ
3767 pane--;
3768 i += MENU_ITEMS_PANE_LENGTH;
3769 }
3770 else
3771 {
3772 if (pane == -1)
3773 {
3774 if (selidx == 0)
3775 {
3776 entry
dfe3ac02 3777 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
b5e9cbb6
EZ
3778 if (keymaps != 0)
3779 {
3780 entry = Fcons (entry, Qnil);
3781 if (!NILP (pane_prefix))
3782 entry = Fcons (pane_prefix, entry);
3783 }
3784 break;
3785 }
3786 selidx--;
3787 }
3788 i += MENU_ITEMS_ITEM_LENGTH;
3789 }
3790 }
3791 break;
3792
4a48e94d
EZ
3793 case TTYM_NEXT:
3794 case TTYM_PREV:
3795 tty_menu_new_item_coords (f, status, &item_x, &item_y);
3796 entry = Fcons (make_number (item_x), make_number (item_y));
3797 break;
3798
b5e9cbb6
EZ
3799 case TTYM_FAILURE:
3800 *error_name = "Can't activate menu";
3801 case TTYM_IA_SELECT:
3802 break;
3803 case TTYM_NO_SELECT:
3804 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
3805 the menu was invoked with a mouse event as POSITION). */
3806 if (! for_click)
3807 Fsignal (Qquit, Qnil);
3808 break;
3809 }
3810
9428abbf 3811 tty_menu_end:
b5e9cbb6 3812
9428abbf 3813 unbind_to (specpdl_count, Qnil);
b5e9cbb6
EZ
3814 return entry;
3815}
3816
3817#endif /* HAVE_MENUS && !MSDOS */
3818
3819\f
89ba96f4 3820#ifndef MSDOS
a168702a
GM
3821/***********************************************************************
3822 Initialization
3823 ***********************************************************************/
3824
ed8dad6b
KL
3825/* Initialize the tty-dependent part of frame F. The frame must
3826 already have its device initialized. */
3224dac1 3827
dfcf069d 3828void
ed8dad6b 3829create_tty_output (struct frame *f)
28d440ab 3830{
38182d90 3831 struct tty_output *t = xzalloc (sizeof *t);
ed8dad6b 3832
9c253307 3833 eassert (FRAME_TERMCAP_P (f));
428a555e 3834
6ed8eeff 3835 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
bedb9c0e 3836
ed8dad6b 3837 f->output_data.tty = t;
3224dac1
KL
3838}
3839
9f215d25 3840/* Delete frame F's face cache, and its tty-dependent part. */
da8e1115 3841
ed8dad6b 3842static void
9f215d25 3843tty_free_frame_resources (struct frame *f)
3224dac1 3844{
9c253307 3845 eassert (FRAME_TERMCAP_P (f));
3224dac1 3846
9f215d25
CY
3847 if (FRAME_FACE_CACHE (f))
3848 free_frame_faces (f);
3849
ed8dad6b 3850 xfree (f->output_data.tty);
28d440ab
KL
3851}
3852
89ba96f4
EZ
3853#else /* MSDOS */
3854
3855/* Delete frame F's face cache. */
3856
3857static void
3858tty_free_frame_resources (struct frame *f)
3859{
9c253307 3860 eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
89ba96f4
EZ
3861
3862 if (FRAME_FACE_CACHE (f))
3863 free_frame_faces (f);
3864}
3865#endif /* MSDOS */
ed8dad6b 3866\f
47cc8819 3867/* Reset the hooks in TERMINAL. */
ed8dad6b 3868
4a665758
KL
3869static void
3870clear_tty_hooks (struct terminal *terminal)
3871{
3872 terminal->rif = 0;
3873 terminal->cursor_to_hook = 0;
3874 terminal->raw_cursor_to_hook = 0;
3875 terminal->clear_to_end_hook = 0;
3876 terminal->clear_frame_hook = 0;
3877 terminal->clear_end_of_line_hook = 0;
3878 terminal->ins_del_lines_hook = 0;
3879 terminal->insert_glyphs_hook = 0;
3880 terminal->write_glyphs_hook = 0;
3881 terminal->delete_glyphs_hook = 0;
3882 terminal->ring_bell_hook = 0;
3883 terminal->reset_terminal_modes_hook = 0;
3884 terminal->set_terminal_modes_hook = 0;
3885 terminal->update_begin_hook = 0;
3886 terminal->update_end_hook = 0;
3887 terminal->set_terminal_window_hook = 0;
3888 terminal->mouse_position_hook = 0;
3889 terminal->frame_rehighlight_hook = 0;
3890 terminal->frame_raise_lower_hook = 0;
974b73e8 3891 terminal->fullscreen_hook = 0;
4a665758
KL
3892 terminal->set_vertical_scroll_bar_hook = 0;
3893 terminal->condemn_scroll_bars_hook = 0;
3894 terminal->redeem_scroll_bar_hook = 0;
3895 terminal->judge_scroll_bars_hook = 0;
3896 terminal->read_socket_hook = 0;
3897 terminal->frame_up_to_date_hook = 0;
3898
3899 /* Leave these two set, or suspended frames are not deleted
3900 correctly. */
9f215d25 3901 terminal->delete_frame_hook = &tty_free_frame_resources;
4a665758
KL
3902 terminal->delete_terminal_hook = &delete_tty;
3903}
3904
47cc8819
DN
3905/* Initialize hooks in TERMINAL with the values needed for a tty. */
3906
4a665758
KL
3907static void
3908set_tty_hooks (struct terminal *terminal)
3909{
3910 terminal->rif = 0; /* ttys don't support window-based redisplay. */
3911
3912 terminal->cursor_to_hook = &tty_cursor_to;
3913 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
3914
3915 terminal->clear_to_end_hook = &tty_clear_to_end;
3916 terminal->clear_frame_hook = &tty_clear_frame;
3917 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
3918
3919 terminal->ins_del_lines_hook = &tty_ins_del_lines;
3920
3921 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3922 terminal->write_glyphs_hook = &tty_write_glyphs;
3923 terminal->delete_glyphs_hook = &tty_delete_glyphs;
3924
3925 terminal->ring_bell_hook = &tty_ring_bell;
f4d953fc 3926
4a665758
KL
3927 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3928 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
3929 terminal->update_begin_hook = 0; /* Not needed. */
3930 terminal->update_end_hook = &tty_update_end;
3931 terminal->set_terminal_window_hook = &tty_set_terminal_window;
3932
3933 terminal->mouse_position_hook = 0; /* Not needed. */
3934 terminal->frame_rehighlight_hook = 0; /* Not needed. */
3935 terminal->frame_raise_lower_hook = 0; /* Not needed. */
3936
3937 terminal->set_vertical_scroll_bar_hook = 0; /* Not needed. */
3938 terminal->condemn_scroll_bars_hook = 0; /* Not needed. */
3939 terminal->redeem_scroll_bar_hook = 0; /* Not needed. */
3940 terminal->judge_scroll_bars_hook = 0; /* Not needed. */
3941
3942 terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
3943 terminal->frame_up_to_date_hook = 0; /* Not needed. */
f4d953fc 3944
9f215d25 3945 terminal->delete_frame_hook = &tty_free_frame_resources;
4a665758
KL
3946 terminal->delete_terminal_hook = &delete_tty;
3947}
3948
b8956427 3949/* If FD is the controlling terminal, drop it. */
ed8dad6b 3950static void
03a1d6bd
KL
3951dissociate_if_controlling_tty (int fd)
3952{
b8956427
PE
3953 /* If tcgetpgrp succeeds, fd is the controlling terminal,
3954 so dissociate it by invoking setsid. */
908589fd 3955 if (tcgetpgrp (fd) >= 0 && setsid () < 0)
b8956427
PE
3956 {
3957#ifdef TIOCNOTTY
3958 /* setsid failed, presumably because Emacs is already a process
3959 group leader. Fall back on the obsolescent way to dissociate
3960 a controlling tty. */
3961 block_tty_out_signal ();
3962 ioctl (fd, TIOCNOTTY, 0);
3963 unblock_tty_out_signal ();
3964#endif
3965 }
03a1d6bd
KL
3966}
3967
3224dac1
KL
3968/* Create a termcap display on the tty device with the given name and
3969 type.
3970
ab797f65 3971 If NAME is NULL, then use the controlling tty, i.e., "/dev/tty".
3224dac1
KL
3972 Otherwise NAME should be a path to the tty device file,
3973 e.g. "/dev/pts/7".
28d440ab 3974
3224dac1
KL
3975 TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
3976
a104f656 3977 If MUST_SUCCEED is true, then all errors are fatal. */
da8e1115 3978
6ed8eeff 3979struct terminal *
653d4f43 3980init_tty (const char *name, const char *terminal_type, bool must_succeed)
08a24c47 3981{
1fc8eb33 3982 char *area;
08a24c47 3983 char **address = &area;
08a24c47 3984 int status;
59b3194c
KL
3985 struct tty_display_info *tty = NULL;
3986 struct terminal *terminal = NULL;
a104f656 3987 bool ctty = false; /* True if asked to open controlling tty. */
28d440ab 3988
3224dac1 3989 if (!terminal_type)
d31eee5e 3990 maybe_fatal (must_succeed, 0,
3224dac1
KL
3991 "Unknown terminal type",
3992 "Unknown terminal type");
b6660415 3993
ab797f65 3994 if (name == NULL)
78048085
EZ
3995 name = DEV_TTY;
3996 if (!strcmp (name, DEV_TTY))
ab797f65
KL
3997 ctty = 1;
3998
6ed8eeff
KL
3999 /* If we already have a terminal on the given device, use that. If
4000 all such terminals are suspended, create a new one instead. */
a4c6993d 4001 /* XXX Perhaps this should be made explicit by having init_tty
6ed8eeff 4002 always create a new terminal and separating terminal and frame
b6660415 4003 creation on Lisp level. */
6ed8eeff
KL
4004 terminal = get_named_tty (name);
4005 if (terminal)
4006 return terminal;
78048085 4007
6ed8eeff 4008 terminal = create_terminal ();
84704c5c
EZ
4009#ifdef MSDOS
4010 if (been_here > 0)
762b15be 4011 maybe_fatal (0, 0, "Attempt to create another terminal %s", "",
84704c5c
EZ
4012 name, "");
4013 been_here = 1;
4014 tty = &the_only_display_info;
4015#else
38182d90 4016 tty = xzalloc (sizeof *tty);
84704c5c 4017#endif
c650a5de 4018 tty->top_frame = Qnil;
3224dac1
KL
4019 tty->next = tty_list;
4020 tty_list = tty;
428a555e 4021
6ed8eeff
KL
4022 terminal->type = output_termcap;
4023 terminal->display_info.tty = tty;
4024 tty->terminal = terminal;
28d440ab 4025
38182d90 4026 tty->Wcm = xmalloc (sizeof *tty->Wcm);
7b00d185 4027 Wcm_clear (tty);
daf01701 4028
dce4c2ac
DN
4029 encode_terminal_src_size = 0;
4030 encode_terminal_dst_size = 0;
4031
51b59d79 4032
84704c5c 4033#ifndef DOS_NT
4a665758 4034 set_tty_hooks (terminal);
78048085 4035
59b3194c 4036 {
49cdacda 4037 /* Open the terminal device. */
0c72d684 4038
49cdacda
PE
4039 /* If !ctty, don't recognize it as our controlling terminal, and
4040 don't make it the controlling tty if we don't have one now.
4041
4042 Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
4043 defined on Hurd. On other systems, we need to explicitly
4044 dissociate ourselves from the controlling tty when we want to
4045 open a frame on the same terminal. */
4046 int flags = O_RDWR | O_NOCTTY | (ctty ? 0 : O_IGNORE_CTTY);
4047 int fd = emacs_open (name, flags, 0);
ef30e638 4048 tty->input = tty->output = fd < 0 || ! isatty (fd) ? 0 : fdopen (fd, "w+");
0c72d684 4049
ef30e638 4050 if (! tty->input)
59b3194c 4051 {
ef30e638
PE
4052 char const *diagnostic
4053 = tty->input ? "Not a tty device: %s" : "Could not open file: %s";
4054 emacs_close (fd);
4055 maybe_fatal (must_succeed, terminal, diagnostic, diagnostic, name);
59b3194c 4056 }
0c72d684 4057
ef30e638
PE
4058 tty->name = xstrdup (name);
4059 terminal->name = xstrdup (name);
4060
49cdacda 4061 if (!O_IGNORE_CTTY && !ctty)
03a1d6bd 4062 dissociate_if_controlling_tty (fd);
59b3194c 4063 }
78048085 4064
28d7d09f 4065 tty->type = xstrdup (terminal_type);
28d440ab 4066
819b8f00 4067 add_keyboard_wait_descriptor (fileno (tty->input));
08a24c47 4068
6548cf00 4069 Wcm_clear (tty);
08a24c47 4070
03a1d6bd 4071 /* On some systems, tgetent tries to access the controlling
a104f656 4072 terminal. */
b8956427
PE
4073 block_tty_out_signal ();
4074 status = tgetent (tty->termcap_term_buffer, terminal_type);
1fc8eb33
PE
4075 if (tty->termcap_term_buffer[TERMCAP_BUFFER_SIZE - 1])
4076 emacs_abort ();
b8956427 4077 unblock_tty_out_signal ();
78048085 4078
08a24c47 4079 if (status < 0)
b0347178
KH
4080 {
4081#ifdef TERMINFO
d31eee5e 4082 maybe_fatal (must_succeed, terminal,
3224dac1
KL
4083 "Cannot open terminfo database file",
4084 "Cannot open terminfo database file");
b0347178 4085#else
d31eee5e 4086 maybe_fatal (must_succeed, terminal,
3224dac1
KL
4087 "Cannot open termcap database file",
4088 "Cannot open termcap database file");
b0347178
KH
4089#endif
4090 }
08a24c47 4091 if (status == 0)
b0347178 4092 {
d31eee5e 4093 maybe_fatal (must_succeed, terminal,
3224dac1
KL
4094 "Terminal type %s is not defined",
4095 "Terminal type %s is not defined.\n\
b0347178
KH
4096If that is not the actual type of terminal you have,\n\
4097use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
84164a0d
SM
4098`setenv TERM ...') to specify the correct type. It may be necessary\n"
4099#ifdef TERMINFO
4100"to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
b0347178 4101#else
84164a0d 4102"to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
b0347178 4103#endif
84164a0d 4104 terminal_type);
b0347178 4105 }
6b61353c 4106
1fc8eb33 4107 area = tty->termcap_strings_buffer;
fca177d4
KL
4108 tty->TS_ins_line = tgetstr ("al", address);
4109 tty->TS_ins_multi_lines = tgetstr ("AL", address);
4110 tty->TS_bell = tgetstr ("bl", address);
6548cf00 4111 BackTab (tty) = tgetstr ("bt", address);
fca177d4
KL
4112 tty->TS_clr_to_bottom = tgetstr ("cd", address);
4113 tty->TS_clr_line = tgetstr ("ce", address);
4114 tty->TS_clr_frame = tgetstr ("cl", address);
6548cf00
KL
4115 ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
4116 AbsPosition (tty) = tgetstr ("cm", address);
4117 CR (tty) = tgetstr ("cr", address);
fca177d4
KL
4118 tty->TS_set_scroll_region = tgetstr ("cs", address);
4119 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
6548cf00 4120 RowPosition (tty) = tgetstr ("cv", address);
fca177d4
KL
4121 tty->TS_del_char = tgetstr ("dc", address);
4122 tty->TS_del_multi_chars = tgetstr ("DC", address);
4123 tty->TS_del_line = tgetstr ("dl", address);
4124 tty->TS_del_multi_lines = tgetstr ("DL", address);
4125 tty->TS_delete_mode = tgetstr ("dm", address);
4126 tty->TS_end_delete_mode = tgetstr ("ed", address);
4127 tty->TS_end_insert_mode = tgetstr ("ei", address);
6548cf00 4128 Home (tty) = tgetstr ("ho", address);
fca177d4
KL
4129 tty->TS_ins_char = tgetstr ("ic", address);
4130 tty->TS_ins_multi_chars = tgetstr ("IC", address);
4131 tty->TS_insert_mode = tgetstr ("im", address);
4132 tty->TS_pad_inserted_char = tgetstr ("ip", address);
4133 tty->TS_end_keypad_mode = tgetstr ("ke", address);
4134 tty->TS_keypad_mode = tgetstr ("ks", address);
6548cf00
KL
4135 LastLine (tty) = tgetstr ("ll", address);
4136 Right (tty) = tgetstr ("nd", address);
4137 Down (tty) = tgetstr ("do", address);
4138 if (!Down (tty))
a104f656 4139 Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do". */
08a24c47 4140 if (tgetflag ("bs"))
a104f656
SM
4141 Left (tty) = "\b"; /* Can't possibly be longer! */
4142 else /* (Actually, "bs" is obsolete...) */
6548cf00
KL
4143 Left (tty) = tgetstr ("le", address);
4144 if (!Left (tty))
a104f656 4145 Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le". */
fca177d4
KL
4146 tty->TS_pad_char = tgetstr ("pc", address);
4147 tty->TS_repeat = tgetstr ("rp", address);
4148 tty->TS_end_standout_mode = tgetstr ("se", address);
4149 tty->TS_fwd_scroll = tgetstr ("sf", address);
4150 tty->TS_standout_mode = tgetstr ("so", address);
4151 tty->TS_rev_scroll = tgetstr ("sr", address);
6548cf00 4152 tty->Wcm->cm_tab = tgetstr ("ta", address);
fca177d4
KL
4153 tty->TS_end_termcap_modes = tgetstr ("te", address);
4154 tty->TS_termcap_modes = tgetstr ("ti", address);
6548cf00 4155 Up (tty) = tgetstr ("up", address);
fca177d4
KL
4156 tty->TS_visible_bell = tgetstr ("vb", address);
4157 tty->TS_cursor_normal = tgetstr ("ve", address);
4158 tty->TS_cursor_visible = tgetstr ("vs", address);
4159 tty->TS_cursor_invisible = tgetstr ("vi", address);
4160 tty->TS_set_window = tgetstr ("wi", address);
4161
4162 tty->TS_enter_underline_mode = tgetstr ("us", address);
4163 tty->TS_exit_underline_mode = tgetstr ("ue", address);
4164 tty->TS_enter_bold_mode = tgetstr ("md", address);
cd4eb164 4165 tty->TS_enter_italic_mode = tgetstr ("ZH", address);
fca177d4 4166 tty->TS_enter_dim_mode = tgetstr ("mh", address);
fca177d4
KL
4167 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
4168 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
4169 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
4170 tty->TS_exit_attribute_mode = tgetstr ("me", address);
177c0ea7 4171
6548cf00
KL
4172 MultiUp (tty) = tgetstr ("UP", address);
4173 MultiDown (tty) = tgetstr ("DO", address);
4174 MultiLeft (tty) = tgetstr ("LE", address);
4175 MultiRight (tty) = tgetstr ("RI", address);
08a24c47 4176
5c32d3f2 4177 /* SVr4/ANSI color support. If "op" isn't available, don't support
e7f90eab
GM
4178 color because we can't switch back to the default foreground and
4179 background. */
fca177d4
KL
4180 tty->TS_orig_pair = tgetstr ("op", address);
4181 if (tty->TS_orig_pair)
a168702a 4182 {
fca177d4
KL
4183 tty->TS_set_foreground = tgetstr ("AF", address);
4184 tty->TS_set_background = tgetstr ("AB", address);
4185 if (!tty->TS_set_foreground)
e7f90eab
GM
4186 {
4187 /* SVr4. */
fca177d4
KL
4188 tty->TS_set_foreground = tgetstr ("Sf", address);
4189 tty->TS_set_background = tgetstr ("Sb", address);
e7f90eab 4190 }
177c0ea7 4191
fca177d4
KL
4192 tty->TN_max_colors = tgetnum ("Co");
4193 tty->TN_max_pairs = tgetnum ("pa");
177c0ea7 4194
fca177d4
KL
4195 tty->TN_no_color_video = tgetnum ("NC");
4196 if (tty->TN_no_color_video == -1)
4197 tty->TN_no_color_video = 0;
a168702a 4198 }
a168702a 4199
fca177d4 4200 tty_default_color_capabilities (tty, 1);
ace28297 4201
6548cf00 4202 MagicWrap (tty) = tgetflag ("xn");
e4058338
KH
4203 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
4204 the former flag imply the latter. */
6548cf00 4205 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
77e3b1b7 4206 tty->memory_below_frame = tgetflag ("db");
fca177d4 4207 tty->TF_hazeltine = tgetflag ("hz");
77e3b1b7 4208 tty->must_write_spaces = tgetflag ("in");
fca177d4
KL
4209 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
4210 tty->TF_insmode_motion = tgetflag ("mi");
4211 tty->TF_standout_motion = tgetflag ("ms");
4212 tty->TF_underscore = tgetflag ("ul");
4213 tty->TF_teleray = tgetflag ("xt");
08a24c47 4214
dce4c2ac
DN
4215#else /* DOS_NT */
4216#ifdef WINDOWSNT
4217 {
4218 struct frame *f = XFRAME (selected_frame);
9337e206 4219 int height, width;
dce4c2ac 4220
9337e206 4221 initialize_w32_display (terminal, &width, &height);
dce4c2ac 4222
9337e206
EZ
4223 FrameRows (tty) = height;
4224 FrameCols (tty) = width;
4225 tty->specified_window = height;
dce4c2ac 4226
dce4c2ac 4227 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
77e3b1b7 4228 tty->char_ins_del_ok = 1;
dce4c2ac
DN
4229 baud_rate = 19200;
4230 }
4231#else /* MSDOS */
4232 {
4233 int height, width;
4234 if (strcmp (terminal_type, "internal") == 0)
4235 terminal->type = output_msdos_raw;
4236 initialize_msdos_display (terminal);
4237
4238 get_tty_size (fileno (tty->input), &width, &height);
4239 FrameCols (tty) = width;
4240 FrameRows (tty) = height;
77e3b1b7 4241 tty->char_ins_del_ok = 0;
dce4c2ac
DN
4242 init_baud_rate (fileno (tty->input));
4243 }
4244#endif /* MSDOS */
4245 tty->output = stdout;
4246 tty->input = stdin;
4247 /* The following two are inaccessible from w32console.c. */
4248 terminal->delete_frame_hook = &tty_free_frame_resources;
4249 terminal->delete_terminal_hook = &delete_tty;
4250
4251 tty->name = xstrdup (name);
4252 terminal->name = xstrdup (name);
4253 tty->type = xstrdup (terminal_type);
4254
4255 add_keyboard_wait_descriptor (0);
4256
dce4c2ac
DN
4257 tty->delete_in_insert_mode = 1;
4258
4259 UseTabs (tty) = 0;
77e3b1b7 4260 tty->scroll_region_ok = 0;
dce4c2ac
DN
4261
4262 /* Seems to insert lines when it's not supposed to, messing up the
4263 display. In doing a trace, it didn't seem to be called much, so I
4264 don't think we're losing anything by turning it off. */
77e3b1b7 4265 tty->line_ins_del_ok = 0;
dce4c2ac 4266
a104f656 4267 tty->TN_max_colors = 16; /* Must be non-zero for tty-display-color-p. */
dce4c2ac
DN
4268#endif /* DOS_NT */
4269
6bc8cd65
JB
4270#ifdef HAVE_GPM
4271 terminal->mouse_position_hook = term_mouse_position;
4272 tty->mouse_highlight.mouse_face_window = Qnil;
4273#endif
4274
1afcba63 4275 terminal->kboard = allocate_kboard (Qnil);
6ed8eeff 4276 terminal->kboard->reference_count++;
e7cf0fa0
KL
4277 /* Don't let the initial kboard remain current longer than necessary.
4278 That would cause problems if a file loaded on startup tries to
4279 prompt in the mini-buffer. */
4280 if (current_kboard == initial_kboard)
6ed8eeff 4281 current_kboard = terminal->kboard;
84704c5c 4282#ifndef DOS_NT
6ed8eeff 4283 term_get_fkeys (address, terminal->kboard);
5c2c7893 4284
ff11dfa1 4285 /* Get frame size from system, or else from termcap. */
3b12ce12
RS
4286 {
4287 int height, width;
0b0d3e0b 4288 get_tty_size (fileno (tty->input), &width, &height);
0a125897
KL
4289 FrameCols (tty) = width;
4290 FrameRows (tty) = height;
3b12ce12
RS
4291 }
4292
0a125897
KL
4293 if (FrameCols (tty) <= 0)
4294 FrameCols (tty) = tgetnum ("co");
4295 if (FrameRows (tty) <= 0)
4296 FrameRows (tty) = tgetnum ("li");
177c0ea7 4297
0a125897 4298 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
d31eee5e 4299 maybe_fatal (must_succeed, terminal,
b3ffc17c 4300 "Screen size %dx%d is too small",
3224dac1 4301 "Screen size %dx%d is too small",
0a125897 4302 FrameCols (tty), FrameRows (tty));
ee7a2de4 4303
6548cf00 4304 TabWidth (tty) = tgetnum ("tw");
08a24c47 4305
fca177d4
KL
4306 if (!tty->TS_bell)
4307 tty->TS_bell = "\07";
08a24c47 4308
fca177d4
KL
4309 if (!tty->TS_fwd_scroll)
4310 tty->TS_fwd_scroll = Down (tty);
08a24c47 4311
fca177d4 4312 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
08a24c47 4313
6548cf00
KL
4314 if (TabWidth (tty) < 0)
4315 TabWidth (tty) = 8;
177c0ea7 4316
08a24c47
JB
4317/* Turned off since /etc/termcap seems to have :ta= for most terminals
4318 and newer termcap doc does not seem to say there is a default.
6548cf00
KL
4319 if (!tty->Wcm->cm_tab)
4320 tty->Wcm->cm_tab = "\t";
08a24c47
JB
4321*/
4322
54800acb
MB
4323 /* We don't support standout modes that use `magic cookies', so
4324 turn off any that do. */
fca177d4 4325 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
54800acb 4326 {
fca177d4
KL
4327 tty->TS_standout_mode = 0;
4328 tty->TS_end_standout_mode = 0;
54800acb 4329 }
fca177d4 4330 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
54800acb 4331 {
fca177d4
KL
4332 tty->TS_enter_underline_mode = 0;
4333 tty->TS_exit_underline_mode = 0;
54800acb
MB
4334 }
4335
4336 /* If there's no standout mode, try to use underlining instead. */
fca177d4 4337 if (tty->TS_standout_mode == 0)
08a24c47 4338 {
fca177d4
KL
4339 tty->TS_standout_mode = tty->TS_enter_underline_mode;
4340 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
08a24c47
JB
4341 }
4342
afd359c4
RS
4343 /* If no `se' string, try using a `me' string instead.
4344 If that fails, we can't use standout mode at all. */
fca177d4 4345 if (tty->TS_end_standout_mode == 0)
afd359c4 4346 {
e4bfb3b6 4347 char *s = tgetstr ("me", address);
afd359c4 4348 if (s != 0)
fca177d4 4349 tty->TS_end_standout_mode = s;
afd359c4 4350 else
fca177d4 4351 tty->TS_standout_mode = 0;
afd359c4
RS
4352 }
4353
fca177d4 4354 if (tty->TF_teleray)
08a24c47 4355 {
6548cf00 4356 tty->Wcm->cm_tab = 0;
54800acb 4357 /* We can't support standout mode, because it uses magic cookies. */
fca177d4 4358 tty->TS_standout_mode = 0;
a104f656 4359 /* But that means we cannot rely on ^M to go to column zero! */
6548cf00 4360 CR (tty) = 0;
a104f656
SM
4361 /* LF can't be trusted either -- can alter hpos. */
4362 /* If move at column 0 thru a line with TS_standout_mode. */
6548cf00 4363 Down (tty) = 0;
08a24c47
JB
4364 }
4365
0a125897 4366 tty->specified_window = FrameRows (tty);
08a24c47 4367
a104f656 4368 if (Wcm_init (tty) == -1) /* Can't do cursor motion. */
3224dac1 4369 {
d31eee5e 4370 maybe_fatal (must_succeed, terminal,
3224dac1 4371 "Terminal type \"%s\" is not powerful enough to run Emacs",
3224dac1 4372 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
37dad45a
RS
4373It lacks the ability to position the cursor.\n\
4374If that is not the actual type of terminal you have,\n\
4375use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
84164a0d
SM
4376`setenv TERM ...') to specify the correct type. It may be necessary\n"
4377# ifdef TERMINFO
4378"to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
37dad45a 4379# else /* TERMCAP */
84164a0d 4380"to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
37dad45a 4381# endif /* TERMINFO */
3224dac1 4382 terminal_type);
fca177d4 4383 }
daf01701 4384
0a125897 4385 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
d31eee5e 4386 maybe_fatal (must_succeed, terminal,
3224dac1
KL
4387 "Could not determine the frame size",
4388 "Could not determine the frame size");
08a24c47 4389
fca177d4
KL
4390 tty->delete_in_insert_mode
4391 = tty->TS_delete_mode && tty->TS_insert_mode
4392 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
08a24c47 4393
0b0d3e0b 4394 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
08a24c47 4395
77e3b1b7 4396 tty->scroll_region_ok
6548cf00 4397 = (tty->Wcm->cm_abs
fca177d4 4398 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
08a24c47 4399
77e3b1b7 4400 tty->line_ins_del_ok
fca177d4
KL
4401 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
4402 && (tty->TS_del_line || tty->TS_del_multi_lines))
77e3b1b7 4403 || (tty->scroll_region_ok
fca177d4 4404 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
08a24c47 4405
77e3b1b7 4406 tty->char_ins_del_ok
fca177d4
KL
4407 = ((tty->TS_ins_char || tty->TS_insert_mode
4408 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
4409 && (tty->TS_del_char || tty->TS_del_multi_chars));
08a24c47 4410
0b0d3e0b 4411 init_baud_rate (fileno (tty->input));
20a558dc 4412
84704c5c 4413#endif /* not DOS_NT */
635e3b29 4414
0a125897
KL
4415 /* Init system terminal modes (RAW or CBREAK, etc.). */
4416 init_sys_modes (tty);
daf01701 4417
6ed8eeff 4418 return terminal;
08a24c47
JB
4419}
4420
b3ffc17c
DN
4421
4422static void
4423vfatal (const char *str, va_list ap)
4424{
4425 fprintf (stderr, "emacs: ");
4426 vfprintf (stderr, str, ap);
4427 if (!(strlen (str) > 0 && str[strlen (str) - 1] == '\n'))
4428 fprintf (stderr, "\n");
b3ffc17c
DN
4429 fflush (stderr);
4430 exit (1);
4431}
4432
4433
a4c6993d 4434/* Auxiliary error-handling function for init_tty.
d31eee5e 4435 Delete TERMINAL, then call error or fatal with str1 or str2,
653d4f43 4436 respectively, according to whether MUST_SUCCEED is true. */
6b61353c 4437
3224dac1 4438static void
653d4f43 4439maybe_fatal (bool must_succeed, struct terminal *terminal,
b3ffc17c 4440 const char *str1, const char *str2, ...)
3224dac1 4441{
b3ffc17c
DN
4442 va_list ap;
4443 va_start (ap, str2);
6ed8eeff
KL
4444 if (terminal)
4445 delete_tty (terminal);
f4d953fc 4446
3224dac1 4447 if (must_succeed)
b3ffc17c 4448 vfatal (str2, ap);
3224dac1 4449 else
b3ffc17c 4450 verror (str1, ap);
08a24c47
JB
4451}
4452
dfcf069d 4453void
7c401d15 4454fatal (const char *str, ...)
08a24c47 4455{
7c401d15
DN
4456 va_list ap;
4457 va_start (ap, str);
b3ffc17c 4458 vfatal (str, ap);
08a24c47 4459}
07c57952 4460
819b8f00
KL
4461\f
4462
6ed8eeff 4463/* Delete the given tty terminal, closing all frames on it. */
da8e1115 4464
ed8dad6b 4465static void
6ed8eeff 4466delete_tty (struct terminal *terminal)
072d84a6 4467{
428a555e 4468 struct tty_display_info *tty;
f4d953fc 4469
e2749141 4470 /* Protect against recursive calls. delete_frame in
ab797f65 4471 delete_terminal calls us back when it deletes our last frame. */
59a7bc63 4472 if (!terminal->name)
0a125897 4473 return;
fca177d4 4474
9c253307 4475 eassert (terminal->type == output_termcap);
428a555e 4476
6ed8eeff 4477 tty = terminal->display_info.tty;
f4d953fc 4478
fca177d4
KL
4479 if (tty == tty_list)
4480 tty_list = tty->next;
4481 else
4482 {
28d7d09f 4483 struct tty_display_info *p;
fca177d4
KL
4484 for (p = tty_list; p && p->next != tty; p = p->next)
4485 ;
4486
4487 if (! p)
4488 /* This should not happen. */
1088b922 4489 emacs_abort ();
fca177d4 4490
0a125897
KL
4491 p->next = tty->next;
4492 tty->next = 0;
fca177d4
KL
4493 }
4494
7e59217d 4495 /* reset_sys_modes needs a valid device, so this call needs to be
6ed8eeff 4496 before delete_terminal. */
04c3243c 4497 reset_sys_modes (tty);
fca177d4 4498
6ed8eeff 4499 delete_terminal (terminal);
3224dac1 4500
70fdbb46
JM
4501 xfree (tty->name);
4502 xfree (tty->type);
daf01701 4503
fca177d4 4504 if (tty->input)
819b8f00
KL
4505 {
4506 delete_keyboard_wait_descriptor (fileno (tty->input));
4507 if (tty->input != stdin)
4508 fclose (tty->input);
4509 }
4510 if (tty->output && tty->output != stdout && tty->output != tty->input)
fca177d4
KL
4511 fclose (tty->output);
4512 if (tty->termscript)
4513 fclose (tty->termscript);
daf01701 4514
70fdbb46
JM
4515 xfree (tty->old_tty);
4516 xfree (tty->Wcm);
fca177d4 4517 xfree (tty);
fca177d4
KL
4518}
4519
dfcf069d 4520void
d3da34e0 4521syms_of_term (void)
07c57952 4522{
29208e82 4523 DEFVAR_BOOL ("system-uses-terminfo", system_uses_terminfo,
7ee72033 4524 doc: /* Non-nil means the system uses terminfo rather than termcap.
228299fa 4525This variable can be used by terminal emulator packages. */);
07c57952
KH
4526#ifdef TERMINFO
4527 system_uses_terminfo = 1;
4528#else
4529 system_uses_terminfo = 0;
4530#endif
c291d9ef 4531
29208e82 4532 DEFVAR_LISP ("suspend-tty-functions", Vsuspend_tty_functions,
e5d9c0d1 4533 doc: /* Functions run after suspending a tty.
fdc496e7 4534The functions are run with one argument, the terminal object to be suspended.
0b0d3e0b 4535See `suspend-tty'. */);
e4019195 4536 Vsuspend_tty_functions = Qnil;
0b0d3e0b
KL
4537
4538
29208e82 4539 DEFVAR_LISP ("resume-tty-functions", Vresume_tty_functions,
e5d9c0d1 4540 doc: /* Functions run after resuming a tty.
fdc496e7 4541The functions are run with one argument, the terminal object that was revived.
0b0d3e0b 4542See `resume-tty'. */);
e4019195 4543 Vresume_tty_functions = Qnil;
a168702a 4544
29208e82 4545 DEFVAR_BOOL ("visible-cursor", visible_cursor,
0db017c0
SM
4546 doc: /* Non-nil means to make the cursor very visible.
4547This only has an effect when running in a text terminal.
4548What means \"very visible\" is up to your terminal. It may make the cursor
4549bigger, or it may make it blink, or it may do nothing at all. */);
4550 visible_cursor = 1;
4551
a168702a 4552 defsubr (&Stty_display_color_p);
bfa62f96 4553 defsubr (&Stty_display_color_cells);
072d84a6 4554 defsubr (&Stty_no_underline);
6ed8eeff
KL
4555 defsubr (&Stty_type);
4556 defsubr (&Scontrolling_tty_p);
c6bf3022 4557 defsubr (&Stty_top_frame);
0b0d3e0b
KL
4558 defsubr (&Ssuspend_tty);
4559 defsubr (&Sresume_tty);
7e5a23bd 4560#ifdef HAVE_GPM
6178ce5e
SM
4561 defsubr (&Sgpm_mouse_start);
4562 defsubr (&Sgpm_mouse_stop);
7e5a23bd 4563#endif /* HAVE_GPM */
3a7c5d40 4564
84704c5c 4565#ifndef DOS_NT
3a7c5d40
CY
4566 default_orig_pair = NULL;
4567 default_set_foreground = NULL;
4568 default_set_background = NULL;
84704c5c 4569#endif /* !DOS_NT */
d31eee5e
CY
4570
4571 encode_terminal_src = NULL;
4572 encode_terminal_dst = NULL;
f0177f86 4573
df782309
EZ
4574 DEFSYM (Qtty_menu_next_item, "tty-menu-next-item");
4575 DEFSYM (Qtty_menu_prev_item, "tty-menu-prev-item");
4576 DEFSYM (Qtty_menu_next_menu, "tty-menu-next-menu");
4577 DEFSYM (Qtty_menu_prev_menu, "tty-menu-prev-menu");
4578 DEFSYM (Qtty_menu_select, "tty-menu-select");
4579 DEFSYM (Qtty_menu_ignore, "tty-menu-ignore");
4580 DEFSYM (Qtty_menu_exit, "tty-menu-exit");
e648f699 4581 DEFSYM (Qtty_menu_mouse_movement, "tty-menu-mouse-movement");
df782309 4582 DEFSYM (Qtty_menu_navigation_map, "tty-menu-navigation-map");
07c57952 4583}