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