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