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