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