Typo.
[emacs.git] / src / term.c
blob1c686eb521cea51bc6a4f366cc7848b66c2dd247
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, 2008, 2009
4 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 /* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>. */
23 #include <config.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/file.h>
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
34 #if HAVE_TERMIOS_H
35 #include <termios.h> /* For TIOCNOTTY. */
36 #endif
38 #include <signal.h>
39 #include <stdarg.h>
41 #include "lisp.h"
42 #include "termchar.h"
43 #include "termopts.h"
44 #include "buffer.h"
45 #include "character.h"
46 #include "charset.h"
47 #include "coding.h"
48 #include "composite.h"
49 #include "keyboard.h"
50 #include "frame.h"
51 #include "disptab.h"
52 #include "termhooks.h"
53 #include "dispextern.h"
54 #include "window.h"
55 #include "keymap.h"
56 #include "blockinput.h"
57 #include "syssignal.h"
58 #include "systty.h"
59 #include "intervals.h"
60 #ifdef MSDOS
61 #include "msdos.h"
62 static int been_here = -1;
63 #endif
65 /* For now, don't try to include termcap.h. On some systems,
66 configure finds a non-standard termcap.h that the main build
67 won't find. */
69 #if defined HAVE_TERMCAP_H && 0
70 #include <termcap.h>
71 #else
72 extern void tputs P_ ((const char *, int, int (*)(int)));
73 extern int tgetent P_ ((char *, const char *));
74 extern int tgetflag P_ ((char *id));
75 extern int tgetnum P_ ((char *id));
76 #endif
78 #include "cm.h"
79 #ifdef HAVE_X_WINDOWS
80 #include "xterm.h"
81 #endif
83 #ifndef O_RDWR
84 #define O_RDWR 2
85 #endif
87 #ifndef O_NOCTTY
88 #define O_NOCTTY 0
89 #endif
91 /* The name of the default console device. */
92 #ifdef WINDOWSNT
93 #define DEV_TTY "CONOUT$"
94 #else
95 #define DEV_TTY "/dev/tty"
96 #endif
98 static void tty_set_scroll_region P_ ((struct frame *f, int start, int stop));
99 static void turn_on_face P_ ((struct frame *, int face_id));
100 static void turn_off_face P_ ((struct frame *, int face_id));
101 static void tty_show_cursor P_ ((struct tty_display_info *));
102 static void tty_hide_cursor P_ ((struct tty_display_info *));
103 static void tty_background_highlight P_ ((struct tty_display_info *tty));
104 static void clear_tty_hooks P_ ((struct terminal *terminal));
105 static void set_tty_hooks P_ ((struct terminal *terminal));
106 static void dissociate_if_controlling_tty P_ ((int fd));
107 static void delete_tty P_ ((struct terminal *));
109 #define OUTPUT(tty, a) \
110 emacs_tputs ((tty), a, \
111 (int) (FRAME_LINES (XFRAME (selected_frame)) \
112 - curY (tty)), \
113 cmputc)
115 #define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
116 #define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
118 #define OUTPUT_IF(tty, a) \
119 do { \
120 if (a) \
121 emacs_tputs ((tty), a, \
122 (int) (FRAME_LINES (XFRAME (selected_frame)) \
123 - curY (tty) ), \
124 cmputc); \
125 } while (0)
127 #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
129 /* If true, use "vs", otherwise use "ve" to make the cursor visible. */
131 static int visible_cursor;
133 /* Display space properties */
135 extern Lisp_Object Qspace, QCalign_to, QCwidth;
137 /* Functions to call after suspending a tty. */
138 Lisp_Object Vsuspend_tty_functions;
140 /* Functions to call after resuming a tty. */
141 Lisp_Object Vresume_tty_functions;
143 /* Chain of all tty device parameters. */
144 struct tty_display_info *tty_list;
146 /* Nonzero means no need to redraw the entire frame on resuming a
147 suspended Emacs. This is useful on terminals with multiple
148 pages, where one page is used for Emacs and another for all
149 else. */
150 int no_redraw_on_reenter;
152 /* Meaning of bits in no_color_video. Each bit set means that the
153 corresponding attribute cannot be combined with colors. */
155 enum no_color_bit
157 NC_STANDOUT = 1 << 0,
158 NC_UNDERLINE = 1 << 1,
159 NC_REVERSE = 1 << 2,
160 NC_BLINK = 1 << 3,
161 NC_DIM = 1 << 4,
162 NC_BOLD = 1 << 5,
163 NC_INVIS = 1 << 6,
164 NC_PROTECT = 1 << 7,
165 NC_ALT_CHARSET = 1 << 8
168 /* internal state */
170 /* The largest frame width in any call to calculate_costs. */
172 int max_frame_cols;
174 /* The largest frame height in any call to calculate_costs. */
176 int max_frame_lines;
178 /* Non-zero if we have dropped our controlling tty and therefore
179 should not open a frame on stdout. */
180 static int no_controlling_tty;
182 /* Provided for lisp packages. */
184 static int system_uses_terminfo;
186 char *tparam ();
188 extern char *tgetstr ();
191 #ifdef HAVE_GPM
192 #include <sys/fcntl.h>
194 static void term_clear_mouse_face ();
195 static void term_mouse_highlight (struct frame *f, int x, int y);
197 /* The device for which we have enabled gpm support (or NULL). */
198 struct tty_display_info *gpm_tty = NULL;
200 /* These variables describe the range of text currently shown in its
201 mouse-face, together with the window they apply to. As long as
202 the mouse stays within this range, we need not redraw anything on
203 its account. Rows and columns are glyph matrix positions in
204 MOUSE_FACE_WINDOW. */
205 static int mouse_face_beg_row, mouse_face_beg_col;
206 static int mouse_face_end_row, mouse_face_end_col;
207 static int mouse_face_past_end;
208 static Lisp_Object mouse_face_window;
209 static int mouse_face_face_id;
211 static int pos_x, pos_y;
212 static int last_mouse_x, last_mouse_y;
213 #endif /* HAVE_GPM */
215 /* Ring the bell on a tty. */
217 static void
218 tty_ring_bell (struct frame *f)
220 struct tty_display_info *tty = FRAME_TTY (f);
222 if (tty->output)
224 OUTPUT (tty, (tty->TS_visible_bell && visible_bell
225 ? tty->TS_visible_bell
226 : tty->TS_bell));
227 fflush (tty->output);
231 /* Set up termcap modes for Emacs. */
233 void
234 tty_set_terminal_modes (struct terminal *terminal)
236 struct tty_display_info *tty = terminal->display_info.tty;
238 if (tty->output)
240 if (tty->TS_termcap_modes)
241 OUTPUT (tty, tty->TS_termcap_modes);
242 else
244 /* Output enough newlines to scroll all the old screen contents
245 off the screen, so it won't be overwritten and lost. */
246 int i;
247 current_tty = tty;
248 for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
249 cmputc ('\n');
252 OUTPUT_IF (tty, tty->TS_termcap_modes);
253 OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
254 OUTPUT_IF (tty, tty->TS_keypad_mode);
255 losecursor (tty);
256 fflush (tty->output);
260 /* Reset termcap modes before exiting Emacs. */
262 void
263 tty_reset_terminal_modes (struct terminal *terminal)
265 struct tty_display_info *tty = terminal->display_info.tty;
267 if (tty->output)
269 tty_turn_off_highlight (tty);
270 tty_turn_off_insert (tty);
271 OUTPUT_IF (tty, tty->TS_end_keypad_mode);
272 OUTPUT_IF (tty, tty->TS_cursor_normal);
273 OUTPUT_IF (tty, tty->TS_end_termcap_modes);
274 OUTPUT_IF (tty, tty->TS_orig_pair);
275 /* Output raw CR so kernel can track the cursor hpos. */
276 current_tty = tty;
277 cmputc ('\r');
278 fflush (tty->output);
282 /* Flag the end of a display update on a termcap terminal. */
284 static void
285 tty_update_end (struct frame *f)
287 struct tty_display_info *tty = FRAME_TTY (f);
289 if (!XWINDOW (selected_window)->cursor_off_p)
290 tty_show_cursor (tty);
291 tty_turn_off_insert (tty);
292 tty_background_highlight (tty);
295 /* The implementation of set_terminal_window for termcap frames. */
297 static void
298 tty_set_terminal_window (struct frame *f, int size)
300 struct tty_display_info *tty = FRAME_TTY (f);
302 tty->specified_window = size ? size : FRAME_LINES (f);
303 if (FRAME_SCROLL_REGION_OK (f))
304 tty_set_scroll_region (f, 0, tty->specified_window);
307 static void
308 tty_set_scroll_region (struct frame *f, int start, int stop)
310 char *buf;
311 struct tty_display_info *tty = FRAME_TTY (f);
313 if (tty->TS_set_scroll_region)
314 buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1);
315 else if (tty->TS_set_scroll_region_1)
316 buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
317 FRAME_LINES (f), start,
318 FRAME_LINES (f) - stop,
319 FRAME_LINES (f));
320 else
321 buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
323 OUTPUT (tty, buf);
324 xfree (buf);
325 losecursor (tty);
329 static void
330 tty_turn_on_insert (struct tty_display_info *tty)
332 if (!tty->insert_mode)
333 OUTPUT (tty, tty->TS_insert_mode);
334 tty->insert_mode = 1;
337 void
338 tty_turn_off_insert (struct tty_display_info *tty)
340 if (tty->insert_mode)
341 OUTPUT (tty, tty->TS_end_insert_mode);
342 tty->insert_mode = 0;
345 /* Handle highlighting. */
347 void
348 tty_turn_off_highlight (struct tty_display_info *tty)
350 if (tty->standout_mode)
351 OUTPUT_IF (tty, tty->TS_end_standout_mode);
352 tty->standout_mode = 0;
355 static void
356 tty_turn_on_highlight (struct tty_display_info *tty)
358 if (!tty->standout_mode)
359 OUTPUT_IF (tty, tty->TS_standout_mode);
360 tty->standout_mode = 1;
363 static void
364 tty_toggle_highlight (struct tty_display_info *tty)
366 if (tty->standout_mode)
367 tty_turn_off_highlight (tty);
368 else
369 tty_turn_on_highlight (tty);
373 /* Make cursor invisible. */
375 static void
376 tty_hide_cursor (struct tty_display_info *tty)
378 if (tty->cursor_hidden == 0)
380 tty->cursor_hidden = 1;
381 OUTPUT_IF (tty, tty->TS_cursor_invisible);
386 /* Ensure that cursor is visible. */
388 static void
389 tty_show_cursor (struct tty_display_info *tty)
391 if (tty->cursor_hidden)
393 tty->cursor_hidden = 0;
394 OUTPUT_IF (tty, tty->TS_cursor_normal);
395 if (visible_cursor)
396 OUTPUT_IF (tty, tty->TS_cursor_visible);
401 /* Set standout mode to the state it should be in for
402 empty space inside windows. What this is,
403 depends on the user option inverse-video. */
405 static void
406 tty_background_highlight (struct tty_display_info *tty)
408 if (inverse_video)
409 tty_turn_on_highlight (tty);
410 else
411 tty_turn_off_highlight (tty);
414 /* Set standout mode to the mode specified for the text to be output. */
416 static void
417 tty_highlight_if_desired (struct tty_display_info *tty)
419 if (inverse_video)
420 tty_turn_on_highlight (tty);
421 else
422 tty_turn_off_highlight (tty);
426 /* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are
427 frame-relative coordinates. */
429 static void
430 tty_cursor_to (struct frame *f, int vpos, int hpos)
432 struct tty_display_info *tty = FRAME_TTY (f);
434 /* Detect the case where we are called from reset_sys_modes
435 and the costs have never been calculated. Do nothing. */
436 if (! tty->costs_set)
437 return;
439 if (curY (tty) == vpos
440 && curX (tty) == hpos)
441 return;
442 if (!tty->TF_standout_motion)
443 tty_background_highlight (tty);
444 if (!tty->TF_insmode_motion)
445 tty_turn_off_insert (tty);
446 cmgoto (tty, vpos, hpos);
449 /* Similar but don't take any account of the wasted characters. */
451 static void
452 tty_raw_cursor_to (struct frame *f, int row, int col)
454 struct tty_display_info *tty = FRAME_TTY (f);
456 if (curY (tty) == row
457 && curX (tty) == col)
458 return;
459 if (!tty->TF_standout_motion)
460 tty_background_highlight (tty);
461 if (!tty->TF_insmode_motion)
462 tty_turn_off_insert (tty);
463 cmgoto (tty, row, col);
466 /* Erase operations */
468 /* Clear from cursor to end of frame on a termcap device. */
470 static void
471 tty_clear_to_end (struct frame *f)
473 register int i;
474 struct tty_display_info *tty = FRAME_TTY (f);
476 if (tty->TS_clr_to_bottom)
478 tty_background_highlight (tty);
479 OUTPUT (tty, tty->TS_clr_to_bottom);
481 else
483 for (i = curY (tty); i < FRAME_LINES (f); i++)
485 cursor_to (f, i, 0);
486 clear_end_of_line (f, FRAME_COLS (f));
491 /* Clear an entire termcap frame. */
493 static void
494 tty_clear_frame (struct frame *f)
496 struct tty_display_info *tty = FRAME_TTY (f);
498 if (tty->TS_clr_frame)
500 tty_background_highlight (tty);
501 OUTPUT (tty, tty->TS_clr_frame);
502 cmat (tty, 0, 0);
504 else
506 cursor_to (f, 0, 0);
507 clear_to_end (f);
511 /* An implementation of clear_end_of_line for termcap frames.
513 Note that the cursor may be moved, on terminals lacking a `ce' string. */
515 static void
516 tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
518 register int i;
519 struct tty_display_info *tty = FRAME_TTY (f);
521 /* Detect the case where we are called from reset_sys_modes
522 and the costs have never been calculated. Do nothing. */
523 if (! tty->costs_set)
524 return;
526 if (curX (tty) >= first_unused_hpos)
527 return;
528 tty_background_highlight (tty);
529 if (tty->TS_clr_line)
531 OUTPUT1 (tty, tty->TS_clr_line);
533 else
534 { /* have to do it the hard way */
535 tty_turn_off_insert (tty);
537 /* Do not write in last row last col with Auto-wrap on. */
538 if (AutoWrap (tty)
539 && curY (tty) == FrameRows (tty) - 1
540 && first_unused_hpos == FrameCols (tty))
541 first_unused_hpos--;
543 for (i = curX (tty); i < first_unused_hpos; i++)
545 if (tty->termscript)
546 fputc (' ', tty->termscript);
547 fputc (' ', tty->output);
549 cmplus (tty, first_unused_hpos - curX (tty));
553 /* Buffers to store the source and result of code conversion for terminal. */
554 static unsigned char *encode_terminal_src;
555 static unsigned char *encode_terminal_dst;
556 /* Allocated sizes of the above buffers. */
557 static int encode_terminal_src_size;
558 static int encode_terminal_dst_size;
560 /* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
561 Set CODING->produced to the byte-length of the resulting byte
562 sequence, and return a pointer to that byte sequence. */
564 unsigned char *
565 encode_terminal_code (src, src_len, coding)
566 struct glyph *src;
567 int src_len;
568 struct coding_system *coding;
570 struct glyph *src_end = src + src_len;
571 unsigned char *buf;
572 int nchars, nbytes, required;
573 register int tlen = GLYPH_TABLE_LENGTH;
574 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
575 Lisp_Object charset_list;
577 /* Allocate sufficient size of buffer to store all characters in
578 multibyte-form. But, it may be enlarged on demand if
579 Vglyph_table contains a string or a composite glyph is
580 encountered. */
581 required = MAX_MULTIBYTE_LENGTH * src_len;
582 if (encode_terminal_src_size < required)
584 if (encode_terminal_src)
585 encode_terminal_src = xrealloc (encode_terminal_src, required);
586 else
587 encode_terminal_src = xmalloc (required);
588 encode_terminal_src_size = required;
591 charset_list = coding_charset_list (coding);
593 buf = encode_terminal_src;
594 nchars = 0;
595 while (src < src_end)
597 if (src->type == COMPOSITE_GLYPH)
599 struct composition *cmp;
600 Lisp_Object gstring;
601 int i;
603 nbytes = buf - encode_terminal_src;
604 if (src->u.cmp.automatic)
606 gstring = composition_gstring_from_id (src->u.cmp.id);
607 required = src->u.cmp.to + 1 - src->u.cmp.from;
609 else
611 cmp = composition_table[src->u.cmp.id];
612 required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len;
615 if (encode_terminal_src_size < nbytes + required)
617 encode_terminal_src_size = nbytes + required;
618 encode_terminal_src = xrealloc (encode_terminal_src,
619 encode_terminal_src_size);
620 buf = encode_terminal_src + nbytes;
623 if (src->u.cmp.automatic)
624 for (i = src->u.cmp.from; i <= src->u.cmp.to; i++)
626 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
627 int c = LGLYPH_CHAR (g);
629 if (! char_charset (c, charset_list, NULL))
630 c = '?';
631 buf += CHAR_STRING (c, buf);
632 nchars++;
634 else
635 for (i = 0; i < cmp->glyph_len; i++)
637 int c = COMPOSITION_GLYPH (cmp, i);
639 if (c == '\t')
640 continue;
641 if (char_charset (c, charset_list, NULL))
643 if (CHAR_WIDTH (c) == 0
644 && i > 0 && COMPOSITION_GLYPH (cmp, i - 1) == '\t')
645 /* Should be left-padded */
647 buf += CHAR_STRING (' ', buf);
648 nchars++;
651 else
652 c = '?';
653 buf += CHAR_STRING (c, buf);
654 nchars++;
657 /* We must skip glyphs to be padded for a wide character. */
658 else if (! CHAR_GLYPH_PADDING_P (*src))
660 GLYPH g;
661 int c;
662 Lisp_Object string;
664 string = Qnil;
665 SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
667 if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
669 /* This glyph doesn't have an entry in Vglyph_table. */
670 c = src->u.ch;
672 else
674 /* This glyph has an entry in Vglyph_table,
675 so process any alias before testing for simpleness. */
676 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
678 if (GLYPH_SIMPLE_P (tbase, tlen, g))
679 /* We set the multi-byte form of a character in G
680 (that should be an ASCII character) at WORKBUF. */
681 c = GLYPH_CHAR (g);
682 else
683 /* We have a string in Vglyph_table. */
684 string = tbase[GLYPH_CHAR (g)];
687 if (NILP (string))
689 nbytes = buf - encode_terminal_src;
690 if (encode_terminal_src_size < nbytes + MAX_MULTIBYTE_LENGTH)
692 encode_terminal_src_size = nbytes + MAX_MULTIBYTE_LENGTH;
693 encode_terminal_src = xrealloc (encode_terminal_src,
694 encode_terminal_src_size);
695 buf = encode_terminal_src + nbytes;
697 if (char_charset (c, charset_list, NULL))
699 /* Store the multibyte form of C at BUF. */
700 buf += CHAR_STRING (c, buf);
701 nchars++;
703 else
705 /* C is not encodable. */
706 *buf++ = '?';
707 nchars++;
708 while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
710 *buf++ = '?';
711 nchars++;
712 src++;
716 else
718 unsigned char *p = SDATA (string), *pend = p + SBYTES (string);
720 if (! STRING_MULTIBYTE (string))
721 string = string_to_multibyte (string);
722 nbytes = buf - encode_terminal_src;
723 if (encode_terminal_src_size < nbytes + SBYTES (string))
725 encode_terminal_src_size = nbytes + SBYTES (string);
726 encode_terminal_src = xrealloc (encode_terminal_src,
727 encode_terminal_src_size);
728 buf = encode_terminal_src + nbytes;
730 bcopy (SDATA (string), buf, SBYTES (string));
731 buf += SBYTES (string);
732 nchars += SCHARS (string);
735 src++;
738 if (nchars == 0)
740 coding->produced = 0;
741 return NULL;
744 nbytes = buf - encode_terminal_src;
745 coding->source = encode_terminal_src;
746 if (encode_terminal_dst_size == 0)
748 encode_terminal_dst_size = encode_terminal_src_size;
749 if (encode_terminal_dst)
750 encode_terminal_dst = xrealloc (encode_terminal_dst,
751 encode_terminal_dst_size);
752 else
753 encode_terminal_dst = xmalloc (encode_terminal_dst_size);
755 coding->destination = encode_terminal_dst;
756 coding->dst_bytes = encode_terminal_dst_size;
757 encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
758 /* coding->destination may have been reallocated. */
759 encode_terminal_dst = coding->destination;
760 encode_terminal_dst_size = coding->dst_bytes;
762 return (encode_terminal_dst);
767 /* An implementation of write_glyphs for termcap frames. */
769 static void
770 tty_write_glyphs (struct frame *f, struct glyph *string, int len)
772 unsigned char *conversion_buffer;
773 struct coding_system *coding;
775 struct tty_display_info *tty = FRAME_TTY (f);
777 tty_turn_off_insert (tty);
778 tty_hide_cursor (tty);
780 /* Don't dare write in last column of bottom line, if Auto-Wrap,
781 since that would scroll the whole frame on some terminals. */
783 if (AutoWrap (tty)
784 && curY (tty) + 1 == FRAME_LINES (f)
785 && (curX (tty) + len) == FRAME_COLS (f))
786 len --;
787 if (len <= 0)
788 return;
790 cmplus (tty, len);
792 /* If terminal_coding does any conversion, use it, otherwise use
793 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
794 because it always return 1 if the member src_multibyte is 1. */
795 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
796 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
797 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
798 the tail. */
799 coding->mode &= ~CODING_MODE_LAST_BLOCK;
801 while (len > 0)
803 /* Identify a run of glyphs with the same face. */
804 int face_id = string->face_id;
805 int n;
807 for (n = 1; n < len; ++n)
808 if (string[n].face_id != face_id)
809 break;
811 /* Turn appearance modes of the face of the run on. */
812 tty_highlight_if_desired (tty);
813 turn_on_face (f, face_id);
815 if (n == len)
816 /* This is the last run. */
817 coding->mode |= CODING_MODE_LAST_BLOCK;
818 conversion_buffer = encode_terminal_code (string, n, coding);
819 if (coding->produced > 0)
821 BLOCK_INPUT;
822 fwrite (conversion_buffer, 1, coding->produced, tty->output);
823 if (ferror (tty->output))
824 clearerr (tty->output);
825 if (tty->termscript)
826 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
827 UNBLOCK_INPUT;
829 len -= n;
830 string += n;
832 /* Turn appearance modes off. */
833 turn_off_face (f, face_id);
834 tty_turn_off_highlight (tty);
837 cmcheckmagic (tty);
840 #ifdef HAVE_GPM /* Only used by GPM code. */
842 static void
843 tty_write_glyphs_with_face (f, string, len, face_id)
844 register struct frame *f;
845 register struct glyph *string;
846 register int len, face_id;
848 unsigned char *conversion_buffer;
849 struct coding_system *coding;
851 struct tty_display_info *tty = FRAME_TTY (f);
853 tty_turn_off_insert (tty);
854 tty_hide_cursor (tty);
856 /* Don't dare write in last column of bottom line, if Auto-Wrap,
857 since that would scroll the whole frame on some terminals. */
859 if (AutoWrap (tty)
860 && curY (tty) + 1 == FRAME_LINES (f)
861 && (curX (tty) + len) == FRAME_COLS (f))
862 len --;
863 if (len <= 0)
864 return;
866 cmplus (tty, len);
868 /* If terminal_coding does any conversion, use it, otherwise use
869 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
870 because it always return 1 if the member src_multibyte is 1. */
871 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
872 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
873 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
874 the tail. */
875 coding->mode &= ~CODING_MODE_LAST_BLOCK;
877 /* Turn appearance modes of the face. */
878 tty_highlight_if_desired (tty);
879 turn_on_face (f, face_id);
881 coding->mode |= CODING_MODE_LAST_BLOCK;
882 conversion_buffer = encode_terminal_code (string, len, coding);
883 if (coding->produced > 0)
885 BLOCK_INPUT;
886 fwrite (conversion_buffer, 1, coding->produced, tty->output);
887 if (ferror (tty->output))
888 clearerr (tty->output);
889 if (tty->termscript)
890 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
891 UNBLOCK_INPUT;
894 /* Turn appearance modes off. */
895 turn_off_face (f, face_id);
896 tty_turn_off_highlight (tty);
898 cmcheckmagic (tty);
900 #endif
902 /* An implementation of insert_glyphs for termcap frames. */
904 static void
905 tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
907 char *buf;
908 struct glyph *glyph = NULL;
909 unsigned char *conversion_buffer;
910 unsigned char space[1];
911 struct coding_system *coding;
913 struct tty_display_info *tty = FRAME_TTY (f);
915 if (tty->TS_ins_multi_chars)
917 buf = tparam (tty->TS_ins_multi_chars, 0, 0, len);
918 OUTPUT1 (tty, buf);
919 xfree (buf);
920 if (start)
921 write_glyphs (f, start, len);
922 return;
925 tty_turn_on_insert (tty);
926 cmplus (tty, len);
928 if (! start)
929 space[0] = SPACEGLYPH;
931 /* If terminal_coding does any conversion, use it, otherwise use
932 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
933 because it always return 1 if the member src_multibyte is 1. */
934 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
935 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
936 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
937 the tail. */
938 coding->mode &= ~CODING_MODE_LAST_BLOCK;
940 while (len-- > 0)
942 OUTPUT1_IF (tty, tty->TS_ins_char);
943 if (!start)
945 conversion_buffer = space;
946 coding->produced = 1;
948 else
950 tty_highlight_if_desired (tty);
951 turn_on_face (f, start->face_id);
952 glyph = start;
953 ++start;
954 /* We must open sufficient space for a character which
955 occupies more than one column. */
956 while (len && CHAR_GLYPH_PADDING_P (*start))
958 OUTPUT1_IF (tty, tty->TS_ins_char);
959 start++, len--;
962 if (len <= 0)
963 /* This is the last glyph. */
964 coding->mode |= CODING_MODE_LAST_BLOCK;
966 conversion_buffer = encode_terminal_code (glyph, 1, coding);
969 if (coding->produced > 0)
971 BLOCK_INPUT;
972 fwrite (conversion_buffer, 1, coding->produced, tty->output);
973 if (ferror (tty->output))
974 clearerr (tty->output);
975 if (tty->termscript)
976 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
977 UNBLOCK_INPUT;
980 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
981 if (start)
983 turn_off_face (f, glyph->face_id);
984 tty_turn_off_highlight (tty);
988 cmcheckmagic (tty);
991 /* An implementation of delete_glyphs for termcap frames. */
993 static void
994 tty_delete_glyphs (struct frame *f, int n)
996 char *buf;
997 register int i;
999 struct tty_display_info *tty = FRAME_TTY (f);
1001 if (tty->delete_in_insert_mode)
1003 tty_turn_on_insert (tty);
1005 else
1007 tty_turn_off_insert (tty);
1008 OUTPUT_IF (tty, tty->TS_delete_mode);
1011 if (tty->TS_del_multi_chars)
1013 buf = tparam (tty->TS_del_multi_chars, 0, 0, n);
1014 OUTPUT1 (tty, buf);
1015 xfree (buf);
1017 else
1018 for (i = 0; i < n; i++)
1019 OUTPUT1 (tty, tty->TS_del_char);
1020 if (!tty->delete_in_insert_mode)
1021 OUTPUT_IF (tty, tty->TS_end_delete_mode);
1024 /* An implementation of ins_del_lines for termcap frames. */
1026 static void
1027 tty_ins_del_lines (struct frame *f, int vpos, int n)
1029 struct tty_display_info *tty = FRAME_TTY (f);
1030 char *multi = n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
1031 char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
1032 char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
1034 register int i = n > 0 ? n : -n;
1035 register char *buf;
1037 /* If the lines below the insertion are being pushed
1038 into the end of the window, this is the same as clearing;
1039 and we know the lines are already clear, since the matching
1040 deletion has already been done. So can ignore this. */
1041 /* If the lines below the deletion are blank lines coming
1042 out of the end of the window, don't bother,
1043 as there will be a matching inslines later that will flush them. */
1044 if (FRAME_SCROLL_REGION_OK (f)
1045 && vpos + i >= tty->specified_window)
1046 return;
1047 if (!FRAME_MEMORY_BELOW_FRAME (f)
1048 && vpos + i >= FRAME_LINES (f))
1049 return;
1051 if (multi)
1053 raw_cursor_to (f, vpos, 0);
1054 tty_background_highlight (tty);
1055 buf = tparam (multi, 0, 0, i);
1056 OUTPUT (tty, buf);
1057 xfree (buf);
1059 else if (single)
1061 raw_cursor_to (f, vpos, 0);
1062 tty_background_highlight (tty);
1063 while (--i >= 0)
1064 OUTPUT (tty, single);
1065 if (tty->TF_teleray)
1066 curX (tty) = 0;
1068 else
1070 tty_set_scroll_region (f, vpos, tty->specified_window);
1071 if (n < 0)
1072 raw_cursor_to (f, tty->specified_window - 1, 0);
1073 else
1074 raw_cursor_to (f, vpos, 0);
1075 tty_background_highlight (tty);
1076 while (--i >= 0)
1077 OUTPUTL (tty, scroll, tty->specified_window - vpos);
1078 tty_set_scroll_region (f, 0, tty->specified_window);
1081 if (!FRAME_SCROLL_REGION_OK (f)
1082 && FRAME_MEMORY_BELOW_FRAME (f)
1083 && n < 0)
1085 cursor_to (f, FRAME_LINES (f) + n, 0);
1086 clear_to_end (f);
1090 /* Compute cost of sending "str", in characters,
1091 not counting any line-dependent padding. */
1094 string_cost (char *str)
1096 cost = 0;
1097 if (str)
1098 tputs (str, 0, evalcost);
1099 return cost;
1102 /* Compute cost of sending "str", in characters,
1103 counting any line-dependent padding at one line. */
1105 static int
1106 string_cost_one_line (char *str)
1108 cost = 0;
1109 if (str)
1110 tputs (str, 1, evalcost);
1111 return cost;
1114 /* Compute per line amount of line-dependent padding,
1115 in tenths of characters. */
1118 per_line_cost (char *str)
1120 cost = 0;
1121 if (str)
1122 tputs (str, 0, evalcost);
1123 cost = - cost;
1124 if (str)
1125 tputs (str, 10, evalcost);
1126 return cost;
1129 #ifndef old
1130 /* char_ins_del_cost[n] is cost of inserting N characters.
1131 char_ins_del_cost[-n] is cost of deleting N characters.
1132 The length of this vector is based on max_frame_cols. */
1134 int *char_ins_del_vector;
1136 #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_COLS ((f))])
1137 #endif
1139 /* ARGSUSED */
1140 static void
1141 calculate_ins_del_char_costs (struct frame *f)
1143 struct tty_display_info *tty = FRAME_TTY (f);
1144 int ins_startup_cost, del_startup_cost;
1145 int ins_cost_per_char, del_cost_per_char;
1146 register int i;
1147 register int *p;
1149 if (tty->TS_ins_multi_chars)
1151 ins_cost_per_char = 0;
1152 ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars);
1154 else if (tty->TS_ins_char || tty->TS_pad_inserted_char
1155 || (tty->TS_insert_mode && tty->TS_end_insert_mode))
1157 ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode)
1158 + string_cost (tty->TS_end_insert_mode))) / 100;
1159 ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char)
1160 + string_cost_one_line (tty->TS_pad_inserted_char));
1162 else
1164 ins_startup_cost = 9999;
1165 ins_cost_per_char = 0;
1168 if (tty->TS_del_multi_chars)
1170 del_cost_per_char = 0;
1171 del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars);
1173 else if (tty->TS_del_char)
1175 del_startup_cost = (string_cost (tty->TS_delete_mode)
1176 + string_cost (tty->TS_end_delete_mode));
1177 if (tty->delete_in_insert_mode)
1178 del_startup_cost /= 2;
1179 del_cost_per_char = string_cost_one_line (tty->TS_del_char);
1181 else
1183 del_startup_cost = 9999;
1184 del_cost_per_char = 0;
1187 /* Delete costs are at negative offsets */
1188 p = &char_ins_del_cost (f)[0];
1189 for (i = FRAME_COLS (f); --i >= 0;)
1190 *--p = (del_startup_cost += del_cost_per_char);
1192 /* Doing nothing is free */
1193 p = &char_ins_del_cost (f)[0];
1194 *p++ = 0;
1196 /* Insert costs are at positive offsets */
1197 for (i = FRAME_COLS (f); --i >= 0;)
1198 *p++ = (ins_startup_cost += ins_cost_per_char);
1201 void
1202 calculate_costs (struct frame *frame)
1204 FRAME_COST_BAUD_RATE (frame) = baud_rate;
1206 if (FRAME_TERMCAP_P (frame))
1208 struct tty_display_info *tty = FRAME_TTY (frame);
1209 register char *f = (tty->TS_set_scroll_region
1210 ? tty->TS_set_scroll_region
1211 : tty->TS_set_scroll_region_1);
1213 FRAME_SCROLL_REGION_COST (frame) = string_cost (f);
1215 tty->costs_set = 1;
1217 /* These variables are only used for terminal stuff. They are
1218 allocated once for the terminal frame of X-windows emacs, but not
1219 used afterwards.
1221 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1222 X turns off char_ins_del_ok. */
1224 max_frame_lines = max (max_frame_lines, FRAME_LINES (frame));
1225 max_frame_cols = max (max_frame_cols, FRAME_COLS (frame));
1227 if (char_ins_del_vector != 0)
1228 char_ins_del_vector
1229 = (int *) xrealloc (char_ins_del_vector,
1230 (sizeof (int)
1231 + 2 * max_frame_cols * sizeof (int)));
1232 else
1233 char_ins_del_vector
1234 = (int *) xmalloc (sizeof (int)
1235 + 2 * max_frame_cols * sizeof (int));
1237 bzero (char_ins_del_vector, (sizeof (int)
1238 + 2 * max_frame_cols * sizeof (int)));
1241 if (f && (!tty->TS_ins_line && !tty->TS_del_line))
1242 do_line_insertion_deletion_costs (frame,
1243 tty->TS_rev_scroll, tty->TS_ins_multi_lines,
1244 tty->TS_fwd_scroll, tty->TS_del_multi_lines,
1245 f, f, 1);
1246 else
1247 do_line_insertion_deletion_costs (frame,
1248 tty->TS_ins_line, tty->TS_ins_multi_lines,
1249 tty->TS_del_line, tty->TS_del_multi_lines,
1250 0, 0, 1);
1252 calculate_ins_del_char_costs (frame);
1254 /* Don't use TS_repeat if its padding is worse than sending the chars */
1255 if (tty->TS_repeat && per_line_cost (tty->TS_repeat) * baud_rate < 9000)
1256 tty->RPov = string_cost (tty->TS_repeat);
1257 else
1258 tty->RPov = FRAME_COLS (frame) * 2;
1260 cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */
1264 struct fkey_table {
1265 char *cap, *name;
1268 /* Termcap capability names that correspond directly to X keysyms.
1269 Some of these (marked "terminfo") aren't supplied by old-style
1270 (Berkeley) termcap entries. They're listed in X keysym order;
1271 except we put the keypad keys first, so that if they clash with
1272 other keys (as on the IBM PC keyboard) they get overridden.
1275 static struct fkey_table keys[] =
1277 {"kh", "home"}, /* termcap */
1278 {"kl", "left"}, /* termcap */
1279 {"ku", "up"}, /* termcap */
1280 {"kr", "right"}, /* termcap */
1281 {"kd", "down"}, /* termcap */
1282 {"%8", "prior"}, /* terminfo */
1283 {"%5", "next"}, /* terminfo */
1284 {"@7", "end"}, /* terminfo */
1285 {"@1", "begin"}, /* terminfo */
1286 {"*6", "select"}, /* terminfo */
1287 {"%9", "print"}, /* terminfo */
1288 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1290 * "insert" --- see below
1292 {"&8", "undo"}, /* terminfo */
1293 {"%0", "redo"}, /* terminfo */
1294 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1295 {"@0", "find"}, /* terminfo */
1296 {"@2", "cancel"}, /* terminfo */
1297 {"%1", "help"}, /* terminfo */
1299 * "break" goes here, but can't be reliably intercepted with termcap
1301 {"&4", "reset"}, /* terminfo --- actually `restart' */
1303 * "system" and "user" --- no termcaps
1305 {"kE", "clearline"}, /* terminfo */
1306 {"kA", "insertline"}, /* terminfo */
1307 {"kL", "deleteline"}, /* terminfo */
1308 {"kI", "insertchar"}, /* terminfo */
1309 {"kD", "deletechar"}, /* terminfo */
1310 {"kB", "backtab"}, /* terminfo */
1312 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1314 {"@8", "kp-enter"}, /* terminfo */
1316 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1317 * "kp-multiply", "kp-add", "kp-separator",
1318 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1319 * --- no termcaps for any of these.
1321 {"K4", "kp-1"}, /* terminfo */
1323 * "kp-2" --- no termcap
1325 {"K5", "kp-3"}, /* terminfo */
1327 * "kp-4" --- no termcap
1329 {"K2", "kp-5"}, /* terminfo */
1331 * "kp-6" --- no termcap
1333 {"K1", "kp-7"}, /* terminfo */
1335 * "kp-8" --- no termcap
1337 {"K3", "kp-9"}, /* terminfo */
1339 * "kp-equal" --- no termcap
1341 {"k1", "f1"},
1342 {"k2", "f2"},
1343 {"k3", "f3"},
1344 {"k4", "f4"},
1345 {"k5", "f5"},
1346 {"k6", "f6"},
1347 {"k7", "f7"},
1348 {"k8", "f8"},
1349 {"k9", "f9"},
1351 {"&0", "S-cancel"}, /*shifted cancel key*/
1352 {"&9", "S-begin"}, /*shifted begin key*/
1353 {"*0", "S-find"}, /*shifted find key*/
1354 {"*1", "S-execute"}, /*shifted execute? actually shifted command key*/
1355 {"*4", "S-delete"}, /*shifted delete-character key*/
1356 {"*7", "S-end"}, /*shifted end key*/
1357 {"*8", "S-clearline"}, /*shifted clear-to end-of-line key*/
1358 {"#1", "S-help"}, /*shifted help key*/
1359 {"#2", "S-home"}, /*shifted home key*/
1360 {"#3", "S-insert"}, /*shifted insert-character key*/
1361 {"#4", "S-left"}, /*shifted left-arrow key*/
1362 {"%d", "S-menu"}, /*shifted menu? actually shifted options key*/
1363 {"%c", "S-next"}, /*shifted next key*/
1364 {"%e", "S-prior"}, /*shifted previous key*/
1365 {"%f", "S-print"}, /*shifted print key*/
1366 {"%g", "S-redo"}, /*shifted redo key*/
1367 {"%i", "S-right"}, /*shifted right-arrow key*/
1368 {"!3", "S-undo"} /*shifted undo key*/
1371 static char **term_get_fkeys_address;
1372 static KBOARD *term_get_fkeys_kboard;
1373 static Lisp_Object term_get_fkeys_1 ();
1375 /* Find the escape codes sent by the function keys for Vinput_decode_map.
1376 This function scans the termcap function key sequence entries, and
1377 adds entries to Vinput_decode_map for each function key it finds. */
1379 static void
1380 term_get_fkeys (address, kboard)
1381 char **address;
1382 KBOARD *kboard;
1384 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1385 errors during the call. The only errors should be from Fdefine_key
1386 when given a key sequence containing an invalid prefix key. If the
1387 termcap defines function keys which use a prefix that is already bound
1388 to a command by the default bindings, we should silently ignore that
1389 function key specification, rather than giving the user an error and
1390 refusing to run at all on such a terminal. */
1392 extern Lisp_Object Fidentity ();
1393 term_get_fkeys_address = address;
1394 term_get_fkeys_kboard = kboard;
1395 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1398 static Lisp_Object
1399 term_get_fkeys_1 ()
1401 int i;
1403 char **address = term_get_fkeys_address;
1404 KBOARD *kboard = term_get_fkeys_kboard;
1406 /* This can happen if CANNOT_DUMP or with strange options. */
1407 if (!KEYMAPP (kboard->Vinput_decode_map))
1408 kboard->Vinput_decode_map = Fmake_sparse_keymap (Qnil);
1410 for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
1412 char *sequence = tgetstr (keys[i].cap, address);
1413 if (sequence)
1414 Fdefine_key (kboard->Vinput_decode_map, build_string (sequence),
1415 Fmake_vector (make_number (1),
1416 intern (keys[i].name)));
1419 /* The uses of the "k0" capability are inconsistent; sometimes it
1420 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1421 We will attempt to politely accommodate both systems by testing for
1422 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1425 char *k_semi = tgetstr ("k;", address);
1426 char *k0 = tgetstr ("k0", address);
1427 char *k0_name = "f10";
1429 if (k_semi)
1431 if (k0)
1432 /* Define f0 first, so that f10 takes precedence in case the
1433 key sequences happens to be the same. */
1434 Fdefine_key (kboard->Vinput_decode_map, build_string (k0),
1435 Fmake_vector (make_number (1), intern ("f0")));
1436 Fdefine_key (kboard->Vinput_decode_map, build_string (k_semi),
1437 Fmake_vector (make_number (1), intern ("f10")));
1439 else if (k0)
1440 Fdefine_key (kboard->Vinput_decode_map, build_string (k0),
1441 Fmake_vector (make_number (1), intern (k0_name)));
1444 /* Set up cookies for numbered function keys above f10. */
1446 char fcap[3], fkey[4];
1448 fcap[0] = 'F'; fcap[2] = '\0';
1449 for (i = 11; i < 64; i++)
1451 if (i <= 19)
1452 fcap[1] = '1' + i - 11;
1453 else if (i <= 45)
1454 fcap[1] = 'A' + i - 20;
1455 else
1456 fcap[1] = 'a' + i - 46;
1459 char *sequence = tgetstr (fcap, address);
1460 if (sequence)
1462 sprintf (fkey, "f%d", i);
1463 Fdefine_key (kboard->Vinput_decode_map, build_string (sequence),
1464 Fmake_vector (make_number (1),
1465 intern (fkey)));
1472 * Various mappings to try and get a better fit.
1475 #define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1476 if (!tgetstr (cap1, address)) \
1478 char *sequence = tgetstr (cap2, address); \
1479 if (sequence) \
1480 Fdefine_key (kboard->Vinput_decode_map, build_string (sequence), \
1481 Fmake_vector (make_number (1), \
1482 intern (sym))); \
1485 /* if there's no key_next keycap, map key_npage to `next' keysym */
1486 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1487 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1488 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1489 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1490 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1491 /* if there's no key_end keycap, map key_ll to 'end' keysym */
1492 CONDITIONAL_REASSIGN ("@7", "kH", "end");
1494 /* IBM has their own non-standard dialect of terminfo.
1495 If the standard name isn't found, try the IBM name. */
1496 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1497 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1498 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1499 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1500 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1501 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1502 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1503 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1504 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1505 #undef CONDITIONAL_REASSIGN
1508 return Qnil;
1512 /***********************************************************************
1513 Character Display Information
1514 ***********************************************************************/
1516 /* Avoid name clash with functions defined in xterm.c */
1517 #ifdef static
1518 #define append_glyph append_glyph_term
1519 #define produce_stretch_glyph produce_stretch_glyph_term
1520 #define append_composite_glyph append_composite_glyph_term
1521 #define produce_composite_glyph produce_composite_glyph_term
1522 #endif
1524 static void append_glyph P_ ((struct it *));
1525 static void produce_stretch_glyph P_ ((struct it *));
1526 static void append_composite_glyph P_ ((struct it *));
1527 static void produce_composite_glyph P_ ((struct it *));
1529 /* Append glyphs to IT's glyph_row. Called from produce_glyphs for
1530 terminal frames if IT->glyph_row != NULL. IT->char_to_display is
1531 the character for which to produce glyphs; IT->face_id contains the
1532 character's face. Padding glyphs are appended if IT->c has a
1533 IT->pixel_width > 1. */
1535 static void
1536 append_glyph (it)
1537 struct it *it;
1539 struct glyph *glyph, *end;
1540 int i;
1542 xassert (it->glyph_row);
1543 glyph = (it->glyph_row->glyphs[it->area]
1544 + it->glyph_row->used[it->area]);
1545 end = it->glyph_row->glyphs[1 + it->area];
1547 for (i = 0;
1548 i < it->pixel_width && glyph < end;
1549 ++i)
1551 glyph->type = CHAR_GLYPH;
1552 glyph->pixel_width = 1;
1553 glyph->u.ch = it->char_to_display;
1554 glyph->face_id = it->face_id;
1555 glyph->padding_p = i > 0;
1556 glyph->charpos = CHARPOS (it->position);
1557 glyph->object = it->object;
1559 ++it->glyph_row->used[it->area];
1560 ++glyph;
1565 /* Produce glyphs for the display element described by IT. *IT
1566 specifies what we want to produce a glyph for (character, image, ...),
1567 and where in the glyph matrix we currently are (glyph row and hpos).
1568 produce_glyphs fills in output fields of *IT with information such as the
1569 pixel width and height of a character, and maybe output actual glyphs at
1570 the same time if IT->glyph_row is non-null. See the explanation of
1571 struct display_iterator in dispextern.h for an overview.
1573 produce_glyphs also stores the result of glyph width, ascent
1574 etc. computations in *IT.
1576 IT->glyph_row may be null, in which case produce_glyphs does not
1577 actually fill in the glyphs. This is used in the move_* functions
1578 in xdisp.c for text width and height computations.
1580 Callers usually don't call produce_glyphs directly;
1581 instead they use the macro PRODUCE_GLYPHS. */
1583 void
1584 produce_glyphs (it)
1585 struct it *it;
1587 /* If a hook is installed, let it do the work. */
1589 /* Nothing but characters are supported on terminal frames. */
1590 xassert (it->what == IT_CHARACTER
1591 || it->what == IT_COMPOSITION
1592 || it->what == IT_STRETCH);
1594 if (it->what == IT_STRETCH)
1596 produce_stretch_glyph (it);
1597 goto done;
1600 if (it->what == IT_COMPOSITION)
1602 produce_composite_glyph (it);
1603 goto done;
1606 /* Maybe translate single-byte characters to multibyte. */
1607 it->char_to_display = it->c;
1609 if (it->c >= 040 && it->c < 0177)
1611 it->pixel_width = it->nglyphs = 1;
1612 if (it->glyph_row)
1613 append_glyph (it);
1615 else if (it->c == '\n')
1616 it->pixel_width = it->nglyphs = 0;
1617 else if (it->c == '\t')
1619 int absolute_x = (it->current_x
1620 + it->continuation_lines_width);
1621 int next_tab_x
1622 = (((1 + absolute_x + it->tab_width - 1)
1623 / it->tab_width)
1624 * it->tab_width);
1625 int nspaces;
1627 /* If part of the TAB has been displayed on the previous line
1628 which is continued now, continuation_lines_width will have
1629 been incremented already by the part that fitted on the
1630 continued line. So, we will get the right number of spaces
1631 here. */
1632 nspaces = next_tab_x - absolute_x;
1634 if (it->glyph_row)
1636 int n = nspaces;
1638 it->char_to_display = ' ';
1639 it->pixel_width = it->len = 1;
1641 while (n--)
1642 append_glyph (it);
1645 it->pixel_width = nspaces;
1646 it->nglyphs = nspaces;
1648 else if (CHAR_BYTE8_P (it->c))
1650 if (unibyte_display_via_language_environment
1651 && (it->c >= 0240))
1653 it->char_to_display = unibyte_char_to_multibyte (it->c);
1654 it->pixel_width = CHAR_WIDTH (it->char_to_display);
1655 it->nglyphs = it->pixel_width;
1656 if (it->glyph_row)
1657 append_glyph (it);
1659 else
1661 /* Coming here means that it->c is from display table, thus
1662 we must send the raw 8-bit byte as is to the terminal.
1663 Although there's no way to know how many columns it
1664 occupies on a screen, it is a good assumption that a
1665 single byte code has 1-column width. */
1666 it->pixel_width = it->nglyphs = 1;
1667 if (it->glyph_row)
1668 append_glyph (it);
1671 else
1673 it->pixel_width = CHAR_WIDTH (it->c);
1674 it->nglyphs = it->pixel_width;
1676 if (it->glyph_row)
1677 append_glyph (it);
1680 done:
1681 /* Advance current_x by the pixel width as a convenience for
1682 the caller. */
1683 if (it->area == TEXT_AREA)
1684 it->current_x += it->pixel_width;
1685 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1686 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
1690 /* Produce a stretch glyph for iterator IT. IT->object is the value
1691 of the glyph property displayed. The value must be a list
1692 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1693 being recognized:
1695 1. `:width WIDTH' specifies that the space should be WIDTH *
1696 canonical char width wide. WIDTH may be an integer or floating
1697 point number.
1699 2. `:align-to HPOS' specifies that the space should be wide enough
1700 to reach HPOS, a value in canonical character units. */
1702 static void
1703 produce_stretch_glyph (it)
1704 struct it *it;
1706 /* (space :width WIDTH ...) */
1707 Lisp_Object prop, plist;
1708 int width = 0, align_to = -1;
1709 int zero_width_ok_p = 0;
1710 double tem;
1712 /* List should start with `space'. */
1713 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1714 plist = XCDR (it->object);
1716 /* Compute the width of the stretch. */
1717 if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
1718 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, 0))
1720 /* Absolute width `:width WIDTH' specified and valid. */
1721 zero_width_ok_p = 1;
1722 width = (int)(tem + 0.5);
1724 else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
1725 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, &align_to))
1727 if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
1728 align_to = (align_to < 0
1730 : align_to - window_box_left_offset (it->w, TEXT_AREA));
1731 else if (align_to < 0)
1732 align_to = window_box_left_offset (it->w, TEXT_AREA);
1733 width = max (0, (int)(tem + 0.5) + align_to - it->current_x);
1734 zero_width_ok_p = 1;
1736 else
1737 /* Nothing specified -> width defaults to canonical char width. */
1738 width = FRAME_COLUMN_WIDTH (it->f);
1740 if (width <= 0 && (width < 0 || !zero_width_ok_p))
1741 width = 1;
1743 if (width > 0 && it->line_wrap != TRUNCATE
1744 && it->current_x + width > it->last_visible_x)
1745 width = it->last_visible_x - it->current_x - 1;
1747 if (width > 0 && it->glyph_row)
1749 Lisp_Object o_object = it->object;
1750 Lisp_Object object = it->stack[it->sp - 1].string;
1751 int n = width;
1753 if (!STRINGP (object))
1754 object = it->w->buffer;
1755 it->object = object;
1756 it->char_to_display = ' ';
1757 it->pixel_width = it->len = 1;
1758 while (n--)
1759 append_glyph (it);
1760 it->object = o_object;
1762 it->pixel_width = width;
1763 it->nglyphs = width;
1767 /* Append glyphs to IT's glyph_row for the composition IT->cmp_id.
1768 Called from produce_composite_glyph for terminal frames if
1769 IT->glyph_row != NULL. IT->face_id contains the character's
1770 face. */
1772 static void
1773 append_composite_glyph (it)
1774 struct it *it;
1776 struct glyph *glyph;
1778 xassert (it->glyph_row);
1779 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1780 if (glyph < it->glyph_row->glyphs[1 + it->area])
1782 glyph->type = COMPOSITE_GLYPH;
1783 glyph->pixel_width = it->pixel_width;
1784 glyph->u.cmp.id = it->cmp_it.id;
1785 if (it->cmp_it.ch < 0)
1787 glyph->u.cmp.automatic = 0;
1788 glyph->u.cmp.id = it->cmp_it.id;
1790 else
1792 glyph->u.cmp.automatic = 1;
1793 glyph->u.cmp.id = it->cmp_it.id;
1794 glyph->u.cmp.from = it->cmp_it.from;
1795 glyph->u.cmp.to = it->cmp_it.to - 1;
1798 glyph->face_id = it->face_id;
1799 glyph->padding_p = 0;
1800 glyph->charpos = CHARPOS (it->position);
1801 glyph->object = it->object;
1803 ++it->glyph_row->used[it->area];
1804 ++glyph;
1809 /* Produce a composite glyph for iterator IT. IT->cmp_id is the ID of
1810 the composition. We simply produces components of the composition
1811 assuming that that the terminal has a capability to layout/render
1812 it correctly. */
1814 static void
1815 produce_composite_glyph (it)
1816 struct it *it;
1818 int c;
1820 if (it->cmp_it.ch < 0)
1822 struct composition *cmp = composition_table[it->cmp_it.id];
1824 it->pixel_width = cmp->width;
1826 else
1828 Lisp_Object gstring = composition_gstring_from_id (it->cmp_it.id);
1830 it->pixel_width = composition_gstring_width (gstring, it->cmp_it.from,
1831 it->cmp_it.to, NULL);
1833 it->nglyphs = 1;
1834 if (it->glyph_row)
1835 append_composite_glyph (it);
1839 /* Get information about special display element WHAT in an
1840 environment described by IT. WHAT is one of IT_TRUNCATION or
1841 IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a
1842 non-null glyph_row member. This function ensures that fields like
1843 face_id, c, len of IT are left untouched. */
1845 void
1846 produce_special_glyphs (it, what)
1847 struct it *it;
1848 enum display_element_type what;
1850 struct it temp_it;
1851 Lisp_Object gc;
1852 GLYPH glyph;
1854 temp_it = *it;
1855 temp_it.dp = NULL;
1856 temp_it.what = IT_CHARACTER;
1857 temp_it.len = 1;
1858 temp_it.object = make_number (0);
1859 bzero (&temp_it.current, sizeof temp_it.current);
1861 if (what == IT_CONTINUATION)
1863 /* Continuation glyph. */
1864 SET_GLYPH_FROM_CHAR (glyph, '\\');
1865 if (it->dp
1866 && (gc = DISP_CONTINUE_GLYPH (it->dp), GLYPH_CODE_P (gc))
1867 && GLYPH_CODE_CHAR_VALID_P (gc))
1869 SET_GLYPH_FROM_GLYPH_CODE (glyph, gc);
1870 spec_glyph_lookup_face (XWINDOW (it->window), &glyph);
1873 else if (what == IT_TRUNCATION)
1875 /* Truncation glyph. */
1876 SET_GLYPH_FROM_CHAR (glyph, '$');
1877 if (it->dp
1878 && (gc = DISP_TRUNC_GLYPH (it->dp), GLYPH_CODE_P (gc))
1879 && GLYPH_CODE_CHAR_VALID_P (gc))
1881 SET_GLYPH_FROM_GLYPH_CODE (glyph, gc);
1882 spec_glyph_lookup_face (XWINDOW (it->window), &glyph);
1885 else
1886 abort ();
1888 temp_it.c = GLYPH_CHAR (glyph);
1889 temp_it.face_id = GLYPH_FACE (glyph);
1890 temp_it.len = CHAR_BYTES (temp_it.c);
1892 produce_glyphs (&temp_it);
1893 it->pixel_width = temp_it.pixel_width;
1894 it->nglyphs = temp_it.pixel_width;
1899 /***********************************************************************
1900 Faces
1901 ***********************************************************************/
1903 /* Value is non-zero if attribute ATTR may be used. ATTR should be
1904 one of the enumerators from enum no_color_bit, or a bit set built
1905 from them. Some display attributes may not be used together with
1906 color; the termcap capability `NC' specifies which ones. */
1908 #define MAY_USE_WITH_COLORS_P(tty, ATTR) \
1909 (tty->TN_max_colors > 0 \
1910 ? (tty->TN_no_color_video & (ATTR)) == 0 \
1911 : 1)
1913 /* Turn appearances of face FACE_ID on tty frame F on.
1914 FACE_ID is a realized face ID number, in the face cache. */
1916 static void
1917 turn_on_face (f, face_id)
1918 struct frame *f;
1919 int face_id;
1921 struct face *face = FACE_FROM_ID (f, face_id);
1922 long fg = face->foreground;
1923 long bg = face->background;
1924 struct tty_display_info *tty = FRAME_TTY (f);
1926 /* Do this first because TS_end_standout_mode may be the same
1927 as TS_exit_attribute_mode, which turns all appearances off. */
1928 if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE))
1930 if (tty->TN_max_colors > 0)
1932 if (fg >= 0 && bg >= 0)
1934 /* If the terminal supports colors, we can set them
1935 below without using reverse video. The face's fg
1936 and bg colors are set as they should appear on
1937 the screen, i.e. they take the inverse-video'ness
1938 of the face already into account. */
1940 else if (inverse_video)
1942 if (fg == FACE_TTY_DEFAULT_FG_COLOR
1943 || bg == FACE_TTY_DEFAULT_BG_COLOR)
1944 tty_toggle_highlight (tty);
1946 else
1948 if (fg == FACE_TTY_DEFAULT_BG_COLOR
1949 || bg == FACE_TTY_DEFAULT_FG_COLOR)
1950 tty_toggle_highlight (tty);
1953 else
1955 /* If we can't display colors, use reverse video
1956 if the face specifies that. */
1957 if (inverse_video)
1959 if (fg == FACE_TTY_DEFAULT_FG_COLOR
1960 || bg == FACE_TTY_DEFAULT_BG_COLOR)
1961 tty_toggle_highlight (tty);
1963 else
1965 if (fg == FACE_TTY_DEFAULT_BG_COLOR
1966 || bg == FACE_TTY_DEFAULT_FG_COLOR)
1967 tty_toggle_highlight (tty);
1972 if (face->tty_bold_p)
1974 if (MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
1975 OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
1977 else if (face->tty_dim_p)
1978 if (MAY_USE_WITH_COLORS_P (tty, NC_DIM))
1979 OUTPUT1_IF (tty, tty->TS_enter_dim_mode);
1981 /* Alternate charset and blinking not yet used. */
1982 if (face->tty_alt_charset_p
1983 && MAY_USE_WITH_COLORS_P (tty, NC_ALT_CHARSET))
1984 OUTPUT1_IF (tty, tty->TS_enter_alt_charset_mode);
1986 if (face->tty_blinking_p
1987 && MAY_USE_WITH_COLORS_P (tty, NC_BLINK))
1988 OUTPUT1_IF (tty, tty->TS_enter_blink_mode);
1990 if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
1991 OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
1993 if (tty->TN_max_colors > 0)
1995 char *ts, *p;
1997 ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
1998 if (fg >= 0 && ts)
2000 p = tparam (ts, NULL, 0, (int) fg);
2001 OUTPUT (tty, p);
2002 xfree (p);
2005 ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
2006 if (bg >= 0 && ts)
2008 p = tparam (ts, NULL, 0, (int) bg);
2009 OUTPUT (tty, p);
2010 xfree (p);
2016 /* Turn off appearances of face FACE_ID on tty frame F. */
2018 static void
2019 turn_off_face (f, face_id)
2020 struct frame *f;
2021 int face_id;
2023 struct face *face = FACE_FROM_ID (f, face_id);
2024 struct tty_display_info *tty = FRAME_TTY (f);
2026 xassert (face != NULL);
2028 if (tty->TS_exit_attribute_mode)
2030 /* Capability "me" will turn off appearance modes double-bright,
2031 half-bright, reverse-video, standout, underline. It may or
2032 may not turn off alt-char-mode. */
2033 if (face->tty_bold_p
2034 || face->tty_dim_p
2035 || face->tty_reverse_p
2036 || face->tty_alt_charset_p
2037 || face->tty_blinking_p
2038 || face->tty_underline_p)
2040 OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
2041 if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0)
2042 tty->standout_mode = 0;
2045 if (face->tty_alt_charset_p)
2046 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
2048 else
2050 /* If we don't have "me" we can only have those appearances
2051 that have exit sequences defined. */
2052 if (face->tty_alt_charset_p)
2053 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
2055 if (face->tty_underline_p)
2056 OUTPUT_IF (tty, tty->TS_exit_underline_mode);
2059 /* Switch back to default colors. */
2060 if (tty->TN_max_colors > 0
2061 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
2062 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
2063 || (face->background != FACE_TTY_DEFAULT_COLOR
2064 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
2065 OUTPUT1_IF (tty, tty->TS_orig_pair);
2069 /* Return non-zero if the terminal on frame F supports all of the
2070 capabilities in CAPS simultaneously, with foreground and background
2071 colors FG and BG. */
2074 tty_capable_p (tty, caps, fg, bg)
2075 struct tty_display_info *tty;
2076 unsigned caps;
2077 unsigned long fg, bg;
2079 #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
2080 if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
2081 return 0;
2083 TTY_CAPABLE_P_TRY (tty, TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE);
2084 TTY_CAPABLE_P_TRY (tty, TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode, NC_UNDERLINE);
2085 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
2086 TTY_CAPABLE_P_TRY (tty, TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM);
2087 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BLINK, tty->TS_enter_blink_mode, NC_BLINK);
2088 TTY_CAPABLE_P_TRY (tty, TTY_CAP_ALT_CHARSET, tty->TS_enter_alt_charset_mode, NC_ALT_CHARSET);
2090 /* We can do it! */
2091 return 1;
2094 /* Return non-zero if the terminal is capable to display colors. */
2096 DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
2097 0, 1, 0,
2098 doc: /* Return non-nil if the tty device TERMINAL can display colors.
2100 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2101 frame's terminal). This function always returns nil if TERMINAL
2102 is not on a tty device. */)
2103 (terminal)
2104 Lisp_Object terminal;
2106 struct terminal *t = get_tty_terminal (terminal, 0);
2107 if (!t)
2108 return Qnil;
2109 else
2110 return t->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
2113 /* Return the number of supported colors. */
2114 DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
2115 Stty_display_color_cells, 0, 1, 0,
2116 doc: /* Return the number of colors supported by the tty device TERMINAL.
2118 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2119 frame's terminal). This function always returns 0 if TERMINAL
2120 is not on a tty device. */)
2121 (terminal)
2122 Lisp_Object terminal;
2124 struct terminal *t = get_tty_terminal (terminal, 0);
2125 if (!t)
2126 return make_number (0);
2127 else
2128 return make_number (t->display_info.tty->TN_max_colors);
2131 #ifndef DOS_NT
2133 /* Declare here rather than in the function, as in the rest of Emacs,
2134 to work around an HPUX compiler bug (?). See
2135 http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00410.html */
2136 static int default_max_colors;
2137 static int default_max_pairs;
2138 static int default_no_color_video;
2139 static char *default_orig_pair;
2140 static char *default_set_foreground;
2141 static char *default_set_background;
2143 /* Save or restore the default color-related capabilities of this
2144 terminal. */
2145 static void
2146 tty_default_color_capabilities (struct tty_display_info *tty, int save)
2149 if (save)
2151 xfree (default_orig_pair);
2152 default_orig_pair = tty->TS_orig_pair ? xstrdup (tty->TS_orig_pair) : NULL;
2154 xfree (default_set_foreground);
2155 default_set_foreground = tty->TS_set_foreground ? xstrdup (tty->TS_set_foreground)
2156 : NULL;
2158 xfree (default_set_background);
2159 default_set_background = tty->TS_set_background ? xstrdup (tty->TS_set_background)
2160 : NULL;
2162 default_max_colors = tty->TN_max_colors;
2163 default_max_pairs = tty->TN_max_pairs;
2164 default_no_color_video = tty->TN_no_color_video;
2166 else
2168 tty->TS_orig_pair = default_orig_pair;
2169 tty->TS_set_foreground = default_set_foreground;
2170 tty->TS_set_background = default_set_background;
2171 tty->TN_max_colors = default_max_colors;
2172 tty->TN_max_pairs = default_max_pairs;
2173 tty->TN_no_color_video = default_no_color_video;
2177 /* Setup one of the standard tty color schemes according to MODE.
2178 MODE's value is generally the number of colors which we want to
2179 support; zero means set up for the default capabilities, the ones
2180 we saw at init_tty time; -1 means turn off color support. */
2181 static void
2182 tty_setup_colors (struct tty_display_info *tty, int mode)
2184 /* Canonicalize all negative values of MODE. */
2185 if (mode < -1)
2186 mode = -1;
2188 switch (mode)
2190 case -1: /* no colors at all */
2191 tty->TN_max_colors = 0;
2192 tty->TN_max_pairs = 0;
2193 tty->TN_no_color_video = 0;
2194 tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL;
2195 break;
2196 case 0: /* default colors, if any */
2197 default:
2198 tty_default_color_capabilities (tty, 0);
2199 break;
2200 case 8: /* 8 standard ANSI colors */
2201 tty->TS_orig_pair = "\033[0m";
2202 #ifdef TERMINFO
2203 tty->TS_set_foreground = "\033[3%p1%dm";
2204 tty->TS_set_background = "\033[4%p1%dm";
2205 #else
2206 tty->TS_set_foreground = "\033[3%dm";
2207 tty->TS_set_background = "\033[4%dm";
2208 #endif
2209 tty->TN_max_colors = 8;
2210 tty->TN_max_pairs = 64;
2211 tty->TN_no_color_video = 0;
2212 break;
2216 void
2217 set_tty_color_mode (tty, f)
2218 struct tty_display_info *tty;
2219 struct frame *f;
2221 Lisp_Object tem, val, color_mode_spec;
2222 Lisp_Object color_mode;
2223 int mode;
2224 extern Lisp_Object Qtty_color_mode;
2225 Lisp_Object tty_color_mode_alist
2226 = Fintern_soft (build_string ("tty-color-mode-alist"), Qnil);
2228 tem = assq_no_quit (Qtty_color_mode, f->param_alist);
2229 val = CONSP (tem) ? XCDR (tem) : Qnil;
2231 if (INTEGERP (val))
2232 color_mode = val;
2233 else
2235 tem = (NILP (tty_color_mode_alist) ? Qnil
2236 : Fassq (val, XSYMBOL (tty_color_mode_alist)->value));
2237 color_mode = CONSP (tem) ? XCDR (tem) : Qnil;
2240 mode = INTEGERP (color_mode) ? XINT (color_mode) : 0;
2242 if (mode != tty->previous_color_mode)
2244 Lisp_Object funsym = intern ("tty-set-up-initial-frame-faces");
2245 tty->previous_color_mode = mode;
2246 tty_setup_colors (tty , mode);
2247 /* This recomputes all the faces given the new color definitions. */
2248 safe_call (1, &funsym);
2252 #endif /* !DOS_NT */
2256 /* Return the tty display object specified by TERMINAL. */
2258 struct terminal *
2259 get_tty_terminal (Lisp_Object terminal, int throw)
2261 struct terminal *t = get_terminal (terminal, throw);
2263 if (t && t->type != output_termcap && t->type != output_msdos_raw)
2265 if (throw)
2266 error ("Device %d is not a termcap terminal device", t->id);
2267 else
2268 return NULL;
2271 return t;
2274 /* Return an active termcap device that uses the tty device with the
2275 given name.
2277 This function ignores suspended devices.
2279 Returns NULL if the named terminal device is not opened. */
2281 struct terminal *
2282 get_named_tty (name)
2283 char *name;
2285 struct terminal *t;
2287 if (!name)
2288 abort ();
2290 for (t = terminal_list; t; t = t->next_terminal)
2292 if ((t->type == output_termcap || t->type == output_msdos_raw)
2293 && !strcmp (t->display_info.tty->name, name)
2294 && TERMINAL_ACTIVE_P (t))
2295 return t;
2298 return 0;
2302 DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
2303 doc: /* Return the type of the tty device that TERMINAL uses.
2304 Returns nil if TERMINAL is not on a tty device.
2306 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2307 frame's terminal). */)
2308 (terminal)
2309 Lisp_Object terminal;
2311 struct terminal *t = get_terminal (terminal, 1);
2313 if (t->type != output_termcap && t->type != output_msdos_raw)
2314 return Qnil;
2316 if (t->display_info.tty->type)
2317 return build_string (t->display_info.tty->type);
2318 else
2319 return Qnil;
2322 DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
2323 doc: /* Return non-nil if TERMINAL is the controlling tty of the Emacs process.
2325 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2326 frame's terminal). This function always returns nil if TERMINAL
2327 is not on a tty device. */)
2328 (terminal)
2329 Lisp_Object terminal;
2331 struct terminal *t = get_terminal (terminal, 1);
2333 if ((t->type != output_termcap && t->type != output_msdos_raw)
2334 || strcmp (t->display_info.tty->name, DEV_TTY) != 0)
2335 return Qnil;
2336 else
2337 return Qt;
2340 DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
2341 doc: /* Declare that the tty used by TERMINAL does not handle underlining.
2342 This is used to override the terminfo data, for certain terminals that
2343 do not really do underlining, but say that they do. This function has
2344 no effect if used on a non-tty terminal.
2346 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2347 frame's terminal). This function always returns nil if TERMINAL
2348 is not on a tty device. */)
2349 (terminal)
2350 Lisp_Object terminal;
2352 struct terminal *t = get_terminal (terminal, 1);
2354 if (t->type == output_termcap)
2355 t->display_info.tty->TS_enter_underline_mode = 0;
2356 return Qnil;
2361 DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
2362 doc: /* Suspend the terminal device TTY.
2364 The device is restored to its default state, and Emacs ceases all
2365 access to the tty device. Frames that use the device are not deleted,
2366 but input is not read from them and if they change, their display is
2367 not updated.
2369 TTY may be a terminal id, a frame, or nil for the terminal device of
2370 the currently selected frame.
2372 This function runs `suspend-tty-functions' after suspending the
2373 device. The functions are run with one arg, the id of the suspended
2374 terminal device.
2376 `suspend-tty' does nothing if it is called on a device that is already
2377 suspended.
2379 A suspended tty may be resumed by calling `resume-tty' on it. */)
2380 (tty)
2381 Lisp_Object tty;
2383 struct terminal *t = get_tty_terminal (tty, 1);
2384 FILE *f;
2386 if (!t)
2387 error ("Unknown tty device");
2389 f = t->display_info.tty->input;
2391 if (f)
2393 /* First run `suspend-tty-functions' and then clean up the tty
2394 state because `suspend-tty-functions' might need to change
2395 the tty state. */
2396 if (!NILP (Vrun_hooks))
2398 Lisp_Object args[2];
2399 args[0] = intern ("suspend-tty-functions");
2400 XSETTERMINAL (args[1], t);
2401 Frun_hook_with_args (2, args);
2404 reset_sys_modes (t->display_info.tty);
2406 #ifdef subprocesses
2407 delete_keyboard_wait_descriptor (fileno (f));
2408 #endif
2410 #ifndef MSDOS
2411 fclose (f);
2412 if (f != t->display_info.tty->output)
2413 fclose (t->display_info.tty->output);
2414 #endif
2416 t->display_info.tty->input = 0;
2417 t->display_info.tty->output = 0;
2419 if (FRAMEP (t->display_info.tty->top_frame))
2420 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
2424 /* Clear display hooks to prevent further output. */
2425 clear_tty_hooks (t);
2427 return Qnil;
2430 DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
2431 doc: /* Resume the previously suspended terminal device TTY.
2432 The terminal is opened and reinitialized. Frames that are on the
2433 suspended terminal are revived.
2435 It is an error to resume a terminal while another terminal is active
2436 on the same device.
2438 This function runs `resume-tty-functions' after resuming the terminal.
2439 The functions are run with one arg, the id of the resumed terminal
2440 device.
2442 `resume-tty' does nothing if it is called on a device that is not
2443 suspended.
2445 TTY may be a terminal id, a frame, or nil for the terminal device of
2446 the currently selected frame. */)
2447 (tty)
2448 Lisp_Object tty;
2450 struct terminal *t = get_tty_terminal (tty, 1);
2451 int fd;
2453 if (!t)
2454 error ("Unknown tty device");
2456 if (!t->display_info.tty->input)
2458 if (get_named_tty (t->display_info.tty->name))
2459 error ("Cannot resume display while another display is active on the same device");
2461 #ifdef MSDOS
2462 t->display_info.tty->output = stdout;
2463 t->display_info.tty->input = stdin;
2464 #else /* !MSDOS */
2465 fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
2467 if (fd == -1)
2468 error ("Can not reopen tty device %s: %s", t->display_info.tty->name, strerror (errno));
2470 if (strcmp (t->display_info.tty->name, DEV_TTY))
2471 dissociate_if_controlling_tty (fd);
2473 t->display_info.tty->output = fdopen (fd, "w+");
2474 t->display_info.tty->input = t->display_info.tty->output;
2475 #endif
2477 #ifdef subprocesses
2478 add_keyboard_wait_descriptor (fd);
2479 #endif
2481 if (FRAMEP (t->display_info.tty->top_frame))
2483 struct frame *f = XFRAME (t->display_info.tty->top_frame);
2484 int width, height;
2485 int old_height = FRAME_COLS (f);
2486 int old_width = FRAME_LINES (f);
2488 /* Check if terminal/window size has changed while the frame
2489 was suspended. */
2490 get_tty_size (fileno (t->display_info.tty->input), &width, &height);
2491 if (width != old_width || height != old_height)
2492 change_frame_size (f, height, width, 0, 0, 0);
2493 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
2496 init_sys_modes (t->display_info.tty);
2498 /* Run `resume-tty-functions'. */
2499 if (!NILP (Vrun_hooks))
2501 Lisp_Object args[2];
2502 args[0] = intern ("resume-tty-functions");
2503 XSETTERMINAL (args[1], t);
2504 Frun_hook_with_args (2, args);
2508 set_tty_hooks (t);
2510 return Qnil;
2514 /***********************************************************************
2515 Mouse
2516 ***********************************************************************/
2518 #ifdef HAVE_GPM
2519 void
2520 term_mouse_moveto (int x, int y)
2522 /* TODO: how to set mouse position?
2523 const char *name;
2524 int fd;
2525 name = (const char *) ttyname (0);
2526 fd = open (name, O_WRONLY);
2527 SOME_FUNCTION (x, y, fd);
2528 close (fd);
2529 last_mouse_x = x;
2530 last_mouse_y = y; */
2533 static void
2534 term_show_mouse_face (enum draw_glyphs_face draw)
2536 struct window *w = XWINDOW (mouse_face_window);
2537 int save_x, save_y;
2538 int i;
2540 struct frame *f = XFRAME (w->frame);
2541 struct tty_display_info *tty = FRAME_TTY (f);
2543 if (/* If window is in the process of being destroyed, don't bother
2544 to do anything. */
2545 w->current_matrix != NULL
2546 /* Recognize when we are called to operate on rows that don't exist
2547 anymore. This can happen when a window is split. */
2548 && mouse_face_end_row < w->current_matrix->nrows)
2550 /* write_glyphs writes at cursor position, so we need to
2551 temporarily move cursor coordinates to the beginning of
2552 the highlight region. */
2554 /* Save current cursor co-ordinates */
2555 save_y = curY (tty);
2556 save_x = curX (tty);
2558 /* Note that mouse_face_beg_row etc. are window relative. */
2559 for (i = mouse_face_beg_row; i <= mouse_face_end_row; i++)
2561 int start_hpos, end_hpos, nglyphs;
2562 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
2564 /* Don't do anything if row doesn't have valid contents. */
2565 if (!row->enabled_p)
2566 continue;
2568 /* For all but the first row, the highlight starts at column 0. */
2569 if (i == mouse_face_beg_row)
2570 start_hpos = mouse_face_beg_col;
2571 else
2572 start_hpos = 0;
2574 if (i == mouse_face_end_row)
2575 end_hpos = mouse_face_end_col;
2576 else
2578 end_hpos = row->used[TEXT_AREA];
2579 if (draw == DRAW_NORMAL_TEXT)
2580 row->fill_line_p = 1; /* Clear to end of line */
2583 if (end_hpos <= start_hpos)
2584 continue;
2585 /* Record that some glyphs of this row are displayed in
2586 mouse-face. */
2587 row->mouse_face_p = draw > 0;
2589 nglyphs = end_hpos - start_hpos;
2591 if (end_hpos >= row->used[TEXT_AREA])
2592 nglyphs = row->used[TEXT_AREA] - start_hpos;
2594 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
2595 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos
2596 + WINDOW_LEFT_EDGE_X (w);
2598 cursor_to (f, pos_y, pos_x);
2600 if (draw == DRAW_MOUSE_FACE)
2602 tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
2603 nglyphs, mouse_face_face_id);
2605 else /* draw == DRAW_NORMAL_TEXT */
2606 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
2608 cursor_to (f, save_y, save_x);
2612 static void
2613 term_clear_mouse_face ()
2615 if (!NILP (mouse_face_window))
2616 term_show_mouse_face (DRAW_NORMAL_TEXT);
2618 mouse_face_beg_row = mouse_face_beg_col = -1;
2619 mouse_face_end_row = mouse_face_end_col = -1;
2620 mouse_face_window = Qnil;
2623 /* Find the glyph matrix position of buffer position POS in window W.
2624 *HPOS and *VPOS are set to the positions found. W's current glyphs
2625 must be up to date. If POS is above window start return (0, 0).
2626 If POS is after end of W, return end of last line in W.
2627 - taken from msdos.c */
2628 static int
2629 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
2631 int i, lastcol, line_start_position, maybe_next_line_p = 0;
2632 int yb = window_text_bottom_y (w);
2633 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
2635 while (row->y < yb)
2637 if (row->used[TEXT_AREA])
2638 line_start_position = row->glyphs[TEXT_AREA]->charpos;
2639 else
2640 line_start_position = 0;
2642 if (line_start_position > pos)
2643 break;
2644 /* If the position sought is the end of the buffer,
2645 don't include the blank lines at the bottom of the window. */
2646 else if (line_start_position == pos
2647 && pos == BUF_ZV (XBUFFER (w->buffer)))
2649 maybe_next_line_p = 1;
2650 break;
2652 else if (line_start_position > 0)
2653 best_row = row;
2655 /* Don't overstep the last matrix row, lest we get into the
2656 never-never land... */
2657 if (row->y + 1 >= yb)
2658 break;
2660 ++row;
2663 /* Find the right column within BEST_ROW. */
2664 lastcol = 0;
2665 row = best_row;
2666 for (i = 0; i < row->used[TEXT_AREA]; i++)
2668 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
2669 int charpos;
2671 charpos = glyph->charpos;
2672 if (charpos == pos)
2674 *hpos = i;
2675 *vpos = row->y;
2676 return 1;
2678 else if (charpos > pos)
2679 break;
2680 else if (charpos > 0)
2681 lastcol = i;
2684 /* If we're looking for the end of the buffer,
2685 and we didn't find it in the line we scanned,
2686 use the start of the following line. */
2687 if (maybe_next_line_p)
2689 ++row;
2690 lastcol = 0;
2693 *vpos = row->y;
2694 *hpos = lastcol + 1;
2695 return 0;
2698 static void
2699 term_mouse_highlight (struct frame *f, int x, int y)
2701 enum window_part part;
2702 Lisp_Object window;
2703 struct window *w;
2704 struct buffer *b;
2706 if (NILP (Vmouse_highlight)
2707 || !f->glyphs_initialized_p)
2708 return;
2710 /* Which window is that in? */
2711 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
2713 /* Not on a window -> return. */
2714 if (!WINDOWP (window))
2715 return;
2717 if (!EQ (window, mouse_face_window))
2718 term_clear_mouse_face ();
2720 w = XWINDOW (window);
2722 /* Are we in a window whose display is up to date?
2723 And verify the buffer's text has not changed. */
2724 b = XBUFFER (w->buffer);
2725 if (part == ON_TEXT
2726 && EQ (w->window_end_valid, w->buffer)
2727 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
2728 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
2730 int pos, i, nrows = w->current_matrix->nrows;
2731 struct glyph_row *row;
2732 struct glyph *glyph;
2734 /* Find the glyph under X/Y. */
2735 glyph = NULL;
2736 if (y >= 0 && y < nrows)
2738 row = MATRIX_ROW (w->current_matrix, y);
2739 /* Give up if some row before the one we are looking for is
2740 not enabled. */
2741 for (i = 0; i <= y; i++)
2742 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
2743 break;
2744 if (i > y /* all rows upto and including the one at Y are enabled */
2745 && row->displays_text_p
2746 && x < window_box_width (w, TEXT_AREA))
2748 glyph = row->glyphs[TEXT_AREA];
2749 if (x >= row->used[TEXT_AREA])
2750 glyph = NULL;
2751 else
2753 glyph += x;
2754 if (!BUFFERP (glyph->object))
2755 glyph = NULL;
2760 /* Clear mouse face if X/Y not over text. */
2761 if (glyph == NULL)
2763 term_clear_mouse_face ();
2764 return;
2767 if (!BUFFERP (glyph->object))
2768 abort ();
2769 pos = glyph->charpos;
2771 /* Check for mouse-face. */
2773 extern Lisp_Object Qmouse_face;
2774 Lisp_Object mouse_face, overlay, position, *overlay_vec;
2775 int noverlays, obegv, ozv;
2776 struct buffer *obuf;
2778 /* If we get an out-of-range value, return now; avoid an error. */
2779 if (pos > BUF_Z (b))
2780 return;
2782 /* Make the window's buffer temporarily current for
2783 overlays_at and compute_char_face. */
2784 obuf = current_buffer;
2785 current_buffer = b;
2786 obegv = BEGV;
2787 ozv = ZV;
2788 BEGV = BEG;
2789 ZV = Z;
2791 /* Is this char mouse-active? */
2792 XSETINT (position, pos);
2794 /* Put all the overlays we want in a vector in overlay_vec. */
2795 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
2796 /* Sort overlays into increasing priority order. */
2797 noverlays = sort_overlays (overlay_vec, noverlays, w);
2799 /* Check mouse-face highlighting. */
2800 if (!(EQ (window, mouse_face_window)
2801 && y >= mouse_face_beg_row
2802 && y <= mouse_face_end_row
2803 && (y > mouse_face_beg_row
2804 || x >= mouse_face_beg_col)
2805 && (y < mouse_face_end_row
2806 || x < mouse_face_end_col
2807 || mouse_face_past_end)))
2809 /* Clear the display of the old active region, if any. */
2810 term_clear_mouse_face ();
2812 /* Find the highest priority overlay that has a mouse-face
2813 property. */
2814 overlay = Qnil;
2815 for (i = noverlays - 1; i >= 0; --i)
2817 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
2818 if (!NILP (mouse_face))
2820 overlay = overlay_vec[i];
2821 break;
2825 /* If no overlay applies, get a text property. */
2826 if (NILP (overlay))
2827 mouse_face = Fget_text_property (position, Qmouse_face,
2828 w->buffer);
2830 /* Handle the overlay case. */
2831 if (!NILP (overlay))
2833 /* Find the range of text around this char that
2834 should be active. */
2835 Lisp_Object before, after;
2836 EMACS_INT ignore;
2839 before = Foverlay_start (overlay);
2840 after = Foverlay_end (overlay);
2841 /* Record this as the current active region. */
2842 fast_find_position (w, XFASTINT (before),
2843 &mouse_face_beg_col,
2844 &mouse_face_beg_row);
2846 mouse_face_past_end
2847 = !fast_find_position (w, XFASTINT (after),
2848 &mouse_face_end_col,
2849 &mouse_face_end_row);
2850 mouse_face_window = window;
2852 mouse_face_face_id
2853 = face_at_buffer_position (w, pos, 0, 0,
2854 &ignore, pos + 1, 1);
2856 /* Display it as active. */
2857 term_show_mouse_face (DRAW_MOUSE_FACE);
2859 /* Handle the text property case. */
2860 else if (!NILP (mouse_face))
2862 /* Find the range of text around this char that
2863 should be active. */
2864 Lisp_Object before, after, beginning, end;
2865 EMACS_INT ignore;
2867 beginning = Fmarker_position (w->start);
2868 XSETINT (end, (BUF_Z (b) - XFASTINT (w->window_end_pos)));
2869 before
2870 = Fprevious_single_property_change (make_number (pos + 1),
2871 Qmouse_face,
2872 w->buffer, beginning);
2873 after
2874 = Fnext_single_property_change (position, Qmouse_face,
2875 w->buffer, end);
2877 /* Record this as the current active region. */
2878 fast_find_position (w, XFASTINT (before),
2879 &mouse_face_beg_col,
2880 &mouse_face_beg_row);
2881 mouse_face_past_end
2882 = !fast_find_position (w, XFASTINT (after),
2883 &mouse_face_end_col,
2884 &mouse_face_end_row);
2885 mouse_face_window = window;
2887 mouse_face_face_id
2888 = face_at_buffer_position (w, pos, 0, 0,
2889 &ignore, pos + 1, 1);
2891 /* Display it as active. */
2892 term_show_mouse_face (DRAW_MOUSE_FACE);
2896 /* Look for a `help-echo' property. */
2898 Lisp_Object help;
2899 extern Lisp_Object Qhelp_echo;
2901 /* Check overlays first. */
2902 help = Qnil;
2903 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
2905 overlay = overlay_vec[i];
2906 help = Foverlay_get (overlay, Qhelp_echo);
2909 if (!NILP (help))
2911 help_echo_string = help;
2912 help_echo_window = window;
2913 help_echo_object = overlay;
2914 help_echo_pos = pos;
2916 /* Try text properties. */
2917 else if (NILP (help)
2918 && ((STRINGP (glyph->object)
2919 && glyph->charpos >= 0
2920 && glyph->charpos < SCHARS (glyph->object))
2921 || (BUFFERP (glyph->object)
2922 && glyph->charpos >= BEGV
2923 && glyph->charpos < ZV)))
2925 help = Fget_text_property (make_number (glyph->charpos),
2926 Qhelp_echo, glyph->object);
2927 if (!NILP (help))
2929 help_echo_string = help;
2930 help_echo_window = window;
2931 help_echo_object = glyph->object;
2932 help_echo_pos = glyph->charpos;
2937 BEGV = obegv;
2938 ZV = ozv;
2939 current_buffer = obuf;
2944 static int
2945 term_mouse_movement (FRAME_PTR frame, Gpm_Event *event)
2947 /* Has the mouse moved off the glyph it was on at the last sighting? */
2948 if (event->x != last_mouse_x || event->y != last_mouse_y)
2950 frame->mouse_moved = 1;
2951 term_mouse_highlight (frame, event->x, event->y);
2952 /* Remember which glyph we're now on. */
2953 last_mouse_x = event->x;
2954 last_mouse_y = event->y;
2955 return 1;
2957 return 0;
2960 /* Return the current position of the mouse.
2962 Set *f to the frame the mouse is in, or zero if the mouse is in no
2963 Emacs frame. If it is set to zero, all the other arguments are
2964 garbage.
2966 Set *bar_window to Qnil, and *x and *y to the column and
2967 row of the character cell the mouse is over.
2969 Set *time to the time the mouse was at the returned position.
2971 This clears mouse_moved until the next motion
2972 event arrives. */
2973 static void
2974 term_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window,
2975 enum scroll_bar_part *part, Lisp_Object *x,
2976 Lisp_Object *y, unsigned long *time)
2978 struct timeval now;
2980 *fp = SELECTED_FRAME ();
2981 (*fp)->mouse_moved = 0;
2983 *bar_window = Qnil;
2984 *part = 0;
2986 XSETINT (*x, last_mouse_x);
2987 XSETINT (*y, last_mouse_y);
2988 gettimeofday(&now, 0);
2989 *time = (now.tv_sec * 1000) + (now.tv_usec / 1000);
2992 /* Prepare a mouse-event in *RESULT for placement in the input queue.
2994 If the event is a button press, then note that we have grabbed
2995 the mouse. */
2997 static Lisp_Object
2998 term_mouse_click (struct input_event *result, Gpm_Event *event,
2999 struct frame *f)
3001 struct timeval now;
3002 int i, j;
3004 result->kind = GPM_CLICK_EVENT;
3005 for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
3007 if (event->buttons & j) {
3008 result->code = i; /* button number */
3009 break;
3012 gettimeofday(&now, 0);
3013 result->timestamp = (now.tv_sec * 1000) + (now.tv_usec / 1000);
3015 if (event->type & GPM_UP)
3016 result->modifiers = up_modifier;
3017 else if (event->type & GPM_DOWN)
3018 result->modifiers = down_modifier;
3019 else
3020 result->modifiers = 0;
3022 if (event->type & GPM_SINGLE)
3023 result->modifiers |= click_modifier;
3025 if (event->type & GPM_DOUBLE)
3026 result->modifiers |= double_modifier;
3028 if (event->type & GPM_TRIPLE)
3029 result->modifiers |= triple_modifier;
3031 if (event->type & GPM_DRAG)
3032 result->modifiers |= drag_modifier;
3034 if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
3036 /* 1 << KG_SHIFT */
3037 if (event->modifiers & (1 << 0))
3038 result->modifiers |= shift_modifier;
3040 /* 1 << KG_CTRL */
3041 if (event->modifiers & (1 << 2))
3042 result->modifiers |= ctrl_modifier;
3044 /* 1 << KG_ALT || KG_ALTGR */
3045 if (event->modifiers & (1 << 3)
3046 || event->modifiers & (1 << 1))
3047 result->modifiers |= meta_modifier;
3050 XSETINT (result->x, event->x);
3051 XSETINT (result->y, event->y);
3052 XSETFRAME (result->frame_or_window, f);
3053 result->arg = Qnil;
3054 return Qnil;
3058 handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event, struct input_event* hold_quit)
3060 struct frame *f = XFRAME (tty->top_frame);
3061 struct input_event ie;
3062 int do_help = 0;
3063 int count = 0;
3065 EVENT_INIT (ie);
3066 ie.kind = NO_EVENT;
3067 ie.arg = Qnil;
3069 if (event->type & (GPM_MOVE | GPM_DRAG)) {
3070 previous_help_echo_string = help_echo_string;
3071 help_echo_string = Qnil;
3073 Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
3075 if (!term_mouse_movement (f, event))
3076 help_echo_string = previous_help_echo_string;
3078 /* If the contents of the global variable help_echo_string
3079 has changed, generate a HELP_EVENT. */
3080 if (!NILP (help_echo_string)
3081 || !NILP (previous_help_echo_string))
3082 do_help = 1;
3084 goto done;
3086 else {
3087 f->mouse_moved = 0;
3088 term_mouse_click (&ie, event, f);
3091 done:
3092 if (ie.kind != NO_EVENT)
3094 kbd_buffer_store_event_hold (&ie, hold_quit);
3095 count++;
3098 if (do_help
3099 && !(hold_quit && hold_quit->kind != NO_EVENT))
3101 Lisp_Object frame;
3103 if (f)
3104 XSETFRAME (frame, f);
3105 else
3106 frame = Qnil;
3108 gen_help_event (help_echo_string, frame, help_echo_window,
3109 help_echo_object, help_echo_pos);
3110 count++;
3113 return count;
3116 DEFUN ("gpm-mouse-start", Fgpm_mouse_start, Sgpm_mouse_start,
3117 0, 0, 0,
3118 doc: /* Open a connection to Gpm.
3119 Gpm-mouse can only be activated for one tty at a time. */)
3122 struct frame *f = SELECTED_FRAME ();
3123 struct tty_display_info *tty
3124 = ((f)->output_method == output_termcap
3125 ? (f)->terminal->display_info.tty : NULL);
3126 Gpm_Connect connection;
3128 if (!tty)
3129 error ("Gpm-mouse only works in the GNU/Linux console");
3130 if (gpm_tty == tty)
3131 return Qnil; /* Already activated, nothing to do. */
3132 if (gpm_tty)
3133 error ("Gpm-mouse can only be activated for one tty at a time");
3135 connection.eventMask = ~0;
3136 connection.defaultMask = ~GPM_HARD;
3137 connection.maxMod = ~0;
3138 connection.minMod = 0;
3139 gpm_zerobased = 1;
3141 if (Gpm_Open (&connection, 0) < 0)
3142 error ("Gpm-mouse failed to connect to the gpm daemon");
3143 else
3145 gpm_tty = tty;
3146 /* `init_sys_modes' arranges for mouse movements sent through gpm_fd
3147 to generate SIGIOs. Apparently we need to call reset_sys_modes
3148 before calling init_sys_modes. */
3149 reset_sys_modes (tty);
3150 init_sys_modes (tty);
3151 add_gpm_wait_descriptor (gpm_fd);
3152 return Qnil;
3156 void
3157 close_gpm (int fd)
3159 if (fd >= 0)
3160 delete_gpm_wait_descriptor (fd);
3161 while (Gpm_Close()); /* close all the stack */
3162 gpm_tty = NULL;
3165 DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
3166 0, 0, 0,
3167 doc: /* Close a connection to Gpm. */)
3170 struct frame *f = SELECTED_FRAME ();
3171 struct tty_display_info *tty
3172 = ((f)->output_method == output_termcap
3173 ? (f)->terminal->display_info.tty : NULL);
3175 if (!tty || gpm_tty != tty)
3176 return Qnil; /* Not activated on this terminal, nothing to do. */
3178 close_gpm (gpm_fd);
3179 return Qnil;
3181 #endif /* HAVE_GPM */
3184 /***********************************************************************
3185 Initialization
3186 ***********************************************************************/
3188 /* Initialize the tty-dependent part of frame F. The frame must
3189 already have its device initialized. */
3191 void
3192 create_tty_output (struct frame *f)
3194 struct tty_output *t;
3196 if (! FRAME_TERMCAP_P (f))
3197 abort ();
3199 t = xmalloc (sizeof (struct tty_output));
3200 bzero (t, sizeof (struct tty_output));
3202 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
3204 f->output_data.tty = t;
3207 /* Delete frame F's face cache, and its tty-dependent part. */
3209 static void
3210 tty_free_frame_resources (struct frame *f)
3212 if (! FRAME_TERMCAP_P (f))
3213 abort ();
3215 if (FRAME_FACE_CACHE (f))
3216 free_frame_faces (f);
3218 xfree (f->output_data.tty);
3222 /* Reset the hooks in TERMINAL. */
3224 static void
3225 clear_tty_hooks (struct terminal *terminal)
3227 terminal->rif = 0;
3228 terminal->cursor_to_hook = 0;
3229 terminal->raw_cursor_to_hook = 0;
3230 terminal->clear_to_end_hook = 0;
3231 terminal->clear_frame_hook = 0;
3232 terminal->clear_end_of_line_hook = 0;
3233 terminal->ins_del_lines_hook = 0;
3234 terminal->insert_glyphs_hook = 0;
3235 terminal->write_glyphs_hook = 0;
3236 terminal->delete_glyphs_hook = 0;
3237 terminal->ring_bell_hook = 0;
3238 terminal->reset_terminal_modes_hook = 0;
3239 terminal->set_terminal_modes_hook = 0;
3240 terminal->update_begin_hook = 0;
3241 terminal->update_end_hook = 0;
3242 terminal->set_terminal_window_hook = 0;
3243 terminal->mouse_position_hook = 0;
3244 terminal->frame_rehighlight_hook = 0;
3245 terminal->frame_raise_lower_hook = 0;
3246 terminal->fullscreen_hook = 0;
3247 terminal->set_vertical_scroll_bar_hook = 0;
3248 terminal->condemn_scroll_bars_hook = 0;
3249 terminal->redeem_scroll_bar_hook = 0;
3250 terminal->judge_scroll_bars_hook = 0;
3251 terminal->read_socket_hook = 0;
3252 terminal->frame_up_to_date_hook = 0;
3254 /* Leave these two set, or suspended frames are not deleted
3255 correctly. */
3256 terminal->delete_frame_hook = &tty_free_frame_resources;
3257 terminal->delete_terminal_hook = &delete_tty;
3260 /* Initialize hooks in TERMINAL with the values needed for a tty. */
3262 static void
3263 set_tty_hooks (struct terminal *terminal)
3265 terminal->rif = 0; /* ttys don't support window-based redisplay. */
3267 terminal->cursor_to_hook = &tty_cursor_to;
3268 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
3270 terminal->clear_to_end_hook = &tty_clear_to_end;
3271 terminal->clear_frame_hook = &tty_clear_frame;
3272 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
3274 terminal->ins_del_lines_hook = &tty_ins_del_lines;
3276 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3277 terminal->write_glyphs_hook = &tty_write_glyphs;
3278 terminal->delete_glyphs_hook = &tty_delete_glyphs;
3280 terminal->ring_bell_hook = &tty_ring_bell;
3282 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3283 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
3284 terminal->update_begin_hook = 0; /* Not needed. */
3285 terminal->update_end_hook = &tty_update_end;
3286 terminal->set_terminal_window_hook = &tty_set_terminal_window;
3288 terminal->mouse_position_hook = 0; /* Not needed. */
3289 terminal->frame_rehighlight_hook = 0; /* Not needed. */
3290 terminal->frame_raise_lower_hook = 0; /* Not needed. */
3292 terminal->set_vertical_scroll_bar_hook = 0; /* Not needed. */
3293 terminal->condemn_scroll_bars_hook = 0; /* Not needed. */
3294 terminal->redeem_scroll_bar_hook = 0; /* Not needed. */
3295 terminal->judge_scroll_bars_hook = 0; /* Not needed. */
3297 terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
3298 terminal->frame_up_to_date_hook = 0; /* Not needed. */
3300 terminal->delete_frame_hook = &tty_free_frame_resources;
3301 terminal->delete_terminal_hook = &delete_tty;
3304 /* Drop the controlling terminal if fd is the same device. */
3305 static void
3306 dissociate_if_controlling_tty (int fd)
3308 #ifndef DOS_NT
3309 int pgid;
3310 EMACS_GET_TTY_PGRP (fd, &pgid); /* If tcgetpgrp succeeds, fd is the ctty. */
3311 if (pgid != -1)
3313 #if defined (USG) && !defined (BSD_PGRPS)
3314 setpgrp ();
3315 no_controlling_tty = 1;
3316 #elif defined (CYGWIN)
3317 setsid ();
3318 no_controlling_tty = 1;
3319 #else
3320 #ifdef TIOCNOTTY /* Try BSD ioctls. */
3321 sigblock (sigmask (SIGTTOU));
3322 fd = emacs_open (DEV_TTY, O_RDWR, 0);
3323 if (fd != -1 && ioctl (fd, TIOCNOTTY, 0) != -1)
3325 no_controlling_tty = 1;
3327 if (fd != -1)
3328 emacs_close (fd);
3329 sigunblock (sigmask (SIGTTOU));
3330 #else
3331 /* Unknown system. */
3332 croak ();
3333 #endif /* ! TIOCNOTTY */
3334 #endif /* ! USG */
3336 #endif /* !DOS_NT */
3339 static void maybe_fatal();
3341 /* Create a termcap display on the tty device with the given name and
3342 type.
3344 If NAME is NULL, then use the controlling tty, i.e., "/dev/tty".
3345 Otherwise NAME should be a path to the tty device file,
3346 e.g. "/dev/pts/7".
3348 TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
3350 If MUST_SUCCEED is true, then all errors are fatal. */
3352 struct terminal *
3353 init_tty (char *name, char *terminal_type, int must_succeed)
3355 char *area = NULL;
3356 char **address = &area;
3357 int buffer_size = 4096;
3358 register char *p = NULL;
3359 int status;
3360 struct tty_display_info *tty = NULL;
3361 struct terminal *terminal = NULL;
3362 int ctty = 0; /* 1 if asked to open controlling tty. */
3364 if (!terminal_type)
3365 maybe_fatal (must_succeed, 0,
3366 "Unknown terminal type",
3367 "Unknown terminal type");
3369 if (name == NULL)
3370 name = DEV_TTY;
3371 if (!strcmp (name, DEV_TTY))
3372 ctty = 1;
3374 /* If we already have a terminal on the given device, use that. If
3375 all such terminals are suspended, create a new one instead. */
3376 /* XXX Perhaps this should be made explicit by having init_tty
3377 always create a new terminal and separating terminal and frame
3378 creation on Lisp level. */
3379 terminal = get_named_tty (name);
3380 if (terminal)
3381 return terminal;
3383 terminal = create_terminal ();
3384 #ifdef MSDOS
3385 if (been_here > 0)
3386 maybe_fatal (1, 0, "Attempt to create another terminal %s", "",
3387 name, "");
3388 been_here = 1;
3389 tty = &the_only_display_info;
3390 #else
3391 tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info));
3392 #endif
3393 bzero (tty, sizeof (struct tty_display_info));
3394 tty->next = tty_list;
3395 tty_list = tty;
3397 terminal->type = output_termcap;
3398 terminal->display_info.tty = tty;
3399 tty->terminal = terminal;
3401 tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
3402 Wcm_clear (tty);
3404 #ifndef DOS_NT
3405 set_tty_hooks (terminal);
3408 int fd;
3409 FILE *file;
3411 #ifdef O_IGNORE_CTTY
3412 if (!ctty)
3413 /* Open the terminal device. Don't recognize it as our
3414 controlling terminal, and don't make it the controlling tty
3415 if we don't have one at the moment. */
3416 fd = emacs_open (name, O_RDWR | O_IGNORE_CTTY | O_NOCTTY, 0);
3417 else
3418 #else
3419 /* Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
3420 defined on Hurd. On other systems, we need to explicitly
3421 dissociate ourselves from the controlling tty when we want to
3422 open a frame on the same terminal. */
3423 fd = emacs_open (name, O_RDWR | O_NOCTTY, 0);
3424 #endif /* O_IGNORE_CTTY */
3426 tty->name = xstrdup (name);
3427 terminal->name = xstrdup (name);
3429 if (fd < 0)
3430 maybe_fatal (must_succeed, terminal,
3431 "Could not open file: %s",
3432 "Could not open file: %s",
3433 name);
3434 if (!isatty (fd))
3436 close (fd);
3437 maybe_fatal (must_succeed, terminal,
3438 "Not a tty device: %s",
3439 "Not a tty device: %s",
3440 name);
3443 #ifndef O_IGNORE_CTTY
3444 if (!ctty)
3445 dissociate_if_controlling_tty (fd);
3446 #endif
3448 file = fdopen (fd, "w+");
3449 tty->input = file;
3450 tty->output = file;
3453 tty->type = xstrdup (terminal_type);
3455 #ifdef subprocesses
3456 add_keyboard_wait_descriptor (fileno (tty->input));
3457 #endif
3459 #endif /* !DOS_NT */
3461 encode_terminal_src_size = 0;
3462 encode_terminal_dst_size = 0;
3464 #ifdef HAVE_GPM
3465 terminal->mouse_position_hook = term_mouse_position;
3466 mouse_face_window = Qnil;
3467 #endif
3469 #ifdef DOS_NT
3470 #ifdef WINDOWSNT
3471 initialize_w32_display (terminal);
3472 #else /* MSDOS */
3473 if (strcmp (terminal_type, "internal") == 0)
3474 terminal->type = output_msdos_raw;
3475 initialize_msdos_display (terminal);
3476 #endif /* MSDOS */
3477 tty->output = stdout;
3478 tty->input = stdin;
3479 /* The following two are inaccessible from w32console.c. */
3480 terminal->delete_frame_hook = &tty_free_frame_resources;
3481 terminal->delete_terminal_hook = &delete_tty;
3483 tty->name = xstrdup (name);
3484 terminal->name = xstrdup (name);
3485 tty->type = xstrdup (terminal_type);
3487 #ifdef subprocesses
3488 add_keyboard_wait_descriptor (0);
3489 #endif
3491 Wcm_clear (tty);
3493 #ifdef WINDOWSNT
3495 struct frame *f = XFRAME (selected_frame);
3497 FrameRows (tty) = FRAME_LINES (f);
3498 FrameCols (tty) = FRAME_COLS (f);
3499 tty->specified_window = FRAME_LINES (f);
3501 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
3502 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
3504 #else /* MSDOS */
3506 int height, width;
3507 get_tty_size (fileno (tty->input), &width, &height);
3508 FrameCols (tty) = width;
3509 FrameRows (tty) = height;
3511 #endif /* MSDOS */
3512 tty->delete_in_insert_mode = 1;
3514 UseTabs (tty) = 0;
3515 terminal->scroll_region_ok = 0;
3517 /* Seems to insert lines when it's not supposed to, messing up the
3518 display. In doing a trace, it didn't seem to be called much, so I
3519 don't think we're losing anything by turning it off. */
3520 terminal->line_ins_del_ok = 0;
3521 #ifdef WINDOWSNT
3522 terminal->char_ins_del_ok = 1;
3523 baud_rate = 19200;
3524 #else /* MSDOS */
3525 terminal->char_ins_del_ok = 0;
3526 init_baud_rate (fileno (tty->input));
3527 #endif /* MSDOS */
3529 tty->TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */
3531 #else /* not DOS_NT */
3533 Wcm_clear (tty);
3535 tty->termcap_term_buffer = (char *) xmalloc (buffer_size);
3537 /* On some systems, tgetent tries to access the controlling
3538 terminal. */
3539 sigblock (sigmask (SIGTTOU));
3540 status = tgetent (tty->termcap_term_buffer, terminal_type);
3541 sigunblock (sigmask (SIGTTOU));
3543 if (status < 0)
3545 #ifdef TERMINFO
3546 maybe_fatal (must_succeed, terminal,
3547 "Cannot open terminfo database file",
3548 "Cannot open terminfo database file");
3549 #else
3550 maybe_fatal (must_succeed, terminal,
3551 "Cannot open termcap database file",
3552 "Cannot open termcap database file");
3553 #endif
3555 if (status == 0)
3557 #ifdef TERMINFO
3558 maybe_fatal (must_succeed, terminal,
3559 "Terminal type %s is not defined",
3560 "Terminal type %s is not defined.\n\
3561 If that is not the actual type of terminal you have,\n\
3562 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3563 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3564 to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
3565 terminal_type);
3566 #else
3567 maybe_fatal (must_succeed, terminal,
3568 "Terminal type %s is not defined",
3569 "Terminal type %s is not defined.\n\
3570 If that is not the actual type of terminal you have,\n\
3571 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3572 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3573 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
3574 terminal_type);
3575 #endif
3578 #ifndef TERMINFO
3579 if (strlen (tty->termcap_term_buffer) >= buffer_size)
3580 abort ();
3581 buffer_size = strlen (tty->termcap_term_buffer);
3582 #endif
3583 tty->termcap_strings_buffer = area = (char *) xmalloc (buffer_size);
3584 tty->TS_ins_line = tgetstr ("al", address);
3585 tty->TS_ins_multi_lines = tgetstr ("AL", address);
3586 tty->TS_bell = tgetstr ("bl", address);
3587 BackTab (tty) = tgetstr ("bt", address);
3588 tty->TS_clr_to_bottom = tgetstr ("cd", address);
3589 tty->TS_clr_line = tgetstr ("ce", address);
3590 tty->TS_clr_frame = tgetstr ("cl", address);
3591 ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
3592 AbsPosition (tty) = tgetstr ("cm", address);
3593 CR (tty) = tgetstr ("cr", address);
3594 tty->TS_set_scroll_region = tgetstr ("cs", address);
3595 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
3596 RowPosition (tty) = tgetstr ("cv", address);
3597 tty->TS_del_char = tgetstr ("dc", address);
3598 tty->TS_del_multi_chars = tgetstr ("DC", address);
3599 tty->TS_del_line = tgetstr ("dl", address);
3600 tty->TS_del_multi_lines = tgetstr ("DL", address);
3601 tty->TS_delete_mode = tgetstr ("dm", address);
3602 tty->TS_end_delete_mode = tgetstr ("ed", address);
3603 tty->TS_end_insert_mode = tgetstr ("ei", address);
3604 Home (tty) = tgetstr ("ho", address);
3605 tty->TS_ins_char = tgetstr ("ic", address);
3606 tty->TS_ins_multi_chars = tgetstr ("IC", address);
3607 tty->TS_insert_mode = tgetstr ("im", address);
3608 tty->TS_pad_inserted_char = tgetstr ("ip", address);
3609 tty->TS_end_keypad_mode = tgetstr ("ke", address);
3610 tty->TS_keypad_mode = tgetstr ("ks", address);
3611 LastLine (tty) = tgetstr ("ll", address);
3612 Right (tty) = tgetstr ("nd", address);
3613 Down (tty) = tgetstr ("do", address);
3614 if (!Down (tty))
3615 Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */
3616 if (tgetflag ("bs"))
3617 Left (tty) = "\b"; /* can't possibly be longer! */
3618 else /* (Actually, "bs" is obsolete...) */
3619 Left (tty) = tgetstr ("le", address);
3620 if (!Left (tty))
3621 Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */
3622 tty->TS_pad_char = tgetstr ("pc", address);
3623 tty->TS_repeat = tgetstr ("rp", address);
3624 tty->TS_end_standout_mode = tgetstr ("se", address);
3625 tty->TS_fwd_scroll = tgetstr ("sf", address);
3626 tty->TS_standout_mode = tgetstr ("so", address);
3627 tty->TS_rev_scroll = tgetstr ("sr", address);
3628 tty->Wcm->cm_tab = tgetstr ("ta", address);
3629 tty->TS_end_termcap_modes = tgetstr ("te", address);
3630 tty->TS_termcap_modes = tgetstr ("ti", address);
3631 Up (tty) = tgetstr ("up", address);
3632 tty->TS_visible_bell = tgetstr ("vb", address);
3633 tty->TS_cursor_normal = tgetstr ("ve", address);
3634 tty->TS_cursor_visible = tgetstr ("vs", address);
3635 tty->TS_cursor_invisible = tgetstr ("vi", address);
3636 tty->TS_set_window = tgetstr ("wi", address);
3638 tty->TS_enter_underline_mode = tgetstr ("us", address);
3639 tty->TS_exit_underline_mode = tgetstr ("ue", address);
3640 tty->TS_enter_bold_mode = tgetstr ("md", address);
3641 tty->TS_enter_dim_mode = tgetstr ("mh", address);
3642 tty->TS_enter_blink_mode = tgetstr ("mb", address);
3643 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
3644 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
3645 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
3646 tty->TS_exit_attribute_mode = tgetstr ("me", address);
3648 MultiUp (tty) = tgetstr ("UP", address);
3649 MultiDown (tty) = tgetstr ("DO", address);
3650 MultiLeft (tty) = tgetstr ("LE", address);
3651 MultiRight (tty) = tgetstr ("RI", address);
3653 /* SVr4/ANSI color suppert. If "op" isn't available, don't support
3654 color because we can't switch back to the default foreground and
3655 background. */
3656 tty->TS_orig_pair = tgetstr ("op", address);
3657 if (tty->TS_orig_pair)
3659 tty->TS_set_foreground = tgetstr ("AF", address);
3660 tty->TS_set_background = tgetstr ("AB", address);
3661 if (!tty->TS_set_foreground)
3663 /* SVr4. */
3664 tty->TS_set_foreground = tgetstr ("Sf", address);
3665 tty->TS_set_background = tgetstr ("Sb", address);
3668 tty->TN_max_colors = tgetnum ("Co");
3669 tty->TN_max_pairs = tgetnum ("pa");
3671 tty->TN_no_color_video = tgetnum ("NC");
3672 if (tty->TN_no_color_video == -1)
3673 tty->TN_no_color_video = 0;
3676 tty_default_color_capabilities (tty, 1);
3678 MagicWrap (tty) = tgetflag ("xn");
3679 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
3680 the former flag imply the latter. */
3681 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
3682 terminal->memory_below_frame = tgetflag ("db");
3683 tty->TF_hazeltine = tgetflag ("hz");
3684 terminal->must_write_spaces = tgetflag ("in");
3685 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
3686 tty->TF_insmode_motion = tgetflag ("mi");
3687 tty->TF_standout_motion = tgetflag ("ms");
3688 tty->TF_underscore = tgetflag ("ul");
3689 tty->TF_teleray = tgetflag ("xt");
3691 #endif /* !DOS_NT */
3692 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3693 init_kboard (terminal->kboard);
3694 terminal->kboard->Vwindow_system = Qnil;
3695 terminal->kboard->next_kboard = all_kboards;
3696 all_kboards = terminal->kboard;
3697 terminal->kboard->reference_count++;
3698 /* Don't let the initial kboard remain current longer than necessary.
3699 That would cause problems if a file loaded on startup tries to
3700 prompt in the mini-buffer. */
3701 if (current_kboard == initial_kboard)
3702 current_kboard = terminal->kboard;
3703 #ifndef DOS_NT
3704 term_get_fkeys (address, terminal->kboard);
3706 /* Get frame size from system, or else from termcap. */
3708 int height, width;
3709 get_tty_size (fileno (tty->input), &width, &height);
3710 FrameCols (tty) = width;
3711 FrameRows (tty) = height;
3714 if (FrameCols (tty) <= 0)
3715 FrameCols (tty) = tgetnum ("co");
3716 if (FrameRows (tty) <= 0)
3717 FrameRows (tty) = tgetnum ("li");
3719 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
3720 maybe_fatal (must_succeed, terminal,
3721 "Screen size %dx%d is too small"
3722 "Screen size %dx%d is too small",
3723 FrameCols (tty), FrameRows (tty));
3725 #if 0 /* This is not used anywhere. */
3726 tty->terminal->min_padding_speed = tgetnum ("pb");
3727 #endif
3729 TabWidth (tty) = tgetnum ("tw");
3731 if (!tty->TS_bell)
3732 tty->TS_bell = "\07";
3734 if (!tty->TS_fwd_scroll)
3735 tty->TS_fwd_scroll = Down (tty);
3737 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
3739 if (TabWidth (tty) < 0)
3740 TabWidth (tty) = 8;
3742 /* Turned off since /etc/termcap seems to have :ta= for most terminals
3743 and newer termcap doc does not seem to say there is a default.
3744 if (!tty->Wcm->cm_tab)
3745 tty->Wcm->cm_tab = "\t";
3748 /* We don't support standout modes that use `magic cookies', so
3749 turn off any that do. */
3750 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
3752 tty->TS_standout_mode = 0;
3753 tty->TS_end_standout_mode = 0;
3755 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
3757 tty->TS_enter_underline_mode = 0;
3758 tty->TS_exit_underline_mode = 0;
3761 /* If there's no standout mode, try to use underlining instead. */
3762 if (tty->TS_standout_mode == 0)
3764 tty->TS_standout_mode = tty->TS_enter_underline_mode;
3765 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
3768 /* If no `se' string, try using a `me' string instead.
3769 If that fails, we can't use standout mode at all. */
3770 if (tty->TS_end_standout_mode == 0)
3772 char *s = tgetstr ("me", address);
3773 if (s != 0)
3774 tty->TS_end_standout_mode = s;
3775 else
3776 tty->TS_standout_mode = 0;
3779 if (tty->TF_teleray)
3781 tty->Wcm->cm_tab = 0;
3782 /* We can't support standout mode, because it uses magic cookies. */
3783 tty->TS_standout_mode = 0;
3784 /* But that means we cannot rely on ^M to go to column zero! */
3785 CR (tty) = 0;
3786 /* LF can't be trusted either -- can alter hpos */
3787 /* if move at column 0 thru a line with TS_standout_mode */
3788 Down (tty) = 0;
3791 /* Special handling for certain terminal types known to need it */
3793 if (!strcmp (terminal_type, "supdup"))
3795 terminal->memory_below_frame = 1;
3796 tty->Wcm->cm_losewrap = 1;
3798 if (!strncmp (terminal_type, "c10", 3)
3799 || !strcmp (terminal_type, "perq"))
3801 /* Supply a makeshift :wi string.
3802 This string is not valid in general since it works only
3803 for windows starting at the upper left corner;
3804 but that is all Emacs uses.
3806 This string works only if the frame is using
3807 the top of the video memory, because addressing is memory-relative.
3808 So first check the :ti string to see if that is true.
3810 It would be simpler if the :wi string could go in the termcap
3811 entry, but it can't because it is not fully valid.
3812 If it were in the termcap entry, it would confuse other programs. */
3813 if (!tty->TS_set_window)
3815 p = tty->TS_termcap_modes;
3816 while (*p && strcmp (p, "\033v "))
3817 p++;
3818 if (*p)
3819 tty->TS_set_window = "\033v%C %C %C %C ";
3821 /* Termcap entry often fails to have :in: flag */
3822 terminal->must_write_spaces = 1;
3823 /* :ti string typically fails to have \E^G! in it */
3824 /* This limits scope of insert-char to one line. */
3825 strcpy (area, tty->TS_termcap_modes);
3826 strcat (area, "\033\007!");
3827 tty->TS_termcap_modes = area;
3828 area += strlen (area) + 1;
3829 p = AbsPosition (tty);
3830 /* Change all %+ parameters to %C, to handle
3831 values above 96 correctly for the C100. */
3832 while (*p)
3834 if (p[0] == '%' && p[1] == '+')
3835 p[1] = 'C';
3836 p++;
3840 tty->specified_window = FrameRows (tty);
3842 if (Wcm_init (tty) == -1) /* can't do cursor motion */
3844 maybe_fatal (must_succeed, terminal,
3845 "Terminal type \"%s\" is not powerful enough to run Emacs",
3846 # ifdef TERMINFO
3847 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
3848 It lacks the ability to position the cursor.\n\
3849 If that is not the actual type of terminal you have,\n\
3850 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3851 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3852 to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
3853 # else /* TERMCAP */
3854 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
3855 It lacks the ability to position the cursor.\n\
3856 If that is not the actual type of terminal you have,\n\
3857 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3858 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3859 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
3860 # endif /* TERMINFO */
3861 terminal_type);
3864 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
3865 maybe_fatal (must_succeed, terminal,
3866 "Could not determine the frame size",
3867 "Could not determine the frame size");
3869 tty->delete_in_insert_mode
3870 = tty->TS_delete_mode && tty->TS_insert_mode
3871 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
3873 tty->se_is_so = (tty->TS_standout_mode
3874 && tty->TS_end_standout_mode
3875 && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode));
3877 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
3879 terminal->scroll_region_ok
3880 = (tty->Wcm->cm_abs
3881 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
3883 terminal->line_ins_del_ok
3884 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
3885 && (tty->TS_del_line || tty->TS_del_multi_lines))
3886 || (terminal->scroll_region_ok
3887 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
3889 terminal->char_ins_del_ok
3890 = ((tty->TS_ins_char || tty->TS_insert_mode
3891 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
3892 && (tty->TS_del_char || tty->TS_del_multi_chars));
3894 terminal->fast_clear_end_of_line = tty->TS_clr_line != 0;
3896 init_baud_rate (fileno (tty->input));
3898 #endif /* not DOS_NT */
3900 /* Init system terminal modes (RAW or CBREAK, etc.). */
3901 init_sys_modes (tty);
3903 return terminal;
3906 /* Auxiliary error-handling function for init_tty.
3907 Delete TERMINAL, then call error or fatal with str1 or str2,
3908 respectively, according to MUST_SUCCEED. */
3910 static void
3911 maybe_fatal (must_succeed, terminal, str1, str2, arg1, arg2)
3912 int must_succeed;
3913 struct terminal *terminal;
3914 char *str1, *str2, *arg1, *arg2;
3916 if (terminal)
3917 delete_tty (terminal);
3919 if (must_succeed)
3920 fatal (str2, arg1, arg2);
3921 else
3922 error (str1, arg1, arg2);
3924 abort ();
3927 void
3928 fatal (const char *str, ...)
3930 va_list ap;
3931 va_start (ap, str);
3932 fprintf (stderr, "emacs: ");
3933 vfprintf (stderr, str, ap);
3934 va_end (ap);
3935 fflush (stderr);
3936 exit (1);
3941 /* Delete the given tty terminal, closing all frames on it. */
3943 static void
3944 delete_tty (struct terminal *terminal)
3946 struct tty_display_info *tty;
3947 Lisp_Object tail, frame;
3948 int last_terminal;
3950 /* Protect against recursive calls. delete_frame in
3951 delete_terminal calls us back when it deletes our last frame. */
3952 if (!terminal->name)
3953 return;
3955 if (terminal->type != output_termcap)
3956 abort ();
3958 tty = terminal->display_info.tty;
3960 last_terminal = 1;
3961 FOR_EACH_FRAME (tail, frame)
3963 struct frame *f = XFRAME (frame);
3964 if (FRAME_LIVE_P (f) && (!FRAME_TERMCAP_P (f) || FRAME_TTY (f) != tty))
3966 last_terminal = 0;
3967 break;
3970 if (last_terminal)
3971 error ("Attempt to delete the sole terminal device with live frames");
3973 if (tty == tty_list)
3974 tty_list = tty->next;
3975 else
3977 struct tty_display_info *p;
3978 for (p = tty_list; p && p->next != tty; p = p->next)
3981 if (! p)
3982 /* This should not happen. */
3983 abort ();
3985 p->next = tty->next;
3986 tty->next = 0;
3989 /* reset_sys_modes needs a valid device, so this call needs to be
3990 before delete_terminal. */
3991 reset_sys_modes (tty);
3993 delete_terminal (terminal);
3995 xfree (tty->name);
3996 xfree (tty->type);
3998 if (tty->input)
4000 #ifdef subprocesses
4001 delete_keyboard_wait_descriptor (fileno (tty->input));
4002 #endif
4003 if (tty->input != stdin)
4004 fclose (tty->input);
4006 if (tty->output && tty->output != stdout && tty->output != tty->input)
4007 fclose (tty->output);
4008 if (tty->termscript)
4009 fclose (tty->termscript);
4011 xfree (tty->old_tty);
4012 xfree (tty->Wcm);
4013 if (tty->termcap_strings_buffer)
4014 xfree (tty->termcap_strings_buffer);
4015 if (tty->termcap_term_buffer)
4016 xfree (tty->termcap_term_buffer);
4018 bzero (tty, sizeof (struct tty_display_info));
4019 xfree (tty);
4024 /* Mark the pointers in the tty_display_info objects.
4025 Called by the Fgarbage_collector. */
4027 void
4028 mark_ttys (void)
4030 struct tty_display_info *tty;
4032 for (tty = tty_list; tty; tty = tty->next)
4033 mark_object (tty->top_frame);
4038 void
4039 syms_of_term ()
4041 DEFVAR_BOOL ("system-uses-terminfo", &system_uses_terminfo,
4042 doc: /* Non-nil means the system uses terminfo rather than termcap.
4043 This variable can be used by terminal emulator packages. */);
4044 #ifdef TERMINFO
4045 system_uses_terminfo = 1;
4046 #else
4047 system_uses_terminfo = 0;
4048 #endif
4050 DEFVAR_LISP ("suspend-tty-functions", &Vsuspend_tty_functions,
4051 doc: /* Functions to be run after suspending a tty.
4052 The functions are run with one argument, the terminal id to be suspended.
4053 See `suspend-tty'. */);
4054 Vsuspend_tty_functions = Qnil;
4057 DEFVAR_LISP ("resume-tty-functions", &Vresume_tty_functions,
4058 doc: /* Functions to be run after resuming a tty.
4059 The functions are run with one argument, the terminal id that was revived.
4060 See `resume-tty'. */);
4061 Vresume_tty_functions = Qnil;
4063 DEFVAR_BOOL ("visible-cursor", &visible_cursor,
4064 doc: /* Non-nil means to make the cursor very visible.
4065 This only has an effect when running in a text terminal.
4066 What means \"very visible\" is up to your terminal. It may make the cursor
4067 bigger, or it may make it blink, or it may do nothing at all. */);
4068 visible_cursor = 1;
4070 defsubr (&Stty_display_color_p);
4071 defsubr (&Stty_display_color_cells);
4072 defsubr (&Stty_no_underline);
4073 defsubr (&Stty_type);
4074 defsubr (&Scontrolling_tty_p);
4075 defsubr (&Ssuspend_tty);
4076 defsubr (&Sresume_tty);
4077 #ifdef HAVE_GPM
4078 defsubr (&Sgpm_mouse_start);
4079 defsubr (&Sgpm_mouse_stop);
4081 staticpro (&mouse_face_window);
4082 #endif /* HAVE_GPM */
4084 #ifndef DOS_NT
4085 default_orig_pair = NULL;
4086 default_set_foreground = NULL;
4087 default_set_background = NULL;
4088 #endif /* !DOS_NT */
4090 encode_terminal_src = NULL;
4091 encode_terminal_dst = NULL;
4096 /* arch-tag: 498e7449-6f2e-45e2-91dd-b7d4ca488193
4097 (do not change this comment) */