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