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