* term.c (tty_menu_show) [!HAVE_NTGUI]: Now static.
[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 }
a55ea27f
EZ
2927 /* Take note of the coordinates of the active menu item, to
2928 display the cursor there. */
2929 if (mousehere)
2930 {
2931 row = y + i;
2932 col = x;
2933 }
ccd4a783
EZ
2934 display_tty_menu_item (menu->text[j], max_width, face, x, y + i,
2935 menu->submenu[j] != NULL);
b5e9cbb6
EZ
2936 }
2937 update_frame_with_menu (sf);
2938 cursor_to (sf, row, col);
2939}
2940
2941/* --------------------------- X Menu emulation ---------------------- */
2942
b5e9cbb6
EZ
2943/* Create a new pane and place it on the outer-most level. */
2944
e7873136
EZ
2945static int
2946tty_menu_add_pane (tty_menu *menu, const char *txt)
b5e9cbb6
EZ
2947{
2948 int len;
3b158d11 2949 const unsigned char *p;
b5e9cbb6
EZ
2950
2951 tty_menu_make_room (menu);
2952 menu->submenu[menu->count] = tty_menu_create ();
2953 menu->text[menu->count] = (char *)txt;
2954 menu->panenumber[menu->count] = ++menu->panecount;
2955 menu->help_text[menu->count] = NULL;
2956 menu->count++;
2957
2958 /* Update the menu width, if necessary. */
3b158d11 2959 for (len = 0, p = (unsigned char *) txt; *p; )
b5e9cbb6
EZ
2960 {
2961 int ch_len;
2962 int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
2963
2964 len += CHAR_WIDTH (ch);
2965 p += ch_len;
2966 }
2967
2968 if (len > menu->width)
2969 menu->width = len;
2970
2971 return menu->panecount;
2972}
2973
2974/* Create a new item in a menu pane. */
2975
798aef02 2976static bool
b5e9cbb6 2977tty_menu_add_selection (tty_menu *menu, int pane,
798aef02 2978 char *txt, bool enable, char const *help_text)
b5e9cbb6
EZ
2979{
2980 int len;
3b158d11 2981 unsigned char *p;
b5e9cbb6
EZ
2982
2983 if (pane)
798aef02
PE
2984 {
2985 menu = tty_menu_search_pane (menu, pane);
2986 if (! menu)
2987 return 0;
2988 }
b5e9cbb6
EZ
2989 tty_menu_make_room (menu);
2990 menu->submenu[menu->count] = (tty_menu *) 0;
2991 menu->text[menu->count] = txt;
2992 menu->panenumber[menu->count] = enable;
2993 menu->help_text[menu->count] = help_text;
2994 menu->count++;
2995
2996 /* Update the menu width, if necessary. */
3b158d11 2997 for (len = 0, p = (unsigned char *) txt; *p; )
b5e9cbb6
EZ
2998 {
2999 int ch_len;
3000 int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
3001
3002 len += CHAR_WIDTH (ch);
3003 p += ch_len;
3004 }
3005
3006 if (len > menu->width)
3007 menu->width = len;
3008
798aef02 3009 return 1;
b5e9cbb6
EZ
3010}
3011
3012/* Decide where the menu would be placed if requested at (X,Y). */
3013
3b158d11 3014static void
b5e9cbb6
EZ
3015tty_menu_locate (tty_menu *menu, int x, int y,
3016 int *ulx, int *uly, int *width, int *height)
3017{
3018 tty_menu_calc_size (menu, width, height);
3019 *ulx = x + 1;
3020 *uly = y;
3021 *width += 2;
3022}
3023
3024struct tty_menu_state
3025{
141f1ff7 3026 struct glyph_matrix *screen_behind;
b5e9cbb6
EZ
3027 tty_menu *menu;
3028 int pane;
3029 int x, y;
3030};
3031
f34729ea
EZ
3032/* Save away the contents of frame F's current frame matrix, and
3033 enable all its rows. Value is a glyph matrix holding the contents
3034 of F's current frame matrix with all its glyph rows enabled. */
3035
4ed77415 3036static struct glyph_matrix *
f34729ea
EZ
3037save_and_enable_current_matrix (struct frame *f)
3038{
3039 int i;
3040 struct glyph_matrix *saved = xzalloc (sizeof *saved);
3041 saved->nrows = f->current_matrix->nrows;
3042 saved->rows = xzalloc (saved->nrows * sizeof *saved->rows);
3043
3044 for (i = 0; i < saved->nrows; ++i)
3045 {
3046 struct glyph_row *from = f->current_matrix->rows + i;
3047 struct glyph_row *to = saved->rows + i;
3048 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
3049
3050 to->glyphs[TEXT_AREA] = xmalloc (nbytes);
3051 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
3052 to->used[TEXT_AREA] = from->used[TEXT_AREA];
3053 /* Make sure every row is enabled, or else update_frame will not
3054 redraw them. (Rows that are identical to what is already on
3055 screen will not be redrawn anyway.) */
96c06863 3056 to->enabled_p = true;
f34729ea 3057 to->hash = from->hash;
f34729ea
EZ
3058 }
3059
3060 return saved;
3061}
3062
141f1ff7
EZ
3063/* Restore the contents of frame F's desired frame matrix from SAVED,
3064 and free memory associated with SAVED. */
b5e9cbb6 3065
141f1ff7
EZ
3066static void
3067restore_desired_matrix (struct frame *f, struct glyph_matrix *saved)
3068{
3069 int i;
3070
3071 for (i = 0; i < saved->nrows; ++i)
3072 {
3073 struct glyph_row *from = saved->rows + i;
3074 struct glyph_row *to = f->desired_matrix->rows + i;
3075 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
3076
96114a30 3077 eassert (to->glyphs[TEXT_AREA] != from->glyphs[TEXT_AREA]);
141f1ff7
EZ
3078 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
3079 to->used[TEXT_AREA] = from->used[TEXT_AREA];
fa93733d
EZ
3080 to->enabled_p = from->enabled_p;
3081 to->hash = from->hash;
141f1ff7 3082 }
141f1ff7
EZ
3083}
3084
3085static void
3086free_saved_screen (struct glyph_matrix *saved)
3087{
3088 int i;
3089
3090 if (!saved)
caecb91c 3091 return; /* Already freed! */
141f1ff7
EZ
3092
3093 for (i = 0; i < saved->nrows; ++i)
3094 {
3095 struct glyph_row *from = saved->rows + i;
3096
3097 xfree (from->glyphs[TEXT_AREA]);
141f1ff7
EZ
3098 }
3099
3100 xfree (saved->rows);
3101 xfree (saved);
3102}
3103
3104/* Update the display of frame F from its saved contents. */
3105static void
3106screen_update (struct frame *f, struct glyph_matrix *mtx)
3107{
3108 restore_desired_matrix (f, mtx);
3109 update_frame_with_menu (f);
3110}
3111
ccd4a783
EZ
3112typedef enum {
3113 MI_QUIT_MENU = -1,
3114 MI_CONTINUE = 0,
3115 MI_ITEM_SELECTED = 1,
3116 MI_NEXT_ITEM = 2,
3117 MI_PREV_ITEM = 3,
3118 MI_SCROLL_FORWARD = 4,
3119 MI_SCROLL_BACK = 5
3120} mi_result;
0de83597 3121
ccd4a783
EZ
3122/* Read user input and return X and Y coordinates where that input
3123 puts us. We only consider mouse movement and click events, and
3124 keyboard movement commands; the rest are ignored. */
3125static mi_result
df782309
EZ
3126read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
3127 bool *first_time)
141f1ff7 3128{
ffc3882f
EZ
3129 if (*first_time)
3130 {
3131 *first_time = false;
3132 sf->mouse_moved = 1;
ffc3882f 3133 }
afd8eb2c 3134 else
141f1ff7 3135 {
7ace9265 3136 Lisp_Object cmd;
798aef02 3137 bool usable_input = 1;
ccd4a783 3138 mi_result st = MI_CONTINUE;
f34729ea 3139 struct tty_display_info *tty = FRAME_TTY (sf);
e648f699 3140 Lisp_Object saved_mouse_tracking = do_mouse_tracking;
f0177f86 3141
f34729ea
EZ
3142 /* Signal the keyboard reading routines we are displaying a menu
3143 on this terminal. */
3144 tty->showing_menu = 1;
e648f699
EZ
3145 /* We want mouse movements be reported by read_menu_command. */
3146 do_mouse_tracking = Qt;
7ace9265
EZ
3147 do {
3148 cmd = read_menu_command ();
e648f699 3149 } while (NILP (cmd));
f34729ea 3150 tty->showing_menu = 0;
e648f699 3151 do_mouse_tracking = saved_mouse_tracking;
7ace9265 3152
e96f7bf1
EZ
3153 if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit)
3154 /* If some input switched frames under our feet, exit the
3155 menu, since the menu faces are no longer valid, and the
3156 menu is no longer relevant anyway. */
3157 || sf != SELECTED_FRAME ())
ccd4a783 3158 return MI_QUIT_MENU;
e648f699 3159 if (EQ (cmd, Qtty_menu_mouse_movement))
3b158d11 3160 mouse_get_xy (x, y);
e648f699 3161 else if (EQ (cmd, Qtty_menu_next_menu))
4a48e94d
EZ
3162 {
3163 usable_input = 0;
ccd4a783 3164 st = MI_NEXT_ITEM;
4a48e94d 3165 }
df782309 3166 else if (EQ (cmd, Qtty_menu_prev_menu))
4a48e94d
EZ
3167 {
3168 usable_input = 0;
ccd4a783 3169 st = MI_PREV_ITEM;
4a48e94d 3170 }
df782309
EZ
3171 else if (EQ (cmd, Qtty_menu_next_item))
3172 {
3173 if (*y < max_y)
3174 *y += 1;
052bac0b 3175 else
ccd4a783 3176 st = MI_SCROLL_FORWARD;
df782309
EZ
3177 }
3178 else if (EQ (cmd, Qtty_menu_prev_item))
3179 {
3180 if (*y > min_y)
3181 *y -= 1;
052bac0b 3182 else
ccd4a783 3183 st = MI_SCROLL_BACK;
df782309
EZ
3184 }
3185 else if (EQ (cmd, Qtty_menu_select))
ccd4a783 3186 st = MI_ITEM_SELECTED;
df782309 3187 else if (!EQ (cmd, Qtty_menu_ignore))
e648f699 3188 usable_input = 0;
f0177f86
EZ
3189 if (usable_input)
3190 sf->mouse_moved = 1;
0de83597 3191 return st;
141f1ff7 3192 }
ccd4a783 3193 return MI_CONTINUE;
141f1ff7
EZ
3194}
3195
3196/* Display menu, wait for user's response, and return that response. */
4a48e94d 3197static int
b5e9cbb6
EZ
3198tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
3199 int x0, int y0, char **txt,
4a48e94d 3200 void (*help_callback)(char const *, int, int),
798aef02 3201 bool kbd_navigation)
b5e9cbb6
EZ
3202{
3203 struct tty_menu_state *state;
798aef02
PE
3204 int statecount, x, y, i;
3205 bool leave, onepane;
3b158d11 3206 int result IF_LINT (= 0);
caecb91c 3207 int title_faces[4]; /* Face to display the menu title. */
b5e9cbb6
EZ
3208 int faces[4], buffers_num_deleted = 0;
3209 struct frame *sf = SELECTED_FRAME ();
28a16449 3210 struct tty_display_info *tty = FRAME_TTY (sf);
ffc3882f 3211 bool first_time;
3b158d11 3212 Lisp_Object selectface;
ccd4a783 3213 int first_item = 0;
a55ea27f 3214 int col, row;
b5e9cbb6
EZ
3215
3216 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3217 around the display. */
3218 if (x0 <= 0)
3219 x0 = 1;
3220 if (y0 <= 0)
3221 y0 = 1;
3222
b5e9cbb6 3223 state = alloca (menu->panecount * sizeof (struct tty_menu_state));
141f1ff7 3224 memset (state, 0, sizeof (*state));
b5e9cbb6
EZ
3225 faces[0]
3226 = lookup_derived_face (sf, intern ("tty-menu-disabled-face"),
3227 DEFAULT_FACE_ID, 1);
3228 faces[1]
3229 = lookup_derived_face (sf, intern ("tty-menu-enabled-face"),
3230 DEFAULT_FACE_ID, 1);
3231 selectface = intern ("tty-menu-selected-face");
3232 faces[2] = lookup_derived_face (sf, selectface,
3233 faces[0], 1);
3234 faces[3] = lookup_derived_face (sf, selectface,
3235 faces[1], 1);
3236
3237 /* Make sure the menu title is always displayed with
50a5f95e 3238 `tty-menu-selected-face', no matter where the mouse pointer is. */
b5e9cbb6
EZ
3239 for (i = 0; i < 4; i++)
3240 title_faces[i] = faces[3];
3241
3242 statecount = 1;
3243
3244 /* Don't let the title for the "Buffers" popup menu include a
3245 digit (which is ugly).
3246
3247 This is a terrible kludge, but I think the "Buffers" case is
3248 the only one where the title includes a number, so it doesn't
3249 seem to be necessary to make this more general. */
3250 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3251 {
3252 menu->text[0][7] = '\0';
3253 buffers_num_deleted = 1;
3254 }
3255
141f1ff7
EZ
3256 /* Force update of the current frame, so that the desired and the
3257 current matrices are identical. */
3258 update_frame_with_menu (sf);
b5e9cbb6 3259 state[0].menu = menu;
f34729ea 3260 state[0].screen_behind = save_and_enable_current_matrix (sf);
b5e9cbb6 3261
ffc3882f
EZ
3262 /* Display the menu title. We subtract 1 from x0 and y0 because we
3263 want to interpret them as zero-based column and row coordinates,
3264 and also because we want the first item of the menu, not its
3265 title, to appear at x0,y0. */
ccd4a783 3266 tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0, 0);
6270e29e
EZ
3267
3268 /* Turn off the cursor. Otherwise it shows through the menu
3269 panes, which is ugly. */
28c05b69
EZ
3270 col = cursorX (tty);
3271 row = cursorY (tty);
6270e29e 3272 tty_hide_cursor (tty);
28c05b69 3273
b5e9cbb6
EZ
3274 if (buffers_num_deleted)
3275 menu->text[0][7] = ' ';
798aef02
PE
3276 onepane = menu->count == 1 && menu->submenu[0];
3277 if (onepane)
b5e9cbb6
EZ
3278 {
3279 menu->width = menu->submenu[0]->width;
3280 state[0].menu = menu->submenu[0];
3281 }
3282 else
3283 {
3284 state[0].menu = menu;
3285 }
3286 state[0].x = x0 - 1;
3287 state[0].y = y0;
3288 state[0].pane = onepane;
3289
141f1ff7
EZ
3290 x = state[0].x;
3291 y = state[0].y;
ffc3882f 3292 first_time = true;
141f1ff7 3293
b5e9cbb6
EZ
3294 leave = 0;
3295 while (!leave)
3296 {
ccd4a783 3297 mi_result input_status;
48621e69 3298 int min_y = state[0].y;
052bac0b 3299 int max_y = min (min_y + state[0].menu->count, FRAME_LINES (sf) - 1) - 1;
e7873136 3300
df782309 3301 input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
f0177f86
EZ
3302 if (input_status)
3303 {
4a48e94d 3304 leave = 1;
ccd4a783 3305 switch (input_status)
824682ea 3306 {
ccd4a783 3307 case MI_QUIT_MENU:
824682ea
EZ
3308 /* Remove the last help-echo, so that it doesn't
3309 re-appear after "Quit". */
3310 show_help_echo (Qnil, Qnil, Qnil, Qnil);
3311 result = TTYM_NO_SELECT;
ccd4a783
EZ
3312 break;
3313 case MI_NEXT_ITEM:
4a48e94d
EZ
3314 if (kbd_navigation)
3315 result = TTYM_NEXT;
3316 else
3317 leave = 0;
ccd4a783
EZ
3318 break;
3319 case MI_PREV_ITEM:
4a48e94d
EZ
3320 if (kbd_navigation)
3321 result = TTYM_PREV;
3322 else
3323 leave = 0;
ccd4a783
EZ
3324 break;
3325 case MI_SCROLL_FORWARD:
3326 if (y - min_y == state[0].menu->count - 1 - first_item)
3327 {
3328 y = min_y;
3329 first_item = 0;
3330 }
3331 else
3332 first_item++;
3333 leave = 0;
3334 break;
3335 case MI_SCROLL_BACK:
3336 if (first_item == 0)
3337 {
3338 y = max_y;
3339 first_item = state[0].menu->count - 1 - (y - min_y);
3340 }
3341 else
3342 first_item--;
3343 leave = 0;
3344 break;
3345 default:
3346 /* MI_ITEM_SELECTED is handled below, so nothing to do. */
3347 break;
4a48e94d 3348 }
f0177f86 3349 }
ccd4a783 3350 if (sf->mouse_moved && input_status != MI_QUIT_MENU)
b5e9cbb6
EZ
3351 {
3352 sf->mouse_moved = 0;
3353 result = TTYM_IA_SELECT;
b5e9cbb6
EZ
3354 for (i = 0; i < statecount; i++)
3355 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3356 {
ccd4a783 3357 int dy = y - state[i].y + first_item;
b5e9cbb6
EZ
3358 if (0 <= dy && dy < state[i].menu->count)
3359 {
3360 if (!state[i].menu->submenu[dy])
3361 {
3362 if (state[i].menu->panenumber[dy])
3363 result = TTYM_SUCCESS;
3364 else
3365 result = TTYM_IA_SELECT;
3366 }
3367 *pane = state[i].pane - 1;
3368 *selidx = dy;
3369 /* We hit some part of a menu, so drop extra menus that
3370 have been opened. That does not include an open and
3371 active submenu. */
3372 if (i != statecount - 2
caecb91c 3373 || state[i].menu->submenu[dy] != state[i + 1].menu)
b5e9cbb6
EZ
3374 while (i != statecount - 1)
3375 {
3376 statecount--;
e7873136 3377 screen_update (sf, state[statecount].screen_behind);
141f1ff7 3378 state[statecount].screen_behind = NULL;
b5e9cbb6
EZ
3379 }
3380 if (i == statecount - 1 && state[i].menu->submenu[dy])
3381 {
3382 tty_menu_display (state[i].menu,
b5e9cbb6 3383 state[i].x,
ffc3882f 3384 state[i].y,
b5e9cbb6 3385 state[i].pane,
ccd4a783 3386 faces, x, y, first_item, 1);
b5e9cbb6
EZ
3387 state[statecount].menu = state[i].menu->submenu[dy];
3388 state[statecount].pane = state[i].menu->panenumber[dy];
141f1ff7 3389 state[statecount].screen_behind
f34729ea 3390 = save_and_enable_current_matrix (sf);
b5e9cbb6
EZ
3391 state[statecount].x
3392 = state[i].x + state[i].menu->width + 2;
3393 state[statecount].y = y;
3394 statecount++;
3395 }
3396 }
3397 }
3398 tty_menu_display (state[statecount - 1].menu,
b5e9cbb6 3399 state[statecount - 1].x,
ffc3882f 3400 state[statecount - 1].y,
b5e9cbb6 3401 state[statecount - 1].pane,
ccd4a783 3402 faces, x, y, first_item, 1);
6270e29e
EZ
3403 tty_hide_cursor (tty);
3404 fflush (tty->output);
a55ea27f
EZ
3405 /* The call to display help-echo below will move the cursor,
3406 so remember its current position as computed by
3407 tty_menu_display. */
3408 col = cursorX (tty);
3409 row = cursorY (tty);
b5e9cbb6 3410 }
824682ea
EZ
3411
3412 /* Display the help-echo message for the currently-selected menu
3413 item. */
3414 if ((menu_help_message || prev_menu_help_message)
3415 && menu_help_message != prev_menu_help_message)
b5e9cbb6 3416 {
824682ea
EZ
3417 help_callback (menu_help_message,
3418 menu_help_paneno, menu_help_itemno);
a55ea27f
EZ
3419 /* Move the cursor to the beginning of the current menu
3420 item, so that screen readers and other accessibility aids
3421 know where the active region is. */
28c05b69 3422 cursor_to (sf, row, col);
824682ea 3423 tty_hide_cursor (tty);
6270e29e 3424 fflush (tty->output);
824682ea 3425 prev_menu_help_message = menu_help_message;
b5e9cbb6 3426 }
b5e9cbb6
EZ
3427 }
3428
ffc3882f 3429 sf->mouse_moved = 0;
141f1ff7 3430 screen_update (sf, state[0].screen_behind);
b5e9cbb6 3431 while (statecount--)
141f1ff7 3432 free_saved_screen (state[statecount].screen_behind);
caecb91c 3433 tty_show_cursor (tty); /* Turn cursor back on. */
9f6a18d2 3434 fflush (tty->output);
28a16449
EZ
3435
3436/* Clean up any mouse events that are waiting inside Emacs event queue.
b5e9cbb6
EZ
3437 These events are likely to be generated before the menu was even
3438 displayed, probably because the user pressed and released the button
3439 (which invoked the menu) too quickly. If we don't remove these events,
3440 Emacs will process them after we return and surprise the user. */
3441 discard_mouse_events ();
e7873136 3442 if (!kbd_buffer_events_waiting ())
b5e9cbb6 3443 clear_input_pending ();
b5e9cbb6
EZ
3444 return result;
3445}
3446
3447/* Dispose of a menu. */
3448
3b158d11 3449static void
b5e9cbb6
EZ
3450tty_menu_destroy (tty_menu *menu)
3451{
3452 int i;
3453 if (menu->allocated)
3454 {
3455 for (i = 0; i < menu->count; i++)
3456 if (menu->submenu[i])
3457 tty_menu_destroy (menu->submenu[i]);
3458 xfree (menu->text);
3459 xfree (menu->submenu);
3460 xfree (menu->panenumber);
3461 xfree (menu->help_text);
3462 }
3463 xfree (menu);
3464 menu_help_message = prev_menu_help_message = NULL;
3465}
3466
e7873136
EZ
3467/* Show help HELP_STRING, or clear help if HELP_STRING is null.
3468
3469 PANE is the pane number, and ITEM is the menu item number in
5cbcc455 3470 the menu (currently not used). */
e7873136
EZ
3471
3472static void
3473tty_menu_help_callback (char const *help_string, int pane, int item)
3474{
3475 Lisp_Object *first_item;
3476 Lisp_Object pane_name;
3477 Lisp_Object menu_object;
3478
91f2d272 3479 first_item = XVECTOR (menu_items)->contents;
e7873136
EZ
3480 if (EQ (first_item[0], Qt))
3481 pane_name = first_item[MENU_ITEMS_PANE_NAME];
3482 else if (EQ (first_item[0], Qquote))
3483 /* This shouldn't happen, see xmenu_show. */
3484 pane_name = empty_unibyte_string;
3485 else
3486 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
3487
3488 /* (menu-item MENU-NAME PANE-NUMBER) */
3489 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
3490 show_help_echo (help_string ? build_string (help_string) : Qnil,
3491 Qnil, menu_object, make_number (item));
3492}
3493
3494static void
3495tty_pop_down_menu (Lisp_Object arg)
3496{
3497 tty_menu *menu = XSAVE_POINTER (arg, 0);
3498
3499 block_input ();
3500 tty_menu_destroy (menu);
3501 unblock_input ();
3502}
3503
4a48e94d
EZ
3504/* Return the zero-based index of the last menu-bar item on frame F. */
3505static int
3506tty_menu_last_menubar_item (struct frame *f)
3507{
3508 int i = 0;
3509
3510 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3511 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3512 {
3513 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3514
3515 while (i < ASIZE (items))
3516 {
3517 Lisp_Object str;
3518
3519 str = AREF (items, i + 1);
3520 if (NILP (str))
3521 break;
3522 i += 4;
3523 }
caecb91c 3524 i -= 4; /* Went one too far! */
4a48e94d
EZ
3525 }
3526 return i;
3527}
3528
3529/* Find in frame F's menu bar the menu item that is next or previous
3530 to the item at X/Y, and return that item's position in X/Y. WHICH
3531 says which one--next or previous--item to look for. X and Y are
3532 measured in character cells. This should only be called on TTY
3533 frames. */
3534static void
3535tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
3536{
3537 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3538 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3539 {
3540 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3541 int last_i = tty_menu_last_menubar_item (f);
3542 int i, prev_x;
3543
3544 /* This loop assumes a single menu-bar line, and will fail to
3545 find an item if it is not in the first line. Note that
3546 make_lispy_event in keyboard.c makes the same assumption. */
3547 for (i = 0, prev_x = -1; i < ASIZE (items); i += 4)
3548 {
3549 Lisp_Object pos, str;
3550 int ix;
3551
3552 str = AREF (items, i + 1);
3553 pos = AREF (items, i + 3);
3554 if (NILP (str))
3555 return;
3556 ix = XINT (pos);
3557 if (ix <= *x
3558 /* We use <= so the blank between 2 items on a TTY is
3559 considered part of the previous item. */
3b158d11 3560 && *x <= ix + menu_item_width (SDATA (str)))
4a48e94d
EZ
3561 {
3562 /* Found current item. Now compute the X coordinate of
3563 the previous or next item. */
3564 if (which == TTYM_NEXT)
3565 {
3566 if (i < last_i)
3567 *x = XINT (AREF (items, i + 4 + 3));
3568 else
caecb91c 3569 *x = 0; /* Wrap around to the first item. */
4a48e94d
EZ
3570 }
3571 else if (prev_x < 0)
3572 {
3573 /* Wrap around to the last item. */
3574 *x = XINT (AREF (items, last_i + 3));
3575 }
3576 else
3577 *x = prev_x;
3578 return;
3579 }
3580 prev_x = ix;
3581 }
3582 }
3583}
3584
5dda54d6
PE
3585#ifndef HAVE_NTGUI
3586static
3587#endif
b5e9cbb6 3588Lisp_Object
cfd794af
DA
3589tty_menu_show (struct frame *f, int x, int y, int menuflags,
3590 Lisp_Object title, const char **error_name)
b5e9cbb6
EZ
3591{
3592 tty_menu *menu;
3593 int pane, selidx, lpane, status;
3594 Lisp_Object entry, pane_prefix;
3595 char *datap;
3596 int ulx, uly, width, height;
4a48e94d 3597 int item_x, item_y;
b5e9cbb6
EZ
3598 int dispwidth, dispheight;
3599 int i, j, lines, maxlines;
3600 int maxwidth;
9428abbf 3601 ptrdiff_t specpdl_count;
b5e9cbb6 3602
9428abbf 3603 eassert (FRAME_TERMCAP_P (f));
b5e9cbb6
EZ
3604
3605 *error_name = 0;
3606 if (menu_items_n_panes == 0)
3607 return Qnil;
3608
3609 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
3610 {
3611 *error_name = "Empty menu";
3612 return Qnil;
3613 }
3614
3615 /* Make the menu on that window. */
3616 menu = tty_menu_create ();
3617 if (menu == NULL)
3618 {
3619 *error_name = "Can't create menu";
3620 return Qnil;
3621 }
3622
3623 /* Don't GC while we prepare and show the menu, because we give the
3624 menu functions pointers to the contents of strings. */
9428abbf 3625 specpdl_count = inhibit_garbage_collection ();
b5e9cbb6 3626
cfd794af
DA
3627 /* Avoid crashes if, e.g., another client will connect while we
3628 are in a menu. */
3629 temporarily_switch_to_single_kboard (f);
3630
b5e9cbb6 3631 /* Adjust coordinates to be root-window-relative. */
4a48e94d
EZ
3632 item_x = x += f->left_pos;
3633 item_y = y += f->top_pos;
b5e9cbb6
EZ
3634
3635 /* Create all the necessary panes and their items. */
3636 maxwidth = maxlines = lines = i = 0;
3637 lpane = TTYM_FAILURE;
3638 while (i < menu_items_used)
3639 {
dfe3ac02 3640 if (EQ (AREF (menu_items, i), Qt))
b5e9cbb6
EZ
3641 {
3642 /* Create a new pane. */
3643 Lisp_Object pane_name, prefix;
3644 const char *pane_string;
3645
3646 maxlines = max (maxlines, lines);
3647 lines = 0;
dfe3ac02
EZ
3648 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
3649 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
b5e9cbb6
EZ
3650 pane_string = (NILP (pane_name)
3651 ? "" : SSDATA (pane_name));
cfd794af 3652 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
b5e9cbb6
EZ
3653 pane_string++;
3654
3655 lpane = tty_menu_add_pane (menu, pane_string);
3656 if (lpane == TTYM_FAILURE)
3657 {
3658 tty_menu_destroy (menu);
3659 *error_name = "Can't create pane";
9428abbf
DA
3660 entry = Qnil;
3661 goto tty_menu_end;
b5e9cbb6
EZ
3662 }
3663 i += MENU_ITEMS_PANE_LENGTH;
3664
3665 /* Find the width of the widest item in this pane. */
3666 j = i;
3667 while (j < menu_items_used)
3668 {
3669 Lisp_Object item;
dfe3ac02 3670 item = AREF (menu_items, j);
b5e9cbb6
EZ
3671 if (EQ (item, Qt))
3672 break;
3673 if (NILP (item))
3674 {
3675 j++;
3676 continue;
3677 }
3678 width = SBYTES (item);
3679 if (width > maxwidth)
3680 maxwidth = width;
3681
3682 j += MENU_ITEMS_ITEM_LENGTH;
3683 }
3684 }
3685 /* Ignore a nil in the item list.
3686 It's meaningful only for dialog boxes. */
dfe3ac02 3687 else if (EQ (AREF (menu_items, i), Qquote))
b5e9cbb6
EZ
3688 i += 1;
3689 else
3690 {
3691 /* Create a new item within current pane. */
3692 Lisp_Object item_name, enable, descrip, help;
3693 char *item_data;
3694 char const *help_string;
3695
dfe3ac02
EZ
3696 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
3697 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
3698 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
3699 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
b5e9cbb6
EZ
3700 help_string = STRINGP (help) ? SSDATA (help) : NULL;
3701
3702 if (!NILP (descrip))
3703 {
caecb91c 3704 /* If alloca is fast, use that to make the space,
b5e9cbb6
EZ
3705 to reduce gc needs. */
3706 item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1);
3707 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
3708 for (j = SCHARS (item_name); j < maxwidth; j++)
3709 item_data[j] = ' ';
3710 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
3711 item_data[j + SBYTES (descrip)] = 0;
3712 }
3713 else
3714 item_data = SSDATA (item_name);
3715
3716 if (lpane == TTYM_FAILURE
798aef02
PE
3717 || (! tty_menu_add_selection (menu, lpane, item_data,
3718 !NILP (enable), help_string)))
b5e9cbb6
EZ
3719 {
3720 tty_menu_destroy (menu);
3721 *error_name = "Can't add selection to menu";
9428abbf
DA
3722 entry = Qnil;
3723 goto tty_menu_end;
b5e9cbb6
EZ
3724 }
3725 i += MENU_ITEMS_ITEM_LENGTH;
3726 lines++;
3727 }
3728 }
3729
3730 maxlines = max (maxlines, lines);
3731
3732 /* All set and ready to fly. */
3733 dispwidth = f->text_cols;
3734 dispheight = f->text_lines;
3735 x = min (x, dispwidth);
3736 y = min (y, dispheight);
3737 x = max (x, 1);
3738 y = max (y, 1);
3739 tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
9428abbf 3740 if (ulx + width > dispwidth)
b5e9cbb6
EZ
3741 {
3742 x -= (ulx + width) - dispwidth;
3743 ulx = dispwidth - width;
3744 }
9428abbf 3745 if (uly + height > dispheight)
b5e9cbb6
EZ
3746 {
3747 y -= (uly + height) - dispheight;
3748 uly = dispheight - height;
3749 }
3750
caecb91c 3751 if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 2)
b5e9cbb6
EZ
3752 {
3753 /* Move the menu away of the echo area, to avoid overwriting the
3754 menu with help echo messages or vice versa. */
3755 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
3756 {
df782309
EZ
3757 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
3758 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
b5e9cbb6
EZ
3759 }
3760 else
3761 {
df782309
EZ
3762 y -= 2;
3763 uly -= 2;
b5e9cbb6
EZ
3764 }
3765 }
3766
3767 if (ulx < 0) x -= ulx;
3768 if (uly < 0) y -= uly;
3769
a01f89af
EZ
3770#if 0
3771 /* This code doesn't make sense on a TTY, since it can easily annul
3772 the adjustments above that carefully avoid truncation of the menu
5cbcc455
EZ
3773 items. I think it was written to fix some problem that only
3774 happens on X11. */
b5e9cbb6
EZ
3775 if (! for_click)
3776 {
3777 /* If position was not given by a mouse click, adjust so upper left
3778 corner of the menu as a whole ends up at given coordinates. This
3779 is what x-popup-menu says in its documentation. */
caecb91c
SM
3780 x += width / 2;
3781 y += 1.5 * height / (maxlines + 2);
b5e9cbb6 3782 }
a01f89af 3783#endif
b5e9cbb6
EZ
3784
3785 pane = selidx = 0;
3786
e7873136 3787 record_unwind_protect (tty_pop_down_menu, make_save_ptr (menu));
b5e9cbb6 3788
df782309
EZ
3789 specbind (Qoverriding_terminal_local_map,
3790 Fsymbol_value (Qtty_menu_navigation_map));
b5e9cbb6 3791 status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
cfd794af
DA
3792 tty_menu_help_callback,
3793 menuflags & MENU_KBD_NAVIGATION);
b5e9cbb6
EZ
3794 entry = pane_prefix = Qnil;
3795
3796 switch (status)
3797 {
3798 case TTYM_SUCCESS:
3799 /* Find the item number SELIDX in pane number PANE. */
3800 i = 0;
3801 while (i < menu_items_used)
3802 {
dfe3ac02 3803 if (EQ (AREF (menu_items, i), Qt))
b5e9cbb6
EZ
3804 {
3805 if (pane == 0)
3806 pane_prefix
dfe3ac02 3807 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
b5e9cbb6
EZ
3808 pane--;
3809 i += MENU_ITEMS_PANE_LENGTH;
3810 }
3811 else
3812 {
3813 if (pane == -1)
3814 {
3815 if (selidx == 0)
3816 {
3817 entry
dfe3ac02 3818 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
cfd794af 3819 if (menuflags & MENU_KEYMAPS)
b5e9cbb6
EZ
3820 {
3821 entry = Fcons (entry, Qnil);
3822 if (!NILP (pane_prefix))
3823 entry = Fcons (pane_prefix, entry);
3824 }
3825 break;
3826 }
3827 selidx--;
3828 }
3829 i += MENU_ITEMS_ITEM_LENGTH;
3830 }
3831 }
3832 break;
3833
4a48e94d
EZ
3834 case TTYM_NEXT:
3835 case TTYM_PREV:
3836 tty_menu_new_item_coords (f, status, &item_x, &item_y);
3837 entry = Fcons (make_number (item_x), make_number (item_y));
3838 break;
3839
b5e9cbb6
EZ
3840 case TTYM_FAILURE:
3841 *error_name = "Can't activate menu";
3842 case TTYM_IA_SELECT:
3843 break;
3844 case TTYM_NO_SELECT:
e96f7bf1
EZ
3845 /* If the selected frame was changed while we displayed a menu,
3846 throw to top level in order to undo any temporary settings
3847 made by TTY menu code. */
3848 if (f != SELECTED_FRAME ())
3849 Ftop_level ();
b5e9cbb6
EZ
3850 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
3851 the menu was invoked with a mouse event as POSITION). */
cfd794af 3852 if (!(menuflags & MENU_FOR_CLICK))
b5e9cbb6
EZ
3853 Fsignal (Qquit, Qnil);
3854 break;
3855 }
3856
9428abbf 3857 tty_menu_end:
b5e9cbb6 3858
9428abbf 3859 unbind_to (specpdl_count, Qnil);
b5e9cbb6
EZ
3860 return entry;
3861}
3862
7cdf484b 3863#endif /* !MSDOS */
b5e9cbb6
EZ
3864
3865\f
89ba96f4 3866#ifndef MSDOS
a168702a
GM
3867/***********************************************************************
3868 Initialization
3869 ***********************************************************************/
3870
ed8dad6b 3871/* Initialize the tty-dependent part of frame F. The frame must
7cdf484b 3872 already have its device initialized. */
3224dac1 3873
dfcf069d 3874void
ed8dad6b 3875create_tty_output (struct frame *f)
28d440ab 3876{
38182d90 3877 struct tty_output *t = xzalloc (sizeof *t);
ed8dad6b 3878
9c253307 3879 eassert (FRAME_TERMCAP_P (f));
428a555e 3880
6ed8eeff 3881 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
bedb9c0e 3882
ed8dad6b 3883 f->output_data.tty = t;
3224dac1
KL
3884}
3885
7cdf484b 3886/* Delete frame F's face cache, and its tty-dependent part. */
da8e1115 3887
ed8dad6b 3888static void
9f215d25 3889tty_free_frame_resources (struct frame *f)
3224dac1 3890{
9c253307 3891 eassert (FRAME_TERMCAP_P (f));
5a80236f 3892 free_frame_faces (f);
ed8dad6b 3893 xfree (f->output_data.tty);
28d440ab
KL
3894}
3895
89ba96f4
EZ
3896#else /* MSDOS */
3897
7cdf484b 3898/* Delete frame F's face cache. */
89ba96f4
EZ
3899
3900static void
3901tty_free_frame_resources (struct frame *f)
3902{
9c253307 3903 eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
5a80236f 3904 free_frame_faces (f);
89ba96f4
EZ
3905}
3906#endif /* MSDOS */
ed8dad6b 3907\f
47cc8819 3908/* Reset the hooks in TERMINAL. */
ed8dad6b 3909
4a665758
KL
3910static void
3911clear_tty_hooks (struct terminal *terminal)
3912{
3913 terminal->rif = 0;
3914 terminal->cursor_to_hook = 0;
3915 terminal->raw_cursor_to_hook = 0;
3916 terminal->clear_to_end_hook = 0;
3917 terminal->clear_frame_hook = 0;
3918 terminal->clear_end_of_line_hook = 0;
3919 terminal->ins_del_lines_hook = 0;
3920 terminal->insert_glyphs_hook = 0;
3921 terminal->write_glyphs_hook = 0;
3922 terminal->delete_glyphs_hook = 0;
3923 terminal->ring_bell_hook = 0;
3924 terminal->reset_terminal_modes_hook = 0;
3925 terminal->set_terminal_modes_hook = 0;
3926 terminal->update_begin_hook = 0;
3927 terminal->update_end_hook = 0;
3928 terminal->set_terminal_window_hook = 0;
3929 terminal->mouse_position_hook = 0;
3930 terminal->frame_rehighlight_hook = 0;
3931 terminal->frame_raise_lower_hook = 0;
974b73e8 3932 terminal->fullscreen_hook = 0;
cfd794af 3933 terminal->menu_show_hook = 0;
4a665758
KL
3934 terminal->set_vertical_scroll_bar_hook = 0;
3935 terminal->condemn_scroll_bars_hook = 0;
3936 terminal->redeem_scroll_bar_hook = 0;
3937 terminal->judge_scroll_bars_hook = 0;
3938 terminal->read_socket_hook = 0;
3939 terminal->frame_up_to_date_hook = 0;
3940
3941 /* Leave these two set, or suspended frames are not deleted
3942 correctly. */
9f215d25 3943 terminal->delete_frame_hook = &tty_free_frame_resources;
4a665758
KL
3944 terminal->delete_terminal_hook = &delete_tty;
3945}
3946
47cc8819
DN
3947/* Initialize hooks in TERMINAL with the values needed for a tty. */
3948
4a665758
KL
3949static void
3950set_tty_hooks (struct terminal *terminal)
3951{
4a665758
KL
3952 terminal->cursor_to_hook = &tty_cursor_to;
3953 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
4a665758
KL
3954 terminal->clear_to_end_hook = &tty_clear_to_end;
3955 terminal->clear_frame_hook = &tty_clear_frame;
3956 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
4a665758 3957 terminal->ins_del_lines_hook = &tty_ins_del_lines;
4a665758
KL
3958 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3959 terminal->write_glyphs_hook = &tty_write_glyphs;
3960 terminal->delete_glyphs_hook = &tty_delete_glyphs;
4a665758 3961 terminal->ring_bell_hook = &tty_ring_bell;
4a665758
KL
3962 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3963 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
4a665758 3964 terminal->update_end_hook = &tty_update_end;
cfd794af 3965 terminal->menu_show_hook = &tty_menu_show;
4a665758 3966 terminal->set_terminal_window_hook = &tty_set_terminal_window;
4a665758 3967 terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
9f215d25 3968 terminal->delete_frame_hook = &tty_free_frame_resources;
4a665758 3969 terminal->delete_terminal_hook = &delete_tty;
6f1d9822 3970 /* Other hooks are NULL by default. */
4a665758
KL
3971}
3972
b8956427 3973/* If FD is the controlling terminal, drop it. */
ed8dad6b 3974static void
03a1d6bd
KL
3975dissociate_if_controlling_tty (int fd)
3976{
b8956427
PE
3977 /* If tcgetpgrp succeeds, fd is the controlling terminal,
3978 so dissociate it by invoking setsid. */
908589fd 3979 if (tcgetpgrp (fd) >= 0 && setsid () < 0)
b8956427
PE
3980 {
3981#ifdef TIOCNOTTY
3982 /* setsid failed, presumably because Emacs is already a process
3983 group leader. Fall back on the obsolescent way to dissociate
3984 a controlling tty. */
1e952f0a
PE
3985 sigset_t oldset;
3986 block_tty_out_signal (&oldset);
b8956427 3987 ioctl (fd, TIOCNOTTY, 0);
1e952f0a 3988 unblock_tty_out_signal (&oldset);
b8956427
PE
3989#endif
3990 }
03a1d6bd
KL
3991}
3992
3224dac1
KL
3993/* Create a termcap display on the tty device with the given name and
3994 type.
3995
ab797f65 3996 If NAME is NULL, then use the controlling tty, i.e., "/dev/tty".
3224dac1
KL
3997 Otherwise NAME should be a path to the tty device file,
3998 e.g. "/dev/pts/7".
28d440ab 3999
3224dac1
KL
4000 TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
4001
a104f656 4002 If MUST_SUCCEED is true, then all errors are fatal. */
da8e1115 4003
6ed8eeff 4004struct terminal *
653d4f43 4005init_tty (const char *name, const char *terminal_type, bool must_succeed)
08a24c47 4006{
1fc8eb33 4007 char *area;
08a24c47 4008 char **address = &area;
08a24c47 4009 int status;
59b3194c
KL
4010 struct tty_display_info *tty = NULL;
4011 struct terminal *terminal = NULL;
1e952f0a 4012 sigset_t oldset;
a104f656 4013 bool ctty = false; /* True if asked to open controlling tty. */
28d440ab 4014
3224dac1 4015 if (!terminal_type)
d31eee5e 4016 maybe_fatal (must_succeed, 0,
3224dac1
KL
4017 "Unknown terminal type",
4018 "Unknown terminal type");
b6660415 4019
ab797f65 4020 if (name == NULL)
78048085
EZ
4021 name = DEV_TTY;
4022 if (!strcmp (name, DEV_TTY))
ab797f65
KL
4023 ctty = 1;
4024
6ed8eeff
KL
4025 /* If we already have a terminal on the given device, use that. If
4026 all such terminals are suspended, create a new one instead. */
a4c6993d 4027 /* XXX Perhaps this should be made explicit by having init_tty
6ed8eeff 4028 always create a new terminal and separating terminal and frame
b6660415 4029 creation on Lisp level. */
6ed8eeff
KL
4030 terminal = get_named_tty (name);
4031 if (terminal)
4032 return terminal;
78048085 4033
6f1d9822 4034 terminal = create_terminal (output_termcap, NULL);
84704c5c
EZ
4035#ifdef MSDOS
4036 if (been_here > 0)
762b15be 4037 maybe_fatal (0, 0, "Attempt to create another terminal %s", "",
84704c5c
EZ
4038 name, "");
4039 been_here = 1;
4040 tty = &the_only_display_info;
4041#else
38182d90 4042 tty = xzalloc (sizeof *tty);
84704c5c 4043#endif
c650a5de 4044 tty->top_frame = Qnil;
3224dac1
KL
4045 tty->next = tty_list;
4046 tty_list = tty;
428a555e 4047
6ed8eeff
KL
4048 terminal->display_info.tty = tty;
4049 tty->terminal = terminal;
28d440ab 4050
38182d90 4051 tty->Wcm = xmalloc (sizeof *tty->Wcm);
7b00d185 4052 Wcm_clear (tty);
daf01701 4053
dce4c2ac
DN
4054 encode_terminal_src_size = 0;
4055 encode_terminal_dst_size = 0;
4056
51b59d79 4057
84704c5c 4058#ifndef DOS_NT
4a665758 4059 set_tty_hooks (terminal);
78048085 4060
59b3194c 4061 {
49cdacda 4062 /* Open the terminal device. */
0c72d684 4063
49cdacda
PE
4064 /* If !ctty, don't recognize it as our controlling terminal, and
4065 don't make it the controlling tty if we don't have one now.
4066
4067 Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
4068 defined on Hurd. On other systems, we need to explicitly
4069 dissociate ourselves from the controlling tty when we want to
4070 open a frame on the same terminal. */
4071 int flags = O_RDWR | O_NOCTTY | (ctty ? 0 : O_IGNORE_CTTY);
4072 int fd = emacs_open (name, flags, 0);
a3116188
DC
4073 tty->input = tty->output =
4074 ((fd < 0 || ! isatty (fd))
4075 ? NULL
4076 : fdopen (fd, "w+"));
0c72d684 4077
ef30e638 4078 if (! tty->input)
59b3194c 4079 {
ef30e638 4080 char const *diagnostic
a3116188 4081 = (fd < 0) ? "Could not open file: %s" : "Not a tty device: %s";
ef30e638
PE
4082 emacs_close (fd);
4083 maybe_fatal (must_succeed, terminal, diagnostic, diagnostic, name);
59b3194c 4084 }
0c72d684 4085
ef30e638
PE
4086 tty->name = xstrdup (name);
4087 terminal->name = xstrdup (name);
4088
49cdacda 4089 if (!O_IGNORE_CTTY && !ctty)
03a1d6bd 4090 dissociate_if_controlling_tty (fd);
59b3194c 4091 }
78048085 4092
28d7d09f 4093 tty->type = xstrdup (terminal_type);
28d440ab 4094
819b8f00 4095 add_keyboard_wait_descriptor (fileno (tty->input));
08a24c47 4096
6548cf00 4097 Wcm_clear (tty);
08a24c47 4098
03a1d6bd 4099 /* On some systems, tgetent tries to access the controlling
a104f656 4100 terminal. */
1e952f0a 4101 block_tty_out_signal (&oldset);
b8956427 4102 status = tgetent (tty->termcap_term_buffer, terminal_type);
1fc8eb33
PE
4103 if (tty->termcap_term_buffer[TERMCAP_BUFFER_SIZE - 1])
4104 emacs_abort ();
1e952f0a 4105 unblock_tty_out_signal (&oldset);
78048085 4106
08a24c47 4107 if (status < 0)
b0347178
KH
4108 {
4109#ifdef TERMINFO
d31eee5e 4110 maybe_fatal (must_succeed, terminal,
3224dac1
KL
4111 "Cannot open terminfo database file",
4112 "Cannot open terminfo database file");
b0347178 4113#else
d31eee5e 4114 maybe_fatal (must_succeed, terminal,
3224dac1
KL
4115 "Cannot open termcap database file",
4116 "Cannot open termcap database file");
b0347178
KH
4117#endif
4118 }
08a24c47 4119 if (status == 0)
b0347178 4120 {
d31eee5e 4121 maybe_fatal (must_succeed, terminal,
3224dac1
KL
4122 "Terminal type %s is not defined",
4123 "Terminal type %s is not defined.\n\
b0347178
KH
4124If that is not the actual type of terminal you have,\n\
4125use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
84164a0d
SM
4126`setenv TERM ...') to specify the correct type. It may be necessary\n"
4127#ifdef TERMINFO
4128"to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
b0347178 4129#else
84164a0d 4130"to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
b0347178 4131#endif
84164a0d 4132 terminal_type);
b0347178 4133 }
6b61353c 4134
1fc8eb33 4135 area = tty->termcap_strings_buffer;
fca177d4
KL
4136 tty->TS_ins_line = tgetstr ("al", address);
4137 tty->TS_ins_multi_lines = tgetstr ("AL", address);
4138 tty->TS_bell = tgetstr ("bl", address);
6548cf00 4139 BackTab (tty) = tgetstr ("bt", address);
fca177d4
KL
4140 tty->TS_clr_to_bottom = tgetstr ("cd", address);
4141 tty->TS_clr_line = tgetstr ("ce", address);
4142 tty->TS_clr_frame = tgetstr ("cl", address);
6548cf00
KL
4143 ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
4144 AbsPosition (tty) = tgetstr ("cm", address);
4145 CR (tty) = tgetstr ("cr", address);
fca177d4
KL
4146 tty->TS_set_scroll_region = tgetstr ("cs", address);
4147 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
6548cf00 4148 RowPosition (tty) = tgetstr ("cv", address);
fca177d4
KL
4149 tty->TS_del_char = tgetstr ("dc", address);
4150 tty->TS_del_multi_chars = tgetstr ("DC", address);
4151 tty->TS_del_line = tgetstr ("dl", address);
4152 tty->TS_del_multi_lines = tgetstr ("DL", address);
4153 tty->TS_delete_mode = tgetstr ("dm", address);
4154 tty->TS_end_delete_mode = tgetstr ("ed", address);
4155 tty->TS_end_insert_mode = tgetstr ("ei", address);
6548cf00 4156 Home (tty) = tgetstr ("ho", address);
fca177d4
KL
4157 tty->TS_ins_char = tgetstr ("ic", address);
4158 tty->TS_ins_multi_chars = tgetstr ("IC", address);
4159 tty->TS_insert_mode = tgetstr ("im", address);
4160 tty->TS_pad_inserted_char = tgetstr ("ip", address);
4161 tty->TS_end_keypad_mode = tgetstr ("ke", address);
4162 tty->TS_keypad_mode = tgetstr ("ks", address);
6548cf00
KL
4163 LastLine (tty) = tgetstr ("ll", address);
4164 Right (tty) = tgetstr ("nd", address);
4165 Down (tty) = tgetstr ("do", address);
4166 if (!Down (tty))
a104f656 4167 Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do". */
08a24c47 4168 if (tgetflag ("bs"))
a104f656
SM
4169 Left (tty) = "\b"; /* Can't possibly be longer! */
4170 else /* (Actually, "bs" is obsolete...) */
6548cf00
KL
4171 Left (tty) = tgetstr ("le", address);
4172 if (!Left (tty))
a104f656 4173 Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le". */
fca177d4
KL
4174 tty->TS_pad_char = tgetstr ("pc", address);
4175 tty->TS_repeat = tgetstr ("rp", address);
4176 tty->TS_end_standout_mode = tgetstr ("se", address);
4177 tty->TS_fwd_scroll = tgetstr ("sf", address);
4178 tty->TS_standout_mode = tgetstr ("so", address);
4179 tty->TS_rev_scroll = tgetstr ("sr", address);
6548cf00 4180 tty->Wcm->cm_tab = tgetstr ("ta", address);
fca177d4
KL
4181 tty->TS_end_termcap_modes = tgetstr ("te", address);
4182 tty->TS_termcap_modes = tgetstr ("ti", address);
6548cf00 4183 Up (tty) = tgetstr ("up", address);
fca177d4
KL
4184 tty->TS_visible_bell = tgetstr ("vb", address);
4185 tty->TS_cursor_normal = tgetstr ("ve", address);
4186 tty->TS_cursor_visible = tgetstr ("vs", address);
4187 tty->TS_cursor_invisible = tgetstr ("vi", address);
4188 tty->TS_set_window = tgetstr ("wi", address);
4189
4190 tty->TS_enter_underline_mode = tgetstr ("us", address);
4191 tty->TS_exit_underline_mode = tgetstr ("ue", address);
4192 tty->TS_enter_bold_mode = tgetstr ("md", address);
cd4eb164 4193 tty->TS_enter_italic_mode = tgetstr ("ZH", address);
fca177d4 4194 tty->TS_enter_dim_mode = tgetstr ("mh", address);
fca177d4
KL
4195 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
4196 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
4197 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
4198 tty->TS_exit_attribute_mode = tgetstr ("me", address);
177c0ea7 4199
6548cf00
KL
4200 MultiUp (tty) = tgetstr ("UP", address);
4201 MultiDown (tty) = tgetstr ("DO", address);
4202 MultiLeft (tty) = tgetstr ("LE", address);
4203 MultiRight (tty) = tgetstr ("RI", address);
08a24c47 4204
5c32d3f2 4205 /* SVr4/ANSI color support. If "op" isn't available, don't support
e7f90eab
GM
4206 color because we can't switch back to the default foreground and
4207 background. */
fca177d4
KL
4208 tty->TS_orig_pair = tgetstr ("op", address);
4209 if (tty->TS_orig_pair)
a168702a 4210 {
fca177d4
KL
4211 tty->TS_set_foreground = tgetstr ("AF", address);
4212 tty->TS_set_background = tgetstr ("AB", address);
4213 if (!tty->TS_set_foreground)
e7f90eab
GM
4214 {
4215 /* SVr4. */
fca177d4
KL
4216 tty->TS_set_foreground = tgetstr ("Sf", address);
4217 tty->TS_set_background = tgetstr ("Sb", address);
e7f90eab 4218 }
177c0ea7 4219
fca177d4
KL
4220 tty->TN_max_colors = tgetnum ("Co");
4221 tty->TN_max_pairs = tgetnum ("pa");
177c0ea7 4222
fca177d4
KL
4223 tty->TN_no_color_video = tgetnum ("NC");
4224 if (tty->TN_no_color_video == -1)
4225 tty->TN_no_color_video = 0;
a168702a 4226 }
a168702a 4227
fca177d4 4228 tty_default_color_capabilities (tty, 1);
ace28297 4229
6548cf00 4230 MagicWrap (tty) = tgetflag ("xn");
e4058338
KH
4231 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
4232 the former flag imply the latter. */
6548cf00 4233 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
77e3b1b7 4234 tty->memory_below_frame = tgetflag ("db");
fca177d4 4235 tty->TF_hazeltine = tgetflag ("hz");
77e3b1b7 4236 tty->must_write_spaces = tgetflag ("in");
fca177d4
KL
4237 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
4238 tty->TF_insmode_motion = tgetflag ("mi");
4239 tty->TF_standout_motion = tgetflag ("ms");
4240 tty->TF_underscore = tgetflag ("ul");
4241 tty->TF_teleray = tgetflag ("xt");
08a24c47 4242
dce4c2ac
DN
4243#else /* DOS_NT */
4244#ifdef WINDOWSNT
4245 {
4246 struct frame *f = XFRAME (selected_frame);
9337e206 4247 int height, width;
dce4c2ac 4248
9337e206 4249 initialize_w32_display (terminal, &width, &height);
dce4c2ac 4250
9337e206
EZ
4251 FrameRows (tty) = height;
4252 FrameCols (tty) = width;
4253 tty->specified_window = height;
dce4c2ac 4254
dce4c2ac 4255 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
77e3b1b7 4256 tty->char_ins_del_ok = 1;
dce4c2ac
DN
4257 baud_rate = 19200;
4258 }
4259#else /* MSDOS */
4260 {
4261 int height, width;
4262 if (strcmp (terminal_type, "internal") == 0)
4263 terminal->type = output_msdos_raw;
4264 initialize_msdos_display (terminal);
4265
4266 get_tty_size (fileno (tty->input), &width, &height);
4267 FrameCols (tty) = width;
4268 FrameRows (tty) = height;
77e3b1b7 4269 tty->char_ins_del_ok = 0;
dce4c2ac
DN
4270 init_baud_rate (fileno (tty->input));
4271 }
4272#endif /* MSDOS */
4273 tty->output = stdout;
4274 tty->input = stdin;
4275 /* The following two are inaccessible from w32console.c. */
4276 terminal->delete_frame_hook = &tty_free_frame_resources;
4277 terminal->delete_terminal_hook = &delete_tty;
4278
4279 tty->name = xstrdup (name);
4280 terminal->name = xstrdup (name);
4281 tty->type = xstrdup (terminal_type);
4282
4283 add_keyboard_wait_descriptor (0);
4284
dce4c2ac
DN
4285 tty->delete_in_insert_mode = 1;
4286
4287 UseTabs (tty) = 0;
77e3b1b7 4288 tty->scroll_region_ok = 0;
dce4c2ac
DN
4289
4290 /* Seems to insert lines when it's not supposed to, messing up the
4291 display. In doing a trace, it didn't seem to be called much, so I
4292 don't think we're losing anything by turning it off. */
77e3b1b7 4293 tty->line_ins_del_ok = 0;
dce4c2ac 4294
a104f656 4295 tty->TN_max_colors = 16; /* Must be non-zero for tty-display-color-p. */
dce4c2ac
DN
4296#endif /* DOS_NT */
4297
6bc8cd65
JB
4298#ifdef HAVE_GPM
4299 terminal->mouse_position_hook = term_mouse_position;
4300 tty->mouse_highlight.mouse_face_window = Qnil;
4301#endif
4302
1afcba63 4303 terminal->kboard = allocate_kboard (Qnil);
6ed8eeff 4304 terminal->kboard->reference_count++;
e7cf0fa0
KL
4305 /* Don't let the initial kboard remain current longer than necessary.
4306 That would cause problems if a file loaded on startup tries to
4307 prompt in the mini-buffer. */
4308 if (current_kboard == initial_kboard)
6ed8eeff 4309 current_kboard = terminal->kboard;
84704c5c 4310#ifndef DOS_NT
6ed8eeff 4311 term_get_fkeys (address, terminal->kboard);
5c2c7893 4312
ff11dfa1 4313 /* Get frame size from system, or else from termcap. */
3b12ce12
RS
4314 {
4315 int height, width;
0b0d3e0b 4316 get_tty_size (fileno (tty->input), &width, &height);
0a125897
KL
4317 FrameCols (tty) = width;
4318 FrameRows (tty) = height;
3b12ce12
RS
4319 }
4320
0a125897
KL
4321 if (FrameCols (tty) <= 0)
4322 FrameCols (tty) = tgetnum ("co");
4323 if (FrameRows (tty) <= 0)
4324 FrameRows (tty) = tgetnum ("li");
177c0ea7 4325
0a125897 4326 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
d31eee5e 4327 maybe_fatal (must_succeed, terminal,
b3ffc17c 4328 "Screen size %dx%d is too small",
3224dac1 4329 "Screen size %dx%d is too small",
0a125897 4330 FrameCols (tty), FrameRows (tty));
ee7a2de4 4331
6548cf00 4332 TabWidth (tty) = tgetnum ("tw");
08a24c47 4333
fca177d4
KL
4334 if (!tty->TS_bell)
4335 tty->TS_bell = "\07";
08a24c47 4336
fca177d4
KL
4337 if (!tty->TS_fwd_scroll)
4338 tty->TS_fwd_scroll = Down (tty);
08a24c47 4339
fca177d4 4340 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
08a24c47 4341
6548cf00
KL
4342 if (TabWidth (tty) < 0)
4343 TabWidth (tty) = 8;
177c0ea7 4344
08a24c47
JB
4345/* Turned off since /etc/termcap seems to have :ta= for most terminals
4346 and newer termcap doc does not seem to say there is a default.
6548cf00
KL
4347 if (!tty->Wcm->cm_tab)
4348 tty->Wcm->cm_tab = "\t";
08a24c47
JB
4349*/
4350
54800acb
MB
4351 /* We don't support standout modes that use `magic cookies', so
4352 turn off any that do. */
fca177d4 4353 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
54800acb 4354 {
fca177d4
KL
4355 tty->TS_standout_mode = 0;
4356 tty->TS_end_standout_mode = 0;
54800acb 4357 }
fca177d4 4358 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
54800acb 4359 {
fca177d4
KL
4360 tty->TS_enter_underline_mode = 0;
4361 tty->TS_exit_underline_mode = 0;
54800acb
MB
4362 }
4363
4364 /* If there's no standout mode, try to use underlining instead. */
fca177d4 4365 if (tty->TS_standout_mode == 0)
08a24c47 4366 {
fca177d4
KL
4367 tty->TS_standout_mode = tty->TS_enter_underline_mode;
4368 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
08a24c47
JB
4369 }
4370
afd359c4
RS
4371 /* If no `se' string, try using a `me' string instead.
4372 If that fails, we can't use standout mode at all. */
fca177d4 4373 if (tty->TS_end_standout_mode == 0)
afd359c4 4374 {
e4bfb3b6 4375 char *s = tgetstr ("me", address);
afd359c4 4376 if (s != 0)
fca177d4 4377 tty->TS_end_standout_mode = s;
afd359c4 4378 else
fca177d4 4379 tty->TS_standout_mode = 0;
afd359c4
RS
4380 }
4381
fca177d4 4382 if (tty->TF_teleray)
08a24c47 4383 {
6548cf00 4384 tty->Wcm->cm_tab = 0;
54800acb 4385 /* We can't support standout mode, because it uses magic cookies. */
fca177d4 4386 tty->TS_standout_mode = 0;
a104f656 4387 /* But that means we cannot rely on ^M to go to column zero! */
6548cf00 4388 CR (tty) = 0;
a104f656
SM
4389 /* LF can't be trusted either -- can alter hpos. */
4390 /* If move at column 0 thru a line with TS_standout_mode. */
6548cf00 4391 Down (tty) = 0;
08a24c47
JB
4392 }
4393
0a125897 4394 tty->specified_window = FrameRows (tty);
08a24c47 4395
a104f656 4396 if (Wcm_init (tty) == -1) /* Can't do cursor motion. */
3224dac1 4397 {
d31eee5e 4398 maybe_fatal (must_succeed, terminal,
3224dac1 4399 "Terminal type \"%s\" is not powerful enough to run Emacs",
3224dac1 4400 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
37dad45a
RS
4401It lacks the ability to position the cursor.\n\
4402If that is not the actual type of terminal you have,\n\
4403use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
84164a0d
SM
4404`setenv TERM ...') to specify the correct type. It may be necessary\n"
4405# ifdef TERMINFO
4406"to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
37dad45a 4407# else /* TERMCAP */
84164a0d 4408"to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
37dad45a 4409# endif /* TERMINFO */
3224dac1 4410 terminal_type);
fca177d4 4411 }
daf01701 4412
0a125897 4413 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
d31eee5e 4414 maybe_fatal (must_succeed, terminal,
3224dac1
KL
4415 "Could not determine the frame size",
4416 "Could not determine the frame size");
08a24c47 4417
fca177d4
KL
4418 tty->delete_in_insert_mode
4419 = tty->TS_delete_mode && tty->TS_insert_mode
4420 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
08a24c47 4421
0b0d3e0b 4422 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
08a24c47 4423
77e3b1b7 4424 tty->scroll_region_ok
6548cf00 4425 = (tty->Wcm->cm_abs
fca177d4 4426 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
08a24c47 4427
77e3b1b7 4428 tty->line_ins_del_ok
fca177d4
KL
4429 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
4430 && (tty->TS_del_line || tty->TS_del_multi_lines))
77e3b1b7 4431 || (tty->scroll_region_ok
fca177d4 4432 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
08a24c47 4433
77e3b1b7 4434 tty->char_ins_del_ok
fca177d4
KL
4435 = ((tty->TS_ins_char || tty->TS_insert_mode
4436 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
4437 && (tty->TS_del_char || tty->TS_del_multi_chars));
08a24c47 4438
0b0d3e0b 4439 init_baud_rate (fileno (tty->input));
20a558dc 4440
84704c5c 4441#endif /* not DOS_NT */
635e3b29 4442
0a125897
KL
4443 /* Init system terminal modes (RAW or CBREAK, etc.). */
4444 init_sys_modes (tty);
daf01701 4445
6ed8eeff 4446 return terminal;
08a24c47
JB
4447}
4448
b3ffc17c
DN
4449
4450static void
4451vfatal (const char *str, va_list ap)
4452{
4453 fprintf (stderr, "emacs: ");
4454 vfprintf (stderr, str, ap);
4455 if (!(strlen (str) > 0 && str[strlen (str) - 1] == '\n'))
4456 fprintf (stderr, "\n");
b3ffc17c
DN
4457 fflush (stderr);
4458 exit (1);
4459}
4460
4461
a4c6993d 4462/* Auxiliary error-handling function for init_tty.
d31eee5e 4463 Delete TERMINAL, then call error or fatal with str1 or str2,
653d4f43 4464 respectively, according to whether MUST_SUCCEED is true. */
6b61353c 4465
3224dac1 4466static void
653d4f43 4467maybe_fatal (bool must_succeed, struct terminal *terminal,
b3ffc17c 4468 const char *str1, const char *str2, ...)
3224dac1 4469{
b3ffc17c
DN
4470 va_list ap;
4471 va_start (ap, str2);
6ed8eeff
KL
4472 if (terminal)
4473 delete_tty (terminal);
f4d953fc 4474
3224dac1 4475 if (must_succeed)
b3ffc17c 4476 vfatal (str2, ap);
3224dac1 4477 else
b3ffc17c 4478 verror (str1, ap);
08a24c47
JB
4479}
4480
dfcf069d 4481void
7c401d15 4482fatal (const char *str, ...)
08a24c47 4483{
7c401d15
DN
4484 va_list ap;
4485 va_start (ap, str);
b3ffc17c 4486 vfatal (str, ap);
08a24c47 4487}
07c57952 4488
819b8f00
KL
4489\f
4490
6ed8eeff 4491/* Delete the given tty terminal, closing all frames on it. */
da8e1115 4492
ed8dad6b 4493static void
6ed8eeff 4494delete_tty (struct terminal *terminal)
072d84a6 4495{
428a555e 4496 struct tty_display_info *tty;
f4d953fc 4497
e2749141 4498 /* Protect against recursive calls. delete_frame in
ab797f65 4499 delete_terminal calls us back when it deletes our last frame. */
59a7bc63 4500 if (!terminal->name)
0a125897 4501 return;
fca177d4 4502
9c253307 4503 eassert (terminal->type == output_termcap);
428a555e 4504
6ed8eeff 4505 tty = terminal->display_info.tty;
f4d953fc 4506
fca177d4
KL
4507 if (tty == tty_list)
4508 tty_list = tty->next;
4509 else
4510 {
28d7d09f 4511 struct tty_display_info *p;
fca177d4
KL
4512 for (p = tty_list; p && p->next != tty; p = p->next)
4513 ;
4514
4515 if (! p)
4516 /* This should not happen. */
1088b922 4517 emacs_abort ();
fca177d4 4518
0a125897
KL
4519 p->next = tty->next;
4520 tty->next = 0;
fca177d4
KL
4521 }
4522
7e59217d 4523 /* reset_sys_modes needs a valid device, so this call needs to be
6ed8eeff 4524 before delete_terminal. */
04c3243c 4525 reset_sys_modes (tty);
fca177d4 4526
6ed8eeff 4527 delete_terminal (terminal);
3224dac1 4528
70fdbb46
JM
4529 xfree (tty->name);
4530 xfree (tty->type);
daf01701 4531
fca177d4 4532 if (tty->input)
819b8f00
KL
4533 {
4534 delete_keyboard_wait_descriptor (fileno (tty->input));
4535 if (tty->input != stdin)
4536 fclose (tty->input);
4537 }
4538 if (tty->output && tty->output != stdout && tty->output != tty->input)
fca177d4
KL
4539 fclose (tty->output);
4540 if (tty->termscript)
4541 fclose (tty->termscript);
daf01701 4542
70fdbb46
JM
4543 xfree (tty->old_tty);
4544 xfree (tty->Wcm);
fca177d4 4545 xfree (tty);
fca177d4
KL
4546}
4547
dfcf069d 4548void
d3da34e0 4549syms_of_term (void)
07c57952 4550{
29208e82 4551 DEFVAR_BOOL ("system-uses-terminfo", system_uses_terminfo,
7ee72033 4552 doc: /* Non-nil means the system uses terminfo rather than termcap.
228299fa 4553This variable can be used by terminal emulator packages. */);
07c57952
KH
4554#ifdef TERMINFO
4555 system_uses_terminfo = 1;
4556#else
4557 system_uses_terminfo = 0;
4558#endif
c291d9ef 4559
29208e82 4560 DEFVAR_LISP ("suspend-tty-functions", Vsuspend_tty_functions,
e5d9c0d1 4561 doc: /* Functions run after suspending a tty.
fdc496e7 4562The functions are run with one argument, the terminal object to be suspended.
0b0d3e0b 4563See `suspend-tty'. */);
e4019195 4564 Vsuspend_tty_functions = Qnil;
0b0d3e0b
KL
4565
4566
29208e82 4567 DEFVAR_LISP ("resume-tty-functions", Vresume_tty_functions,
e5d9c0d1 4568 doc: /* Functions run after resuming a tty.
fdc496e7 4569The functions are run with one argument, the terminal object that was revived.
0b0d3e0b 4570See `resume-tty'. */);
e4019195 4571 Vresume_tty_functions = Qnil;
a168702a 4572
29208e82 4573 DEFVAR_BOOL ("visible-cursor", visible_cursor,
0db017c0
SM
4574 doc: /* Non-nil means to make the cursor very visible.
4575This only has an effect when running in a text terminal.
4576What means \"very visible\" is up to your terminal. It may make the cursor
4577bigger, or it may make it blink, or it may do nothing at all. */);
4578 visible_cursor = 1;
4579
a168702a 4580 defsubr (&Stty_display_color_p);
bfa62f96 4581 defsubr (&Stty_display_color_cells);
072d84a6 4582 defsubr (&Stty_no_underline);
6ed8eeff
KL
4583 defsubr (&Stty_type);
4584 defsubr (&Scontrolling_tty_p);
c6bf3022 4585 defsubr (&Stty_top_frame);
0b0d3e0b
KL
4586 defsubr (&Ssuspend_tty);
4587 defsubr (&Sresume_tty);
7e5a23bd 4588#ifdef HAVE_GPM
6178ce5e
SM
4589 defsubr (&Sgpm_mouse_start);
4590 defsubr (&Sgpm_mouse_stop);
7e5a23bd 4591#endif /* HAVE_GPM */
3a7c5d40 4592
84704c5c 4593#ifndef DOS_NT
3a7c5d40
CY
4594 default_orig_pair = NULL;
4595 default_set_foreground = NULL;
4596 default_set_background = NULL;
84704c5c 4597#endif /* !DOS_NT */
d31eee5e
CY
4598
4599 encode_terminal_src = NULL;
4600 encode_terminal_dst = NULL;
f0177f86 4601
bfc30790
DC
4602 DEFSYM (Qtty_mode_set_strings, "tty-mode-set-strings");
4603 DEFSYM (Qtty_mode_reset_strings, "tty-mode-reset-strings");
4604
bf6b4923 4605#ifndef MSDOS
df782309
EZ
4606 DEFSYM (Qtty_menu_next_item, "tty-menu-next-item");
4607 DEFSYM (Qtty_menu_prev_item, "tty-menu-prev-item");
4608 DEFSYM (Qtty_menu_next_menu, "tty-menu-next-menu");
4609 DEFSYM (Qtty_menu_prev_menu, "tty-menu-prev-menu");
4610 DEFSYM (Qtty_menu_select, "tty-menu-select");
4611 DEFSYM (Qtty_menu_ignore, "tty-menu-ignore");
4612 DEFSYM (Qtty_menu_exit, "tty-menu-exit");
e648f699 4613 DEFSYM (Qtty_menu_mouse_movement, "tty-menu-mouse-movement");
df782309 4614 DEFSYM (Qtty_menu_navigation_map, "tty-menu-navigation-map");
bf6b4923 4615#endif
07c57952 4616}