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