Merge from emacs-23; up to 2010-06-03T05:41:49Z!rgm@gnu.org.
[bpt/emacs.git] / src / term.c
CommitLineData
d284f58f 1/* Terminal control module for terminals described by TERMCAP
73b0cd50 2 Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2011
8cabe764 3 Free Software 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>
08a24c47
JB
23#include <stdio.h>
24#include <ctype.h>
59b3194c 25#include <errno.h>
28d440ab 26#include <sys/file.h>
1ec5dc77 27#include <unistd.h>
03a1d6bd 28#include <signal.h>
7c401d15 29#include <stdarg.h>
d7306fe6 30#include <setjmp.h>
0c72d684 31
9628b887 32#include "lisp.h"
08a24c47
JB
33#include "termchar.h"
34#include "termopts.h"
9332ea03
KH
35#include "buffer.h"
36#include "character.h"
a4decb7f
KH
37#include "charset.h"
38#include "coding.h"
4c12d738 39#include "composite.h"
2538fae4 40#include "keyboard.h"
ff11dfa1 41#include "frame.h"
08a24c47
JB
42#include "disptab.h"
43#include "termhooks.h"
dfcf069d 44#include "dispextern.h"
a168702a 45#include "window.h"
8feddab4 46#include "keymap.h"
1a935bfd 47#include "blockinput.h"
03a1d6bd
KL
48#include "syssignal.h"
49#include "systty.h"
c9612b8e 50#include "intervals.h"
84704c5c
EZ
51#ifdef MSDOS
52#include "msdos.h"
53static int been_here = -1;
54#endif
a168702a 55
ff23e1dd
GM
56/* For now, don't try to include termcap.h. On some systems,
57 configure finds a non-standard termcap.h that the main build
58 won't find. */
f57e2426
J
59extern void tputs (const char *, int, int (*)(int));
60extern int tgetent (char *, const char *);
61extern int tgetflag (char *id);
62extern int tgetnum (char *id);
b0f61f15 63
b932f8b1
DN
64char *tparam (char *, char *, int, int, ...);
65
66extern char *tgetstr (char *, char **);
67
eccec691 68#include "cm.h"
dfcf069d
AS
69#ifdef HAVE_X_WINDOWS
70#include "xterm.h"
71#endif
c8951b18 72
28d440ab
KL
73#ifndef O_RDWR
74#define O_RDWR 2
75#endif
6b61353c 76
0c72d684
KL
77#ifndef O_NOCTTY
78#define O_NOCTTY 0
79#endif
6b61353c 80
78048085
EZ
81/* The name of the default console device. */
82#ifdef WINDOWSNT
83#define DEV_TTY "CONOUT$"
84#else
85#define DEV_TTY "/dev/tty"
86#endif
a168702a 87
f57e2426
J
88static void tty_set_scroll_region (struct frame *f, int start, int stop);
89static void turn_on_face (struct frame *, int face_id);
90static void turn_off_face (struct frame *, int face_id);
91static void tty_show_cursor (struct tty_display_info *);
92static void tty_hide_cursor (struct tty_display_info *);
93static void tty_background_highlight (struct tty_display_info *tty);
94static void clear_tty_hooks (struct terminal *terminal);
95static void set_tty_hooks (struct terminal *terminal);
96static void dissociate_if_controlling_tty (int fd);
97static void delete_tty (struct terminal *);
b3ffc17c
DN
98static void maybe_fatal (int must_succeed, struct terminal *terminal,
99 const char *str1, const char *str2, ...) NO_RETURN;
100static void vfatal (const char *str, va_list ap) NO_RETURN;
101
a168702a 102
6548cf00
KL
103#define OUTPUT(tty, a) \
104 emacs_tputs ((tty), a, \
105 (int) (FRAME_LINES (XFRAME (selected_frame)) \
106 - curY (tty)), \
107 cmputc)
108
28d440ab
KL
109#define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
110#define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
a168702a 111
28d440ab 112#define OUTPUT_IF(tty, a) \
6548cf00
KL
113 do { \
114 if (a) \
b286858c 115 OUTPUT (tty, a); \
6548cf00 116 } while (0)
177c0ea7 117
28d440ab 118#define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
c291d9ef 119
f46c2aff 120/* Display space properties */
08a24c47 121
428a555e 122/* Chain of all tty device parameters. */
28d7d09f 123struct tty_display_info *tty_list;
08a24c47 124
4e6ba4a4
GM
125/* Meaning of bits in no_color_video. Each bit set means that the
126 corresponding attribute cannot be combined with colors. */
127
128enum no_color_bit
129{
130 NC_STANDOUT = 1 << 0,
131 NC_UNDERLINE = 1 << 1,
132 NC_REVERSE = 1 << 2,
133 NC_BLINK = 1 << 3,
134 NC_DIM = 1 << 4,
135 NC_BOLD = 1 << 5,
136 NC_INVIS = 1 << 6,
137 NC_PROTECT = 1 << 7,
138 NC_ALT_CHARSET = 1 << 8
139};
140
08a24c47
JB
141/* internal state */
142
8dd0c7cb 143/* The largest frame width in any call to calculate_costs. */
a168702a 144
9882535b 145int max_frame_cols;
a168702a 146
8dd0c7cb 147/* The largest frame height in any call to calculate_costs. */
a168702a 148
9882535b 149int max_frame_lines;
8dd0c7cb 150
0c72d684
KL
151/* Non-zero if we have dropped our controlling tty and therefore
152 should not open a frame on stdout. */
153static int no_controlling_tty;
08a24c47 154
08a24c47 155\f
cb28b9c2 156
7e5a23bd 157#ifdef HAVE_GPM
e882229c 158#include <sys/fcntl.h>
e882229c 159
71f44e7a
SM
160/* The device for which we have enabled gpm support (or NULL). */
161struct tty_display_info *gpm_tty = NULL;
e882229c 162
cf482c50 163/* Last recorded mouse coordinates. */
e882229c 164static int last_mouse_x, last_mouse_y;
7e5a23bd 165#endif /* HAVE_GPM */
e882229c 166
da8e1115 167/* Ring the bell on a tty. */
c291d9ef 168
ed8dad6b 169static void
385ed61f 170tty_ring_bell (struct frame *f)
3224dac1 171{
3224dac1 172 struct tty_display_info *tty = FRAME_TTY (f);
c291d9ef 173
b6660415
KL
174 if (tty->output)
175 {
176 OUTPUT (tty, (tty->TS_visible_bell && visible_bell
177 ? tty->TS_visible_bell
178 : tty->TS_bell));
179 fflush (tty->output);
08a24c47 180 }
08a24c47
JB
181}
182
da8e1115
KL
183/* Set up termcap modes for Emacs. */
184
dfcf069d 185void
6ed8eeff 186tty_set_terminal_modes (struct terminal *terminal)
08a24c47 187{
6ed8eeff 188 struct tty_display_info *tty = terminal->display_info.tty;
f4d953fc 189
0b0d3e0b 190 if (tty->output)
08a24c47 191 {
fbf34973
KL
192 if (tty->TS_termcap_modes)
193 OUTPUT (tty, tty->TS_termcap_modes);
3ae9c96a 194 else
fbf34973
KL
195 {
196 /* Output enough newlines to scroll all the old screen contents
197 off the screen, so it won't be overwritten and lost. */
198 int i;
a3c07f68 199 current_tty = tty;
fbf34973 200 for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
a3c07f68 201 cmputc ('\n');
fbf34973
KL
202 }
203
b58cb614 204 OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
0b0d3e0b
KL
205 OUTPUT_IF (tty, tty->TS_keypad_mode);
206 losecursor (tty);
2f98e6e3 207 fflush (tty->output);
08a24c47 208 }
08a24c47
JB
209}
210
da8e1115
KL
211/* Reset termcap modes before exiting Emacs. */
212
dfcf069d 213void
6ed8eeff 214tty_reset_terminal_modes (struct terminal *terminal)
08a24c47 215{
6ed8eeff 216 struct tty_display_info *tty = terminal->display_info.tty;
0b0d3e0b
KL
217
218 if (tty->output)
08a24c47 219 {
ed8dad6b
KL
220 tty_turn_off_highlight (tty);
221 tty_turn_off_insert (tty);
0b0d3e0b
KL
222 OUTPUT_IF (tty, tty->TS_end_keypad_mode);
223 OUTPUT_IF (tty, tty->TS_cursor_normal);
224 OUTPUT_IF (tty, tty->TS_end_termcap_modes);
225 OUTPUT_IF (tty, tty->TS_orig_pair);
d284f58f 226 /* Output raw CR so kernel can track the cursor hpos. */
0b0d3e0b 227 current_tty = tty;
d284f58f 228 cmputc ('\r');
2f98e6e3 229 fflush (tty->output);
08a24c47 230 }
08a24c47
JB
231}
232
6ed8eeff 233/* Flag the end of a display update on a termcap terminal. */
08a24c47 234
ed8dad6b 235static void
3224dac1 236tty_update_end (struct frame *f)
08a24c47 237{
3224dac1 238 struct tty_display_info *tty = FRAME_TTY (f);
177c0ea7 239
3224dac1
KL
240 if (!XWINDOW (selected_window)->cursor_off_p)
241 tty_show_cursor (tty);
ed8dad6b
KL
242 tty_turn_off_insert (tty);
243 tty_background_highlight (tty);
08a24c47
JB
244}
245
da8e1115
KL
246/* The implementation of set_terminal_window for termcap frames. */
247
ed8dad6b 248static void
385ed61f 249tty_set_terminal_window (struct frame *f, int size)
08a24c47 250{
3224dac1
KL
251 struct tty_display_info *tty = FRAME_TTY (f);
252
253 tty->specified_window = size ? size : FRAME_LINES (f);
254 if (FRAME_SCROLL_REGION_OK (f))
ed8dad6b 255 tty_set_scroll_region (f, 0, tty->specified_window);
08a24c47
JB
256}
257
ed8dad6b
KL
258static void
259tty_set_scroll_region (struct frame *f, int start, int stop)
08a24c47
JB
260{
261 char *buf;
28d7d09f 262 struct tty_display_info *tty = FRAME_TTY (f);
177c0ea7 263
fca177d4
KL
264 if (tty->TS_set_scroll_region)
265 buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1);
266 else if (tty->TS_set_scroll_region_1)
267 buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
ed02974b
KL
268 FRAME_LINES (f), start,
269 FRAME_LINES (f) - stop,
270 FRAME_LINES (f));
08a24c47 271 else
fca177d4 272 buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
177c0ea7 273
6548cf00 274 OUTPUT (tty, buf);
9ac0d9e0 275 xfree (buf);
6548cf00 276 losecursor (tty);
08a24c47 277}
d284f58f 278
08a24c47 279\f
d284f58f 280static void
ed8dad6b 281tty_turn_on_insert (struct tty_display_info *tty)
08a24c47 282{
fca177d4
KL
283 if (!tty->insert_mode)
284 OUTPUT (tty, tty->TS_insert_mode);
285 tty->insert_mode = 1;
08a24c47
JB
286}
287
dfcf069d 288void
ed8dad6b 289tty_turn_off_insert (struct tty_display_info *tty)
08a24c47 290{
fca177d4
KL
291 if (tty->insert_mode)
292 OUTPUT (tty, tty->TS_end_insert_mode);
293 tty->insert_mode = 0;
08a24c47
JB
294}
295\f
54800acb 296/* Handle highlighting. */
08a24c47 297
dfcf069d 298void
ed8dad6b 299tty_turn_off_highlight (struct tty_display_info *tty)
08a24c47 300{
fca177d4
KL
301 if (tty->standout_mode)
302 OUTPUT_IF (tty, tty->TS_end_standout_mode);
303 tty->standout_mode = 0;
08a24c47
JB
304}
305
d284f58f 306static void
ed8dad6b 307tty_turn_on_highlight (struct tty_display_info *tty)
08a24c47 308{
fca177d4
KL
309 if (!tty->standout_mode)
310 OUTPUT_IF (tty, tty->TS_standout_mode);
311 tty->standout_mode = 1;
08a24c47
JB
312}
313
86a7d192 314static void
ed8dad6b 315tty_toggle_highlight (struct tty_display_info *tty)
86a7d192 316{
fca177d4 317 if (tty->standout_mode)
ed8dad6b 318 tty_turn_off_highlight (tty);
86a7d192 319 else
ed8dad6b 320 tty_turn_on_highlight (tty);
86a7d192
GM
321}
322
a168702a
GM
323
324/* Make cursor invisible. */
325
326static void
28d7d09f 327tty_hide_cursor (struct tty_display_info *tty)
a168702a 328{
fca177d4 329 if (tty->cursor_hidden == 0)
d284f58f 330 {
fca177d4
KL
331 tty->cursor_hidden = 1;
332 OUTPUT_IF (tty, tty->TS_cursor_invisible);
d284f58f 333 }
a168702a
GM
334}
335
336
337/* Ensure that cursor is visible. */
338
339static void
28d7d09f 340tty_show_cursor (struct tty_display_info *tty)
a168702a 341{
fca177d4 342 if (tty->cursor_hidden)
d284f58f 343 {
fca177d4
KL
344 tty->cursor_hidden = 0;
345 OUTPUT_IF (tty, tty->TS_cursor_normal);
0db017c0 346 if (visible_cursor)
b58cb614 347 OUTPUT_IF (tty, tty->TS_cursor_visible);
d284f58f 348 }
a168702a
GM
349}
350
351
08a24c47
JB
352/* Set standout mode to the state it should be in for
353 empty space inside windows. What this is,
354 depends on the user option inverse-video. */
355
ed8dad6b
KL
356static void
357tty_background_highlight (struct tty_display_info *tty)
08a24c47 358{
08a24c47 359 if (inverse_video)
ed8dad6b 360 tty_turn_on_highlight (tty);
08a24c47 361 else
ed8dad6b 362 tty_turn_off_highlight (tty);
08a24c47
JB
363}
364
365/* Set standout mode to the mode specified for the text to be output. */
366
dfcf069d 367static void
ed8dad6b 368tty_highlight_if_desired (struct tty_display_info *tty)
08a24c47 369{
8ede64a5 370 if (inverse_video)
ed8dad6b 371 tty_turn_on_highlight (tty);
8ede64a5 372 else
ed8dad6b 373 tty_turn_off_highlight (tty);
08a24c47
JB
374}
375\f
376
a168702a
GM
377/* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are
378 frame-relative coordinates. */
08a24c47 379
ed8dad6b 380static void
385ed61f 381tty_cursor_to (struct frame *f, int vpos, int hpos)
08a24c47 382{
3224dac1 383 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 384
36cae867
KH
385 /* Detect the case where we are called from reset_sys_modes
386 and the costs have never been calculated. Do nothing. */
fca177d4 387 if (! tty->costs_set)
36cae867
KH
388 return;
389
6548cf00
KL
390 if (curY (tty) == vpos
391 && curX (tty) == hpos)
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, vpos, hpos);
08a24c47
JB
398}
399
400/* Similar but don't take any account of the wasted characters. */
401
ed8dad6b 402static void
385ed61f 403tty_raw_cursor_to (struct frame *f, int row, int col)
08a24c47 404{
3224dac1
KL
405 struct tty_display_info *tty = FRAME_TTY (f);
406
6548cf00
KL
407 if (curY (tty) == row
408 && curX (tty) == col)
08a24c47 409 return;
fca177d4 410 if (!tty->TF_standout_motion)
ed8dad6b 411 tty_background_highlight (tty);
fca177d4 412 if (!tty->TF_insmode_motion)
ed8dad6b 413 tty_turn_off_insert (tty);
6548cf00 414 cmgoto (tty, row, col);
08a24c47
JB
415}
416\f
417/* Erase operations */
418
da8e1115
KL
419/* Clear from cursor to end of frame on a termcap device. */
420
ed8dad6b 421static void
385ed61f 422tty_clear_to_end (struct frame *f)
08a24c47
JB
423{
424 register int i;
3224dac1 425 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 426
fca177d4 427 if (tty->TS_clr_to_bottom)
08a24c47 428 {
ed8dad6b 429 tty_background_highlight (tty);
fca177d4 430 OUTPUT (tty, tty->TS_clr_to_bottom);
08a24c47
JB
431 }
432 else
433 {
6548cf00 434 for (i = curY (tty); i < FRAME_LINES (f); i++)
08a24c47 435 {
385ed61f
KL
436 cursor_to (f, i, 0);
437 clear_end_of_line (f, FRAME_COLS (f));
08a24c47
JB
438 }
439 }
440}
441
da8e1115 442/* Clear an entire termcap frame. */
08a24c47 443
ed8dad6b 444static void
385ed61f 445tty_clear_frame (struct frame *f)
08a24c47 446{
3224dac1 447 struct tty_display_info *tty = FRAME_TTY (f);
177c0ea7 448
fca177d4 449 if (tty->TS_clr_frame)
08a24c47 450 {
ed8dad6b 451 tty_background_highlight (tty);
fca177d4 452 OUTPUT (tty, tty->TS_clr_frame);
6548cf00 453 cmat (tty, 0, 0);
08a24c47
JB
454 }
455 else
456 {
385ed61f
KL
457 cursor_to (f, 0, 0);
458 clear_to_end (f);
08a24c47
JB
459 }
460}
461
da8e1115 462/* An implementation of clear_end_of_line for termcap frames.
08a24c47
JB
463
464 Note that the cursor may be moved, on terminals lacking a `ce' string. */
465
ed8dad6b 466static void
385ed61f 467tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
08a24c47
JB
468{
469 register int i;
3224dac1 470 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 471
36cae867
KH
472 /* Detect the case where we are called from reset_sys_modes
473 and the costs have never been calculated. Do nothing. */
fca177d4 474 if (! tty->costs_set)
36cae867
KH
475 return;
476
6548cf00 477 if (curX (tty) >= first_unused_hpos)
08a24c47 478 return;
ed8dad6b 479 tty_background_highlight (tty);
fca177d4 480 if (tty->TS_clr_line)
08a24c47 481 {
fca177d4 482 OUTPUT1 (tty, tty->TS_clr_line);
08a24c47
JB
483 }
484 else
485 { /* have to do it the hard way */
ed8dad6b 486 tty_turn_off_insert (tty);
08a24c47 487
a168702a 488 /* Do not write in last row last col with Auto-wrap on. */
6548cf00 489 if (AutoWrap (tty)
0a125897
KL
490 && curY (tty) == FrameRows (tty) - 1
491 && first_unused_hpos == FrameCols (tty))
08a24c47
JB
492 first_unused_hpos--;
493
6548cf00 494 for (i = curX (tty); i < first_unused_hpos; i++)
08a24c47 495 {
0b0d3e0b
KL
496 if (tty->termscript)
497 fputc (' ', tty->termscript);
498 fputc (' ', tty->output);
08a24c47 499 }
6548cf00 500 cmplus (tty, first_unused_hpos - curX (tty));
08a24c47
JB
501 }
502}
503\f
288d5132
KH
504/* Buffers to store the source and result of code conversion for terminal. */
505static unsigned char *encode_terminal_src;
506static unsigned char *encode_terminal_dst;
507/* Allocated sizes of the above buffers. */
508static int encode_terminal_src_size;
509static int encode_terminal_dst_size;
510
511/* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
512 Set CODING->produced to the byte-length of the resulting byte
513 sequence, and return a pointer to that byte sequence. */
514
515unsigned char *
d3da34e0 516encode_terminal_code (struct glyph *src, int src_len, struct coding_system *coding)
a4decb7f 517{
feef4f84 518 struct glyph *src_end = src + src_len;
288d5132
KH
519 unsigned char *buf;
520 int nchars, nbytes, required;
a4decb7f
KH
521 register int tlen = GLYPH_TABLE_LENGTH;
522 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
288d5132 523 Lisp_Object charset_list;
c5a518df 524
288d5132
KH
525 /* Allocate sufficient size of buffer to store all characters in
526 multibyte-form. But, it may be enlarged on demand if
4c12d738
KH
527 Vglyph_table contains a string or a composite glyph is
528 encountered. */
288d5132
KH
529 required = MAX_MULTIBYTE_LENGTH * src_len;
530 if (encode_terminal_src_size < required)
531 {
d31eee5e 532 if (encode_terminal_src)
288d5132 533 encode_terminal_src = xrealloc (encode_terminal_src, required);
d31eee5e
CY
534 else
535 encode_terminal_src = xmalloc (required);
288d5132
KH
536 encode_terminal_src_size = required;
537 }
6589fd67 538
288d5132 539 charset_list = coding_charset_list (coding);
a4decb7f 540
288d5132
KH
541 buf = encode_terminal_src;
542 nchars = 0;
543 while (src < src_end)
a4decb7f 544 {
4c12d738
KH
545 if (src->type == COMPOSITE_GLYPH)
546 {
75a10786
KH
547 struct composition *cmp;
548 Lisp_Object gstring;
4c12d738
KH
549 int i;
550
551 nbytes = buf - encode_terminal_src;
75a10786
KH
552 if (src->u.cmp.automatic)
553 {
554 gstring = composition_gstring_from_id (src->u.cmp.id);
4be9765d 555 required = src->slice.cmp.to + 1 - src->slice.cmp.from;
75a10786
KH
556 }
557 else
558 {
559 cmp = composition_table[src->u.cmp.id];
560 required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len;
561 }
4c12d738
KH
562
563 if (encode_terminal_src_size < nbytes + required)
564 {
565 encode_terminal_src_size = nbytes + required;
566 encode_terminal_src = xrealloc (encode_terminal_src,
567 encode_terminal_src_size);
568 buf = encode_terminal_src + nbytes;
569 }
570
75a10786 571 if (src->u.cmp.automatic)
4be9765d 572 for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
75a10786
KH
573 {
574 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
575 int c = LGLYPH_CHAR (g);
576
577 if (! char_charset (c, charset_list, NULL))
d0984aff 578 c = '?';
75a10786
KH
579 buf += CHAR_STRING (c, buf);
580 nchars++;
581 }
582 else
583 for (i = 0; i < cmp->glyph_len; i++)
584 {
585 int c = COMPOSITION_GLYPH (cmp, i);
586
d0984aff
KH
587 if (c == '\t')
588 continue;
589 if (char_charset (c, charset_list, NULL))
590 {
591 if (CHAR_WIDTH (c) == 0
592 && i > 0 && COMPOSITION_GLYPH (cmp, i - 1) == '\t')
593 /* Should be left-padded */
594 {
595 buf += CHAR_STRING (' ', buf);
596 nchars++;
597 }
598 }
599 else
600 c = '?';
75a10786
KH
601 buf += CHAR_STRING (c, buf);
602 nchars++;
603 }
4c12d738 604 }
a4decb7f 605 /* We must skip glyphs to be padded for a wide character. */
4c12d738 606 else if (! CHAR_GLYPH_PADDING_P (*src))
a4decb7f 607 {
f4d953fc 608 GLYPH g;
288d5132
KH
609 int c;
610 Lisp_Object string;
611
4ae0a2c0 612 string = Qnil;
f4d953fc 613 SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
32de38e4 614
f4d953fc 615 if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
288d5132 616 {
f185a758 617 /* This glyph doesn't have an entry in Vglyph_table. */
288d5132
KH
618 c = src->u.ch;
619 }
32de38e4 620 else
a4decb7f 621 {
32de38e4 622 /* This glyph has an entry in Vglyph_table,
a4decb7f
KH
623 so process any alias before testing for simpleness. */
624 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
32de38e4
KH
625
626 if (GLYPH_SIMPLE_P (tbase, tlen, g))
4ae0a2c0
KH
627 /* We set the multi-byte form of a character in G
628 (that should be an ASCII character) at WORKBUF. */
f4d953fc 629 c = GLYPH_CHAR (g);
32de38e4 630 else
4ae0a2c0 631 /* We have a string in Vglyph_table. */
f4d953fc 632 string = tbase[GLYPH_CHAR (g)];
171d7f24 633 }
177c0ea7 634
4ae0a2c0 635 if (NILP (string))
c42869c4 636 {
4c12d738
KH
637 nbytes = buf - encode_terminal_src;
638 if (encode_terminal_src_size < nbytes + MAX_MULTIBYTE_LENGTH)
639 {
640 encode_terminal_src_size = nbytes + MAX_MULTIBYTE_LENGTH;
641 encode_terminal_src = xrealloc (encode_terminal_src,
642 encode_terminal_src_size);
643 buf = encode_terminal_src + nbytes;
644 }
d419e1d9
KH
645 if (CHAR_BYTE8_P (c)
646 || char_charset (c, charset_list, NULL))
c5a518df 647 {
288d5132
KH
648 /* Store the multibyte form of C at BUF. */
649 buf += CHAR_STRING (c, buf);
650 nchars++;
c5a518df
KH
651 }
652 else
653 {
288d5132
KH
654 /* C is not encodable. */
655 *buf++ = '?';
c5a518df 656 nchars++;
288d5132
KH
657 while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
658 {
659 *buf++ = '?';
660 nchars++;
661 src++;
662 }
c5a518df 663 }
4ae0a2c0
KH
664 }
665 else
666 {
37254dc1 667 unsigned char *p = SDATA (string);
288d5132
KH
668
669 if (! STRING_MULTIBYTE (string))
670 string = string_to_multibyte (string);
671 nbytes = buf - encode_terminal_src;
54c4c546 672 if (encode_terminal_src_size < nbytes + SBYTES (string))
4ae0a2c0 673 {
288d5132
KH
674 encode_terminal_src_size = nbytes + SBYTES (string);
675 encode_terminal_src = xrealloc (encode_terminal_src,
676 encode_terminal_src_size);
677 buf = encode_terminal_src + nbytes;
4ae0a2c0 678 }
72af86bd 679 memcpy (buf, SDATA (string), SBYTES (string));
288d5132
KH
680 buf += SBYTES (string);
681 nchars += SCHARS (string);
c42869c4 682 }
a4decb7f 683 }
288d5132
KH
684 src++;
685 }
686
687 if (nchars == 0)
688 {
689 coding->produced = 0;
690 return NULL;
a4decb7f 691 }
177c0ea7 692
288d5132
KH
693 nbytes = buf - encode_terminal_src;
694 coding->source = encode_terminal_src;
695 if (encode_terminal_dst_size == 0)
4ae0a2c0 696 {
288d5132 697 encode_terminal_dst_size = encode_terminal_src_size;
d31eee5e
CY
698 if (encode_terminal_dst)
699 encode_terminal_dst = xrealloc (encode_terminal_dst,
700 encode_terminal_dst_size);
701 else
702 encode_terminal_dst = xmalloc (encode_terminal_dst_size);
4ae0a2c0 703 }
288d5132
KH
704 coding->destination = encode_terminal_dst;
705 coding->dst_bytes = encode_terminal_dst_size;
706 encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
c5a518df 707 /* coding->destination may have been reallocated. */
288d5132
KH
708 encode_terminal_dst = coding->destination;
709 encode_terminal_dst_size = coding->dst_bytes;
4ae0a2c0 710
288d5132 711 return (encode_terminal_dst);
a4decb7f
KH
712}
713
08a24c47 714
c73bd236 715
da8e1115
KL
716/* An implementation of write_glyphs for termcap frames. */
717
ed8dad6b 718static void
385ed61f 719tty_write_glyphs (struct frame *f, struct glyph *string, int len)
08a24c47 720{
288d5132
KH
721 unsigned char *conversion_buffer;
722 struct coding_system *coding;
08a24c47 723
3224dac1 724 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 725
ed8dad6b 726 tty_turn_off_insert (tty);
fca177d4 727 tty_hide_cursor (tty);
08a24c47 728
a168702a 729 /* Don't dare write in last column of bottom line, if Auto-Wrap,
ff11dfa1 730 since that would scroll the whole frame on some terminals. */
08a24c47 731
6548cf00
KL
732 if (AutoWrap (tty)
733 && curY (tty) + 1 == FRAME_LINES (f)
734 && (curX (tty) + len) == FRAME_COLS (f))
08a24c47 735 len --;
a4decb7f
KH
736 if (len <= 0)
737 return;
08a24c47 738
6548cf00 739 cmplus (tty, len);
177c0ea7 740
af645abf
KH
741 /* If terminal_coding does any conversion, use it, otherwise use
742 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
743 because it always return 1 if the member src_multibyte is 1. */
fad2f685
KL
744 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
745 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
6589fd67
KH
746 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
747 the tail. */
af645abf 748 coding->mode &= ~CODING_MODE_LAST_BLOCK;
177c0ea7 749
a4decb7f 750 while (len > 0)
08a24c47 751 {
a168702a 752 /* Identify a run of glyphs with the same face. */
32de38e4 753 int face_id = string->face_id;
a168702a 754 int n;
177c0ea7 755
a168702a 756 for (n = 1; n < len; ++n)
32de38e4 757 if (string[n].face_id != face_id)
a168702a
GM
758 break;
759
760 /* Turn appearance modes of the face of the run on. */
ed8dad6b 761 tty_highlight_if_desired (tty);
a168702a
GM
762 turn_on_face (f, face_id);
763
288d5132
KH
764 if (n == len)
765 /* This is the last run. */
766 coding->mode |= CODING_MODE_LAST_BLOCK;
767 conversion_buffer = encode_terminal_code (string, n, coding);
768 if (coding->produced > 0)
08a24c47 769 {
1a935bfd 770 BLOCK_INPUT;
fad2f685
KL
771 fwrite (conversion_buffer, 1, coding->produced, tty->output);
772 if (ferror (tty->output))
773 clearerr (tty->output);
774 if (tty->termscript)
775 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
1a935bfd 776 UNBLOCK_INPUT;
08a24c47 777 }
288d5132
KH
778 len -= n;
779 string += n;
a168702a
GM
780
781 /* Turn appearance modes off. */
782 turn_off_face (f, face_id);
ed8dad6b 783 tty_turn_off_highlight (tty);
a4decb7f 784 }
177c0ea7 785
6548cf00 786 cmcheckmagic (tty);
08a24c47
JB
787}
788
b870aa61
SM
789#ifdef HAVE_GPM /* Only used by GPM code. */
790
7be1c21a 791static void
d3da34e0
JB
792tty_write_glyphs_with_face (register struct frame *f, register struct glyph *string,
793 register int len, register int face_id)
e882229c 794{
e882229c
NR
795 unsigned char *conversion_buffer;
796 struct coding_system *coding;
797
7be1c21a
MB
798 struct tty_display_info *tty = FRAME_TTY (f);
799
800 tty_turn_off_insert (tty);
801 tty_hide_cursor (tty);
e882229c
NR
802
803 /* Don't dare write in last column of bottom line, if Auto-Wrap,
804 since that would scroll the whole frame on some terminals. */
805
7be1c21a
MB
806 if (AutoWrap (tty)
807 && curY (tty) + 1 == FRAME_LINES (f)
808 && (curX (tty) + len) == FRAME_COLS (f))
e882229c
NR
809 len --;
810 if (len <= 0)
811 return;
812
7be1c21a 813 cmplus (tty, len);
e882229c
NR
814
815 /* If terminal_coding does any conversion, use it, otherwise use
816 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
817 because it always return 1 if the member src_multibyte is 1. */
7be1c21a
MB
818 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
819 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
e882229c
NR
820 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
821 the tail. */
822 coding->mode &= ~CODING_MODE_LAST_BLOCK;
823
e882229c 824 /* Turn appearance modes of the face. */
7be1c21a 825 tty_highlight_if_desired (tty);
e882229c
NR
826 turn_on_face (f, face_id);
827
828 coding->mode |= CODING_MODE_LAST_BLOCK;
829 conversion_buffer = encode_terminal_code (string, len, coding);
830 if (coding->produced > 0)
831 {
832 BLOCK_INPUT;
7be1c21a
MB
833 fwrite (conversion_buffer, 1, coding->produced, tty->output);
834 if (ferror (tty->output))
835 clearerr (tty->output);
836 if (tty->termscript)
837 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
e882229c
NR
838 UNBLOCK_INPUT;
839 }
840
841 /* Turn appearance modes off. */
842 turn_off_face (f, face_id);
7be1c21a 843 tty_turn_off_highlight (tty);
e882229c 844
7be1c21a 845 cmcheckmagic (tty);
e882229c 846}
b870aa61 847#endif
e882229c 848
da8e1115 849/* An implementation of insert_glyphs for termcap frames. */
177c0ea7 850
ed8dad6b 851static void
385ed61f 852tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
08a24c47
JB
853{
854 char *buf;
6bbd7a29 855 struct glyph *glyph = NULL;
af645abf
KH
856 unsigned char *conversion_buffer;
857 unsigned char space[1];
858 struct coding_system *coding;
08a24c47 859
3224dac1 860 struct tty_display_info *tty = FRAME_TTY (f);
a168702a 861
fca177d4 862 if (tty->TS_ins_multi_chars)
08a24c47 863 {
fca177d4 864 buf = tparam (tty->TS_ins_multi_chars, 0, 0, len);
6548cf00 865 OUTPUT1 (tty, buf);
9ac0d9e0 866 xfree (buf);
08a24c47 867 if (start)
385ed61f 868 write_glyphs (f, start, len);
08a24c47
JB
869 return;
870 }
871
ed8dad6b 872 tty_turn_on_insert (tty);
6548cf00 873 cmplus (tty, len);
288d5132
KH
874
875 if (! start)
876 space[0] = SPACEGLYPH;
877
878 /* If terminal_coding does any conversion, use it, otherwise use
879 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
880 because it always return 1 if the member src_multibyte is 1. */
fad2f685
KL
881 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
882 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
288d5132
KH
883 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
884 the tail. */
885 coding->mode &= ~CODING_MODE_LAST_BLOCK;
886
07109bf9 887 while (len-- > 0)
08a24c47 888 {
fca177d4 889 OUTPUT1_IF (tty, tty->TS_ins_char);
08a24c47 890 if (!start)
32de38e4 891 {
288d5132
KH
892 conversion_buffer = space;
893 coding->produced = 1;
32de38e4 894 }
08a24c47 895 else
08a24c47 896 {
ed8dad6b 897 tty_highlight_if_desired (tty);
32de38e4 898 turn_on_face (f, start->face_id);
816be8b8 899 glyph = start;
a168702a 900 ++start;
a4decb7f
KH
901 /* We must open sufficient space for a character which
902 occupies more than one column. */
a168702a 903 while (len && CHAR_GLYPH_PADDING_P (*start))
a4decb7f 904 {
fca177d4 905 OUTPUT1_IF (tty, tty->TS_ins_char);
a4decb7f
KH
906 start++, len--;
907 }
288d5132
KH
908
909 if (len <= 0)
910 /* This is the last glyph. */
911 coding->mode |= CODING_MODE_LAST_BLOCK;
912
fad2f685 913 conversion_buffer = encode_terminal_code (glyph, 1, coding);
32de38e4 914 }
a4decb7f 915
288d5132 916 if (coding->produced > 0)
08a24c47 917 {
1a935bfd 918 BLOCK_INPUT;
fad2f685 919 fwrite (conversion_buffer, 1, coding->produced, tty->output);
0b0d3e0b
KL
920 if (ferror (tty->output))
921 clearerr (tty->output);
922 if (tty->termscript)
fad2f685 923 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
1a935bfd 924 UNBLOCK_INPUT;
08a24c47
JB
925 }
926
fca177d4 927 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
32de38e4 928 if (start)
65aa5e85
GM
929 {
930 turn_off_face (f, glyph->face_id);
ed8dad6b 931 tty_turn_off_highlight (tty);
65aa5e85 932 }
9a6b6f92 933 }
177c0ea7 934
6548cf00 935 cmcheckmagic (tty);
08a24c47
JB
936}
937
da8e1115
KL
938/* An implementation of delete_glyphs for termcap frames. */
939
ed8dad6b 940static void
385ed61f 941tty_delete_glyphs (struct frame *f, int n)
08a24c47
JB
942{
943 char *buf;
944 register int i;
945
3224dac1 946 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47 947
fca177d4 948 if (tty->delete_in_insert_mode)
08a24c47 949 {
ed8dad6b 950 tty_turn_on_insert (tty);
08a24c47
JB
951 }
952 else
953 {
ed8dad6b 954 tty_turn_off_insert (tty);
fca177d4 955 OUTPUT_IF (tty, tty->TS_delete_mode);
08a24c47
JB
956 }
957
fca177d4 958 if (tty->TS_del_multi_chars)
08a24c47 959 {
fca177d4 960 buf = tparam (tty->TS_del_multi_chars, 0, 0, n);
6548cf00 961 OUTPUT1 (tty, buf);
9ac0d9e0 962 xfree (buf);
08a24c47
JB
963 }
964 else
965 for (i = 0; i < n; i++)
fca177d4
KL
966 OUTPUT1 (tty, tty->TS_del_char);
967 if (!tty->delete_in_insert_mode)
968 OUTPUT_IF (tty, tty->TS_end_delete_mode);
08a24c47
JB
969}
970\f
da8e1115 971/* An implementation of ins_del_lines for termcap frames. */
08a24c47 972
ed8dad6b 973static void
385ed61f 974tty_ins_del_lines (struct frame *f, int vpos, int n)
08a24c47 975{
3224dac1
KL
976 struct tty_display_info *tty = FRAME_TTY (f);
977 char *multi = n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
978 char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
979 char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
08a24c47
JB
980
981 register int i = n > 0 ? n : -n;
982 register char *buf;
983
08a24c47
JB
984 /* If the lines below the insertion are being pushed
985 into the end of the window, this is the same as clearing;
986 and we know the lines are already clear, since the matching
987 deletion has already been done. So can ignore this. */
988 /* If the lines below the deletion are blank lines coming
989 out of the end of the window, don't bother,
990 as there will be a matching inslines later that will flush them. */
3224dac1
KL
991 if (FRAME_SCROLL_REGION_OK (f)
992 && vpos + i >= tty->specified_window)
08a24c47 993 return;
3224dac1
KL
994 if (!FRAME_MEMORY_BELOW_FRAME (f)
995 && vpos + i >= FRAME_LINES (f))
08a24c47 996 return;
f4d953fc 997
08a24c47
JB
998 if (multi)
999 {
6839f1e2 1000 raw_cursor_to (f, vpos, 0);
ed8dad6b 1001 tty_background_highlight (tty);
08a24c47 1002 buf = tparam (multi, 0, 0, i);
3224dac1 1003 OUTPUT (tty, buf);
9ac0d9e0 1004 xfree (buf);
08a24c47
JB
1005 }
1006 else if (single)
1007 {
6839f1e2 1008 raw_cursor_to (f, vpos, 0);
ed8dad6b 1009 tty_background_highlight (tty);
08a24c47 1010 while (--i >= 0)
3224dac1
KL
1011 OUTPUT (tty, single);
1012 if (tty->TF_teleray)
1013 curX (tty) = 0;
08a24c47
JB
1014 }
1015 else
1016 {
ed8dad6b 1017 tty_set_scroll_region (f, vpos, tty->specified_window);
08a24c47 1018 if (n < 0)
6839f1e2 1019 raw_cursor_to (f, tty->specified_window - 1, 0);
08a24c47 1020 else
6839f1e2 1021 raw_cursor_to (f, vpos, 0);
ed8dad6b 1022 tty_background_highlight (tty);
08a24c47 1023 while (--i >= 0)
3224dac1 1024 OUTPUTL (tty, scroll, tty->specified_window - vpos);
ed8dad6b 1025 tty_set_scroll_region (f, 0, tty->specified_window);
08a24c47 1026 }
f4d953fc 1027
3224dac1
KL
1028 if (!FRAME_SCROLL_REGION_OK (f)
1029 && FRAME_MEMORY_BELOW_FRAME (f)
1030 && n < 0)
08a24c47 1031 {
385ed61f
KL
1032 cursor_to (f, FRAME_LINES (f) + n, 0);
1033 clear_to_end (f);
08a24c47
JB
1034 }
1035}
1036\f
1037/* Compute cost of sending "str", in characters,
1038 not counting any line-dependent padding. */
1039
1040int
8ea90aa3 1041string_cost (const char *str)
08a24c47
JB
1042{
1043 cost = 0;
1044 if (str)
1045 tputs (str, 0, evalcost);
1046 return cost;
1047}
1048
1049/* Compute cost of sending "str", in characters,
1050 counting any line-dependent padding at one line. */
1051
1052static int
8ea90aa3 1053string_cost_one_line (const char *str)
08a24c47
JB
1054{
1055 cost = 0;
1056 if (str)
1057 tputs (str, 1, evalcost);
1058 return cost;
1059}
1060
1061/* Compute per line amount of line-dependent padding,
1062 in tenths of characters. */
1063
1064int
8ea90aa3 1065per_line_cost (const char *str)
08a24c47
JB
1066{
1067 cost = 0;
1068 if (str)
1069 tputs (str, 0, evalcost);
1070 cost = - cost;
1071 if (str)
1072 tputs (str, 10, evalcost);
1073 return cost;
1074}
1075
08a24c47 1076/* char_ins_del_cost[n] is cost of inserting N characters.
8dd0c7cb 1077 char_ins_del_cost[-n] is cost of deleting N characters.
9882535b 1078 The length of this vector is based on max_frame_cols. */
08a24c47
JB
1079
1080int *char_ins_del_vector;
1081
9882535b 1082#define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_COLS ((f))])
08a24c47
JB
1083
1084/* ARGSUSED */
1085static void
6839f1e2 1086calculate_ins_del_char_costs (struct frame *f)
08a24c47 1087{
28d7d09f 1088 struct tty_display_info *tty = FRAME_TTY (f);
08a24c47
JB
1089 int ins_startup_cost, del_startup_cost;
1090 int ins_cost_per_char, del_cost_per_char;
1091 register int i;
1092 register int *p;
1093
fca177d4 1094 if (tty->TS_ins_multi_chars)
08a24c47
JB
1095 {
1096 ins_cost_per_char = 0;
fca177d4 1097 ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars);
08a24c47 1098 }
fca177d4
KL
1099 else if (tty->TS_ins_char || tty->TS_pad_inserted_char
1100 || (tty->TS_insert_mode && tty->TS_end_insert_mode))
08a24c47 1101 {
fca177d4
KL
1102 ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode)
1103 + string_cost (tty->TS_end_insert_mode))) / 100;
1104 ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char)
1105 + string_cost_one_line (tty->TS_pad_inserted_char));
08a24c47
JB
1106 }
1107 else
1108 {
1109 ins_startup_cost = 9999;
1110 ins_cost_per_char = 0;
1111 }
1112
fca177d4 1113 if (tty->TS_del_multi_chars)
08a24c47
JB
1114 {
1115 del_cost_per_char = 0;
fca177d4 1116 del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars);
08a24c47 1117 }
fca177d4 1118 else if (tty->TS_del_char)
08a24c47 1119 {
fca177d4
KL
1120 del_startup_cost = (string_cost (tty->TS_delete_mode)
1121 + string_cost (tty->TS_end_delete_mode));
1122 if (tty->delete_in_insert_mode)
08a24c47 1123 del_startup_cost /= 2;
fca177d4 1124 del_cost_per_char = string_cost_one_line (tty->TS_del_char);
08a24c47
JB
1125 }
1126 else
1127 {
1128 del_startup_cost = 9999;
1129 del_cost_per_char = 0;
1130 }
1131
1132 /* Delete costs are at negative offsets */
fca177d4
KL
1133 p = &char_ins_del_cost (f)[0];
1134 for (i = FRAME_COLS (f); --i >= 0;)
08a24c47
JB
1135 *--p = (del_startup_cost += del_cost_per_char);
1136
1137 /* Doing nothing is free */
fca177d4 1138 p = &char_ins_del_cost (f)[0];
08a24c47
JB
1139 *p++ = 0;
1140
1141 /* Insert costs are at positive offsets */
fca177d4 1142 for (i = FRAME_COLS (f); --i >= 0;)
08a24c47
JB
1143 *p++ = (ins_startup_cost += ins_cost_per_char);
1144}
1145
dfcf069d 1146void
6839f1e2 1147calculate_costs (struct frame *frame)
08a24c47 1148{
9f732a77 1149 FRAME_COST_BAUD_RATE (frame) = baud_rate;
08a24c47 1150
28d440ab 1151 if (FRAME_TERMCAP_P (frame))
daf01701
KL
1152 {
1153 struct tty_display_info *tty = FRAME_TTY (frame);
1154 register char *f = (tty->TS_set_scroll_region
1155 ? tty->TS_set_scroll_region
1156 : tty->TS_set_scroll_region_1);
08a24c47 1157
daf01701 1158 FRAME_SCROLL_REGION_COST (frame) = string_cost (f);
08a24c47 1159
daf01701 1160 tty->costs_set = 1;
08a24c47 1161
daf01701
KL
1162 /* These variables are only used for terminal stuff. They are
1163 allocated once for the terminal frame of X-windows emacs, but not
1164 used afterwards.
8dd0c7cb 1165
daf01701
KL
1166 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1167 X turns off char_ins_del_ok. */
08a24c47 1168
daf01701
KL
1169 max_frame_lines = max (max_frame_lines, FRAME_LINES (frame));
1170 max_frame_cols = max (max_frame_cols, FRAME_COLS (frame));
08a24c47 1171
daf01701
KL
1172 if (char_ins_del_vector != 0)
1173 char_ins_del_vector
1174 = (int *) xrealloc (char_ins_del_vector,
1175 (sizeof (int)
1176 + 2 * max_frame_cols * sizeof (int)));
1177 else
1178 char_ins_del_vector
1179 = (int *) xmalloc (sizeof (int)
1180 + 2 * max_frame_cols * sizeof (int));
08a24c47 1181
72af86bd
AS
1182 memset (char_ins_del_vector, 0,
1183 (sizeof (int) + 2 * max_frame_cols * sizeof (int)));
08a24c47 1184
daf01701
KL
1185
1186 if (f && (!tty->TS_ins_line && !tty->TS_del_line))
1187 do_line_insertion_deletion_costs (frame,
1188 tty->TS_rev_scroll, tty->TS_ins_multi_lines,
1189 tty->TS_fwd_scroll, tty->TS_del_multi_lines,
1190 f, f, 1);
1191 else
1192 do_line_insertion_deletion_costs (frame,
1193 tty->TS_ins_line, tty->TS_ins_multi_lines,
1194 tty->TS_del_line, tty->TS_del_multi_lines,
1195 0, 0, 1);
1196
1197 calculate_ins_del_char_costs (frame);
1198
1199 /* Don't use TS_repeat if its padding is worse than sending the chars */
1200 if (tty->TS_repeat && per_line_cost (tty->TS_repeat) * baud_rate < 9000)
1201 tty->RPov = string_cost (tty->TS_repeat);
1202 else
1203 tty->RPov = FRAME_COLS (frame) * 2;
08a24c47 1204
daf01701
KL
1205 cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */
1206 }
08a24c47
JB
1207}
1208\f
a796ac82
JB
1209struct fkey_table {
1210 char *cap, *name;
1211};
1212
01d8deb0
ER
1213 /* Termcap capability names that correspond directly to X keysyms.
1214 Some of these (marked "terminfo") aren't supplied by old-style
1215 (Berkeley) termcap entries. They're listed in X keysym order;
1216 except we put the keypad keys first, so that if they clash with
1217 other keys (as on the IBM PC keyboard) they get overridden.
1218 */
1219
648801d1 1220static const struct fkey_table keys[] =
a168702a 1221{
8103ad1a
PJ
1222 {"kh", "home"}, /* termcap */
1223 {"kl", "left"}, /* termcap */
1224 {"ku", "up"}, /* termcap */
1225 {"kr", "right"}, /* termcap */
1226 {"kd", "down"}, /* termcap */
1227 {"%8", "prior"}, /* terminfo */
1228 {"%5", "next"}, /* terminfo */
1229 {"@7", "end"}, /* terminfo */
1230 {"@1", "begin"}, /* terminfo */
1231 {"*6", "select"}, /* terminfo */
1232 {"%9", "print"}, /* terminfo */
1233 {"@4", "execute"}, /* terminfo --- actually the `command' key */
01d8deb0
ER
1234 /*
1235 * "insert" --- see below
1236 */
8103ad1a
PJ
1237 {"&8", "undo"}, /* terminfo */
1238 {"%0", "redo"}, /* terminfo */
1239 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1240 {"@0", "find"}, /* terminfo */
1241 {"@2", "cancel"}, /* terminfo */
1242 {"%1", "help"}, /* terminfo */
01d8deb0
ER
1243 /*
1244 * "break" goes here, but can't be reliably intercepted with termcap
1245 */
8103ad1a 1246 {"&4", "reset"}, /* terminfo --- actually `restart' */
01d8deb0
ER
1247 /*
1248 * "system" and "user" --- no termcaps
1249 */
8103ad1a
PJ
1250 {"kE", "clearline"}, /* terminfo */
1251 {"kA", "insertline"}, /* terminfo */
1252 {"kL", "deleteline"}, /* terminfo */
1253 {"kI", "insertchar"}, /* terminfo */
1254 {"kD", "deletechar"}, /* terminfo */
1255 {"kB", "backtab"}, /* terminfo */
01d8deb0
ER
1256 /*
1257 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1258 */
8103ad1a 1259 {"@8", "kp-enter"}, /* terminfo */
01d8deb0
ER
1260 /*
1261 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1262 * "kp-multiply", "kp-add", "kp-separator",
1263 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1264 * --- no termcaps for any of these.
1265 */
8103ad1a 1266 {"K4", "kp-1"}, /* terminfo */
01d8deb0
ER
1267 /*
1268 * "kp-2" --- no termcap
1269 */
8103ad1a 1270 {"K5", "kp-3"}, /* terminfo */
01d8deb0
ER
1271 /*
1272 * "kp-4" --- no termcap
1273 */
8103ad1a 1274 {"K2", "kp-5"}, /* terminfo */
01d8deb0
ER
1275 /*
1276 * "kp-6" --- no termcap
1277 */
8103ad1a 1278 {"K1", "kp-7"}, /* terminfo */
01d8deb0
ER
1279 /*
1280 * "kp-8" --- no termcap
1281 */
8103ad1a 1282 {"K3", "kp-9"}, /* terminfo */
01d8deb0
ER
1283 /*
1284 * "kp-equal" --- no termcap
1285 */
8103ad1a
PJ
1286 {"k1", "f1"},
1287 {"k2", "f2"},
1288 {"k3", "f3"},
1289 {"k4", "f4"},
1290 {"k5", "f5"},
1291 {"k6", "f6"},
1292 {"k7", "f7"},
1293 {"k8", "f8"},
60ec7b7e
DN
1294 {"k9", "f9"},
1295
1296 {"&0", "S-cancel"}, /*shifted cancel key*/
1297 {"&9", "S-begin"}, /*shifted begin key*/
1298 {"*0", "S-find"}, /*shifted find key*/
1299 {"*1", "S-execute"}, /*shifted execute? actually shifted command key*/
1300 {"*4", "S-delete"}, /*shifted delete-character key*/
1301 {"*7", "S-end"}, /*shifted end key*/
1302 {"*8", "S-clearline"}, /*shifted clear-to end-of-line key*/
1303 {"#1", "S-help"}, /*shifted help key*/
1304 {"#2", "S-home"}, /*shifted home key*/
1305 {"#3", "S-insert"}, /*shifted insert-character key*/
1306 {"#4", "S-left"}, /*shifted left-arrow key*/
1307 {"%d", "S-menu"}, /*shifted menu? actually shifted options key*/
1308 {"%c", "S-next"}, /*shifted next key*/
1309 {"%e", "S-prior"}, /*shifted previous key*/
1310 {"%f", "S-print"}, /*shifted print key*/
1311 {"%g", "S-redo"}, /*shifted redo key*/
1312 {"%i", "S-right"}, /*shifted right-arrow key*/
1313 {"!3", "S-undo"} /*shifted undo key*/
a796ac82
JB
1314 };
1315
361358ea 1316#ifndef DOS_NT
e7cf0fa0
KL
1317static char **term_get_fkeys_address;
1318static KBOARD *term_get_fkeys_kboard;
d3da34e0 1319static Lisp_Object term_get_fkeys_1 (void);
465db27b 1320
4f4a84ec 1321/* Find the escape codes sent by the function keys for Vinput_decode_map.
177c0ea7 1322 This function scans the termcap function key sequence entries, and
4f4a84ec 1323 adds entries to Vinput_decode_map for each function key it finds. */
01d8deb0 1324
ed8dad6b 1325static void
d3da34e0 1326term_get_fkeys (char **address, KBOARD *kboard)
f2a00342
RM
1327{
1328 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1329 errors during the call. The only errors should be from Fdefine_key
1330 when given a key sequence containing an invalid prefix key. If the
1331 termcap defines function keys which use a prefix that is already bound
1332 to a command by the default bindings, we should silently ignore that
1333 function key specification, rather than giving the user an error and
1334 refusing to run at all on such a terminal. */
1335
e7cf0fa0
KL
1336 term_get_fkeys_address = address;
1337 term_get_fkeys_kboard = kboard;
f2a00342
RM
1338 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1339}
1340
1341static Lisp_Object
d3da34e0 1342term_get_fkeys_1 (void)
5c2c7893 1343{
5c2c7893
JB
1344 int i;
1345
e7cf0fa0
KL
1346 char **address = term_get_fkeys_address;
1347 KBOARD *kboard = term_get_fkeys_kboard;
f4d953fc 1348
3e65092f 1349 /* This can happen if CANNOT_DUMP or with strange options. */
1344aad4
TT
1350 if (!KEYMAPP (KVAR (kboard, Vinput_decode_map)))
1351 KVAR (kboard, Vinput_decode_map) = Fmake_sparse_keymap (Qnil);
3e65092f 1352
5c2c7893
JB
1353 for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
1354 {
1355 char *sequence = tgetstr (keys[i].cap, address);
1356 if (sequence)
1344aad4 1357 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
f2a00342
RM
1358 Fmake_vector (make_number (1),
1359 intern (keys[i].name)));
5c2c7893 1360 }
a796ac82
JB
1361
1362 /* The uses of the "k0" capability are inconsistent; sometimes it
1363 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
eb8c3be9 1364 We will attempt to politely accommodate both systems by testing for
a796ac82
JB
1365 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1366 */
1367 {
1368 char *k_semi = tgetstr ("k;", address);
1369 char *k0 = tgetstr ("k0", address);
1370 char *k0_name = "f10";
1371
1372 if (k_semi)
1373 {
95c11956
SM
1374 if (k0)
1375 /* Define f0 first, so that f10 takes precedence in case the
1376 key sequences happens to be the same. */
1344aad4 1377 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
95c11956 1378 Fmake_vector (make_number (1), intern ("f0")));
1344aad4 1379 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k_semi),
f2a00342 1380 Fmake_vector (make_number (1), intern ("f10")));
a796ac82 1381 }
95c11956 1382 else if (k0)
1344aad4 1383 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
f2a00342 1384 Fmake_vector (make_number (1), intern (k0_name)));
a796ac82 1385 }
01d8deb0
ER
1386
1387 /* Set up cookies for numbered function keys above f10. */
1388 {
1389 char fcap[3], fkey[4];
1390
fc4f24da 1391 fcap[0] = 'F'; fcap[2] = '\0';
01d8deb0
ER
1392 for (i = 11; i < 64; i++)
1393 {
1394 if (i <= 19)
1395 fcap[1] = '1' + i - 11;
1396 else if (i <= 45)
b59ab95c 1397 fcap[1] = 'A' + i - 20;
01d8deb0 1398 else
b59ab95c 1399 fcap[1] = 'a' + i - 46;
01d8deb0 1400
fc4f24da
RS
1401 {
1402 char *sequence = tgetstr (fcap, address);
1403 if (sequence)
1404 {
465db27b 1405 sprintf (fkey, "f%d", i);
1344aad4 1406 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
f2a00342
RM
1407 Fmake_vector (make_number (1),
1408 intern (fkey)));
fc4f24da
RS
1409 }
1410 }
01d8deb0
ER
1411 }
1412 }
1413
1414 /*
1415 * Various mappings to try and get a better fit.
1416 */
1417 {
fc4f24da
RS
1418#define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1419 if (!tgetstr (cap1, address)) \
1420 { \
1421 char *sequence = tgetstr (cap2, address); \
e7cf0fa0 1422 if (sequence) \
1344aad4 1423 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence), \
e7cf0fa0
KL
1424 Fmake_vector (make_number (1), \
1425 intern (sym))); \
fc4f24da 1426 }
177c0ea7 1427
01d8deb0 1428 /* if there's no key_next keycap, map key_npage to `next' keysym */
27b61785 1429 CONDITIONAL_REASSIGN ("%5", "kN", "next");
01d8deb0 1430 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
381d11a1 1431 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
01d8deb0 1432 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
27b61785 1433 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
403c995b
RS
1434 /* if there's no key_end keycap, map key_ll to 'end' keysym */
1435 CONDITIONAL_REASSIGN ("@7", "kH", "end");
0a7f697a
KH
1436
1437 /* IBM has their own non-standard dialect of terminfo.
1438 If the standard name isn't found, try the IBM name. */
1439 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1440 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1441 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1442 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1443 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1444 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1445 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1446 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1447 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1dd40212 1448#undef CONDITIONAL_REASSIGN
01d8deb0 1449 }
a168702a
GM
1450
1451 return Qnil;
5c2c7893 1452}
361358ea 1453#endif /* not DOS_NT */
5c2c7893
JB
1454
1455\f
a168702a
GM
1456/***********************************************************************
1457 Character Display Information
1458 ***********************************************************************/
f57e2426
J
1459static void append_glyph (struct it *);
1460static void produce_stretch_glyph (struct it *);
1461static void append_composite_glyph (struct it *);
1462static void produce_composite_glyph (struct it *);
b18fad6d
KH
1463static void append_glyphless_glyph (struct it *, int, char *);
1464static void produce_glyphless_glyph (struct it *, int, Lisp_Object);
a168702a
GM
1465
1466/* Append glyphs to IT's glyph_row. Called from produce_glyphs for
d2b4c17d
KH
1467 terminal frames if IT->glyph_row != NULL. IT->char_to_display is
1468 the character for which to produce glyphs; IT->face_id contains the
1469 character's face. Padding glyphs are appended if IT->c has a
1470 IT->pixel_width > 1. */
177c0ea7 1471
a168702a 1472static void
d3da34e0 1473append_glyph (struct it *it)
a168702a
GM
1474{
1475 struct glyph *glyph, *end;
1476 int i;
1477
1478 xassert (it->glyph_row);
1479 glyph = (it->glyph_row->glyphs[it->area]
1480 + it->glyph_row->used[it->area]);
1481 end = it->glyph_row->glyphs[1 + it->area];
1482
5e65aec0
EZ
1483 /* If the glyph row is reversed, we need to prepend the glyph rather
1484 than append it. */
1485 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1486 {
1487 struct glyph *g;
1488 int move_by = it->pixel_width;
1489
1490 /* Make room for the new glyphs. */
1491 if (move_by > end - glyph) /* don't overstep end of this area */
1492 move_by = end - glyph;
1493 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1494 g[move_by] = *g;
1495 glyph = it->glyph_row->glyphs[it->area];
1496 end = glyph + move_by;
1497 }
1498
1499 /* BIDI Note: we put the glyphs of a "multi-pixel" character left to
1500 right, even in the REVERSED_P case, since (a) all of its u.ch are
1501 identical, and (b) the PADDING_P flag needs to be set for the
1502 leftmost one, because we write to the terminal left-to-right. */
177c0ea7
JB
1503 for (i = 0;
1504 i < it->pixel_width && glyph < end;
a168702a
GM
1505 ++i)
1506 {
1507 glyph->type = CHAR_GLYPH;
d13f3e2e 1508 glyph->pixel_width = 1;
d2b4c17d 1509 glyph->u.ch = it->char_to_display;
32de38e4
KH
1510 glyph->face_id = it->face_id;
1511 glyph->padding_p = i > 0;
a168702a
GM
1512 glyph->charpos = CHARPOS (it->position);
1513 glyph->object = it->object;
5e65aec0
EZ
1514 if (it->bidi_p)
1515 {
1516 glyph->resolved_level = it->bidi_it.resolved_level;
9443b3c7
EZ
1517 if ((it->bidi_it.type & 7) != it->bidi_it.type)
1518 abort ();
5e65aec0
EZ
1519 glyph->bidi_type = it->bidi_it.type;
1520 }
9443b3c7
EZ
1521 else
1522 {
1523 glyph->resolved_level = 0;
1524 glyph->bidi_type = UNKNOWN_BT;
1525 }
177c0ea7 1526
a168702a
GM
1527 ++it->glyph_row->used[it->area];
1528 ++glyph;
1529 }
1530}
1531
b50fe468
RS
1532/* Produce glyphs for the display element described by IT. *IT
1533 specifies what we want to produce a glyph for (character, image, ...),
1534 and where in the glyph matrix we currently are (glyph row and hpos).
1535 produce_glyphs fills in output fields of *IT with information such as the
1536 pixel width and height of a character, and maybe output actual glyphs at
e3670e00
EZ
1537 the same time if IT->glyph_row is non-null. For an overview, see
1538 the explanation in dispextern.h, before the definition of the
1539 display_element_type enumeration.
b50fe468
RS
1540
1541 produce_glyphs also stores the result of glyph width, ascent
1542 etc. computations in *IT.
1543
1544 IT->glyph_row may be null, in which case produce_glyphs does not
1545 actually fill in the glyphs. This is used in the move_* functions
1546 in xdisp.c for text width and height computations.
1547
1548 Callers usually don't call produce_glyphs directly;
1549 instead they use the macro PRODUCE_GLYPHS. */
a168702a 1550
177c0ea7 1551void
d3da34e0 1552produce_glyphs (struct it *it)
a168702a
GM
1553{
1554 /* If a hook is installed, let it do the work. */
4c12d738
KH
1555
1556 /* Nothing but characters are supported on terminal frames. */
a168702a 1557 xassert (it->what == IT_CHARACTER
c7cba11d 1558 || it->what == IT_COMPOSITION
a168702a 1559 || it->what == IT_STRETCH);
177c0ea7 1560
6b61353c
KH
1561 if (it->what == IT_STRETCH)
1562 {
1563 produce_stretch_glyph (it);
1564 goto done;
1565 }
1566
4c12d738
KH
1567 if (it->what == IT_COMPOSITION)
1568 {
1569 produce_composite_glyph (it);
1570 goto done;
1571 }
a168702a 1572
b18fad6d
KH
1573 if (it->what == IT_GLYPHLESS)
1574 {
1575 produce_glyphless_glyph (it, 0, Qnil);
1576 goto done;
1577 }
1578
d419e1d9 1579 if (it->char_to_display >= 040 && it->char_to_display < 0177)
a168702a
GM
1580 {
1581 it->pixel_width = it->nglyphs = 1;
1582 if (it->glyph_row)
1583 append_glyph (it);
1584 }
d419e1d9 1585 else if (it->char_to_display == '\n')
a168702a 1586 it->pixel_width = it->nglyphs = 0;
d419e1d9 1587 else if (it->char_to_display == '\t')
a168702a 1588 {
2efdbcdd 1589 int absolute_x = (it->current_x
a168702a 1590 + it->continuation_lines_width);
177c0ea7
JB
1591 int next_tab_x
1592 = (((1 + absolute_x + it->tab_width - 1)
a168702a
GM
1593 / it->tab_width)
1594 * it->tab_width);
1595 int nspaces;
1596
1597 /* If part of the TAB has been displayed on the previous line
1598 which is continued now, continuation_lines_width will have
1599 been incremented already by the part that fitted on the
1600 continued line. So, we will get the right number of spaces
1601 here. */
1602 nspaces = next_tab_x - absolute_x;
177c0ea7 1603
a168702a
GM
1604 if (it->glyph_row)
1605 {
1606 int n = nspaces;
177c0ea7 1607
d2b4c17d 1608 it->char_to_display = ' ';
a168702a 1609 it->pixel_width = it->len = 1;
177c0ea7 1610
a168702a
GM
1611 while (n--)
1612 append_glyph (it);
a168702a
GM
1613 }
1614
1615 it->pixel_width = nspaces;
1616 it->nglyphs = nspaces;
1617 }
d419e1d9 1618 else if (CHAR_BYTE8_P (it->char_to_display))
add44890 1619 {
d419e1d9
KH
1620 /* Coming here means that we must send the raw 8-bit byte as is
1621 to the terminal. Although there's no way to know how many
1622 columns it occupies on a screen, it is a good assumption that
1623 a single byte code has 1-column width. */
1624 it->pixel_width = it->nglyphs = 1;
1625 if (it->glyph_row)
1626 append_glyph (it);
add44890 1627 }
a168702a
GM
1628 else
1629 {
b18fad6d 1630 Lisp_Object charset_list = FRAME_TERMINAL (it->f)->charset_list;
177c0ea7 1631
b18fad6d
KH
1632 if (char_charset (it->char_to_display, charset_list, NULL))
1633 {
1634 it->pixel_width = CHAR_WIDTH (it->char_to_display);
1635 it->nglyphs = it->pixel_width;
1636 if (it->glyph_row)
1637 append_glyph (it);
1638 }
1639 else
1640 {
1641 Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
1642
1643 xassert (it->what == IT_GLYPHLESS);
1644 produce_glyphless_glyph (it, 1, acronym);
1645 }
a168702a
GM
1646 }
1647
6b61353c 1648 done:
177c0ea7 1649 /* Advance current_x by the pixel width as a convenience for
a168702a
GM
1650 the caller. */
1651 if (it->area == TEXT_AREA)
1652 it->current_x += it->pixel_width;
cfe8a05e
GM
1653 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1654 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
a168702a
GM
1655}
1656
1657
6b61353c
KH
1658/* Produce a stretch glyph for iterator IT. IT->object is the value
1659 of the glyph property displayed. The value must be a list
1660 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1661 being recognized:
1662
1663 1. `:width WIDTH' specifies that the space should be WIDTH *
1664 canonical char width wide. WIDTH may be an integer or floating
1665 point number.
1666
1667 2. `:align-to HPOS' specifies that the space should be wide enough
1668 to reach HPOS, a value in canonical character units. */
1669
1670static void
d3da34e0 1671produce_stretch_glyph (struct it *it)
6b61353c
KH
1672{
1673 /* (space :width WIDTH ...) */
1674 Lisp_Object prop, plist;
1675 int width = 0, align_to = -1;
1676 int zero_width_ok_p = 0;
1677 double tem;
1678
1679 /* List should start with `space'. */
1680 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1681 plist = XCDR (it->object);
1682
1683 /* Compute the width of the stretch. */
1684 if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
1685 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, 0))
1686 {
1687 /* Absolute width `:width WIDTH' specified and valid. */
1688 zero_width_ok_p = 1;
1689 width = (int)(tem + 0.5);
1690 }
1691 else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
1692 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, &align_to))
1693 {
1694 if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
feef4f84 1695 align_to = (align_to < 0
6b61353c
KH
1696 ? 0
1697 : align_to - window_box_left_offset (it->w, TEXT_AREA));
1698 else if (align_to < 0)
1699 align_to = window_box_left_offset (it->w, TEXT_AREA);
1700 width = max (0, (int)(tem + 0.5) + align_to - it->current_x);
1701 zero_width_ok_p = 1;
1702 }
1703 else
1704 /* Nothing specified -> width defaults to canonical char width. */
1705 width = FRAME_COLUMN_WIDTH (it->f);
1706
1707 if (width <= 0 && (width < 0 || !zero_width_ok_p))
1708 width = 1;
1709
d5221487
CY
1710 if (width > 0 && it->line_wrap != TRUNCATE
1711 && it->current_x + width > it->last_visible_x)
1712 width = it->last_visible_x - it->current_x - 1;
1713
6b61353c
KH
1714 if (width > 0 && it->glyph_row)
1715 {
1716 Lisp_Object o_object = it->object;
1717 Lisp_Object object = it->stack[it->sp - 1].string;
1718 int n = width;
6b61353c
KH
1719
1720 if (!STRINGP (object))
1721 object = it->w->buffer;
1722 it->object = object;
d2b4c17d 1723 it->char_to_display = ' ';
6b61353c
KH
1724 it->pixel_width = it->len = 1;
1725 while (n--)
1726 append_glyph (it);
1727 it->object = o_object;
6b61353c
KH
1728 }
1729 it->pixel_width = width;
1730 it->nglyphs = width;
1731}
1732
1733
4c12d738
KH
1734/* Append glyphs to IT's glyph_row for the composition IT->cmp_id.
1735 Called from produce_composite_glyph for terminal frames if
1736 IT->glyph_row != NULL. IT->face_id contains the character's
1737 face. */
1738
1739static void
d3da34e0 1740append_composite_glyph (struct it *it)
4c12d738
KH
1741{
1742 struct glyph *glyph;
1743
1744 xassert (it->glyph_row);
1745 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1746 if (glyph < it->glyph_row->glyphs[1 + it->area])
1747 {
93d68d0c
EZ
1748 /* If the glyph row is reversed, we need to prepend the glyph
1749 rather than append it. */
1750 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1751 {
1752 struct glyph *g;
1753
1754 /* Make room for the new glyph. */
1755 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1756 g[1] = *g;
1757 glyph = it->glyph_row->glyphs[it->area];
1758 }
4c12d738
KH
1759 glyph->type = COMPOSITE_GLYPH;
1760 glyph->pixel_width = it->pixel_width;
75a10786
KH
1761 glyph->u.cmp.id = it->cmp_it.id;
1762 if (it->cmp_it.ch < 0)
1763 {
1764 glyph->u.cmp.automatic = 0;
1765 glyph->u.cmp.id = it->cmp_it.id;
1766 }
1767 else
1768 {
1769 glyph->u.cmp.automatic = 1;
1770 glyph->u.cmp.id = it->cmp_it.id;
4be9765d
KH
1771 glyph->slice.cmp.from = it->cmp_it.from;
1772 glyph->slice.cmp.to = it->cmp_it.to - 1;
75a10786
KH
1773 }
1774
4c12d738
KH
1775 glyph->face_id = it->face_id;
1776 glyph->padding_p = 0;
1777 glyph->charpos = CHARPOS (it->position);
1778 glyph->object = it->object;
93d68d0c
EZ
1779 if (it->bidi_p)
1780 {
1781 glyph->resolved_level = it->bidi_it.resolved_level;
1782 if ((it->bidi_it.type & 7) != it->bidi_it.type)
1783 abort ();
1784 glyph->bidi_type = it->bidi_it.type;
1785 }
1786 else
1787 {
1788 glyph->resolved_level = 0;
1789 glyph->bidi_type = UNKNOWN_BT;
1790 }
4c12d738
KH
1791
1792 ++it->glyph_row->used[it->area];
1793 ++glyph;
1794 }
1795}
1796
1797
1798/* Produce a composite glyph for iterator IT. IT->cmp_id is the ID of
1799 the composition. We simply produces components of the composition
2b34df4e
JB
1800 assuming that the terminal has a capability to layout/render it
1801 correctly. */
4c12d738
KH
1802
1803static void
d3da34e0 1804produce_composite_glyph (struct it *it)
4c12d738 1805{
75a10786
KH
1806 if (it->cmp_it.ch < 0)
1807 {
1808 struct composition *cmp = composition_table[it->cmp_it.id];
1809
d0984aff 1810 it->pixel_width = cmp->width;
75a10786
KH
1811 }
1812 else
1813 {
1814 Lisp_Object gstring = composition_gstring_from_id (it->cmp_it.id);
4c12d738 1815
75a10786
KH
1816 it->pixel_width = composition_gstring_width (gstring, it->cmp_it.from,
1817 it->cmp_it.to, NULL);
1818 }
1819 it->nglyphs = 1;
4c12d738
KH
1820 if (it->glyph_row)
1821 append_composite_glyph (it);
1822}
1823
1824
b18fad6d 1825/* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID
0eb025fb
EZ
1826 is a face ID to be used for the glyph. What is actually appended
1827 are glyphs of type CHAR_GLYPH whose characters are in STR (which
1828 comes from it->nglyphs bytes). */
b18fad6d
KH
1829
1830static void
1831append_glyphless_glyph (struct it *it, int face_id, char *str)
1832{
1833 struct glyph *glyph, *end;
b18fad6d
KH
1834 int i;
1835
1836 xassert (it->glyph_row);
1837 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1838 end = it->glyph_row->glyphs[1 + it->area];
1839
1840 /* If the glyph row is reversed, we need to prepend the glyph rather
1841 than append it. */
1842 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1843 {
1844 struct glyph *g;
1845 int move_by = it->pixel_width;
1846
1847 /* Make room for the new glyphs. */
1848 if (move_by > end - glyph) /* don't overstep end of this area */
1849 move_by = end - glyph;
1850 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1851 g[move_by] = *g;
1852 glyph = it->glyph_row->glyphs[it->area];
1853 end = glyph + move_by;
1854 }
1855
1856 if (glyph >= end)
1857 return;
1858 glyph->type = CHAR_GLYPH;
1859 glyph->pixel_width = 1;
1860 glyph->face_id = face_id;
1861 glyph->padding_p = 0;
1862 glyph->charpos = CHARPOS (it->position);
1863 glyph->object = it->object;
1864 if (it->bidi_p)
1865 {
1866 glyph->resolved_level = it->bidi_it.resolved_level;
1867 if ((it->bidi_it.type & 7) != it->bidi_it.type)
1868 abort ();
1869 glyph->bidi_type = it->bidi_it.type;
1870 }
1871 else
1872 {
1873 glyph->resolved_level = 0;
1874 glyph->bidi_type = UNKNOWN_BT;
1875 }
1876
1877 /* BIDI Note: we put the glyphs of characters left to right, even in
1878 the REVERSED_P case because we write to the terminal
1879 left-to-right. */
1880 for (i = 0; i < it->nglyphs && glyph < end; ++i)
1881 {
1882 if (i > 0)
1883 glyph[0] = glyph[-1];
1884 glyph->u.ch = str[i];
1885 ++it->glyph_row->used[it->area];
1886 ++glyph;
1887 }
1888}
1889
b18fad6d
KH
1890/* Produce glyphs for a glyphless character for iterator IT.
1891 IT->glyphless_method specifies which method to use for displaying
1892 the character. See the description of enum
0eb025fb 1893 glyphless_display_method in dispextern.h for the details.
b18fad6d
KH
1894
1895 FOR_NO_FONT is nonzero if and only if this is for a character that
1896 is not supproted by the coding system of the terminal. ACRONYM, if
1897 non-nil, is an acronym string for the character.
1898
1899 The glyphs actually produced are of type CHAR_GLYPH. */
1900
1901static void
1902produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
1903{
1904 int face_id;
0eb025fb 1905 int len;
7c2d713b 1906 char buf[9], *str = " ";
b18fad6d
KH
1907
1908 /* Get a face ID for the glyph by utilizing a cache (the same way as
0eb025fb 1909 done for `escape-glyph' in get_next_display_element). */
b18fad6d
KH
1910 if (it->f == last_glyphless_glyph_frame
1911 && it->face_id == last_glyphless_glyph_face_id)
1912 {
1913 face_id = last_glyphless_glyph_merged_face_id;
1914 }
1915 else
1916 {
1917 /* Merge the `glyphless-char' face into the current face. */
1918 face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id);
1919 last_glyphless_glyph_frame = it->f;
1920 last_glyphless_glyph_face_id = it->face_id;
1921 last_glyphless_glyph_merged_face_id = face_id;
1922 }
1923
1924 if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
1925 {
0eb025fb
EZ
1926 /* As there's no way to produce a thin space, we produce a space
1927 of canonical width. */
b18fad6d
KH
1928 len = 1;
1929 }
1930 else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
1931 {
1932 len = CHAR_WIDTH (it->c);
1933 if (len == 0)
1934 len = 1;
0eb025fb 1935 else if (len > 4)
b18fad6d 1936 len = 4;
0eb025fb
EZ
1937 sprintf (buf, "[%.*s]", len, str);
1938 len += 2;
1939 str = buf;
b18fad6d
KH
1940 }
1941 else
1942 {
1943 if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
1944 {
b18fad6d
KH
1945 if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
1946 acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
1947 buf[0] = '[';
51b59d79 1948 str = STRINGP (acronym) ? SSDATA (acronym) : "";
b18fad6d
KH
1949 for (len = 0; len < 6 && str[len] && ASCII_BYTE_P (str[len]); len++)
1950 buf[1 + len] = str[len];
1951 buf[1 + len] = ']';
1952 len += 2;
1953 }
1954 else
1955 {
0eb025fb 1956 xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEX_CODE);
7c2d713b
EZ
1957 len = (it->c < 0x10000 ? sprintf (buf, "\\u%04X", it->c)
1958 : it->c <= MAX_UNICODE_CHAR ? sprintf (buf, "\\U%06X", it->c)
1959 : sprintf (buf, "\\x%06X", it->c));
b18fad6d
KH
1960 }
1961 str = buf;
1962 }
1963
1964 it->pixel_width = len;
1965 it->nglyphs = len;
1966 if (len > 0 && it->glyph_row)
1967 append_glyphless_glyph (it, face_id, str);
1968}
1969
1970
a168702a
GM
1971/* Get information about special display element WHAT in an
1972 environment described by IT. WHAT is one of IT_TRUNCATION or
1973 IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a
1974 non-null glyph_row member. This function ensures that fields like
1975 face_id, c, len of IT are left untouched. */
1976
1977void
d3da34e0 1978produce_special_glyphs (struct it *it, enum display_element_type what)
a168702a
GM
1979{
1980 struct it temp_it;
f4d953fc 1981 Lisp_Object gc;
072d84a6 1982 GLYPH glyph;
177c0ea7 1983
a168702a
GM
1984 temp_it = *it;
1985 temp_it.dp = NULL;
1986 temp_it.what = IT_CHARACTER;
1987 temp_it.len = 1;
7c752c80 1988 temp_it.object = make_number (0);
72af86bd 1989 memset (&temp_it.current, 0, sizeof temp_it.current);
a168702a
GM
1990
1991 if (what == IT_CONTINUATION)
1992 {
26cdf528
EZ
1993 /* Continuation glyph. For R2L lines, we mirror it by hand. */
1994 if (it->bidi_it.paragraph_dir == R2L)
1995 SET_GLYPH_FROM_CHAR (glyph, '/');
1996 else
1997 SET_GLYPH_FROM_CHAR (glyph, '\\');
a168702a 1998 if (it->dp
f4d953fc
KS
1999 && (gc = DISP_CONTINUE_GLYPH (it->dp), GLYPH_CODE_P (gc))
2000 && GLYPH_CODE_CHAR_VALID_P (gc))
a168702a 2001 {
26cdf528 2002 /* FIXME: Should we mirror GC for R2L lines? */
f4d953fc
KS
2003 SET_GLYPH_FROM_GLYPH_CODE (glyph, gc);
2004 spec_glyph_lookup_face (XWINDOW (it->window), &glyph);
a168702a 2005 }
a168702a
GM
2006 }
2007 else if (what == IT_TRUNCATION)
2008 {
2009 /* Truncation glyph. */
f4d953fc 2010 SET_GLYPH_FROM_CHAR (glyph, '$');
a168702a 2011 if (it->dp
f4d953fc
KS
2012 && (gc = DISP_TRUNC_GLYPH (it->dp), GLYPH_CODE_P (gc))
2013 && GLYPH_CODE_CHAR_VALID_P (gc))
a168702a 2014 {
26cdf528 2015 /* FIXME: Should we mirror GC for R2L lines? */
f4d953fc
KS
2016 SET_GLYPH_FROM_GLYPH_CODE (glyph, gc);
2017 spec_glyph_lookup_face (XWINDOW (it->window), &glyph);
a168702a 2018 }
a168702a
GM
2019 }
2020 else
2021 abort ();
072d84a6 2022
d419e1d9 2023 temp_it.c = temp_it.char_to_display = GLYPH_CHAR (glyph);
f4d953fc 2024 temp_it.face_id = GLYPH_FACE (glyph);
072d84a6
RS
2025 temp_it.len = CHAR_BYTES (temp_it.c);
2026
2027 produce_glyphs (&temp_it);
2028 it->pixel_width = temp_it.pixel_width;
2029 it->nglyphs = temp_it.pixel_width;
a168702a
GM
2030}
2031
2032
a168702a
GM
2033\f
2034/***********************************************************************
2035 Faces
2036 ***********************************************************************/
2037
4e6ba4a4
GM
2038/* Value is non-zero if attribute ATTR may be used. ATTR should be
2039 one of the enumerators from enum no_color_bit, or a bit set built
2040 from them. Some display attributes may not be used together with
2041 color; the termcap capability `NC' specifies which ones. */
2042
fca177d4
KL
2043#define MAY_USE_WITH_COLORS_P(tty, ATTR) \
2044 (tty->TN_max_colors > 0 \
2045 ? (tty->TN_no_color_video & (ATTR)) == 0 \
2046 : 1)
a168702a 2047
072d84a6
RS
2048/* Turn appearances of face FACE_ID on tty frame F on.
2049 FACE_ID is a realized face ID number, in the face cache. */
a168702a
GM
2050
2051static void
d3da34e0 2052turn_on_face (struct frame *f, int face_id)
a168702a
GM
2053{
2054 struct face *face = FACE_FROM_ID (f, face_id);
86a7d192
GM
2055 long fg = face->foreground;
2056 long bg = face->background;
28d7d09f 2057 struct tty_display_info *tty = FRAME_TTY (f);
a168702a 2058
86a7d192
GM
2059 /* Do this first because TS_end_standout_mode may be the same
2060 as TS_exit_attribute_mode, which turns all appearances off. */
fca177d4 2061 if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE))
86a7d192 2062 {
fca177d4 2063 if (tty->TN_max_colors > 0)
86a7d192
GM
2064 {
2065 if (fg >= 0 && bg >= 0)
2066 {
2067 /* If the terminal supports colors, we can set them
2068 below without using reverse video. The face's fg
2069 and bg colors are set as they should appear on
2070 the screen, i.e. they take the inverse-video'ness
2071 of the face already into account. */
2072 }
2073 else if (inverse_video)
2074 {
2075 if (fg == FACE_TTY_DEFAULT_FG_COLOR
2076 || bg == FACE_TTY_DEFAULT_BG_COLOR)
ed8dad6b 2077 tty_toggle_highlight (tty);
86a7d192
GM
2078 }
2079 else
2080 {
2081 if (fg == FACE_TTY_DEFAULT_BG_COLOR
2082 || bg == FACE_TTY_DEFAULT_FG_COLOR)
ed8dad6b 2083 tty_toggle_highlight (tty);
86a7d192
GM
2084 }
2085 }
2086 else
2087 {
2088 /* If we can't display colors, use reverse video
2089 if the face specifies that. */
37526b42
GM
2090 if (inverse_video)
2091 {
2092 if (fg == FACE_TTY_DEFAULT_FG_COLOR
2093 || bg == FACE_TTY_DEFAULT_BG_COLOR)
ed8dad6b 2094 tty_toggle_highlight (tty);
37526b42
GM
2095 }
2096 else
2097 {
2098 if (fg == FACE_TTY_DEFAULT_BG_COLOR
2099 || bg == FACE_TTY_DEFAULT_FG_COLOR)
ed8dad6b 2100 tty_toggle_highlight (tty);
37526b42 2101 }
86a7d192
GM
2102 }
2103 }
a168702a 2104
4189ed40
CY
2105 if (face->tty_bold_p && MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
2106 OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
2107
2108 if (face->tty_dim_p && MAY_USE_WITH_COLORS_P (tty, NC_DIM))
2109 OUTPUT1_IF (tty, tty->TS_enter_dim_mode);
a168702a
GM
2110
2111 /* Alternate charset and blinking not yet used. */
4e6ba4a4 2112 if (face->tty_alt_charset_p
fca177d4
KL
2113 && MAY_USE_WITH_COLORS_P (tty, NC_ALT_CHARSET))
2114 OUTPUT1_IF (tty, tty->TS_enter_alt_charset_mode);
a168702a 2115
4e6ba4a4 2116 if (face->tty_blinking_p
fca177d4
KL
2117 && MAY_USE_WITH_COLORS_P (tty, NC_BLINK))
2118 OUTPUT1_IF (tty, tty->TS_enter_blink_mode);
a168702a 2119
fca177d4
KL
2120 if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
2121 OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
a168702a 2122
fca177d4 2123 if (tty->TN_max_colors > 0)
a168702a 2124 {
753d161b 2125 char *ts, *p;
177c0ea7 2126
fbf34973 2127 ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
753d161b 2128 if (fg >= 0 && ts)
a168702a 2129 {
fbf34973 2130 p = tparam (ts, NULL, 0, (int) fg);
6548cf00 2131 OUTPUT (tty, p);
a168702a
GM
2132 xfree (p);
2133 }
2134
fbf34973 2135 ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
753d161b 2136 if (bg >= 0 && ts)
a168702a 2137 {
fbf34973 2138 p = tparam (ts, NULL, 0, (int) bg);
6548cf00 2139 OUTPUT (tty, p);
a168702a
GM
2140 xfree (p);
2141 }
2142 }
2143}
177c0ea7 2144
a168702a
GM
2145
2146/* Turn off appearances of face FACE_ID on tty frame F. */
2147
2148static void
d3da34e0 2149turn_off_face (struct frame *f, int face_id)
a168702a
GM
2150{
2151 struct face *face = FACE_FROM_ID (f, face_id);
28d7d09f 2152 struct tty_display_info *tty = FRAME_TTY (f);
a168702a
GM
2153
2154 xassert (face != NULL);
2155
fca177d4 2156 if (tty->TS_exit_attribute_mode)
a168702a
GM
2157 {
2158 /* Capability "me" will turn off appearance modes double-bright,
2159 half-bright, reverse-video, standout, underline. It may or
2160 may not turn off alt-char-mode. */
2161 if (face->tty_bold_p
2162 || face->tty_dim_p
2163 || face->tty_reverse_p
2164 || face->tty_alt_charset_p
2165 || face->tty_blinking_p
2166 || face->tty_underline_p)
65aa5e85 2167 {
fca177d4
KL
2168 OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
2169 if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0)
2170 tty->standout_mode = 0;
65aa5e85 2171 }
a168702a
GM
2172
2173 if (face->tty_alt_charset_p)
fca177d4 2174 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
a168702a
GM
2175 }
2176 else
2177 {
2178 /* If we don't have "me" we can only have those appearances
2179 that have exit sequences defined. */
2180 if (face->tty_alt_charset_p)
fca177d4 2181 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
a168702a 2182
54800acb 2183 if (face->tty_underline_p)
fca177d4 2184 OUTPUT_IF (tty, tty->TS_exit_underline_mode);
a168702a
GM
2185 }
2186
2187 /* Switch back to default colors. */
fca177d4 2188 if (tty->TN_max_colors > 0
f9d2fdc4
EZ
2189 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
2190 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
2191 || (face->background != FACE_TTY_DEFAULT_COLOR
2192 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
fca177d4 2193 OUTPUT1_IF (tty, tty->TS_orig_pair);
a168702a 2194}
177c0ea7
JB
2195
2196
b63a55ac
MB
2197/* Return non-zero if the terminal on frame F supports all of the
2198 capabilities in CAPS simultaneously, with foreground and background
2199 colors FG and BG. */
2200
4a8130f2 2201int
d3da34e0
JB
2202tty_capable_p (struct tty_display_info *tty, unsigned int caps,
2203 unsigned long fg, unsigned long bg)
b63a55ac 2204{
fca177d4
KL
2205#define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
2206 if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
b63a55ac
MB
2207 return 0;
2208
fca177d4
KL
2209 TTY_CAPABLE_P_TRY (tty, TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE);
2210 TTY_CAPABLE_P_TRY (tty, TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode, NC_UNDERLINE);
2211 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
2212 TTY_CAPABLE_P_TRY (tty, TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM);
2213 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BLINK, tty->TS_enter_blink_mode, NC_BLINK);
2214 TTY_CAPABLE_P_TRY (tty, TTY_CAP_ALT_CHARSET, tty->TS_enter_alt_charset_mode, NC_ALT_CHARSET);
b63a55ac
MB
2215
2216 /* We can do it! */
2217 return 1;
2218}
2219
a168702a
GM
2220/* Return non-zero if the terminal is capable to display colors. */
2221
2222DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
981e4297 2223 0, 1, 0,
6ed8eeff
KL
2224 doc: /* Return non-nil if the tty device TERMINAL can display colors.
2225
401e9e57
CY
2226TERMINAL can be a terminal object, a frame, or nil (meaning the
2227selected frame's terminal). This function always returns nil if
2228TERMINAL does not refer to a text-only terminal. */)
5842a27b 2229 (Lisp_Object terminal)
a168702a 2230{
717a00ef 2231 struct terminal *t = get_tty_terminal (terminal, 0);
6ed8eeff 2232 if (!t)
428a555e 2233 return Qnil;
3224dac1 2234 else
6ed8eeff 2235 return t->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
a168702a
GM
2236}
2237
bfa62f96
EZ
2238/* Return the number of supported colors. */
2239DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
2240 Stty_display_color_cells, 0, 1, 0,
6ed8eeff
KL
2241 doc: /* Return the number of colors supported by the tty device TERMINAL.
2242
401e9e57
CY
2243TERMINAL can be a terminal object, a frame, or nil (meaning the
2244selected frame's terminal). This function always returns 0 if
2245TERMINAL does not refer to a text-only terminal. */)
5842a27b 2246 (Lisp_Object terminal)
bfa62f96 2247{
717a00ef 2248 struct terminal *t = get_tty_terminal (terminal, 0);
6ed8eeff 2249 if (!t)
8c8d5f35 2250 return make_number (0);
3224dac1 2251 else
6ed8eeff 2252 return make_number (t->display_info.tty->TN_max_colors);
bfa62f96
EZ
2253}
2254
84704c5c 2255#ifndef DOS_NT
a168702a 2256
5205ee62
GM
2257/* Declare here rather than in the function, as in the rest of Emacs,
2258 to work around an HPUX compiler bug (?). See
57407fb4 2259 http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00410.html */
5205ee62
GM
2260static int default_max_colors;
2261static int default_max_pairs;
2262static int default_no_color_video;
2263static char *default_orig_pair;
2264static char *default_set_foreground;
2265static char *default_set_background;
fcf8ff2e 2266
ace28297
EZ
2267/* Save or restore the default color-related capabilities of this
2268 terminal. */
2269static void
28d7d09f 2270tty_default_color_capabilities (struct tty_display_info *tty, int save)
ace28297 2271{
ace28297
EZ
2272
2273 if (save)
2274 {
70fdbb46 2275 xfree (default_orig_pair);
fca177d4 2276 default_orig_pair = tty->TS_orig_pair ? xstrdup (tty->TS_orig_pair) : NULL;
ace28297 2277
70fdbb46 2278 xfree (default_set_foreground);
fca177d4 2279 default_set_foreground = tty->TS_set_foreground ? xstrdup (tty->TS_set_foreground)
ace28297
EZ
2280 : NULL;
2281
70fdbb46 2282 xfree (default_set_background);
fca177d4 2283 default_set_background = tty->TS_set_background ? xstrdup (tty->TS_set_background)
ace28297
EZ
2284 : NULL;
2285
fca177d4
KL
2286 default_max_colors = tty->TN_max_colors;
2287 default_max_pairs = tty->TN_max_pairs;
2288 default_no_color_video = tty->TN_no_color_video;
ace28297
EZ
2289 }
2290 else
2291 {
fca177d4
KL
2292 tty->TS_orig_pair = default_orig_pair;
2293 tty->TS_set_foreground = default_set_foreground;
2294 tty->TS_set_background = default_set_background;
2295 tty->TN_max_colors = default_max_colors;
2296 tty->TN_max_pairs = default_max_pairs;
2297 tty->TN_no_color_video = default_no_color_video;
ace28297
EZ
2298 }
2299}
2300
2301/* Setup one of the standard tty color schemes according to MODE.
2302 MODE's value is generally the number of colors which we want to
2303 support; zero means set up for the default capabilities, the ones
a4c6993d 2304 we saw at init_tty time; -1 means turn off color support. */
ed8dad6b 2305static void
28d7d09f 2306tty_setup_colors (struct tty_display_info *tty, int mode)
ace28297 2307{
6b61353c
KH
2308 /* Canonicalize all negative values of MODE. */
2309 if (mode < -1)
2310 mode = -1;
2311
ace28297
EZ
2312 switch (mode)
2313 {
2314 case -1: /* no colors at all */
fca177d4
KL
2315 tty->TN_max_colors = 0;
2316 tty->TN_max_pairs = 0;
2317 tty->TN_no_color_video = 0;
2318 tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL;
ace28297
EZ
2319 break;
2320 case 0: /* default colors, if any */
2321 default:
fca177d4 2322 tty_default_color_capabilities (tty, 0);
ace28297
EZ
2323 break;
2324 case 8: /* 8 standard ANSI colors */
fca177d4 2325 tty->TS_orig_pair = "\033[0m";
ace28297 2326#ifdef TERMINFO
fca177d4
KL
2327 tty->TS_set_foreground = "\033[3%p1%dm";
2328 tty->TS_set_background = "\033[4%p1%dm";
ace28297 2329#else
fca177d4
KL
2330 tty->TS_set_foreground = "\033[3%dm";
2331 tty->TS_set_background = "\033[4%dm";
ace28297 2332#endif
fca177d4
KL
2333 tty->TN_max_colors = 8;
2334 tty->TN_max_pairs = 64;
2335 tty->TN_no_color_video = 0;
ace28297
EZ
2336 break;
2337 }
2338}
2339
2340void
d3da34e0 2341set_tty_color_mode (struct tty_display_info *tty, struct frame *f)
ace28297 2342{
ce5b453a 2343 Lisp_Object tem, val;
9b2cd403
SM
2344 Lisp_Object color_mode;
2345 int mode;
9b2cd403
SM
2346 Lisp_Object tty_color_mode_alist
2347 = Fintern_soft (build_string ("tty-color-mode-alist"), Qnil);
ace28297 2348
c23b5410 2349 tem = assq_no_quit (Qtty_color_mode, f->param_alist);
9b2cd403 2350 val = CONSP (tem) ? XCDR (tem) : Qnil;
ace28297 2351
6b61353c 2352 if (INTEGERP (val))
ace28297 2353 color_mode = val;
ce5b453a 2354 else if (SYMBOLP (tty_color_mode_alist))
ace28297 2355 {
ce5b453a 2356 tem = Fassq (val, Fsymbol_value (tty_color_mode_alist));
9b2cd403 2357 color_mode = CONSP (tem) ? XCDR (tem) : Qnil;
ace28297 2358 }
ce5b453a
SM
2359 else
2360 color_mode = Qnil;
6b61353c 2361
9b2cd403 2362 mode = INTEGERP (color_mode) ? XINT (color_mode) : 0;
ace28297 2363
9b2cd403 2364 if (mode != tty->previous_color_mode)
ace28297 2365 {
9b2cd403
SM
2366 Lisp_Object funsym = intern ("tty-set-up-initial-frame-faces");
2367 tty->previous_color_mode = mode;
2368 tty_setup_colors (tty , mode);
2369 /* This recomputes all the faces given the new color definitions. */
2370 safe_call (1, &funsym);
ace28297
EZ
2371 }
2372}
2373
84704c5c 2374#endif /* !DOS_NT */
a168702a
GM
2375
2376\f
28d440ab 2377
6ed8eeff 2378/* Return the tty display object specified by TERMINAL. */
b6660415 2379
6ed8eeff 2380struct terminal *
717a00ef 2381get_tty_terminal (Lisp_Object terminal, int throw)
b6660415 2382{
717a00ef 2383 struct terminal *t = get_terminal (terminal, throw);
62af879c 2384
84704c5c 2385 if (t && t->type != output_termcap && t->type != output_msdos_raw)
717a00ef
KL
2386 {
2387 if (throw)
2388 error ("Device %d is not a termcap terminal device", t->id);
2389 else
2390 return NULL;
2391 }
b6660415 2392
6ed8eeff 2393 return t;
b6660415
KL
2394}
2395
ab797f65
KL
2396/* Return an active termcap device that uses the tty device with the
2397 given name.
b6660415 2398
7e59217d 2399 This function ignores suspended devices.
da8e1115
KL
2400
2401 Returns NULL if the named terminal device is not opened. */
f4d953fc 2402
6ed8eeff 2403struct terminal *
8ea90aa3 2404get_named_tty (const char *name)
28d440ab 2405{
6ed8eeff
KL
2406 struct terminal *t;
2407
ab797f65
KL
2408 if (!name)
2409 abort ();
2410
2411 for (t = terminal_list; t; t = t->next_terminal)
2412 {
5cc67f65 2413 if ((t->type == output_termcap || t->type == output_msdos_raw)
ab797f65
KL
2414 && !strcmp (t->display_info.tty->name, name)
2415 && TERMINAL_ACTIVE_P (t))
2416 return t;
2417 }
28d440ab
KL
2418
2419 return 0;
2420}
2421
2422\f
6ed8eeff
KL
2423DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
2424 doc: /* Return the type of the tty device that TERMINAL uses.
ab797f65 2425Returns nil if TERMINAL is not on a tty device.
a3fbb897 2426
401e9e57
CY
2427TERMINAL can be a terminal object, a frame, or nil (meaning the
2428selected frame's terminal). */)
5842a27b 2429 (Lisp_Object terminal)
b6660415 2430{
6ed8eeff 2431 struct terminal *t = get_terminal (terminal, 1);
819b8f00 2432
84704c5c 2433 if (t->type != output_termcap && t->type != output_msdos_raw)
ab797f65
KL
2434 return Qnil;
2435
6ed8eeff
KL
2436 if (t->display_info.tty->type)
2437 return build_string (t->display_info.tty->type);
819b8f00
KL
2438 else
2439 return Qnil;
2440}
2441
6ed8eeff 2442DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
84704c5c 2443 doc: /* Return non-nil if TERMINAL is the controlling tty of the Emacs process.
a3fbb897 2444
401e9e57
CY
2445TERMINAL can be a terminal object, a frame, or nil (meaning the
2446selected frame's terminal). This function always returns nil if
2447TERMINAL is not on a tty device. */)
5842a27b 2448 (Lisp_Object terminal)
4a933ef8 2449{
6ed8eeff 2450 struct terminal *t = get_terminal (terminal, 1);
4a933ef8 2451
84704c5c
EZ
2452 if ((t->type != output_termcap && t->type != output_msdos_raw)
2453 || strcmp (t->display_info.tty->name, DEV_TTY) != 0)
4a933ef8
KL
2454 return Qnil;
2455 else
2456 return Qt;
2457}
2458
a3fbb897 2459DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
6ed8eeff 2460 doc: /* Declare that the tty used by TERMINAL does not handle underlining.
a3fbb897
KL
2461This is used to override the terminfo data, for certain terminals that
2462do not really do underlining, but say that they do. This function has
6ed8eeff 2463no effect if used on a non-tty terminal.
a3fbb897 2464
401e9e57
CY
2465TERMINAL can be a terminal object, a frame or nil (meaning the
2466selected frame's terminal). This function always returns nil if
2467TERMINAL does not refer to a text-only terminal. */)
5842a27b 2468 (Lisp_Object terminal)
a3fbb897 2469{
6ed8eeff 2470 struct terminal *t = get_terminal (terminal, 1);
a3fbb897 2471
6ed8eeff
KL
2472 if (t->type == output_termcap)
2473 t->display_info.tty->TS_enter_underline_mode = 0;
a3fbb897
KL
2474 return Qnil;
2475}
2476
ed8dad6b
KL
2477\f
2478
2479DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
2480 doc: /* Suspend the terminal device TTY.
2481
2482The device is restored to its default state, and Emacs ceases all
2483access to the tty device. Frames that use the device are not deleted,
2484but input is not read from them and if they change, their display is
2485not updated.
2486
401e9e57
CY
2487TTY may be a terminal object, a frame, or nil for the terminal device
2488of the currently selected frame.
ed8dad6b 2489
e4019195 2490This function runs `suspend-tty-functions' after suspending the
ed8dad6b
KL
2491device. The functions are run with one arg, the id of the suspended
2492terminal device.
2493
2494`suspend-tty' does nothing if it is called on a device that is already
2495suspended.
2496
2497A suspended tty may be resumed by calling `resume-tty' on it. */)
5842a27b 2498 (Lisp_Object tty)
ed8dad6b 2499{
717a00ef 2500 struct terminal *t = get_tty_terminal (tty, 1);
ed8dad6b 2501 FILE *f;
f4d953fc 2502
6ed8eeff 2503 if (!t)
ed8dad6b
KL
2504 error ("Unknown tty device");
2505
6ed8eeff 2506 f = t->display_info.tty->input;
f4d953fc 2507
ed8dad6b
KL
2508 if (f)
2509 {
23d4cba5
DN
2510 /* First run `suspend-tty-functions' and then clean up the tty
2511 state because `suspend-tty-functions' might need to change
2512 the tty state. */
2513 if (!NILP (Vrun_hooks))
2514 {
2515 Lisp_Object args[2];
2516 args[0] = intern ("suspend-tty-functions");
2517 XSETTERMINAL (args[1], t);
2518 Frun_hook_with_args (2, args);
2519 }
2520
6ed8eeff 2521 reset_sys_modes (t->display_info.tty);
ed8dad6b 2522 delete_keyboard_wait_descriptor (fileno (f));
f4d953fc 2523
84704c5c 2524#ifndef MSDOS
ed8dad6b 2525 fclose (f);
6ed8eeff
KL
2526 if (f != t->display_info.tty->output)
2527 fclose (t->display_info.tty->output);
84704c5c 2528#endif
f4d953fc 2529
6ed8eeff
KL
2530 t->display_info.tty->input = 0;
2531 t->display_info.tty->output = 0;
ed8dad6b 2532
6ed8eeff
KL
2533 if (FRAMEP (t->display_info.tty->top_frame))
2534 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
f4d953fc 2535
ed8dad6b
KL
2536 }
2537
4a665758
KL
2538 /* Clear display hooks to prevent further output. */
2539 clear_tty_hooks (t);
2540
ed8dad6b
KL
2541 return Qnil;
2542}
2543
2544DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
2545 doc: /* Resume the previously suspended terminal device TTY.
2546The terminal is opened and reinitialized. Frames that are on the
6ed8eeff 2547suspended terminal are revived.
ed8dad6b 2548
6ed8eeff
KL
2549It is an error to resume a terminal while another terminal is active
2550on the same device.
ed8dad6b 2551
e4019195 2552This function runs `resume-tty-functions' after resuming the terminal.
6ed8eeff 2553The functions are run with one arg, the id of the resumed terminal
ed8dad6b
KL
2554device.
2555
2556`resume-tty' does nothing if it is called on a device that is not
2557suspended.
2558
401e9e57
CY
2559TTY may be a terminal object, a frame, or nil (meaning the selected
2560frame's terminal). */)
5842a27b 2561 (Lisp_Object tty)
ed8dad6b 2562{
717a00ef 2563 struct terminal *t = get_tty_terminal (tty, 1);
ed8dad6b
KL
2564 int fd;
2565
6ed8eeff 2566 if (!t)
ed8dad6b
KL
2567 error ("Unknown tty device");
2568
6ed8eeff 2569 if (!t->display_info.tty->input)
ed8dad6b 2570 {
6ed8eeff 2571 if (get_named_tty (t->display_info.tty->name))
ed8dad6b
KL
2572 error ("Cannot resume display while another display is active on the same device");
2573
84704c5c
EZ
2574#ifdef MSDOS
2575 t->display_info.tty->output = stdout;
2576 t->display_info.tty->input = stdin;
2577#else /* !MSDOS */
6ed8eeff 2578 fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
ed8dad6b 2579
59b3194c
KL
2580 if (fd == -1)
2581 error ("Can not reopen tty device %s: %s", t->display_info.tty->name, strerror (errno));
ed8dad6b 2582
78048085 2583 if (strcmp (t->display_info.tty->name, DEV_TTY))
59b3194c 2584 dissociate_if_controlling_tty (fd);
78048085 2585
6ed8eeff
KL
2586 t->display_info.tty->output = fdopen (fd, "w+");
2587 t->display_info.tty->input = t->display_info.tty->output;
84704c5c 2588#endif
78048085 2589
ed8dad6b
KL
2590 add_keyboard_wait_descriptor (fd);
2591
6ed8eeff 2592 if (FRAMEP (t->display_info.tty->top_frame))
db878925
DN
2593 {
2594 struct frame *f = XFRAME (t->display_info.tty->top_frame);
2595 int width, height;
2596 int old_height = FRAME_COLS (f);
2597 int old_width = FRAME_LINES (f);
2598
2599 /* Check if terminal/window size has changed while the frame
2600 was suspended. */
2601 get_tty_size (fileno (t->display_info.tty->input), &width, &height);
2602 if (width != old_width || height != old_height)
2603 change_frame_size (f, height, width, 0, 0, 0);
2604 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
2605 }
ed8dad6b 2606
6ed8eeff 2607 init_sys_modes (t->display_info.tty);
ed8dad6b 2608
e4019195 2609 /* Run `resume-tty-functions'. */
ed8dad6b
KL
2610 if (!NILP (Vrun_hooks))
2611 {
2612 Lisp_Object args[2];
e4019195 2613 args[0] = intern ("resume-tty-functions");
59a7bc63 2614 XSETTERMINAL (args[1], t);
ed8dad6b
KL
2615 Frun_hook_with_args (2, args);
2616 }
2617 }
2618
4a665758
KL
2619 set_tty_hooks (t);
2620
ed8dad6b
KL
2621 return Qnil;
2622}
a3fbb897 2623
819b8f00 2624\f
e882229c
NR
2625/***********************************************************************
2626 Mouse
2627 ***********************************************************************/
2628
7e5a23bd 2629#ifdef HAVE_GPM
5faa03ba
RS
2630void
2631term_mouse_moveto (int x, int y)
94da14a0 2632{
1ec5dc77 2633 /* TODO: how to set mouse position?
94da14a0
NR
2634 const char *name;
2635 int fd;
2636 name = (const char *) ttyname (0);
2637 fd = open (name, O_WRONLY);
80fb2ce0 2638 SOME_FUNCTION (x, y, fd);
94da14a0
NR
2639 close (fd);
2640 last_mouse_x = x;
80fb2ce0 2641 last_mouse_y = y; */
94da14a0
NR
2642}
2643
cf482c50
EZ
2644/* Implementation of draw_row_with_mouse_face for TTY/GPM. */
2645void
2646tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
2647 int start_hpos, int end_hpos,
2648 enum draw_glyphs_face draw)
e882229c 2649{
cf482c50
EZ
2650 int nglyphs = end_hpos - start_hpos;
2651 struct frame *f = XFRAME (WINDOW_FRAME (w));
7be1c21a 2652 struct tty_display_info *tty = FRAME_TTY (f);
cf482c50
EZ
2653 int face_id = tty->mouse_highlight.mouse_face_face_id;
2654 int save_x, save_y, pos_x, pos_y;
7be1c21a 2655
cf482c50
EZ
2656 if (end_hpos >= row->used[TEXT_AREA])
2657 nglyphs = row->used[TEXT_AREA] - start_hpos;
e882229c 2658
cf482c50
EZ
2659 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
2660 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w);
e882229c 2661
cf482c50
EZ
2662 /* Save current cursor co-ordinates. */
2663 save_y = curY (tty);
2664 save_x = curX (tty);
2665 cursor_to (f, pos_y, pos_x);
e882229c 2666
cf482c50
EZ
2667 if (draw == DRAW_MOUSE_FACE)
2668 tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
2669 nglyphs, face_id);
2670 else if (draw == DRAW_NORMAL_TEXT)
2671 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
e882229c 2672
cf482c50 2673 cursor_to (f, save_y, save_x);
e882229c
NR
2674}
2675
2676static int
2677term_mouse_movement (FRAME_PTR frame, Gpm_Event *event)
2678{
2679 /* Has the mouse moved off the glyph it was on at the last sighting? */
2680 if (event->x != last_mouse_x || event->y != last_mouse_y)
2681 {
2682 frame->mouse_moved = 1;
cf482c50 2683 note_mouse_highlight (frame, event->x, event->y);
e882229c
NR
2684 /* Remember which glyph we're now on. */
2685 last_mouse_x = event->x;
2686 last_mouse_y = event->y;
2687 return 1;
2688 }
2689 return 0;
2690}
2691
2692/* Return the current position of the mouse.
2693
2694 Set *f to the frame the mouse is in, or zero if the mouse is in no
2695 Emacs frame. If it is set to zero, all the other arguments are
2696 garbage.
2697
2698 Set *bar_window to Qnil, and *x and *y to the column and
2699 row of the character cell the mouse is over.
2700
2701 Set *time to the time the mouse was at the returned position.
2702
80fb2ce0 2703 This clears mouse_moved until the next motion
94da14a0 2704 event arrives. */
e882229c
NR
2705static void
2706term_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window,
2707 enum scroll_bar_part *part, Lisp_Object *x,
2708 Lisp_Object *y, unsigned long *time)
2709{
e882229c 2710 struct timeval now;
e882229c
NR
2711
2712 *fp = SELECTED_FRAME ();
94da14a0 2713 (*fp)->mouse_moved = 0;
e882229c
NR
2714
2715 *bar_window = Qnil;
2716 *part = 0;
2717
80fb2ce0 2718 XSETINT (*x, last_mouse_x);
94da14a0 2719 XSETINT (*y, last_mouse_y);
e882229c
NR
2720 gettimeofday(&now, 0);
2721 *time = (now.tv_sec * 1000) + (now.tv_usec / 1000);
e882229c
NR
2722}
2723
2724/* Prepare a mouse-event in *RESULT for placement in the input queue.
2725
2726 If the event is a button press, then note that we have grabbed
2727 the mouse. */
2728
2729static Lisp_Object
2730term_mouse_click (struct input_event *result, Gpm_Event *event,
2731 struct frame *f)
2732{
2733 struct timeval now;
2734 int i, j;
2735
2736 result->kind = GPM_CLICK_EVENT;
2737 for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
2738 {
2739 if (event->buttons & j) {
2740 result->code = i; /* button number */
2741 break;
2742 }
2743 }
2744 gettimeofday(&now, 0);
2745 result->timestamp = (now.tv_sec * 1000) + (now.tv_usec / 1000);
2746
2747 if (event->type & GPM_UP)
2748 result->modifiers = up_modifier;
2749 else if (event->type & GPM_DOWN)
2750 result->modifiers = down_modifier;
2751 else
2752 result->modifiers = 0;
f4d953fc 2753
e882229c
NR
2754 if (event->type & GPM_SINGLE)
2755 result->modifiers |= click_modifier;
f4d953fc 2756
e882229c
NR
2757 if (event->type & GPM_DOUBLE)
2758 result->modifiers |= double_modifier;
2759
2760 if (event->type & GPM_TRIPLE)
2761 result->modifiers |= triple_modifier;
2762
2763 if (event->type & GPM_DRAG)
2764 result->modifiers |= drag_modifier;
2765
80fb2ce0 2766 if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
e882229c
NR
2767
2768 /* 1 << KG_SHIFT */
2769 if (event->modifiers & (1 << 0))
2770 result->modifiers |= shift_modifier;
2771
2772 /* 1 << KG_CTRL */
2773 if (event->modifiers & (1 << 2))
2774 result->modifiers |= ctrl_modifier;
2775
2776 /* 1 << KG_ALT || KG_ALTGR */
2777 if (event->modifiers & (1 << 3)
2778 || event->modifiers & (1 << 1))
2779 result->modifiers |= meta_modifier;
2780 }
2781
80fb2ce0
NR
2782 XSETINT (result->x, event->x);
2783 XSETINT (result->y, event->y);
e882229c
NR
2784 XSETFRAME (result->frame_or_window, f);
2785 result->arg = Qnil;
2786 return Qnil;
2787}
2788
f4d953fc 2789int
7be1c21a 2790handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event, struct input_event* hold_quit)
e882229c 2791{
7be1c21a 2792 struct frame *f = XFRAME (tty->top_frame);
e882229c
NR
2793 struct input_event ie;
2794 int do_help = 0;
2795 int count = 0;
2796
2797 EVENT_INIT (ie);
2798 ie.kind = NO_EVENT;
2799 ie.arg = Qnil;
2800
80fb2ce0 2801 if (event->type & (GPM_MOVE | GPM_DRAG)) {
e882229c
NR
2802 previous_help_echo_string = help_echo_string;
2803 help_echo_string = Qnil;
2804
6178ce5e 2805 Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
e882229c 2806
80fb2ce0
NR
2807 if (!term_mouse_movement (f, event))
2808 help_echo_string = previous_help_echo_string;
e882229c
NR
2809
2810 /* If the contents of the global variable help_echo_string
2811 has changed, generate a HELP_EVENT. */
2812 if (!NILP (help_echo_string)
2813 || !NILP (previous_help_echo_string))
2814 do_help = 1;
2815
2816 goto done;
2817 }
2818 else {
2819 f->mouse_moved = 0;
2820 term_mouse_click (&ie, event, f);
e882229c
NR
2821 }
2822
2823 done:
2824 if (ie.kind != NO_EVENT)
2825 {
2826 kbd_buffer_store_event_hold (&ie, hold_quit);
2827 count++;
2828 }
2829
2830 if (do_help
2831 && !(hold_quit && hold_quit->kind != NO_EVENT))
2832 {
2833 Lisp_Object frame;
2834
2835 if (f)
2836 XSETFRAME (frame, f);
2837 else
2838 frame = Qnil;
2839
2840 gen_help_event (help_echo_string, frame, help_echo_window,
2841 help_echo_object, help_echo_pos);
2842 count++;
2843 }
2844
2845 return count;
2846}
2847
6178ce5e 2848DEFUN ("gpm-mouse-start", Fgpm_mouse_start, Sgpm_mouse_start,
e882229c 2849 0, 0, 0,
71f44e7a 2850 doc: /* Open a connection to Gpm.
6178ce5e 2851Gpm-mouse can only be activated for one tty at a time. */)
5842a27b 2852 (void)
e882229c 2853{
71f44e7a
SM
2854 struct frame *f = SELECTED_FRAME ();
2855 struct tty_display_info *tty
2856 = ((f)->output_method == output_termcap
2857 ? (f)->terminal->display_info.tty : NULL);
e882229c
NR
2858 Gpm_Connect connection;
2859
6178ce5e
SM
2860 if (!tty)
2861 error ("Gpm-mouse only works in the GNU/Linux console");
4ce5ab77
SM
2862 if (gpm_tty == tty)
2863 return Qnil; /* Already activated, nothing to do. */
2864 if (gpm_tty)
2865 error ("Gpm-mouse can only be activated for one tty at a time");
71f44e7a 2866
e882229c
NR
2867 connection.eventMask = ~0;
2868 connection.defaultMask = ~GPM_HARD;
2869 connection.maxMod = ~0;
2870 connection.minMod = 0;
80fb2ce0 2871 gpm_zerobased = 1;
e882229c
NR
2872
2873 if (Gpm_Open (&connection, 0) < 0)
6178ce5e 2874 error ("Gpm-mouse failed to connect to the gpm daemon");
e882229c
NR
2875 else
2876 {
71f44e7a 2877 gpm_tty = tty;
1023cbed
SM
2878 /* `init_sys_modes' arranges for mouse movements sent through gpm_fd
2879 to generate SIGIOs. Apparently we need to call reset_sys_modes
2880 before calling init_sys_modes. */
7be1c21a
MB
2881 reset_sys_modes (tty);
2882 init_sys_modes (tty);
e882229c 2883 add_gpm_wait_descriptor (gpm_fd);
6178ce5e 2884 return Qnil;
e882229c
NR
2885 }
2886}
2887
ed5ff21d 2888void
d347e494 2889close_gpm (int fd)
ed5ff21d 2890{
d347e494
SM
2891 if (fd >= 0)
2892 delete_gpm_wait_descriptor (fd);
ed5ff21d
SM
2893 while (Gpm_Close()); /* close all the stack */
2894 gpm_tty = NULL;
2895}
2896
6178ce5e 2897DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
e882229c
NR
2898 0, 0, 0,
2899 doc: /* Close a connection to Gpm. */)
5842a27b 2900 (void)
e882229c 2901{
4ce5ab77
SM
2902 struct frame *f = SELECTED_FRAME ();
2903 struct tty_display_info *tty
2904 = ((f)->output_method == output_termcap
2905 ? (f)->terminal->display_info.tty : NULL);
2906
2907 if (!tty || gpm_tty != tty)
2908 return Qnil; /* Not activated on this terminal, nothing to do. */
f4d953fc 2909
d347e494 2910 close_gpm (gpm_fd);
6178ce5e 2911 return Qnil;
e882229c 2912}
7e5a23bd 2913#endif /* HAVE_GPM */
e882229c
NR
2914
2915\f
89ba96f4 2916#ifndef MSDOS
a168702a
GM
2917/***********************************************************************
2918 Initialization
2919 ***********************************************************************/
2920
ed8dad6b
KL
2921/* Initialize the tty-dependent part of frame F. The frame must
2922 already have its device initialized. */
3224dac1 2923
dfcf069d 2924void
ed8dad6b 2925create_tty_output (struct frame *f)
28d440ab 2926{
ed8dad6b
KL
2927 struct tty_output *t;
2928
2929 if (! FRAME_TERMCAP_P (f))
428a555e
KL
2930 abort ();
2931
ed8dad6b 2932 t = xmalloc (sizeof (struct tty_output));
72af86bd 2933 memset (t, 0, sizeof (struct tty_output));
b6660415 2934
6ed8eeff 2935 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
bedb9c0e 2936
ed8dad6b 2937 f->output_data.tty = t;
3224dac1
KL
2938}
2939
9f215d25 2940/* Delete frame F's face cache, and its tty-dependent part. */
da8e1115 2941
ed8dad6b 2942static void
9f215d25 2943tty_free_frame_resources (struct frame *f)
3224dac1 2944{
ed8dad6b 2945 if (! FRAME_TERMCAP_P (f))
3224dac1
KL
2946 abort ();
2947
9f215d25
CY
2948 if (FRAME_FACE_CACHE (f))
2949 free_frame_faces (f);
2950
ed8dad6b 2951 xfree (f->output_data.tty);
28d440ab
KL
2952}
2953
89ba96f4
EZ
2954#else /* MSDOS */
2955
2956/* Delete frame F's face cache. */
2957
2958static void
2959tty_free_frame_resources (struct frame *f)
2960{
2961 if (! FRAME_TERMCAP_P (f) && ! FRAME_MSDOS_P (f))
2962 abort ();
2963
2964 if (FRAME_FACE_CACHE (f))
2965 free_frame_faces (f);
2966}
2967#endif /* MSDOS */
ed8dad6b 2968\f
47cc8819 2969/* Reset the hooks in TERMINAL. */
ed8dad6b 2970
4a665758
KL
2971static void
2972clear_tty_hooks (struct terminal *terminal)
2973{
2974 terminal->rif = 0;
2975 terminal->cursor_to_hook = 0;
2976 terminal->raw_cursor_to_hook = 0;
2977 terminal->clear_to_end_hook = 0;
2978 terminal->clear_frame_hook = 0;
2979 terminal->clear_end_of_line_hook = 0;
2980 terminal->ins_del_lines_hook = 0;
2981 terminal->insert_glyphs_hook = 0;
2982 terminal->write_glyphs_hook = 0;
2983 terminal->delete_glyphs_hook = 0;
2984 terminal->ring_bell_hook = 0;
2985 terminal->reset_terminal_modes_hook = 0;
2986 terminal->set_terminal_modes_hook = 0;
2987 terminal->update_begin_hook = 0;
2988 terminal->update_end_hook = 0;
2989 terminal->set_terminal_window_hook = 0;
2990 terminal->mouse_position_hook = 0;
2991 terminal->frame_rehighlight_hook = 0;
2992 terminal->frame_raise_lower_hook = 0;
974b73e8 2993 terminal->fullscreen_hook = 0;
4a665758
KL
2994 terminal->set_vertical_scroll_bar_hook = 0;
2995 terminal->condemn_scroll_bars_hook = 0;
2996 terminal->redeem_scroll_bar_hook = 0;
2997 terminal->judge_scroll_bars_hook = 0;
2998 terminal->read_socket_hook = 0;
2999 terminal->frame_up_to_date_hook = 0;
3000
3001 /* Leave these two set, or suspended frames are not deleted
3002 correctly. */
9f215d25 3003 terminal->delete_frame_hook = &tty_free_frame_resources;
4a665758
KL
3004 terminal->delete_terminal_hook = &delete_tty;
3005}
3006
47cc8819
DN
3007/* Initialize hooks in TERMINAL with the values needed for a tty. */
3008
4a665758
KL
3009static void
3010set_tty_hooks (struct terminal *terminal)
3011{
3012 terminal->rif = 0; /* ttys don't support window-based redisplay. */
3013
3014 terminal->cursor_to_hook = &tty_cursor_to;
3015 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
3016
3017 terminal->clear_to_end_hook = &tty_clear_to_end;
3018 terminal->clear_frame_hook = &tty_clear_frame;
3019 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
3020
3021 terminal->ins_del_lines_hook = &tty_ins_del_lines;
3022
3023 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3024 terminal->write_glyphs_hook = &tty_write_glyphs;
3025 terminal->delete_glyphs_hook = &tty_delete_glyphs;
3026
3027 terminal->ring_bell_hook = &tty_ring_bell;
f4d953fc 3028
4a665758
KL
3029 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3030 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
3031 terminal->update_begin_hook = 0; /* Not needed. */
3032 terminal->update_end_hook = &tty_update_end;
3033 terminal->set_terminal_window_hook = &tty_set_terminal_window;
3034
3035 terminal->mouse_position_hook = 0; /* Not needed. */
3036 terminal->frame_rehighlight_hook = 0; /* Not needed. */
3037 terminal->frame_raise_lower_hook = 0; /* Not needed. */
3038
3039 terminal->set_vertical_scroll_bar_hook = 0; /* Not needed. */
3040 terminal->condemn_scroll_bars_hook = 0; /* Not needed. */
3041 terminal->redeem_scroll_bar_hook = 0; /* Not needed. */
3042 terminal->judge_scroll_bars_hook = 0; /* Not needed. */
3043
3044 terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
3045 terminal->frame_up_to_date_hook = 0; /* Not needed. */
f4d953fc 3046
9f215d25 3047 terminal->delete_frame_hook = &tty_free_frame_resources;
4a665758
KL
3048 terminal->delete_terminal_hook = &delete_tty;
3049}
3050
03a1d6bd 3051/* Drop the controlling terminal if fd is the same device. */
ed8dad6b 3052static void
03a1d6bd
KL
3053dissociate_if_controlling_tty (int fd)
3054{
84704c5c 3055#ifndef DOS_NT
12e610e8 3056 int pgid = tcgetpgrp (fd); /* If tcgetpgrp succeeds, fd is the ctty. */
03a1d6bd
KL
3057 if (pgid != -1)
3058 {
6254cdda 3059#if defined (USG5)
03a1d6bd
KL
3060 setpgrp ();
3061 no_controlling_tty = 1;
de52dcbb
DN
3062#elif defined (CYGWIN)
3063 setsid ();
3064 no_controlling_tty = 1;
03a1d6bd
KL
3065#else
3066#ifdef TIOCNOTTY /* Try BSD ioctls. */
8516815b 3067 sigblock (sigmask (SIGTTOU));
78048085 3068 fd = emacs_open (DEV_TTY, O_RDWR, 0);
8516815b
KL
3069 if (fd != -1 && ioctl (fd, TIOCNOTTY, 0) != -1)
3070 {
3071 no_controlling_tty = 1;
3072 }
3073 if (fd != -1)
3074 emacs_close (fd);
3075 sigunblock (sigmask (SIGTTOU));
03a1d6bd 3076#else
8516815b
KL
3077 /* Unknown system. */
3078 croak ();
03a1d6bd
KL
3079#endif /* ! TIOCNOTTY */
3080#endif /* ! USG */
71a96040 3081 }
84704c5c 3082#endif /* !DOS_NT */
03a1d6bd
KL
3083}
3084
3224dac1
KL
3085/* Create a termcap display on the tty device with the given name and
3086 type.
3087
ab797f65 3088 If NAME is NULL, then use the controlling tty, i.e., "/dev/tty".
3224dac1
KL
3089 Otherwise NAME should be a path to the tty device file,
3090 e.g. "/dev/pts/7".
28d440ab 3091
3224dac1
KL
3092 TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
3093
3094 If MUST_SUCCEED is true, then all errors are fatal. */
da8e1115 3095
6ed8eeff 3096struct terminal *
8ea90aa3 3097init_tty (const char *name, const char *terminal_type, int must_succeed)
08a24c47 3098{
59b3194c 3099 char *area = NULL;
08a24c47 3100 char **address = &area;
6b61353c 3101 int buffer_size = 4096;
59b3194c 3102 register char *p = NULL;
08a24c47 3103 int status;
59b3194c
KL
3104 struct tty_display_info *tty = NULL;
3105 struct terminal *terminal = NULL;
3106 int ctty = 0; /* 1 if asked to open controlling tty. */
28d440ab 3107
3224dac1 3108 if (!terminal_type)
d31eee5e 3109 maybe_fatal (must_succeed, 0,
3224dac1
KL
3110 "Unknown terminal type",
3111 "Unknown terminal type");
b6660415 3112
ab797f65 3113 if (name == NULL)
78048085
EZ
3114 name = DEV_TTY;
3115 if (!strcmp (name, DEV_TTY))
ab797f65
KL
3116 ctty = 1;
3117
6ed8eeff
KL
3118 /* If we already have a terminal on the given device, use that. If
3119 all such terminals are suspended, create a new one instead. */
a4c6993d 3120 /* XXX Perhaps this should be made explicit by having init_tty
6ed8eeff 3121 always create a new terminal and separating terminal and frame
b6660415 3122 creation on Lisp level. */
6ed8eeff
KL
3123 terminal = get_named_tty (name);
3124 if (terminal)
3125 return terminal;
78048085 3126
6ed8eeff 3127 terminal = create_terminal ();
84704c5c
EZ
3128#ifdef MSDOS
3129 if (been_here > 0)
d31eee5e 3130 maybe_fatal (1, 0, "Attempt to create another terminal %s", "",
84704c5c
EZ
3131 name, "");
3132 been_here = 1;
3133 tty = &the_only_display_info;
3134#else
3224dac1 3135 tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info));
84704c5c 3136#endif
72af86bd 3137 memset (tty, 0, sizeof (struct tty_display_info));
3224dac1
KL
3138 tty->next = tty_list;
3139 tty_list = tty;
428a555e 3140
6ed8eeff
KL
3141 terminal->type = output_termcap;
3142 terminal->display_info.tty = tty;
3143 tty->terminal = terminal;
28d440ab 3144
7b00d185
KL
3145 tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
3146 Wcm_clear (tty);
daf01701 3147
dce4c2ac
DN
3148 encode_terminal_src_size = 0;
3149 encode_terminal_dst_size = 0;
3150
3151#ifdef HAVE_GPM
3152 terminal->mouse_position_hook = term_mouse_position;
cf482c50 3153 tty->mouse_highlight.mouse_face_window = Qnil;
dce4c2ac
DN
3154#endif
3155
51b59d79 3156
84704c5c 3157#ifndef DOS_NT
4a665758 3158 set_tty_hooks (terminal);
78048085 3159
59b3194c
KL
3160 {
3161 int fd;
3162 FILE *file;
0c72d684
KL
3163
3164#ifdef O_IGNORE_CTTY
59b3194c 3165 if (!ctty)
0c72d684
KL
3166 /* Open the terminal device. Don't recognize it as our
3167 controlling terminal, and don't make it the controlling tty
3168 if we don't have one at the moment. */
3169 fd = emacs_open (name, O_RDWR | O_IGNORE_CTTY | O_NOCTTY, 0);
59b3194c 3170 else
0c72d684 3171#else
2666355c 3172 /* Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
59b3194c
KL
3173 defined on Hurd. On other systems, we need to explicitly
3174 dissociate ourselves from the controlling tty when we want to
3175 open a frame on the same terminal. */
0c72d684 3176 fd = emacs_open (name, O_RDWR | O_NOCTTY, 0);
0c72d684
KL
3177#endif /* O_IGNORE_CTTY */
3178
97c6058a
DN
3179 tty->name = xstrdup (name);
3180 terminal->name = xstrdup (name);
3181
59b3194c 3182 if (fd < 0)
d31eee5e 3183 maybe_fatal (must_succeed, terminal,
59b3194c
KL
3184 "Could not open file: %s",
3185 "Could not open file: %s",
3186 name);
3187 if (!isatty (fd))
3188 {
3189 close (fd);
d31eee5e 3190 maybe_fatal (must_succeed, terminal,
59b3194c
KL
3191 "Not a tty device: %s",
3192 "Not a tty device: %s",
3193 name);
3194 }
0c72d684 3195
59b3194c
KL
3196#ifndef O_IGNORE_CTTY
3197 if (!ctty)
03a1d6bd 3198 dissociate_if_controlling_tty (fd);
59b3194c
KL
3199#endif
3200
3201 file = fdopen (fd, "w+");
59b3194c
KL
3202 tty->input = file;
3203 tty->output = file;
3204 }
78048085 3205
28d7d09f 3206 tty->type = xstrdup (terminal_type);
28d440ab 3207
819b8f00 3208 add_keyboard_wait_descriptor (fileno (tty->input));
08a24c47 3209
6548cf00 3210 Wcm_clear (tty);
08a24c47 3211
d31eee5e 3212 tty->termcap_term_buffer = (char *) xmalloc (buffer_size);
78048085 3213
03a1d6bd
KL
3214 /* On some systems, tgetent tries to access the controlling
3215 terminal. */
3216 sigblock (sigmask (SIGTTOU));
d31eee5e 3217 status = tgetent (tty->termcap_term_buffer, terminal_type);
03a1d6bd 3218 sigunblock (sigmask (SIGTTOU));
78048085 3219
08a24c47 3220 if (status < 0)
b0347178
KH
3221 {
3222#ifdef TERMINFO
d31eee5e 3223 maybe_fatal (must_succeed, terminal,
3224dac1
KL
3224 "Cannot open terminfo database file",
3225 "Cannot open terminfo database file");
b0347178 3226#else
d31eee5e 3227 maybe_fatal (must_succeed, terminal,
3224dac1
KL
3228 "Cannot open termcap database file",
3229 "Cannot open termcap database file");
b0347178
KH
3230#endif
3231 }
08a24c47 3232 if (status == 0)
b0347178 3233 {
d31eee5e 3234 maybe_fatal (must_succeed, terminal,
3224dac1
KL
3235 "Terminal type %s is not defined",
3236 "Terminal type %s is not defined.\n\
b0347178
KH
3237If that is not the actual type of terminal you have,\n\
3238use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
84164a0d
SM
3239`setenv TERM ...') to specify the correct type. It may be necessary\n"
3240#ifdef TERMINFO
3241"to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
b0347178 3242#else
84164a0d 3243"to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
b0347178 3244#endif
84164a0d 3245 terminal_type);
b0347178 3246 }
6b61353c
KH
3247
3248#ifndef TERMINFO
d31eee5e 3249 if (strlen (tty->termcap_term_buffer) >= buffer_size)
08a24c47 3250 abort ();
d31eee5e 3251 buffer_size = strlen (tty->termcap_term_buffer);
6b61353c 3252#endif
d31eee5e 3253 tty->termcap_strings_buffer = area = (char *) xmalloc (buffer_size);
fca177d4
KL
3254 tty->TS_ins_line = tgetstr ("al", address);
3255 tty->TS_ins_multi_lines = tgetstr ("AL", address);
3256 tty->TS_bell = tgetstr ("bl", address);
6548cf00 3257 BackTab (tty) = tgetstr ("bt", address);
fca177d4
KL
3258 tty->TS_clr_to_bottom = tgetstr ("cd", address);
3259 tty->TS_clr_line = tgetstr ("ce", address);
3260 tty->TS_clr_frame = tgetstr ("cl", address);
6548cf00
KL
3261 ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
3262 AbsPosition (tty) = tgetstr ("cm", address);
3263 CR (tty) = tgetstr ("cr", address);
fca177d4
KL
3264 tty->TS_set_scroll_region = tgetstr ("cs", address);
3265 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
6548cf00 3266 RowPosition (tty) = tgetstr ("cv", address);
fca177d4
KL
3267 tty->TS_del_char = tgetstr ("dc", address);
3268 tty->TS_del_multi_chars = tgetstr ("DC", address);
3269 tty->TS_del_line = tgetstr ("dl", address);
3270 tty->TS_del_multi_lines = tgetstr ("DL", address);
3271 tty->TS_delete_mode = tgetstr ("dm", address);
3272 tty->TS_end_delete_mode = tgetstr ("ed", address);
3273 tty->TS_end_insert_mode = tgetstr ("ei", address);
6548cf00 3274 Home (tty) = tgetstr ("ho", address);
fca177d4
KL
3275 tty->TS_ins_char = tgetstr ("ic", address);
3276 tty->TS_ins_multi_chars = tgetstr ("IC", address);
3277 tty->TS_insert_mode = tgetstr ("im", address);
3278 tty->TS_pad_inserted_char = tgetstr ("ip", address);
3279 tty->TS_end_keypad_mode = tgetstr ("ke", address);
3280 tty->TS_keypad_mode = tgetstr ("ks", address);
6548cf00
KL
3281 LastLine (tty) = tgetstr ("ll", address);
3282 Right (tty) = tgetstr ("nd", address);
3283 Down (tty) = tgetstr ("do", address);
3284 if (!Down (tty))
3285 Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */
08a24c47 3286 if (tgetflag ("bs"))
6548cf00 3287 Left (tty) = "\b"; /* can't possibly be longer! */
08a24c47 3288 else /* (Actually, "bs" is obsolete...) */
6548cf00
KL
3289 Left (tty) = tgetstr ("le", address);
3290 if (!Left (tty))
3291 Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */
fca177d4
KL
3292 tty->TS_pad_char = tgetstr ("pc", address);
3293 tty->TS_repeat = tgetstr ("rp", address);
3294 tty->TS_end_standout_mode = tgetstr ("se", address);
3295 tty->TS_fwd_scroll = tgetstr ("sf", address);
3296 tty->TS_standout_mode = tgetstr ("so", address);
3297 tty->TS_rev_scroll = tgetstr ("sr", address);
6548cf00 3298 tty->Wcm->cm_tab = tgetstr ("ta", address);
fca177d4
KL
3299 tty->TS_end_termcap_modes = tgetstr ("te", address);
3300 tty->TS_termcap_modes = tgetstr ("ti", address);
6548cf00 3301 Up (tty) = tgetstr ("up", address);
fca177d4
KL
3302 tty->TS_visible_bell = tgetstr ("vb", address);
3303 tty->TS_cursor_normal = tgetstr ("ve", address);
3304 tty->TS_cursor_visible = tgetstr ("vs", address);
3305 tty->TS_cursor_invisible = tgetstr ("vi", address);
3306 tty->TS_set_window = tgetstr ("wi", address);
3307
3308 tty->TS_enter_underline_mode = tgetstr ("us", address);
3309 tty->TS_exit_underline_mode = tgetstr ("ue", address);
3310 tty->TS_enter_bold_mode = tgetstr ("md", address);
3311 tty->TS_enter_dim_mode = tgetstr ("mh", address);
3312 tty->TS_enter_blink_mode = tgetstr ("mb", address);
3313 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
3314 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
3315 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
3316 tty->TS_exit_attribute_mode = tgetstr ("me", address);
177c0ea7 3317
6548cf00
KL
3318 MultiUp (tty) = tgetstr ("UP", address);
3319 MultiDown (tty) = tgetstr ("DO", address);
3320 MultiLeft (tty) = tgetstr ("LE", address);
3321 MultiRight (tty) = tgetstr ("RI", address);
08a24c47 3322
e7f90eab
GM
3323 /* SVr4/ANSI color suppert. If "op" isn't available, don't support
3324 color because we can't switch back to the default foreground and
3325 background. */
fca177d4
KL
3326 tty->TS_orig_pair = tgetstr ("op", address);
3327 if (tty->TS_orig_pair)
a168702a 3328 {
fca177d4
KL
3329 tty->TS_set_foreground = tgetstr ("AF", address);
3330 tty->TS_set_background = tgetstr ("AB", address);
3331 if (!tty->TS_set_foreground)
e7f90eab
GM
3332 {
3333 /* SVr4. */
fca177d4
KL
3334 tty->TS_set_foreground = tgetstr ("Sf", address);
3335 tty->TS_set_background = tgetstr ("Sb", address);
e7f90eab 3336 }
177c0ea7 3337
fca177d4
KL
3338 tty->TN_max_colors = tgetnum ("Co");
3339 tty->TN_max_pairs = tgetnum ("pa");
177c0ea7 3340
fca177d4
KL
3341 tty->TN_no_color_video = tgetnum ("NC");
3342 if (tty->TN_no_color_video == -1)
3343 tty->TN_no_color_video = 0;
a168702a 3344 }
a168702a 3345
fca177d4 3346 tty_default_color_capabilities (tty, 1);
ace28297 3347
6548cf00 3348 MagicWrap (tty) = tgetflag ("xn");
e4058338
KH
3349 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
3350 the former flag imply the latter. */
6548cf00 3351 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
6ed8eeff 3352 terminal->memory_below_frame = tgetflag ("db");
fca177d4 3353 tty->TF_hazeltine = tgetflag ("hz");
6ed8eeff 3354 terminal->must_write_spaces = tgetflag ("in");
fca177d4
KL
3355 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
3356 tty->TF_insmode_motion = tgetflag ("mi");
3357 tty->TF_standout_motion = tgetflag ("ms");
3358 tty->TF_underscore = tgetflag ("ul");
3359 tty->TF_teleray = tgetflag ("xt");
08a24c47 3360
dce4c2ac
DN
3361#else /* DOS_NT */
3362#ifdef WINDOWSNT
3363 {
3364 struct frame *f = XFRAME (selected_frame);
3365
3366 initialize_w32_display (terminal);
3367
3368 FrameRows (tty) = FRAME_LINES (f);
3369 FrameCols (tty) = FRAME_COLS (f);
3370 tty->specified_window = FRAME_LINES (f);
3371
3372 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
3373 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
3374 terminal->char_ins_del_ok = 1;
3375 baud_rate = 19200;
3376 }
3377#else /* MSDOS */
3378 {
3379 int height, width;
3380 if (strcmp (terminal_type, "internal") == 0)
3381 terminal->type = output_msdos_raw;
3382 initialize_msdos_display (terminal);
3383
3384 get_tty_size (fileno (tty->input), &width, &height);
3385 FrameCols (tty) = width;
3386 FrameRows (tty) = height;
3387 terminal->char_ins_del_ok = 0;
3388 init_baud_rate (fileno (tty->input));
3389 }
3390#endif /* MSDOS */
3391 tty->output = stdout;
3392 tty->input = stdin;
3393 /* The following two are inaccessible from w32console.c. */
3394 terminal->delete_frame_hook = &tty_free_frame_resources;
3395 terminal->delete_terminal_hook = &delete_tty;
3396
3397 tty->name = xstrdup (name);
3398 terminal->name = xstrdup (name);
3399 tty->type = xstrdup (terminal_type);
3400
3401 add_keyboard_wait_descriptor (0);
3402
dce4c2ac
DN
3403 tty->delete_in_insert_mode = 1;
3404
3405 UseTabs (tty) = 0;
3406 terminal->scroll_region_ok = 0;
3407
3408 /* Seems to insert lines when it's not supposed to, messing up the
3409 display. In doing a trace, it didn't seem to be called much, so I
3410 don't think we're losing anything by turning it off. */
3411 terminal->line_ins_del_ok = 0;
3412
3413 tty->TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */
3414#endif /* DOS_NT */
3415
6ed8eeff
KL
3416 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3417 init_kboard (terminal->kboard);
1344aad4 3418 KVAR (terminal->kboard, Vwindow_system) = Qnil;
6ed8eeff
KL
3419 terminal->kboard->next_kboard = all_kboards;
3420 all_kboards = terminal->kboard;
3421 terminal->kboard->reference_count++;
e7cf0fa0
KL
3422 /* Don't let the initial kboard remain current longer than necessary.
3423 That would cause problems if a file loaded on startup tries to
3424 prompt in the mini-buffer. */
3425 if (current_kboard == initial_kboard)
6ed8eeff 3426 current_kboard = terminal->kboard;
84704c5c 3427#ifndef DOS_NT
6ed8eeff 3428 term_get_fkeys (address, terminal->kboard);
5c2c7893 3429
ff11dfa1 3430 /* Get frame size from system, or else from termcap. */
3b12ce12
RS
3431 {
3432 int height, width;
0b0d3e0b 3433 get_tty_size (fileno (tty->input), &width, &height);
0a125897
KL
3434 FrameCols (tty) = width;
3435 FrameRows (tty) = height;
3b12ce12
RS
3436 }
3437
0a125897
KL
3438 if (FrameCols (tty) <= 0)
3439 FrameCols (tty) = tgetnum ("co");
3440 if (FrameRows (tty) <= 0)
3441 FrameRows (tty) = tgetnum ("li");
177c0ea7 3442
0a125897 3443 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
d31eee5e 3444 maybe_fatal (must_succeed, terminal,
b3ffc17c 3445 "Screen size %dx%d is too small",
3224dac1 3446 "Screen size %dx%d is too small",
0a125897 3447 FrameCols (tty), FrameRows (tty));
ee7a2de4 3448
6548cf00 3449 TabWidth (tty) = tgetnum ("tw");
08a24c47 3450
fca177d4
KL
3451 if (!tty->TS_bell)
3452 tty->TS_bell = "\07";
08a24c47 3453
fca177d4
KL
3454 if (!tty->TS_fwd_scroll)
3455 tty->TS_fwd_scroll = Down (tty);
08a24c47 3456
fca177d4 3457 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
08a24c47 3458
6548cf00
KL
3459 if (TabWidth (tty) < 0)
3460 TabWidth (tty) = 8;
177c0ea7 3461
08a24c47
JB
3462/* Turned off since /etc/termcap seems to have :ta= for most terminals
3463 and newer termcap doc does not seem to say there is a default.
6548cf00
KL
3464 if (!tty->Wcm->cm_tab)
3465 tty->Wcm->cm_tab = "\t";
08a24c47
JB
3466*/
3467
54800acb
MB
3468 /* We don't support standout modes that use `magic cookies', so
3469 turn off any that do. */
fca177d4 3470 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
54800acb 3471 {
fca177d4
KL
3472 tty->TS_standout_mode = 0;
3473 tty->TS_end_standout_mode = 0;
54800acb 3474 }
fca177d4 3475 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
54800acb 3476 {
fca177d4
KL
3477 tty->TS_enter_underline_mode = 0;
3478 tty->TS_exit_underline_mode = 0;
54800acb
MB
3479 }
3480
3481 /* If there's no standout mode, try to use underlining instead. */
fca177d4 3482 if (tty->TS_standout_mode == 0)
08a24c47 3483 {
fca177d4
KL
3484 tty->TS_standout_mode = tty->TS_enter_underline_mode;
3485 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
08a24c47
JB
3486 }
3487
afd359c4
RS
3488 /* If no `se' string, try using a `me' string instead.
3489 If that fails, we can't use standout mode at all. */
fca177d4 3490 if (tty->TS_end_standout_mode == 0)
afd359c4 3491 {
e4bfb3b6 3492 char *s = tgetstr ("me", address);
afd359c4 3493 if (s != 0)
fca177d4 3494 tty->TS_end_standout_mode = s;
afd359c4 3495 else
fca177d4 3496 tty->TS_standout_mode = 0;
afd359c4
RS
3497 }
3498
fca177d4 3499 if (tty->TF_teleray)
08a24c47 3500 {
6548cf00 3501 tty->Wcm->cm_tab = 0;
54800acb 3502 /* We can't support standout mode, because it uses magic cookies. */
fca177d4 3503 tty->TS_standout_mode = 0;
08a24c47 3504 /* But that means we cannot rely on ^M to go to column zero! */
6548cf00 3505 CR (tty) = 0;
08a24c47
JB
3506 /* LF can't be trusted either -- can alter hpos */
3507 /* if move at column 0 thru a line with TS_standout_mode */
6548cf00 3508 Down (tty) = 0;
08a24c47
JB
3509 }
3510
3511 /* Special handling for certain terminal types known to need it */
3512
3513 if (!strcmp (terminal_type, "supdup"))
3514 {
6ed8eeff 3515 terminal->memory_below_frame = 1;
6548cf00 3516 tty->Wcm->cm_losewrap = 1;
08a24c47
JB
3517 }
3518 if (!strncmp (terminal_type, "c10", 3)
3519 || !strcmp (terminal_type, "perq"))
3520 {
3521 /* Supply a makeshift :wi string.
3522 This string is not valid in general since it works only
3523 for windows starting at the upper left corner;
3524 but that is all Emacs uses.
3525
ff11dfa1 3526 This string works only if the frame is using
08a24c47
JB
3527 the top of the video memory, because addressing is memory-relative.
3528 So first check the :ti string to see if that is true.
3529
3530 It would be simpler if the :wi string could go in the termcap
3531 entry, but it can't because it is not fully valid.
3532 If it were in the termcap entry, it would confuse other programs. */
fca177d4 3533 if (!tty->TS_set_window)
08a24c47 3534 {
fca177d4 3535 p = tty->TS_termcap_modes;
08a24c47
JB
3536 while (*p && strcmp (p, "\033v "))
3537 p++;
3538 if (*p)
fca177d4 3539 tty->TS_set_window = "\033v%C %C %C %C ";
08a24c47
JB
3540 }
3541 /* Termcap entry often fails to have :in: flag */
6ed8eeff 3542 terminal->must_write_spaces = 1;
08a24c47
JB
3543 /* :ti string typically fails to have \E^G! in it */
3544 /* This limits scope of insert-char to one line. */
fca177d4 3545 strcpy (area, tty->TS_termcap_modes);
08a24c47 3546 strcat (area, "\033\007!");
fca177d4 3547 tty->TS_termcap_modes = area;
08a24c47 3548 area += strlen (area) + 1;
6548cf00 3549 p = AbsPosition (tty);
08a24c47 3550 /* Change all %+ parameters to %C, to handle
28d440ab 3551 values above 96 correctly for the C100. */
08a24c47 3552 while (*p)
28d440ab
KL
3553 {
3554 if (p[0] == '%' && p[1] == '+')
3555 p[1] = 'C';
3556 p++;
3557 }
08a24c47
JB
3558 }
3559
0a125897 3560 tty->specified_window = FrameRows (tty);
08a24c47 3561
6548cf00 3562 if (Wcm_init (tty) == -1) /* can't do cursor motion */
3224dac1 3563 {
d31eee5e 3564 maybe_fatal (must_succeed, terminal,
3224dac1 3565 "Terminal type \"%s\" is not powerful enough to run Emacs",
3224dac1 3566 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
37dad45a
RS
3567It lacks the ability to position the cursor.\n\
3568If that is not the actual type of terminal you have,\n\
3569use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
84164a0d
SM
3570`setenv TERM ...') to specify the correct type. It may be necessary\n"
3571# ifdef TERMINFO
3572"to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
37dad45a 3573# else /* TERMCAP */
84164a0d 3574"to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
37dad45a 3575# endif /* TERMINFO */
3224dac1 3576 terminal_type);
fca177d4 3577 }
daf01701 3578
0a125897 3579 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
d31eee5e 3580 maybe_fatal (must_succeed, terminal,
3224dac1
KL
3581 "Could not determine the frame size",
3582 "Could not determine the frame size");
08a24c47 3583
fca177d4
KL
3584 tty->delete_in_insert_mode
3585 = tty->TS_delete_mode && tty->TS_insert_mode
3586 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
08a24c47 3587
fca177d4
KL
3588 tty->se_is_so = (tty->TS_standout_mode
3589 && tty->TS_end_standout_mode
3590 && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode));
08a24c47 3591
0b0d3e0b 3592 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
08a24c47 3593
6ed8eeff 3594 terminal->scroll_region_ok
6548cf00 3595 = (tty->Wcm->cm_abs
fca177d4 3596 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
08a24c47 3597
6ed8eeff 3598 terminal->line_ins_del_ok
fca177d4
KL
3599 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
3600 && (tty->TS_del_line || tty->TS_del_multi_lines))
6ed8eeff 3601 || (terminal->scroll_region_ok
fca177d4 3602 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
08a24c47 3603
6ed8eeff 3604 terminal->char_ins_del_ok
fca177d4
KL
3605 = ((tty->TS_ins_char || tty->TS_insert_mode
3606 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
3607 && (tty->TS_del_char || tty->TS_del_multi_chars));
08a24c47 3608
6ed8eeff 3609 terminal->fast_clear_end_of_line = tty->TS_clr_line != 0;
08a24c47 3610
0b0d3e0b 3611 init_baud_rate (fileno (tty->input));
20a558dc 3612
84704c5c 3613#endif /* not DOS_NT */
635e3b29 3614
0a125897
KL
3615 /* Init system terminal modes (RAW or CBREAK, etc.). */
3616 init_sys_modes (tty);
daf01701 3617
6ed8eeff 3618 return terminal;
08a24c47
JB
3619}
3620
b3ffc17c
DN
3621
3622static void
3623vfatal (const char *str, va_list ap)
3624{
3625 fprintf (stderr, "emacs: ");
3626 vfprintf (stderr, str, ap);
3627 if (!(strlen (str) > 0 && str[strlen (str) - 1] == '\n'))
3628 fprintf (stderr, "\n");
3629 va_end (ap);
3630 fflush (stderr);
3631 exit (1);
3632}
3633
3634
a4c6993d 3635/* Auxiliary error-handling function for init_tty.
d31eee5e
CY
3636 Delete TERMINAL, then call error or fatal with str1 or str2,
3637 respectively, according to MUST_SUCCEED. */
6b61353c 3638
3224dac1 3639static void
b3ffc17c
DN
3640maybe_fatal (int must_succeed, struct terminal *terminal,
3641 const char *str1, const char *str2, ...)
3224dac1 3642{
b3ffc17c
DN
3643 va_list ap;
3644 va_start (ap, str2);
6ed8eeff
KL
3645 if (terminal)
3646 delete_tty (terminal);
f4d953fc 3647
3224dac1 3648 if (must_succeed)
b3ffc17c 3649 vfatal (str2, ap);
3224dac1 3650 else
b3ffc17c 3651 verror (str1, ap);
3224dac1 3652
b3ffc17c 3653 va_end (ap);
3224dac1 3654 abort ();
08a24c47
JB
3655}
3656
dfcf069d 3657void
7c401d15 3658fatal (const char *str, ...)
08a24c47 3659{
7c401d15
DN
3660 va_list ap;
3661 va_start (ap, str);
b3ffc17c 3662 vfatal (str, ap);
7c401d15 3663 va_end (ap);
08a24c47 3664}
07c57952 3665
819b8f00
KL
3666\f
3667
6ed8eeff 3668/* Delete the given tty terminal, closing all frames on it. */
da8e1115 3669
ed8dad6b 3670static void
6ed8eeff 3671delete_tty (struct terminal *terminal)
072d84a6 3672{
428a555e 3673 struct tty_display_info *tty;
f4d953fc 3674
e2749141 3675 /* Protect against recursive calls. delete_frame in
ab797f65 3676 delete_terminal calls us back when it deletes our last frame. */
59a7bc63 3677 if (!terminal->name)
0a125897 3678 return;
fca177d4 3679
6ed8eeff 3680 if (terminal->type != output_termcap)
428a555e
KL
3681 abort ();
3682
6ed8eeff 3683 tty = terminal->display_info.tty;
f4d953fc 3684
fca177d4
KL
3685 if (tty == tty_list)
3686 tty_list = tty->next;
3687 else
3688 {
28d7d09f 3689 struct tty_display_info *p;
fca177d4
KL
3690 for (p = tty_list; p && p->next != tty; p = p->next)
3691 ;
3692
3693 if (! p)
3694 /* This should not happen. */
3695 abort ();
3696
0a125897
KL
3697 p->next = tty->next;
3698 tty->next = 0;
fca177d4
KL
3699 }
3700
7e59217d 3701 /* reset_sys_modes needs a valid device, so this call needs to be
6ed8eeff 3702 before delete_terminal. */
04c3243c 3703 reset_sys_modes (tty);
fca177d4 3704
6ed8eeff 3705 delete_terminal (terminal);
3224dac1 3706
70fdbb46
JM
3707 xfree (tty->name);
3708 xfree (tty->type);
daf01701 3709
fca177d4 3710 if (tty->input)
819b8f00
KL
3711 {
3712 delete_keyboard_wait_descriptor (fileno (tty->input));
3713 if (tty->input != stdin)
3714 fclose (tty->input);
3715 }
3716 if (tty->output && tty->output != stdout && tty->output != tty->input)
fca177d4
KL
3717 fclose (tty->output);
3718 if (tty->termscript)
3719 fclose (tty->termscript);
daf01701 3720
70fdbb46
JM
3721 xfree (tty->old_tty);
3722 xfree (tty->Wcm);
5f445726
JM
3723 xfree (tty->termcap_strings_buffer);
3724 xfree (tty->termcap_term_buffer);
daf01701 3725
72af86bd 3726 memset (tty, 0, sizeof (struct tty_display_info));
fca177d4 3727 xfree (tty);
fca177d4
KL
3728}
3729
428a555e
KL
3730\f
3731
28d7d09f 3732/* Mark the pointers in the tty_display_info objects.
819b8f00 3733 Called by the Fgarbage_collector. */
da8e1115 3734
fca177d4 3735void
ed8dad6b 3736mark_ttys (void)
fca177d4 3737{
28d7d09f 3738 struct tty_display_info *tty;
0c72d684 3739
819b8f00 3740 for (tty = tty_list; tty; tty = tty->next)
3b6fc48f 3741 mark_object (tty->top_frame);
072d84a6
RS
3742}
3743
428a555e
KL
3744\f
3745
dfcf069d 3746void
d3da34e0 3747syms_of_term (void)
07c57952 3748{
29208e82 3749 DEFVAR_BOOL ("system-uses-terminfo", system_uses_terminfo,
7ee72033 3750 doc: /* Non-nil means the system uses terminfo rather than termcap.
228299fa 3751This variable can be used by terminal emulator packages. */);
07c57952
KH
3752#ifdef TERMINFO
3753 system_uses_terminfo = 1;
3754#else
3755 system_uses_terminfo = 0;
3756#endif
c291d9ef 3757
29208e82 3758 DEFVAR_LISP ("suspend-tty-functions", Vsuspend_tty_functions,
e4019195 3759 doc: /* Functions to be run after suspending a tty.
fdc496e7 3760The functions are run with one argument, the terminal object to be suspended.
0b0d3e0b 3761See `suspend-tty'. */);
e4019195 3762 Vsuspend_tty_functions = Qnil;
0b0d3e0b
KL
3763
3764
29208e82 3765 DEFVAR_LISP ("resume-tty-functions", Vresume_tty_functions,
e4019195 3766 doc: /* Functions to be run after resuming a tty.
fdc496e7 3767The functions are run with one argument, the terminal object that was revived.
0b0d3e0b 3768See `resume-tty'. */);
e4019195 3769 Vresume_tty_functions = Qnil;
a168702a 3770
29208e82 3771 DEFVAR_BOOL ("visible-cursor", visible_cursor,
0db017c0
SM
3772 doc: /* Non-nil means to make the cursor very visible.
3773This only has an effect when running in a text terminal.
3774What means \"very visible\" is up to your terminal. It may make the cursor
3775bigger, or it may make it blink, or it may do nothing at all. */);
3776 visible_cursor = 1;
3777
a168702a 3778 defsubr (&Stty_display_color_p);
bfa62f96 3779 defsubr (&Stty_display_color_cells);
072d84a6 3780 defsubr (&Stty_no_underline);
6ed8eeff
KL
3781 defsubr (&Stty_type);
3782 defsubr (&Scontrolling_tty_p);
0b0d3e0b
KL
3783 defsubr (&Ssuspend_tty);
3784 defsubr (&Sresume_tty);
7e5a23bd 3785#ifdef HAVE_GPM
6178ce5e
SM
3786 defsubr (&Sgpm_mouse_start);
3787 defsubr (&Sgpm_mouse_stop);
7e5a23bd 3788#endif /* HAVE_GPM */
3a7c5d40 3789
84704c5c 3790#ifndef DOS_NT
3a7c5d40
CY
3791 default_orig_pair = NULL;
3792 default_set_foreground = NULL;
3793 default_set_background = NULL;
84704c5c 3794#endif /* !DOS_NT */
d31eee5e
CY
3795
3796 encode_terminal_src = NULL;
3797 encode_terminal_dst = NULL;
07c57952 3798}