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