Fix copyright entries broken by "rearrangement".
[emacs.git] / src / term.c
blob287133a2d4a5d795795247f3ca1dd07de2f991c0
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
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_size == 0)
585 encode_terminal_src = xmalloc (required);
586 else
587 encode_terminal_src = xrealloc (encode_terminal_src, 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 = composition_table[src->u.cmp_id];
600 int i;
602 nbytes = buf - encode_terminal_src;
603 required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len;
605 if (encode_terminal_src_size < nbytes + required)
607 encode_terminal_src_size = nbytes + required;
608 encode_terminal_src = xrealloc (encode_terminal_src,
609 encode_terminal_src_size);
610 buf = encode_terminal_src + nbytes;
613 for (i = 0; i < cmp->glyph_len; i++)
615 int c = COMPOSITION_GLYPH (cmp, i);
617 if (! char_charset (c, charset_list, NULL))
618 break;
619 buf += CHAR_STRING (c, buf);
620 nchars++;
622 if (i == 0)
624 /* The first character of the composition is not encodable. */
625 *buf++ = '?';
626 nchars++;
629 /* We must skip glyphs to be padded for a wide character. */
630 else if (! CHAR_GLYPH_PADDING_P (*src))
632 GLYPH g;
633 int c;
634 Lisp_Object string;
636 string = Qnil;
637 SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
639 if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
641 /* This glyph doesn't has an entry in Vglyph_table. */
642 c = src->u.ch;
644 else
646 /* This glyph has an entry in Vglyph_table,
647 so process any alias before testing for simpleness. */
648 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
650 if (GLYPH_SIMPLE_P (tbase, tlen, g))
651 /* We set the multi-byte form of a character in G
652 (that should be an ASCII character) at WORKBUF. */
653 c = GLYPH_CHAR (g);
654 else
655 /* We have a string in Vglyph_table. */
656 string = tbase[GLYPH_CHAR (g)];
659 if (NILP (string))
661 nbytes = buf - encode_terminal_src;
662 if (encode_terminal_src_size < nbytes + MAX_MULTIBYTE_LENGTH)
664 encode_terminal_src_size = nbytes + MAX_MULTIBYTE_LENGTH;
665 encode_terminal_src = xrealloc (encode_terminal_src,
666 encode_terminal_src_size);
667 buf = encode_terminal_src + nbytes;
669 if (char_charset (c, charset_list, NULL))
671 /* Store the multibyte form of C at BUF. */
672 buf += CHAR_STRING (c, buf);
673 nchars++;
675 else
677 /* C is not encodable. */
678 *buf++ = '?';
679 nchars++;
680 while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
682 *buf++ = '?';
683 nchars++;
684 src++;
688 else
690 unsigned char *p = SDATA (string), *pend = p + SBYTES (string);
692 if (! STRING_MULTIBYTE (string))
693 string = string_to_multibyte (string);
694 nbytes = buf - encode_terminal_src;
695 if (encode_terminal_src_size < nbytes + SBYTES (string))
697 encode_terminal_src_size = nbytes + SBYTES (string);
698 encode_terminal_src = xrealloc (encode_terminal_src,
699 encode_terminal_src_size);
700 buf = encode_terminal_src + nbytes;
702 bcopy (SDATA (string), buf, SBYTES (string));
703 buf += SBYTES (string);
704 nchars += SCHARS (string);
707 src++;
710 if (nchars == 0)
712 coding->produced = 0;
713 return NULL;
716 nbytes = buf - encode_terminal_src;
717 coding->source = encode_terminal_src;
718 if (encode_terminal_dst_size == 0)
720 encode_terminal_dst_size = encode_terminal_src_size;
721 encode_terminal_dst = xmalloc (encode_terminal_dst_size);
723 coding->destination = encode_terminal_dst;
724 coding->dst_bytes = encode_terminal_dst_size;
725 encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
726 /* coding->destination may have been reallocated. */
727 encode_terminal_dst = coding->destination;
728 encode_terminal_dst_size = coding->dst_bytes;
730 return (encode_terminal_dst);
735 /* An implementation of write_glyphs for termcap frames. */
737 static void
738 tty_write_glyphs (struct frame *f, struct glyph *string, int len)
740 unsigned char *conversion_buffer;
741 struct coding_system *coding;
743 struct tty_display_info *tty = FRAME_TTY (f);
745 tty_turn_off_insert (tty);
746 tty_hide_cursor (tty);
748 /* Don't dare write in last column of bottom line, if Auto-Wrap,
749 since that would scroll the whole frame on some terminals. */
751 if (AutoWrap (tty)
752 && curY (tty) + 1 == FRAME_LINES (f)
753 && (curX (tty) + len) == FRAME_COLS (f))
754 len --;
755 if (len <= 0)
756 return;
758 cmplus (tty, len);
760 /* If terminal_coding does any conversion, use it, otherwise use
761 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
762 because it always return 1 if the member src_multibyte is 1. */
763 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
764 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
765 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
766 the tail. */
767 coding->mode &= ~CODING_MODE_LAST_BLOCK;
769 while (len > 0)
771 /* Identify a run of glyphs with the same face. */
772 int face_id = string->face_id;
773 int n;
775 for (n = 1; n < len; ++n)
776 if (string[n].face_id != face_id)
777 break;
779 /* Turn appearance modes of the face of the run on. */
780 tty_highlight_if_desired (tty);
781 turn_on_face (f, face_id);
783 if (n == len)
784 /* This is the last run. */
785 coding->mode |= CODING_MODE_LAST_BLOCK;
786 conversion_buffer = encode_terminal_code (string, n, coding);
787 if (coding->produced > 0)
789 BLOCK_INPUT;
790 fwrite (conversion_buffer, 1, coding->produced, tty->output);
791 if (ferror (tty->output))
792 clearerr (tty->output);
793 if (tty->termscript)
794 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
795 UNBLOCK_INPUT;
797 len -= n;
798 string += n;
800 /* Turn appearance modes off. */
801 turn_off_face (f, face_id);
802 tty_turn_off_highlight (tty);
805 cmcheckmagic (tty);
808 #ifdef HAVE_GPM /* Only used by GPM code. */
810 static void
811 tty_write_glyphs_with_face (f, string, len, face_id)
812 register struct frame *f;
813 register struct glyph *string;
814 register int len, face_id;
816 unsigned char *conversion_buffer;
817 struct coding_system *coding;
819 struct tty_display_info *tty = FRAME_TTY (f);
821 tty_turn_off_insert (tty);
822 tty_hide_cursor (tty);
824 /* Don't dare write in last column of bottom line, if Auto-Wrap,
825 since that would scroll the whole frame on some terminals. */
827 if (AutoWrap (tty)
828 && curY (tty) + 1 == FRAME_LINES (f)
829 && (curX (tty) + len) == FRAME_COLS (f))
830 len --;
831 if (len <= 0)
832 return;
834 cmplus (tty, len);
836 /* If terminal_coding does any conversion, use it, otherwise use
837 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
838 because it always return 1 if the member src_multibyte is 1. */
839 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
840 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
841 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
842 the tail. */
843 coding->mode &= ~CODING_MODE_LAST_BLOCK;
845 /* Turn appearance modes of the face. */
846 tty_highlight_if_desired (tty);
847 turn_on_face (f, face_id);
849 coding->mode |= CODING_MODE_LAST_BLOCK;
850 conversion_buffer = encode_terminal_code (string, len, coding);
851 if (coding->produced > 0)
853 BLOCK_INPUT;
854 fwrite (conversion_buffer, 1, coding->produced, tty->output);
855 if (ferror (tty->output))
856 clearerr (tty->output);
857 if (tty->termscript)
858 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
859 UNBLOCK_INPUT;
862 /* Turn appearance modes off. */
863 turn_off_face (f, face_id);
864 tty_turn_off_highlight (tty);
866 cmcheckmagic (tty);
868 #endif
870 /* An implementation of insert_glyphs for termcap frames. */
872 static void
873 tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
875 char *buf;
876 struct glyph *glyph = NULL;
877 unsigned char *conversion_buffer;
878 unsigned char space[1];
879 struct coding_system *coding;
881 struct tty_display_info *tty = FRAME_TTY (f);
883 if (tty->TS_ins_multi_chars)
885 buf = tparam (tty->TS_ins_multi_chars, 0, 0, len);
886 OUTPUT1 (tty, buf);
887 xfree (buf);
888 if (start)
889 write_glyphs (f, start, len);
890 return;
893 tty_turn_on_insert (tty);
894 cmplus (tty, len);
896 if (! start)
897 space[0] = SPACEGLYPH;
899 /* If terminal_coding does any conversion, use it, otherwise use
900 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
901 because it always return 1 if the member src_multibyte is 1. */
902 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
903 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
904 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
905 the tail. */
906 coding->mode &= ~CODING_MODE_LAST_BLOCK;
908 while (len-- > 0)
910 OUTPUT1_IF (tty, tty->TS_ins_char);
911 if (!start)
913 conversion_buffer = space;
914 coding->produced = 1;
916 else
918 tty_highlight_if_desired (tty);
919 turn_on_face (f, start->face_id);
920 glyph = start;
921 ++start;
922 /* We must open sufficient space for a character which
923 occupies more than one column. */
924 while (len && CHAR_GLYPH_PADDING_P (*start))
926 OUTPUT1_IF (tty, tty->TS_ins_char);
927 start++, len--;
930 if (len <= 0)
931 /* This is the last glyph. */
932 coding->mode |= CODING_MODE_LAST_BLOCK;
934 conversion_buffer = encode_terminal_code (glyph, 1, coding);
937 if (coding->produced > 0)
939 BLOCK_INPUT;
940 fwrite (conversion_buffer, 1, coding->produced, tty->output);
941 if (ferror (tty->output))
942 clearerr (tty->output);
943 if (tty->termscript)
944 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
945 UNBLOCK_INPUT;
948 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
949 if (start)
951 turn_off_face (f, glyph->face_id);
952 tty_turn_off_highlight (tty);
956 cmcheckmagic (tty);
959 /* An implementation of delete_glyphs for termcap frames. */
961 static void
962 tty_delete_glyphs (struct frame *f, int n)
964 char *buf;
965 register int i;
967 struct tty_display_info *tty = FRAME_TTY (f);
969 if (tty->delete_in_insert_mode)
971 tty_turn_on_insert (tty);
973 else
975 tty_turn_off_insert (tty);
976 OUTPUT_IF (tty, tty->TS_delete_mode);
979 if (tty->TS_del_multi_chars)
981 buf = tparam (tty->TS_del_multi_chars, 0, 0, n);
982 OUTPUT1 (tty, buf);
983 xfree (buf);
985 else
986 for (i = 0; i < n; i++)
987 OUTPUT1 (tty, tty->TS_del_char);
988 if (!tty->delete_in_insert_mode)
989 OUTPUT_IF (tty, tty->TS_end_delete_mode);
992 /* An implementation of ins_del_lines for termcap frames. */
994 static void
995 tty_ins_del_lines (struct frame *f, int vpos, int n)
997 struct tty_display_info *tty = FRAME_TTY (f);
998 char *multi = n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
999 char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
1000 char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
1002 register int i = n > 0 ? n : -n;
1003 register char *buf;
1005 /* If the lines below the insertion are being pushed
1006 into the end of the window, this is the same as clearing;
1007 and we know the lines are already clear, since the matching
1008 deletion has already been done. So can ignore this. */
1009 /* If the lines below the deletion are blank lines coming
1010 out of the end of the window, don't bother,
1011 as there will be a matching inslines later that will flush them. */
1012 if (FRAME_SCROLL_REGION_OK (f)
1013 && vpos + i >= tty->specified_window)
1014 return;
1015 if (!FRAME_MEMORY_BELOW_FRAME (f)
1016 && vpos + i >= FRAME_LINES (f))
1017 return;
1019 if (multi)
1021 raw_cursor_to (f, vpos, 0);
1022 tty_background_highlight (tty);
1023 buf = tparam (multi, 0, 0, i);
1024 OUTPUT (tty, buf);
1025 xfree (buf);
1027 else if (single)
1029 raw_cursor_to (f, vpos, 0);
1030 tty_background_highlight (tty);
1031 while (--i >= 0)
1032 OUTPUT (tty, single);
1033 if (tty->TF_teleray)
1034 curX (tty) = 0;
1036 else
1038 tty_set_scroll_region (f, vpos, tty->specified_window);
1039 if (n < 0)
1040 raw_cursor_to (f, tty->specified_window - 1, 0);
1041 else
1042 raw_cursor_to (f, vpos, 0);
1043 tty_background_highlight (tty);
1044 while (--i >= 0)
1045 OUTPUTL (tty, scroll, tty->specified_window - vpos);
1046 tty_set_scroll_region (f, 0, tty->specified_window);
1049 if (!FRAME_SCROLL_REGION_OK (f)
1050 && FRAME_MEMORY_BELOW_FRAME (f)
1051 && n < 0)
1053 cursor_to (f, FRAME_LINES (f) + n, 0);
1054 clear_to_end (f);
1058 /* Compute cost of sending "str", in characters,
1059 not counting any line-dependent padding. */
1062 string_cost (char *str)
1064 cost = 0;
1065 if (str)
1066 tputs (str, 0, evalcost);
1067 return cost;
1070 /* Compute cost of sending "str", in characters,
1071 counting any line-dependent padding at one line. */
1073 static int
1074 string_cost_one_line (char *str)
1076 cost = 0;
1077 if (str)
1078 tputs (str, 1, evalcost);
1079 return cost;
1082 /* Compute per line amount of line-dependent padding,
1083 in tenths of characters. */
1086 per_line_cost (char *str)
1088 cost = 0;
1089 if (str)
1090 tputs (str, 0, evalcost);
1091 cost = - cost;
1092 if (str)
1093 tputs (str, 10, evalcost);
1094 return cost;
1097 #ifndef old
1098 /* char_ins_del_cost[n] is cost of inserting N characters.
1099 char_ins_del_cost[-n] is cost of deleting N characters.
1100 The length of this vector is based on max_frame_cols. */
1102 int *char_ins_del_vector;
1104 #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_COLS ((f))])
1105 #endif
1107 /* ARGSUSED */
1108 static void
1109 calculate_ins_del_char_costs (struct frame *f)
1111 struct tty_display_info *tty = FRAME_TTY (f);
1112 int ins_startup_cost, del_startup_cost;
1113 int ins_cost_per_char, del_cost_per_char;
1114 register int i;
1115 register int *p;
1117 if (tty->TS_ins_multi_chars)
1119 ins_cost_per_char = 0;
1120 ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars);
1122 else if (tty->TS_ins_char || tty->TS_pad_inserted_char
1123 || (tty->TS_insert_mode && tty->TS_end_insert_mode))
1125 ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode)
1126 + string_cost (tty->TS_end_insert_mode))) / 100;
1127 ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char)
1128 + string_cost_one_line (tty->TS_pad_inserted_char));
1130 else
1132 ins_startup_cost = 9999;
1133 ins_cost_per_char = 0;
1136 if (tty->TS_del_multi_chars)
1138 del_cost_per_char = 0;
1139 del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars);
1141 else if (tty->TS_del_char)
1143 del_startup_cost = (string_cost (tty->TS_delete_mode)
1144 + string_cost (tty->TS_end_delete_mode));
1145 if (tty->delete_in_insert_mode)
1146 del_startup_cost /= 2;
1147 del_cost_per_char = string_cost_one_line (tty->TS_del_char);
1149 else
1151 del_startup_cost = 9999;
1152 del_cost_per_char = 0;
1155 /* Delete costs are at negative offsets */
1156 p = &char_ins_del_cost (f)[0];
1157 for (i = FRAME_COLS (f); --i >= 0;)
1158 *--p = (del_startup_cost += del_cost_per_char);
1160 /* Doing nothing is free */
1161 p = &char_ins_del_cost (f)[0];
1162 *p++ = 0;
1164 /* Insert costs are at positive offsets */
1165 for (i = FRAME_COLS (f); --i >= 0;)
1166 *p++ = (ins_startup_cost += ins_cost_per_char);
1169 void
1170 calculate_costs (struct frame *frame)
1172 FRAME_COST_BAUD_RATE (frame) = baud_rate;
1174 if (FRAME_TERMCAP_P (frame))
1176 struct tty_display_info *tty = FRAME_TTY (frame);
1177 register char *f = (tty->TS_set_scroll_region
1178 ? tty->TS_set_scroll_region
1179 : tty->TS_set_scroll_region_1);
1181 FRAME_SCROLL_REGION_COST (frame) = string_cost (f);
1183 tty->costs_set = 1;
1185 /* These variables are only used for terminal stuff. They are
1186 allocated once for the terminal frame of X-windows emacs, but not
1187 used afterwards.
1189 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1190 X turns off char_ins_del_ok. */
1192 max_frame_lines = max (max_frame_lines, FRAME_LINES (frame));
1193 max_frame_cols = max (max_frame_cols, FRAME_COLS (frame));
1195 if (char_ins_del_vector != 0)
1196 char_ins_del_vector
1197 = (int *) xrealloc (char_ins_del_vector,
1198 (sizeof (int)
1199 + 2 * max_frame_cols * sizeof (int)));
1200 else
1201 char_ins_del_vector
1202 = (int *) xmalloc (sizeof (int)
1203 + 2 * max_frame_cols * sizeof (int));
1205 bzero (char_ins_del_vector, (sizeof (int)
1206 + 2 * max_frame_cols * sizeof (int)));
1209 if (f && (!tty->TS_ins_line && !tty->TS_del_line))
1210 do_line_insertion_deletion_costs (frame,
1211 tty->TS_rev_scroll, tty->TS_ins_multi_lines,
1212 tty->TS_fwd_scroll, tty->TS_del_multi_lines,
1213 f, f, 1);
1214 else
1215 do_line_insertion_deletion_costs (frame,
1216 tty->TS_ins_line, tty->TS_ins_multi_lines,
1217 tty->TS_del_line, tty->TS_del_multi_lines,
1218 0, 0, 1);
1220 calculate_ins_del_char_costs (frame);
1222 /* Don't use TS_repeat if its padding is worse than sending the chars */
1223 if (tty->TS_repeat && per_line_cost (tty->TS_repeat) * baud_rate < 9000)
1224 tty->RPov = string_cost (tty->TS_repeat);
1225 else
1226 tty->RPov = FRAME_COLS (frame) * 2;
1228 cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */
1232 struct fkey_table {
1233 char *cap, *name;
1236 /* Termcap capability names that correspond directly to X keysyms.
1237 Some of these (marked "terminfo") aren't supplied by old-style
1238 (Berkeley) termcap entries. They're listed in X keysym order;
1239 except we put the keypad keys first, so that if they clash with
1240 other keys (as on the IBM PC keyboard) they get overridden.
1243 static struct fkey_table keys[] =
1245 {"kh", "home"}, /* termcap */
1246 {"kl", "left"}, /* termcap */
1247 {"ku", "up"}, /* termcap */
1248 {"kr", "right"}, /* termcap */
1249 {"kd", "down"}, /* termcap */
1250 {"%8", "prior"}, /* terminfo */
1251 {"%5", "next"}, /* terminfo */
1252 {"@7", "end"}, /* terminfo */
1253 {"@1", "begin"}, /* terminfo */
1254 {"*6", "select"}, /* terminfo */
1255 {"%9", "print"}, /* terminfo */
1256 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1258 * "insert" --- see below
1260 {"&8", "undo"}, /* terminfo */
1261 {"%0", "redo"}, /* terminfo */
1262 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1263 {"@0", "find"}, /* terminfo */
1264 {"@2", "cancel"}, /* terminfo */
1265 {"%1", "help"}, /* terminfo */
1267 * "break" goes here, but can't be reliably intercepted with termcap
1269 {"&4", "reset"}, /* terminfo --- actually `restart' */
1271 * "system" and "user" --- no termcaps
1273 {"kE", "clearline"}, /* terminfo */
1274 {"kA", "insertline"}, /* terminfo */
1275 {"kL", "deleteline"}, /* terminfo */
1276 {"kI", "insertchar"}, /* terminfo */
1277 {"kD", "deletechar"}, /* terminfo */
1278 {"kB", "backtab"}, /* terminfo */
1280 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1282 {"@8", "kp-enter"}, /* terminfo */
1284 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1285 * "kp-multiply", "kp-add", "kp-separator",
1286 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1287 * --- no termcaps for any of these.
1289 {"K4", "kp-1"}, /* terminfo */
1291 * "kp-2" --- no termcap
1293 {"K5", "kp-3"}, /* terminfo */
1295 * "kp-4" --- no termcap
1297 {"K2", "kp-5"}, /* terminfo */
1299 * "kp-6" --- no termcap
1301 {"K1", "kp-7"}, /* terminfo */
1303 * "kp-8" --- no termcap
1305 {"K3", "kp-9"}, /* terminfo */
1307 * "kp-equal" --- no termcap
1309 {"k1", "f1"},
1310 {"k2", "f2"},
1311 {"k3", "f3"},
1312 {"k4", "f4"},
1313 {"k5", "f5"},
1314 {"k6", "f6"},
1315 {"k7", "f7"},
1316 {"k8", "f8"},
1317 {"k9", "f9"},
1319 {"&0", "S-cancel"}, /*shifted cancel key*/
1320 {"&9", "S-begin"}, /*shifted begin key*/
1321 {"*0", "S-find"}, /*shifted find key*/
1322 {"*1", "S-execute"}, /*shifted execute? actually shifted command key*/
1323 {"*4", "S-delete"}, /*shifted delete-character key*/
1324 {"*7", "S-end"}, /*shifted end key*/
1325 {"*8", "S-clearline"}, /*shifted clear-to end-of-line key*/
1326 {"#1", "S-help"}, /*shifted help key*/
1327 {"#2", "S-home"}, /*shifted home key*/
1328 {"#3", "S-insert"}, /*shifted insert-character key*/
1329 {"#4", "S-left"}, /*shifted left-arrow key*/
1330 {"%d", "S-menu"}, /*shifted menu? actually shifted options key*/
1331 {"%c", "S-next"}, /*shifted next key*/
1332 {"%e", "S-prior"}, /*shifted previous key*/
1333 {"%f", "S-print"}, /*shifted print key*/
1334 {"%g", "S-redo"}, /*shifted redo key*/
1335 {"%i", "S-right"}, /*shifted right-arrow key*/
1336 {"!3", "S-undo"} /*shifted undo key*/
1339 static char **term_get_fkeys_address;
1340 static KBOARD *term_get_fkeys_kboard;
1341 static Lisp_Object term_get_fkeys_1 ();
1343 /* Find the escape codes sent by the function keys for Vinput_decode_map.
1344 This function scans the termcap function key sequence entries, and
1345 adds entries to Vinput_decode_map for each function key it finds. */
1347 static void
1348 term_get_fkeys (address, kboard)
1349 char **address;
1350 KBOARD *kboard;
1352 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1353 errors during the call. The only errors should be from Fdefine_key
1354 when given a key sequence containing an invalid prefix key. If the
1355 termcap defines function keys which use a prefix that is already bound
1356 to a command by the default bindings, we should silently ignore that
1357 function key specification, rather than giving the user an error and
1358 refusing to run at all on such a terminal. */
1360 extern Lisp_Object Fidentity ();
1361 term_get_fkeys_address = address;
1362 term_get_fkeys_kboard = kboard;
1363 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1366 static Lisp_Object
1367 term_get_fkeys_1 ()
1369 int i;
1371 char **address = term_get_fkeys_address;
1372 KBOARD *kboard = term_get_fkeys_kboard;
1374 /* This can happen if CANNOT_DUMP or with strange options. */
1375 if (!KEYMAPP (kboard->Vinput_decode_map))
1376 kboard->Vinput_decode_map = Fmake_sparse_keymap (Qnil);
1378 for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
1380 char *sequence = tgetstr (keys[i].cap, address);
1381 if (sequence)
1382 Fdefine_key (kboard->Vinput_decode_map, build_string (sequence),
1383 Fmake_vector (make_number (1),
1384 intern (keys[i].name)));
1387 /* The uses of the "k0" capability are inconsistent; sometimes it
1388 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1389 We will attempt to politely accommodate both systems by testing for
1390 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1393 char *k_semi = tgetstr ("k;", address);
1394 char *k0 = tgetstr ("k0", address);
1395 char *k0_name = "f10";
1397 if (k_semi)
1399 if (k0)
1400 /* Define f0 first, so that f10 takes precedence in case the
1401 key sequences happens to be the same. */
1402 Fdefine_key (kboard->Vinput_decode_map, build_string (k0),
1403 Fmake_vector (make_number (1), intern ("f0")));
1404 Fdefine_key (kboard->Vinput_decode_map, build_string (k_semi),
1405 Fmake_vector (make_number (1), intern ("f10")));
1407 else if (k0)
1408 Fdefine_key (kboard->Vinput_decode_map, build_string (k0),
1409 Fmake_vector (make_number (1), intern (k0_name)));
1412 /* Set up cookies for numbered function keys above f10. */
1414 char fcap[3], fkey[4];
1416 fcap[0] = 'F'; fcap[2] = '\0';
1417 for (i = 11; i < 64; i++)
1419 if (i <= 19)
1420 fcap[1] = '1' + i - 11;
1421 else if (i <= 45)
1422 fcap[1] = 'A' + i - 20;
1423 else
1424 fcap[1] = 'a' + i - 46;
1427 char *sequence = tgetstr (fcap, address);
1428 if (sequence)
1430 sprintf (fkey, "f%d", i);
1431 Fdefine_key (kboard->Vinput_decode_map, build_string (sequence),
1432 Fmake_vector (make_number (1),
1433 intern (fkey)));
1440 * Various mappings to try and get a better fit.
1443 #define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1444 if (!tgetstr (cap1, address)) \
1446 char *sequence = tgetstr (cap2, address); \
1447 if (sequence) \
1448 Fdefine_key (kboard->Vinput_decode_map, build_string (sequence), \
1449 Fmake_vector (make_number (1), \
1450 intern (sym))); \
1453 /* if there's no key_next keycap, map key_npage to `next' keysym */
1454 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1455 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1456 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1457 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1458 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1459 /* if there's no key_end keycap, map key_ll to 'end' keysym */
1460 CONDITIONAL_REASSIGN ("@7", "kH", "end");
1462 /* IBM has their own non-standard dialect of terminfo.
1463 If the standard name isn't found, try the IBM name. */
1464 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1465 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1466 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1467 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1468 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1469 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1470 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1471 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1472 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1473 #undef CONDITIONAL_REASSIGN
1476 return Qnil;
1480 /***********************************************************************
1481 Character Display Information
1482 ***********************************************************************/
1484 /* Avoid name clash with functions defined in xterm.c */
1485 #ifdef static
1486 #define append_glyph append_glyph_term
1487 #define produce_stretch_glyph produce_stretch_glyph_term
1488 #define append_composite_glyph append_composite_glyph_term
1489 #define produce_composite_glyph produce_composite_glyph_term
1490 #endif
1492 static void append_glyph P_ ((struct it *));
1493 static void produce_stretch_glyph P_ ((struct it *));
1494 static void append_composite_glyph P_ ((struct it *));
1495 static void produce_composite_glyph P_ ((struct it *));
1497 /* Append glyphs to IT's glyph_row. Called from produce_glyphs for
1498 terminal frames if IT->glyph_row != NULL. IT->char_to_display is
1499 the character for which to produce glyphs; IT->face_id contains the
1500 character's face. Padding glyphs are appended if IT->c has a
1501 IT->pixel_width > 1. */
1503 static void
1504 append_glyph (it)
1505 struct it *it;
1507 struct glyph *glyph, *end;
1508 int i;
1510 xassert (it->glyph_row);
1511 glyph = (it->glyph_row->glyphs[it->area]
1512 + it->glyph_row->used[it->area]);
1513 end = it->glyph_row->glyphs[1 + it->area];
1515 for (i = 0;
1516 i < it->pixel_width && glyph < end;
1517 ++i)
1519 glyph->type = CHAR_GLYPH;
1520 glyph->pixel_width = 1;
1521 glyph->u.ch = it->char_to_display;
1522 glyph->face_id = it->face_id;
1523 glyph->padding_p = i > 0;
1524 glyph->charpos = CHARPOS (it->position);
1525 glyph->object = it->object;
1527 ++it->glyph_row->used[it->area];
1528 ++glyph;
1533 /* Produce glyphs for the display element described by IT. *IT
1534 specifies what we want to produce a glyph for (character, image, ...),
1535 and where in the glyph matrix we currently are (glyph row and hpos).
1536 produce_glyphs fills in output fields of *IT with information such as the
1537 pixel width and height of a character, and maybe output actual glyphs at
1538 the same time if IT->glyph_row is non-null. See the explanation of
1539 struct display_iterator in dispextern.h for an overview.
1541 produce_glyphs also stores the result of glyph width, ascent
1542 etc. computations in *IT.
1544 IT->glyph_row may be null, in which case produce_glyphs does not
1545 actually fill in the glyphs. This is used in the move_* functions
1546 in xdisp.c for text width and height computations.
1548 Callers usually don't call produce_glyphs directly;
1549 instead they use the macro PRODUCE_GLYPHS. */
1551 void
1552 produce_glyphs (it)
1553 struct it *it;
1555 /* If a hook is installed, let it do the work. */
1557 /* Nothing but characters are supported on terminal frames. */
1558 xassert (it->what == IT_CHARACTER
1559 || it->what == IT_COMPOSITION
1560 || it->what == IT_STRETCH);
1562 if (it->what == IT_STRETCH)
1564 produce_stretch_glyph (it);
1565 goto done;
1568 if (it->what == IT_COMPOSITION)
1570 produce_composite_glyph (it);
1571 goto done;
1574 /* Maybe translate single-byte characters to multibyte. */
1575 it->char_to_display = it->c;
1577 if (it->c >= 040 && it->c < 0177)
1579 it->pixel_width = it->nglyphs = 1;
1580 if (it->glyph_row)
1581 append_glyph (it);
1583 else if (it->c == '\n')
1584 it->pixel_width = it->nglyphs = 0;
1585 else if (it->c == '\t')
1587 int absolute_x = (it->current_x
1588 + it->continuation_lines_width);
1589 int next_tab_x
1590 = (((1 + absolute_x + it->tab_width - 1)
1591 / it->tab_width)
1592 * it->tab_width);
1593 int nspaces;
1595 /* If part of the TAB has been displayed on the previous line
1596 which is continued now, continuation_lines_width will have
1597 been incremented already by the part that fitted on the
1598 continued line. So, we will get the right number of spaces
1599 here. */
1600 nspaces = next_tab_x - absolute_x;
1602 if (it->glyph_row)
1604 int n = nspaces;
1606 it->char_to_display = ' ';
1607 it->pixel_width = it->len = 1;
1609 while (n--)
1610 append_glyph (it);
1613 it->pixel_width = nspaces;
1614 it->nglyphs = nspaces;
1616 else if (CHAR_BYTE8_P (it->c))
1618 if (unibyte_display_via_language_environment
1619 && (it->c >= 0240))
1621 it->char_to_display = unibyte_char_to_multibyte (it->c);
1622 it->pixel_width = CHAR_WIDTH (it->char_to_display);
1623 it->nglyphs = it->pixel_width;
1624 if (it->glyph_row)
1625 append_glyph (it);
1627 else
1629 /* Coming here means that it->c is from display table, thus
1630 we must send the raw 8-bit byte as is to the terminal.
1631 Although there's no way to know how many columns it
1632 occupies on a screen, it is a good assumption that a
1633 single byte code has 1-column width. */
1634 it->pixel_width = it->nglyphs = 1;
1635 if (it->glyph_row)
1636 append_glyph (it);
1639 else
1641 it->pixel_width = CHAR_WIDTH (it->c);
1642 it->nglyphs = it->pixel_width;
1644 if (it->glyph_row)
1645 append_glyph (it);
1648 done:
1649 /* Advance current_x by the pixel width as a convenience for
1650 the caller. */
1651 if (it->area == TEXT_AREA)
1652 it->current_x += it->pixel_width;
1653 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1654 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
1658 /* Produce a stretch glyph for iterator IT. IT->object is the value
1659 of the glyph property displayed. The value must be a list
1660 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1661 being recognized:
1663 1. `:width WIDTH' specifies that the space should be WIDTH *
1664 canonical char width wide. WIDTH may be an integer or floating
1665 point number.
1667 2. `:align-to HPOS' specifies that the space should be wide enough
1668 to reach HPOS, a value in canonical character units. */
1670 static void
1671 produce_stretch_glyph (it)
1672 struct it *it;
1674 /* (space :width WIDTH ...) */
1675 Lisp_Object prop, plist;
1676 int width = 0, align_to = -1;
1677 int zero_width_ok_p = 0;
1678 double tem;
1680 /* List should start with `space'. */
1681 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1682 plist = XCDR (it->object);
1684 /* Compute the width of the stretch. */
1685 if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
1686 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, 0))
1688 /* Absolute width `:width WIDTH' specified and valid. */
1689 zero_width_ok_p = 1;
1690 width = (int)(tem + 0.5);
1692 else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
1693 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, &align_to))
1695 if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
1696 align_to = (align_to < 0
1698 : align_to - window_box_left_offset (it->w, TEXT_AREA));
1699 else if (align_to < 0)
1700 align_to = window_box_left_offset (it->w, TEXT_AREA);
1701 width = max (0, (int)(tem + 0.5) + align_to - it->current_x);
1702 zero_width_ok_p = 1;
1704 else
1705 /* Nothing specified -> width defaults to canonical char width. */
1706 width = FRAME_COLUMN_WIDTH (it->f);
1708 if (width <= 0 && (width < 0 || !zero_width_ok_p))
1709 width = 1;
1711 if (width > 0 && it->glyph_row)
1713 Lisp_Object o_object = it->object;
1714 Lisp_Object object = it->stack[it->sp - 1].string;
1715 int n = width;
1717 if (!STRINGP (object))
1718 object = it->w->buffer;
1719 it->object = object;
1720 it->char_to_display = ' ';
1721 it->pixel_width = it->len = 1;
1722 while (n--)
1723 append_glyph (it);
1724 it->object = o_object;
1726 it->pixel_width = width;
1727 it->nglyphs = width;
1731 /* Append glyphs to IT's glyph_row for the composition IT->cmp_id.
1732 Called from produce_composite_glyph for terminal frames if
1733 IT->glyph_row != NULL. IT->face_id contains the character's
1734 face. */
1736 static void
1737 append_composite_glyph (it)
1738 struct it *it;
1740 struct glyph *glyph;
1742 xassert (it->glyph_row);
1743 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1744 if (glyph < it->glyph_row->glyphs[1 + it->area])
1746 glyph->type = COMPOSITE_GLYPH;
1747 glyph->pixel_width = it->pixel_width;
1748 glyph->u.cmp_id = it->cmp_id;
1749 glyph->face_id = it->face_id;
1750 glyph->padding_p = 0;
1751 glyph->charpos = CHARPOS (it->position);
1752 glyph->object = it->object;
1754 ++it->glyph_row->used[it->area];
1755 ++glyph;
1760 /* Produce a composite glyph for iterator IT. IT->cmp_id is the ID of
1761 the composition. We simply produces components of the composition
1762 assuming that that the terminal has a capability to layout/render
1763 it correctly. */
1765 static void
1766 produce_composite_glyph (it)
1767 struct it *it;
1769 struct composition *cmp = composition_table[it->cmp_id];
1770 int c;
1772 xassert (cmp->glyph_len > 0);
1773 c = COMPOSITION_GLYPH (cmp, 0);
1774 it->pixel_width = CHAR_WIDTH (it->c);
1775 it->nglyphs = 1;
1777 if (it->glyph_row)
1778 append_composite_glyph (it);
1782 /* Get information about special display element WHAT in an
1783 environment described by IT. WHAT is one of IT_TRUNCATION or
1784 IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a
1785 non-null glyph_row member. This function ensures that fields like
1786 face_id, c, len of IT are left untouched. */
1788 void
1789 produce_special_glyphs (it, what)
1790 struct it *it;
1791 enum display_element_type what;
1793 struct it temp_it;
1794 Lisp_Object gc;
1795 GLYPH glyph;
1797 temp_it = *it;
1798 temp_it.dp = NULL;
1799 temp_it.what = IT_CHARACTER;
1800 temp_it.len = 1;
1801 temp_it.object = make_number (0);
1802 bzero (&temp_it.current, sizeof temp_it.current);
1804 if (what == IT_CONTINUATION)
1806 /* Continuation glyph. */
1807 SET_GLYPH_FROM_CHAR (glyph, '\\');
1808 if (it->dp
1809 && (gc = DISP_CONTINUE_GLYPH (it->dp), GLYPH_CODE_P (gc))
1810 && GLYPH_CODE_CHAR_VALID_P (gc))
1812 SET_GLYPH_FROM_GLYPH_CODE (glyph, gc);
1813 spec_glyph_lookup_face (XWINDOW (it->window), &glyph);
1816 else if (what == IT_TRUNCATION)
1818 /* Truncation glyph. */
1819 SET_GLYPH_FROM_CHAR (glyph, '$');
1820 if (it->dp
1821 && (gc = DISP_TRUNC_GLYPH (it->dp), GLYPH_CODE_P (gc))
1822 && GLYPH_CODE_CHAR_VALID_P (gc))
1824 SET_GLYPH_FROM_GLYPH_CODE (glyph, gc);
1825 spec_glyph_lookup_face (XWINDOW (it->window), &glyph);
1828 else
1829 abort ();
1831 temp_it.c = GLYPH_CHAR (glyph);
1832 temp_it.face_id = GLYPH_FACE (glyph);
1833 temp_it.len = CHAR_BYTES (temp_it.c);
1835 produce_glyphs (&temp_it);
1836 it->pixel_width = temp_it.pixel_width;
1837 it->nglyphs = temp_it.pixel_width;
1842 /***********************************************************************
1843 Faces
1844 ***********************************************************************/
1846 /* Value is non-zero if attribute ATTR may be used. ATTR should be
1847 one of the enumerators from enum no_color_bit, or a bit set built
1848 from them. Some display attributes may not be used together with
1849 color; the termcap capability `NC' specifies which ones. */
1851 #define MAY_USE_WITH_COLORS_P(tty, ATTR) \
1852 (tty->TN_max_colors > 0 \
1853 ? (tty->TN_no_color_video & (ATTR)) == 0 \
1854 : 1)
1856 /* Turn appearances of face FACE_ID on tty frame F on.
1857 FACE_ID is a realized face ID number, in the face cache. */
1859 static void
1860 turn_on_face (f, face_id)
1861 struct frame *f;
1862 int face_id;
1864 struct face *face = FACE_FROM_ID (f, face_id);
1865 long fg = face->foreground;
1866 long bg = face->background;
1867 struct tty_display_info *tty = FRAME_TTY (f);
1869 /* Do this first because TS_end_standout_mode may be the same
1870 as TS_exit_attribute_mode, which turns all appearances off. */
1871 if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE))
1873 if (tty->TN_max_colors > 0)
1875 if (fg >= 0 && bg >= 0)
1877 /* If the terminal supports colors, we can set them
1878 below without using reverse video. The face's fg
1879 and bg colors are set as they should appear on
1880 the screen, i.e. they take the inverse-video'ness
1881 of the face already into account. */
1883 else if (inverse_video)
1885 if (fg == FACE_TTY_DEFAULT_FG_COLOR
1886 || bg == FACE_TTY_DEFAULT_BG_COLOR)
1887 tty_toggle_highlight (tty);
1889 else
1891 if (fg == FACE_TTY_DEFAULT_BG_COLOR
1892 || bg == FACE_TTY_DEFAULT_FG_COLOR)
1893 tty_toggle_highlight (tty);
1896 else
1898 /* If we can't display colors, use reverse video
1899 if the face specifies that. */
1900 if (inverse_video)
1902 if (fg == FACE_TTY_DEFAULT_FG_COLOR
1903 || bg == FACE_TTY_DEFAULT_BG_COLOR)
1904 tty_toggle_highlight (tty);
1906 else
1908 if (fg == FACE_TTY_DEFAULT_BG_COLOR
1909 || bg == FACE_TTY_DEFAULT_FG_COLOR)
1910 tty_toggle_highlight (tty);
1915 if (face->tty_bold_p)
1917 if (MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
1918 OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
1920 else if (face->tty_dim_p)
1921 if (MAY_USE_WITH_COLORS_P (tty, NC_DIM))
1922 OUTPUT1_IF (tty, tty->TS_enter_dim_mode);
1924 /* Alternate charset and blinking not yet used. */
1925 if (face->tty_alt_charset_p
1926 && MAY_USE_WITH_COLORS_P (tty, NC_ALT_CHARSET))
1927 OUTPUT1_IF (tty, tty->TS_enter_alt_charset_mode);
1929 if (face->tty_blinking_p
1930 && MAY_USE_WITH_COLORS_P (tty, NC_BLINK))
1931 OUTPUT1_IF (tty, tty->TS_enter_blink_mode);
1933 if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
1934 OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
1936 if (tty->TN_max_colors > 0)
1938 char *ts, *p;
1940 ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
1941 if (fg >= 0 && ts)
1943 p = tparam (ts, NULL, 0, (int) fg);
1944 OUTPUT (tty, p);
1945 xfree (p);
1948 ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
1949 if (bg >= 0 && ts)
1951 p = tparam (ts, NULL, 0, (int) bg);
1952 OUTPUT (tty, p);
1953 xfree (p);
1959 /* Turn off appearances of face FACE_ID on tty frame F. */
1961 static void
1962 turn_off_face (f, face_id)
1963 struct frame *f;
1964 int face_id;
1966 struct face *face = FACE_FROM_ID (f, face_id);
1967 struct tty_display_info *tty = FRAME_TTY (f);
1969 xassert (face != NULL);
1971 if (tty->TS_exit_attribute_mode)
1973 /* Capability "me" will turn off appearance modes double-bright,
1974 half-bright, reverse-video, standout, underline. It may or
1975 may not turn off alt-char-mode. */
1976 if (face->tty_bold_p
1977 || face->tty_dim_p
1978 || face->tty_reverse_p
1979 || face->tty_alt_charset_p
1980 || face->tty_blinking_p
1981 || face->tty_underline_p)
1983 OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
1984 if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0)
1985 tty->standout_mode = 0;
1988 if (face->tty_alt_charset_p)
1989 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
1991 else
1993 /* If we don't have "me" we can only have those appearances
1994 that have exit sequences defined. */
1995 if (face->tty_alt_charset_p)
1996 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
1998 if (face->tty_underline_p)
1999 OUTPUT_IF (tty, tty->TS_exit_underline_mode);
2002 /* Switch back to default colors. */
2003 if (tty->TN_max_colors > 0
2004 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
2005 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
2006 || (face->background != FACE_TTY_DEFAULT_COLOR
2007 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
2008 OUTPUT1_IF (tty, tty->TS_orig_pair);
2012 /* Return non-zero if the terminal on frame F supports all of the
2013 capabilities in CAPS simultaneously, with foreground and background
2014 colors FG and BG. */
2017 tty_capable_p (tty, caps, fg, bg)
2018 struct tty_display_info *tty;
2019 unsigned caps;
2020 unsigned long fg, bg;
2022 #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
2023 if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
2024 return 0;
2026 TTY_CAPABLE_P_TRY (tty, TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE);
2027 TTY_CAPABLE_P_TRY (tty, TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode, NC_UNDERLINE);
2028 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
2029 TTY_CAPABLE_P_TRY (tty, TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM);
2030 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BLINK, tty->TS_enter_blink_mode, NC_BLINK);
2031 TTY_CAPABLE_P_TRY (tty, TTY_CAP_ALT_CHARSET, tty->TS_enter_alt_charset_mode, NC_ALT_CHARSET);
2033 /* We can do it! */
2034 return 1;
2037 /* Return non-zero if the terminal is capable to display colors. */
2039 DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
2040 0, 1, 0,
2041 doc: /* Return non-nil if the tty device TERMINAL can display colors.
2043 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2044 frame's terminal). This function always returns nil if TERMINAL
2045 is not on a tty device. */)
2046 (terminal)
2047 Lisp_Object terminal;
2049 struct terminal *t = get_tty_terminal (terminal, 0);
2050 if (!t)
2051 return Qnil;
2052 else
2053 return t->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
2056 /* Return the number of supported colors. */
2057 DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
2058 Stty_display_color_cells, 0, 1, 0,
2059 doc: /* Return the number of colors supported by the tty device TERMINAL.
2061 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2062 frame's terminal). This function always returns 0 if TERMINAL
2063 is not on a tty device. */)
2064 (terminal)
2065 Lisp_Object terminal;
2067 struct terminal *t = get_tty_terminal (terminal, 0);
2068 if (!t)
2069 return make_number (0);
2070 else
2071 return make_number (t->display_info.tty->TN_max_colors);
2074 #ifndef DOS_NT
2076 /* Declare here rather than in the function, as in the rest of Emacs,
2077 to work around an HPUX compiler bug (?). See
2078 http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00410.html */
2079 static int default_max_colors;
2080 static int default_max_pairs;
2081 static int default_no_color_video;
2082 static char *default_orig_pair;
2083 static char *default_set_foreground;
2084 static char *default_set_background;
2086 /* Save or restore the default color-related capabilities of this
2087 terminal. */
2088 static void
2089 tty_default_color_capabilities (struct tty_display_info *tty, int save)
2092 if (save)
2094 xfree (default_orig_pair);
2095 default_orig_pair = tty->TS_orig_pair ? xstrdup (tty->TS_orig_pair) : NULL;
2097 xfree (default_set_foreground);
2098 default_set_foreground = tty->TS_set_foreground ? xstrdup (tty->TS_set_foreground)
2099 : NULL;
2101 xfree (default_set_background);
2102 default_set_background = tty->TS_set_background ? xstrdup (tty->TS_set_background)
2103 : NULL;
2105 default_max_colors = tty->TN_max_colors;
2106 default_max_pairs = tty->TN_max_pairs;
2107 default_no_color_video = tty->TN_no_color_video;
2109 else
2111 tty->TS_orig_pair = default_orig_pair;
2112 tty->TS_set_foreground = default_set_foreground;
2113 tty->TS_set_background = default_set_background;
2114 tty->TN_max_colors = default_max_colors;
2115 tty->TN_max_pairs = default_max_pairs;
2116 tty->TN_no_color_video = default_no_color_video;
2120 /* Setup one of the standard tty color schemes according to MODE.
2121 MODE's value is generally the number of colors which we want to
2122 support; zero means set up for the default capabilities, the ones
2123 we saw at init_tty time; -1 means turn off color support. */
2124 static void
2125 tty_setup_colors (struct tty_display_info *tty, int mode)
2127 /* Canonicalize all negative values of MODE. */
2128 if (mode < -1)
2129 mode = -1;
2131 switch (mode)
2133 case -1: /* no colors at all */
2134 tty->TN_max_colors = 0;
2135 tty->TN_max_pairs = 0;
2136 tty->TN_no_color_video = 0;
2137 tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL;
2138 break;
2139 case 0: /* default colors, if any */
2140 default:
2141 tty_default_color_capabilities (tty, 0);
2142 break;
2143 case 8: /* 8 standard ANSI colors */
2144 tty->TS_orig_pair = "\033[0m";
2145 #ifdef TERMINFO
2146 tty->TS_set_foreground = "\033[3%p1%dm";
2147 tty->TS_set_background = "\033[4%p1%dm";
2148 #else
2149 tty->TS_set_foreground = "\033[3%dm";
2150 tty->TS_set_background = "\033[4%dm";
2151 #endif
2152 tty->TN_max_colors = 8;
2153 tty->TN_max_pairs = 64;
2154 tty->TN_no_color_video = 0;
2155 break;
2159 void
2160 set_tty_color_mode (tty, f)
2161 struct tty_display_info *tty;
2162 struct frame *f;
2164 Lisp_Object tem, val, color_mode_spec;
2165 Lisp_Object color_mode;
2166 int mode;
2167 extern Lisp_Object Qtty_color_mode;
2168 Lisp_Object tty_color_mode_alist
2169 = Fintern_soft (build_string ("tty-color-mode-alist"), Qnil);
2171 tem = assq_no_quit (Qtty_color_mode, f->param_alist);
2172 val = CONSP (tem) ? XCDR (tem) : Qnil;
2174 if (INTEGERP (val))
2175 color_mode = val;
2176 else
2178 tem = (NILP (tty_color_mode_alist) ? Qnil
2179 : Fassq (val, XSYMBOL (tty_color_mode_alist)->value));
2180 color_mode = CONSP (tem) ? XCDR (tem) : Qnil;
2183 mode = INTEGERP (color_mode) ? XINT (color_mode) : 0;
2185 if (mode != tty->previous_color_mode)
2187 Lisp_Object funsym = intern ("tty-set-up-initial-frame-faces");
2188 tty->previous_color_mode = mode;
2189 tty_setup_colors (tty , mode);
2190 /* This recomputes all the faces given the new color definitions. */
2191 safe_call (1, &funsym);
2195 #endif /* !DOS_NT */
2199 /* Return the tty display object specified by TERMINAL. */
2201 struct terminal *
2202 get_tty_terminal (Lisp_Object terminal, int throw)
2204 struct terminal *t = get_terminal (terminal, throw);
2206 if (t && t->type != output_termcap && t->type != output_msdos_raw)
2208 if (throw)
2209 error ("Device %d is not a termcap terminal device", t->id);
2210 else
2211 return NULL;
2214 return t;
2217 /* Return an active termcap device that uses the tty device with the
2218 given name.
2220 This function ignores suspended devices.
2222 Returns NULL if the named terminal device is not opened. */
2224 struct terminal *
2225 get_named_tty (name)
2226 char *name;
2228 struct terminal *t;
2230 if (!name)
2231 abort ();
2233 for (t = terminal_list; t; t = t->next_terminal)
2235 if (t->type == output_termcap || t->type == output_msdos_raw
2236 && !strcmp (t->display_info.tty->name, name)
2237 && TERMINAL_ACTIVE_P (t))
2238 return t;
2241 return 0;
2245 DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
2246 doc: /* Return the type of the tty device that TERMINAL uses.
2247 Returns nil if TERMINAL is not on a tty device.
2249 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2250 frame's terminal). */)
2251 (terminal)
2252 Lisp_Object terminal;
2254 struct terminal *t = get_terminal (terminal, 1);
2256 if (t->type != output_termcap && t->type != output_msdos_raw)
2257 return Qnil;
2259 if (t->display_info.tty->type)
2260 return build_string (t->display_info.tty->type);
2261 else
2262 return Qnil;
2265 DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
2266 doc: /* Return non-nil if TERMINAL is the controlling tty of the Emacs process.
2268 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2269 frame's terminal). This function always returns nil if TERMINAL
2270 is not on a tty device. */)
2271 (terminal)
2272 Lisp_Object terminal;
2274 struct terminal *t = get_terminal (terminal, 1);
2276 if ((t->type != output_termcap && t->type != output_msdos_raw)
2277 || strcmp (t->display_info.tty->name, DEV_TTY) != 0)
2278 return Qnil;
2279 else
2280 return Qt;
2283 DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
2284 doc: /* Declare that the tty used by TERMINAL does not handle underlining.
2285 This is used to override the terminfo data, for certain terminals that
2286 do not really do underlining, but say that they do. This function has
2287 no effect if used on a non-tty terminal.
2289 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2290 frame's terminal). This function always returns nil if TERMINAL
2291 is not on a tty device. */)
2292 (terminal)
2293 Lisp_Object terminal;
2295 struct terminal *t = get_terminal (terminal, 1);
2297 if (t->type == output_termcap)
2298 t->display_info.tty->TS_enter_underline_mode = 0;
2299 return Qnil;
2304 DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
2305 doc: /* Suspend the terminal device TTY.
2307 The device is restored to its default state, and Emacs ceases all
2308 access to the tty device. Frames that use the device are not deleted,
2309 but input is not read from them and if they change, their display is
2310 not updated.
2312 TTY may be a terminal id, a frame, or nil for the terminal device of
2313 the currently selected frame.
2315 This function runs `suspend-tty-functions' after suspending the
2316 device. The functions are run with one arg, the id of the suspended
2317 terminal device.
2319 `suspend-tty' does nothing if it is called on a device that is already
2320 suspended.
2322 A suspended tty may be resumed by calling `resume-tty' on it. */)
2323 (tty)
2324 Lisp_Object tty;
2326 struct terminal *t = get_tty_terminal (tty, 1);
2327 FILE *f;
2329 if (!t)
2330 error ("Unknown tty device");
2332 f = t->display_info.tty->input;
2334 if (f)
2336 /* First run `suspend-tty-functions' and then clean up the tty
2337 state because `suspend-tty-functions' might need to change
2338 the tty state. */
2339 if (!NILP (Vrun_hooks))
2341 Lisp_Object args[2];
2342 args[0] = intern ("suspend-tty-functions");
2343 XSETTERMINAL (args[1], t);
2344 Frun_hook_with_args (2, args);
2347 reset_sys_modes (t->display_info.tty);
2349 #ifdef subprocesses
2350 delete_keyboard_wait_descriptor (fileno (f));
2351 #endif
2353 #ifndef MSDOS
2354 fclose (f);
2355 if (f != t->display_info.tty->output)
2356 fclose (t->display_info.tty->output);
2357 #endif
2359 t->display_info.tty->input = 0;
2360 t->display_info.tty->output = 0;
2362 if (FRAMEP (t->display_info.tty->top_frame))
2363 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
2367 /* Clear display hooks to prevent further output. */
2368 clear_tty_hooks (t);
2370 return Qnil;
2373 DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
2374 doc: /* Resume the previously suspended terminal device TTY.
2375 The terminal is opened and reinitialized. Frames that are on the
2376 suspended terminal are revived.
2378 It is an error to resume a terminal while another terminal is active
2379 on the same device.
2381 This function runs `resume-tty-functions' after resuming the terminal.
2382 The functions are run with one arg, the id of the resumed terminal
2383 device.
2385 `resume-tty' does nothing if it is called on a device that is not
2386 suspended.
2388 TTY may be a terminal id, a frame, or nil for the terminal device of
2389 the currently selected frame. */)
2390 (tty)
2391 Lisp_Object tty;
2393 struct terminal *t = get_tty_terminal (tty, 1);
2394 int fd;
2396 if (!t)
2397 error ("Unknown tty device");
2399 if (!t->display_info.tty->input)
2401 if (get_named_tty (t->display_info.tty->name))
2402 error ("Cannot resume display while another display is active on the same device");
2404 #ifdef MSDOS
2405 t->display_info.tty->output = stdout;
2406 t->display_info.tty->input = stdin;
2407 #else /* !MSDOS */
2408 fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
2410 if (fd == -1)
2411 error ("Can not reopen tty device %s: %s", t->display_info.tty->name, strerror (errno));
2413 if (strcmp (t->display_info.tty->name, DEV_TTY))
2414 dissociate_if_controlling_tty (fd);
2416 t->display_info.tty->output = fdopen (fd, "w+");
2417 t->display_info.tty->input = t->display_info.tty->output;
2418 #endif
2420 #ifdef subprocesses
2421 add_keyboard_wait_descriptor (fd);
2422 #endif
2424 if (FRAMEP (t->display_info.tty->top_frame))
2425 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
2427 init_sys_modes (t->display_info.tty);
2429 /* Run `resume-tty-functions'. */
2430 if (!NILP (Vrun_hooks))
2432 Lisp_Object args[2];
2433 args[0] = intern ("resume-tty-functions");
2434 XSETTERMINAL (args[1], t);
2435 Frun_hook_with_args (2, args);
2439 set_tty_hooks (t);
2441 return Qnil;
2445 /***********************************************************************
2446 Mouse
2447 ***********************************************************************/
2449 #ifdef HAVE_GPM
2450 void
2451 term_mouse_moveto (int x, int y)
2453 /* TODO: how to set mouse position?
2454 const char *name;
2455 int fd;
2456 name = (const char *) ttyname (0);
2457 fd = open (name, O_WRONLY);
2458 SOME_FUNCTION (x, y, fd);
2459 close (fd);
2460 last_mouse_x = x;
2461 last_mouse_y = y; */
2464 static void
2465 term_show_mouse_face (enum draw_glyphs_face draw)
2467 struct window *w = XWINDOW (mouse_face_window);
2468 int save_x, save_y;
2469 int i;
2471 struct frame *f = XFRAME (w->frame);
2472 struct tty_display_info *tty = FRAME_TTY (f);
2474 if (/* If window is in the process of being destroyed, don't bother
2475 to do anything. */
2476 w->current_matrix != NULL
2477 /* Recognize when we are called to operate on rows that don't exist
2478 anymore. This can happen when a window is split. */
2479 && mouse_face_end_row < w->current_matrix->nrows)
2481 /* write_glyphs writes at cursor position, so we need to
2482 temporarily move cursor coordinates to the beginning of
2483 the highlight region. */
2485 /* Save current cursor co-ordinates */
2486 save_y = curY (tty);
2487 save_x = curX (tty);
2489 /* Note that mouse_face_beg_row etc. are window relative. */
2490 for (i = mouse_face_beg_row; i <= mouse_face_end_row; i++)
2492 int start_hpos, end_hpos, nglyphs;
2493 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
2495 /* Don't do anything if row doesn't have valid contents. */
2496 if (!row->enabled_p)
2497 continue;
2499 /* For all but the first row, the highlight starts at column 0. */
2500 if (i == mouse_face_beg_row)
2501 start_hpos = mouse_face_beg_col;
2502 else
2503 start_hpos = 0;
2505 if (i == mouse_face_end_row)
2506 end_hpos = mouse_face_end_col;
2507 else
2509 end_hpos = row->used[TEXT_AREA];
2510 if (draw == DRAW_NORMAL_TEXT)
2511 row->fill_line_p = 1; /* Clear to end of line */
2514 if (end_hpos <= start_hpos)
2515 continue;
2516 /* Record that some glyphs of this row are displayed in
2517 mouse-face. */
2518 row->mouse_face_p = draw > 0;
2520 nglyphs = end_hpos - start_hpos;
2522 if (end_hpos >= row->used[TEXT_AREA])
2523 nglyphs = row->used[TEXT_AREA] - start_hpos;
2525 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
2526 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos
2527 + WINDOW_LEFT_EDGE_X (w);
2529 cursor_to (f, pos_y, pos_x);
2531 if (draw == DRAW_MOUSE_FACE)
2533 tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
2534 nglyphs, mouse_face_face_id);
2536 else /* draw == DRAW_NORMAL_TEXT */
2537 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
2539 cursor_to (f, save_y, save_x);
2543 static void
2544 term_clear_mouse_face ()
2546 if (!NILP (mouse_face_window))
2547 term_show_mouse_face (DRAW_NORMAL_TEXT);
2549 mouse_face_beg_row = mouse_face_beg_col = -1;
2550 mouse_face_end_row = mouse_face_end_col = -1;
2551 mouse_face_window = Qnil;
2554 /* Find the glyph matrix position of buffer position POS in window W.
2555 *HPOS and *VPOS are set to the positions found. W's current glyphs
2556 must be up to date. If POS is above window start return (0, 0).
2557 If POS is after end of W, return end of last line in W.
2558 - taken from msdos.c */
2559 static int
2560 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
2562 int i, lastcol, line_start_position, maybe_next_line_p = 0;
2563 int yb = window_text_bottom_y (w);
2564 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
2566 while (row->y < yb)
2568 if (row->used[TEXT_AREA])
2569 line_start_position = row->glyphs[TEXT_AREA]->charpos;
2570 else
2571 line_start_position = 0;
2573 if (line_start_position > pos)
2574 break;
2575 /* If the position sought is the end of the buffer,
2576 don't include the blank lines at the bottom of the window. */
2577 else if (line_start_position == pos
2578 && pos == BUF_ZV (XBUFFER (w->buffer)))
2580 maybe_next_line_p = 1;
2581 break;
2583 else if (line_start_position > 0)
2584 best_row = row;
2586 /* Don't overstep the last matrix row, lest we get into the
2587 never-never land... */
2588 if (row->y + 1 >= yb)
2589 break;
2591 ++row;
2594 /* Find the right column within BEST_ROW. */
2595 lastcol = 0;
2596 row = best_row;
2597 for (i = 0; i < row->used[TEXT_AREA]; i++)
2599 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
2600 int charpos;
2602 charpos = glyph->charpos;
2603 if (charpos == pos)
2605 *hpos = i;
2606 *vpos = row->y;
2607 return 1;
2609 else if (charpos > pos)
2610 break;
2611 else if (charpos > 0)
2612 lastcol = i;
2615 /* If we're looking for the end of the buffer,
2616 and we didn't find it in the line we scanned,
2617 use the start of the following line. */
2618 if (maybe_next_line_p)
2620 ++row;
2621 lastcol = 0;
2624 *vpos = row->y;
2625 *hpos = lastcol + 1;
2626 return 0;
2629 static void
2630 term_mouse_highlight (struct frame *f, int x, int y)
2632 enum window_part part;
2633 Lisp_Object window;
2634 struct window *w;
2635 struct buffer *b;
2637 if (NILP (Vmouse_highlight)
2638 || !f->glyphs_initialized_p)
2639 return;
2641 /* Which window is that in? */
2642 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
2644 /* Not on a window -> return. */
2645 if (!WINDOWP (window))
2646 return;
2648 if (!EQ (window, mouse_face_window))
2649 term_clear_mouse_face ();
2651 w = XWINDOW (window);
2653 /* Are we in a window whose display is up to date?
2654 And verify the buffer's text has not changed. */
2655 b = XBUFFER (w->buffer);
2656 if (part == ON_TEXT
2657 && EQ (w->window_end_valid, w->buffer)
2658 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
2659 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
2661 int pos, i, nrows = w->current_matrix->nrows;
2662 struct glyph_row *row;
2663 struct glyph *glyph;
2665 /* Find the glyph under X/Y. */
2666 glyph = NULL;
2667 if (y >= 0 && y < nrows)
2669 row = MATRIX_ROW (w->current_matrix, y);
2670 /* Give up if some row before the one we are looking for is
2671 not enabled. */
2672 for (i = 0; i <= y; i++)
2673 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
2674 break;
2675 if (i > y /* all rows upto and including the one at Y are enabled */
2676 && row->displays_text_p
2677 && x < window_box_width (w, TEXT_AREA))
2679 glyph = row->glyphs[TEXT_AREA];
2680 if (x >= row->used[TEXT_AREA])
2681 glyph = NULL;
2682 else
2684 glyph += x;
2685 if (!BUFFERP (glyph->object))
2686 glyph = NULL;
2691 /* Clear mouse face if X/Y not over text. */
2692 if (glyph == NULL)
2694 term_clear_mouse_face ();
2695 return;
2698 if (!BUFFERP (glyph->object))
2699 abort ();
2700 pos = glyph->charpos;
2702 /* Check for mouse-face. */
2704 extern Lisp_Object Qmouse_face;
2705 Lisp_Object mouse_face, overlay, position, *overlay_vec;
2706 int noverlays, obegv, ozv;
2707 struct buffer *obuf;
2709 /* If we get an out-of-range value, return now; avoid an error. */
2710 if (pos > BUF_Z (b))
2711 return;
2713 /* Make the window's buffer temporarily current for
2714 overlays_at and compute_char_face. */
2715 obuf = current_buffer;
2716 current_buffer = b;
2717 obegv = BEGV;
2718 ozv = ZV;
2719 BEGV = BEG;
2720 ZV = Z;
2722 /* Is this char mouse-active? */
2723 XSETINT (position, pos);
2725 /* Put all the overlays we want in a vector in overlay_vec. */
2726 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
2727 /* Sort overlays into increasing priority order. */
2728 noverlays = sort_overlays (overlay_vec, noverlays, w);
2730 /* Check mouse-face highlighting. */
2731 if (!(EQ (window, mouse_face_window)
2732 && y >= mouse_face_beg_row
2733 && y <= mouse_face_end_row
2734 && (y > mouse_face_beg_row
2735 || x >= mouse_face_beg_col)
2736 && (y < mouse_face_end_row
2737 || x < mouse_face_end_col
2738 || mouse_face_past_end)))
2740 /* Clear the display of the old active region, if any. */
2741 term_clear_mouse_face ();
2743 /* Find the highest priority overlay that has a mouse-face
2744 property. */
2745 overlay = Qnil;
2746 for (i = noverlays - 1; i >= 0; --i)
2748 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
2749 if (!NILP (mouse_face))
2751 overlay = overlay_vec[i];
2752 break;
2756 /* If no overlay applies, get a text property. */
2757 if (NILP (overlay))
2758 mouse_face = Fget_text_property (position, Qmouse_face,
2759 w->buffer);
2761 /* Handle the overlay case. */
2762 if (!NILP (overlay))
2764 /* Find the range of text around this char that
2765 should be active. */
2766 Lisp_Object before, after;
2767 EMACS_INT ignore;
2770 before = Foverlay_start (overlay);
2771 after = Foverlay_end (overlay);
2772 /* Record this as the current active region. */
2773 fast_find_position (w, XFASTINT (before),
2774 &mouse_face_beg_col,
2775 &mouse_face_beg_row);
2777 mouse_face_past_end
2778 = !fast_find_position (w, XFASTINT (after),
2779 &mouse_face_end_col,
2780 &mouse_face_end_row);
2781 mouse_face_window = window;
2783 mouse_face_face_id
2784 = face_at_buffer_position (w, pos, 0, 0,
2785 &ignore, pos + 1, 1);
2787 /* Display it as active. */
2788 term_show_mouse_face (DRAW_MOUSE_FACE);
2790 /* Handle the text property case. */
2791 else if (!NILP (mouse_face))
2793 /* Find the range of text around this char that
2794 should be active. */
2795 Lisp_Object before, after, beginning, end;
2796 EMACS_INT ignore;
2798 beginning = Fmarker_position (w->start);
2799 XSETINT (end, (BUF_Z (b) - XFASTINT (w->window_end_pos)));
2800 before
2801 = Fprevious_single_property_change (make_number (pos + 1),
2802 Qmouse_face,
2803 w->buffer, beginning);
2804 after
2805 = Fnext_single_property_change (position, Qmouse_face,
2806 w->buffer, end);
2808 /* Record this as the current active region. */
2809 fast_find_position (w, XFASTINT (before),
2810 &mouse_face_beg_col,
2811 &mouse_face_beg_row);
2812 mouse_face_past_end
2813 = !fast_find_position (w, XFASTINT (after),
2814 &mouse_face_end_col,
2815 &mouse_face_end_row);
2816 mouse_face_window = window;
2818 mouse_face_face_id
2819 = face_at_buffer_position (w, pos, 0, 0,
2820 &ignore, pos + 1, 1);
2822 /* Display it as active. */
2823 term_show_mouse_face (DRAW_MOUSE_FACE);
2827 /* Look for a `help-echo' property. */
2829 Lisp_Object help;
2830 extern Lisp_Object Qhelp_echo;
2832 /* Check overlays first. */
2833 help = Qnil;
2834 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
2836 overlay = overlay_vec[i];
2837 help = Foverlay_get (overlay, Qhelp_echo);
2840 if (!NILP (help))
2842 help_echo_string = help;
2843 help_echo_window = window;
2844 help_echo_object = overlay;
2845 help_echo_pos = pos;
2847 /* Try text properties. */
2848 else if (NILP (help)
2849 && ((STRINGP (glyph->object)
2850 && glyph->charpos >= 0
2851 && glyph->charpos < SCHARS (glyph->object))
2852 || (BUFFERP (glyph->object)
2853 && glyph->charpos >= BEGV
2854 && glyph->charpos < ZV)))
2856 help = Fget_text_property (make_number (glyph->charpos),
2857 Qhelp_echo, glyph->object);
2858 if (!NILP (help))
2860 help_echo_string = help;
2861 help_echo_window = window;
2862 help_echo_object = glyph->object;
2863 help_echo_pos = glyph->charpos;
2868 BEGV = obegv;
2869 ZV = ozv;
2870 current_buffer = obuf;
2875 static int
2876 term_mouse_movement (FRAME_PTR frame, Gpm_Event *event)
2878 /* Has the mouse moved off the glyph it was on at the last sighting? */
2879 if (event->x != last_mouse_x || event->y != last_mouse_y)
2881 frame->mouse_moved = 1;
2882 term_mouse_highlight (frame, event->x, event->y);
2883 /* Remember which glyph we're now on. */
2884 last_mouse_x = event->x;
2885 last_mouse_y = event->y;
2886 return 1;
2888 return 0;
2891 /* Return the current position of the mouse.
2893 Set *f to the frame the mouse is in, or zero if the mouse is in no
2894 Emacs frame. If it is set to zero, all the other arguments are
2895 garbage.
2897 Set *bar_window to Qnil, and *x and *y to the column and
2898 row of the character cell the mouse is over.
2900 Set *time to the time the mouse was at the returned position.
2902 This clears mouse_moved until the next motion
2903 event arrives. */
2904 static void
2905 term_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window,
2906 enum scroll_bar_part *part, Lisp_Object *x,
2907 Lisp_Object *y, unsigned long *time)
2909 struct timeval now;
2911 *fp = SELECTED_FRAME ();
2912 (*fp)->mouse_moved = 0;
2914 *bar_window = Qnil;
2915 *part = 0;
2917 XSETINT (*x, last_mouse_x);
2918 XSETINT (*y, last_mouse_y);
2919 gettimeofday(&now, 0);
2920 *time = (now.tv_sec * 1000) + (now.tv_usec / 1000);
2923 /* Prepare a mouse-event in *RESULT for placement in the input queue.
2925 If the event is a button press, then note that we have grabbed
2926 the mouse. */
2928 static Lisp_Object
2929 term_mouse_click (struct input_event *result, Gpm_Event *event,
2930 struct frame *f)
2932 struct timeval now;
2933 int i, j;
2935 result->kind = GPM_CLICK_EVENT;
2936 for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
2938 if (event->buttons & j) {
2939 result->code = i; /* button number */
2940 break;
2943 gettimeofday(&now, 0);
2944 result->timestamp = (now.tv_sec * 1000) + (now.tv_usec / 1000);
2946 if (event->type & GPM_UP)
2947 result->modifiers = up_modifier;
2948 else if (event->type & GPM_DOWN)
2949 result->modifiers = down_modifier;
2950 else
2951 result->modifiers = 0;
2953 if (event->type & GPM_SINGLE)
2954 result->modifiers |= click_modifier;
2956 if (event->type & GPM_DOUBLE)
2957 result->modifiers |= double_modifier;
2959 if (event->type & GPM_TRIPLE)
2960 result->modifiers |= triple_modifier;
2962 if (event->type & GPM_DRAG)
2963 result->modifiers |= drag_modifier;
2965 if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
2967 /* 1 << KG_SHIFT */
2968 if (event->modifiers & (1 << 0))
2969 result->modifiers |= shift_modifier;
2971 /* 1 << KG_CTRL */
2972 if (event->modifiers & (1 << 2))
2973 result->modifiers |= ctrl_modifier;
2975 /* 1 << KG_ALT || KG_ALTGR */
2976 if (event->modifiers & (1 << 3)
2977 || event->modifiers & (1 << 1))
2978 result->modifiers |= meta_modifier;
2981 XSETINT (result->x, event->x);
2982 XSETINT (result->y, event->y);
2983 XSETFRAME (result->frame_or_window, f);
2984 result->arg = Qnil;
2985 return Qnil;
2989 handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event, struct input_event* hold_quit)
2991 struct frame *f = XFRAME (tty->top_frame);
2992 struct input_event ie;
2993 int do_help = 0;
2994 int count = 0;
2996 EVENT_INIT (ie);
2997 ie.kind = NO_EVENT;
2998 ie.arg = Qnil;
3000 if (event->type & (GPM_MOVE | GPM_DRAG)) {
3001 previous_help_echo_string = help_echo_string;
3002 help_echo_string = Qnil;
3004 Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
3006 if (!term_mouse_movement (f, event))
3007 help_echo_string = previous_help_echo_string;
3009 /* If the contents of the global variable help_echo_string
3010 has changed, generate a HELP_EVENT. */
3011 if (!NILP (help_echo_string)
3012 || !NILP (previous_help_echo_string))
3013 do_help = 1;
3015 goto done;
3017 else {
3018 f->mouse_moved = 0;
3019 term_mouse_click (&ie, event, f);
3022 done:
3023 if (ie.kind != NO_EVENT)
3025 kbd_buffer_store_event_hold (&ie, hold_quit);
3026 count++;
3029 if (do_help
3030 && !(hold_quit && hold_quit->kind != NO_EVENT))
3032 Lisp_Object frame;
3034 if (f)
3035 XSETFRAME (frame, f);
3036 else
3037 frame = Qnil;
3039 gen_help_event (help_echo_string, frame, help_echo_window,
3040 help_echo_object, help_echo_pos);
3041 count++;
3044 return count;
3047 DEFUN ("gpm-mouse-start", Fgpm_mouse_start, Sgpm_mouse_start,
3048 0, 0, 0,
3049 doc: /* Open a connection to Gpm.
3050 Gpm-mouse can only be activated for one tty at a time. */)
3053 struct frame *f = SELECTED_FRAME ();
3054 struct tty_display_info *tty
3055 = ((f)->output_method == output_termcap
3056 ? (f)->terminal->display_info.tty : NULL);
3057 Gpm_Connect connection;
3059 if (!tty)
3060 error ("Gpm-mouse only works in the GNU/Linux console");
3061 if (gpm_tty == tty)
3062 return Qnil; /* Already activated, nothing to do. */
3063 if (gpm_tty)
3064 error ("Gpm-mouse can only be activated for one tty at a time");
3066 connection.eventMask = ~0;
3067 connection.defaultMask = ~GPM_HARD;
3068 connection.maxMod = ~0;
3069 connection.minMod = 0;
3070 gpm_zerobased = 1;
3072 if (Gpm_Open (&connection, 0) < 0)
3073 error ("Gpm-mouse failed to connect to the gpm daemon");
3074 else
3076 gpm_tty = tty;
3077 /* `init_sys_modes' arranges for mouse movements sent through gpm_fd
3078 to generate SIGIOs. Apparently we need to call reset_sys_modes
3079 before calling init_sys_modes. */
3080 reset_sys_modes (tty);
3081 init_sys_modes (tty);
3082 add_gpm_wait_descriptor (gpm_fd);
3083 return Qnil;
3087 DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
3088 0, 0, 0,
3089 doc: /* Close a connection to Gpm. */)
3092 struct frame *f = SELECTED_FRAME ();
3093 struct tty_display_info *tty
3094 = ((f)->output_method == output_termcap
3095 ? (f)->terminal->display_info.tty : NULL);
3097 if (!tty || gpm_tty != tty)
3098 return Qnil; /* Not activated on this terminal, nothing to do. */
3100 if (gpm_fd >= 0)
3101 delete_gpm_wait_descriptor (gpm_fd);
3102 while (Gpm_Close()); /* close all the stack */
3103 gpm_tty = NULL;
3104 return Qnil;
3106 #endif /* HAVE_GPM */
3109 /***********************************************************************
3110 Initialization
3111 ***********************************************************************/
3113 /* Initialize the tty-dependent part of frame F. The frame must
3114 already have its device initialized. */
3116 void
3117 create_tty_output (struct frame *f)
3119 struct tty_output *t;
3121 if (! FRAME_TERMCAP_P (f))
3122 abort ();
3124 t = xmalloc (sizeof (struct tty_output));
3125 bzero (t, sizeof (struct tty_output));
3127 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
3129 f->output_data.tty = t;
3132 /* Delete the tty-dependent part of frame F. */
3134 static void
3135 delete_tty_output (struct frame *f)
3137 if (! FRAME_TERMCAP_P (f))
3138 abort ();
3140 xfree (f->output_data.tty);
3144 /* Reset the hooks in TERMINAL. */
3146 static void
3147 clear_tty_hooks (struct terminal *terminal)
3149 terminal->rif = 0;
3150 terminal->cursor_to_hook = 0;
3151 terminal->raw_cursor_to_hook = 0;
3152 terminal->clear_to_end_hook = 0;
3153 terminal->clear_frame_hook = 0;
3154 terminal->clear_end_of_line_hook = 0;
3155 terminal->ins_del_lines_hook = 0;
3156 terminal->insert_glyphs_hook = 0;
3157 terminal->write_glyphs_hook = 0;
3158 terminal->delete_glyphs_hook = 0;
3159 terminal->ring_bell_hook = 0;
3160 terminal->reset_terminal_modes_hook = 0;
3161 terminal->set_terminal_modes_hook = 0;
3162 terminal->update_begin_hook = 0;
3163 terminal->update_end_hook = 0;
3164 terminal->set_terminal_window_hook = 0;
3165 terminal->mouse_position_hook = 0;
3166 terminal->frame_rehighlight_hook = 0;
3167 terminal->frame_raise_lower_hook = 0;
3168 terminal->fullscreen_hook = 0;
3169 terminal->set_vertical_scroll_bar_hook = 0;
3170 terminal->condemn_scroll_bars_hook = 0;
3171 terminal->redeem_scroll_bar_hook = 0;
3172 terminal->judge_scroll_bars_hook = 0;
3173 terminal->read_socket_hook = 0;
3174 terminal->frame_up_to_date_hook = 0;
3176 /* Leave these two set, or suspended frames are not deleted
3177 correctly. */
3178 terminal->delete_frame_hook = &delete_tty_output;
3179 terminal->delete_terminal_hook = &delete_tty;
3182 /* Initialize hooks in TERMINAL with the values needed for a tty. */
3184 static void
3185 set_tty_hooks (struct terminal *terminal)
3187 terminal->rif = 0; /* ttys don't support window-based redisplay. */
3189 terminal->cursor_to_hook = &tty_cursor_to;
3190 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
3192 terminal->clear_to_end_hook = &tty_clear_to_end;
3193 terminal->clear_frame_hook = &tty_clear_frame;
3194 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
3196 terminal->ins_del_lines_hook = &tty_ins_del_lines;
3198 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3199 terminal->write_glyphs_hook = &tty_write_glyphs;
3200 terminal->delete_glyphs_hook = &tty_delete_glyphs;
3202 terminal->ring_bell_hook = &tty_ring_bell;
3204 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3205 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
3206 terminal->update_begin_hook = 0; /* Not needed. */
3207 terminal->update_end_hook = &tty_update_end;
3208 terminal->set_terminal_window_hook = &tty_set_terminal_window;
3210 terminal->mouse_position_hook = 0; /* Not needed. */
3211 terminal->frame_rehighlight_hook = 0; /* Not needed. */
3212 terminal->frame_raise_lower_hook = 0; /* Not needed. */
3214 terminal->set_vertical_scroll_bar_hook = 0; /* Not needed. */
3215 terminal->condemn_scroll_bars_hook = 0; /* Not needed. */
3216 terminal->redeem_scroll_bar_hook = 0; /* Not needed. */
3217 terminal->judge_scroll_bars_hook = 0; /* Not needed. */
3219 terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
3220 terminal->frame_up_to_date_hook = 0; /* Not needed. */
3222 terminal->delete_frame_hook = &delete_tty_output;
3223 terminal->delete_terminal_hook = &delete_tty;
3226 /* Drop the controlling terminal if fd is the same device. */
3227 static void
3228 dissociate_if_controlling_tty (int fd)
3230 #ifndef DOS_NT
3231 int pgid;
3232 EMACS_GET_TTY_PGRP (fd, &pgid); /* If tcgetpgrp succeeds, fd is the ctty. */
3233 if (pgid != -1)
3235 #if defined (USG) && !defined (BSD_PGRPS)
3236 setpgrp ();
3237 no_controlling_tty = 1;
3238 #elif defined (CYGWIN)
3239 setsid ();
3240 no_controlling_tty = 1;
3241 #else
3242 #ifdef TIOCNOTTY /* Try BSD ioctls. */
3243 sigblock (sigmask (SIGTTOU));
3244 fd = emacs_open (DEV_TTY, O_RDWR, 0);
3245 if (fd != -1 && ioctl (fd, TIOCNOTTY, 0) != -1)
3247 no_controlling_tty = 1;
3249 if (fd != -1)
3250 emacs_close (fd);
3251 sigunblock (sigmask (SIGTTOU));
3252 #else
3253 /* Unknown system. */
3254 croak ();
3255 #endif /* ! TIOCNOTTY */
3256 #endif /* ! USG */
3258 #endif /* !DOS_NT */
3261 static void maybe_fatal();
3263 /* Create a termcap display on the tty device with the given name and
3264 type.
3266 If NAME is NULL, then use the controlling tty, i.e., "/dev/tty".
3267 Otherwise NAME should be a path to the tty device file,
3268 e.g. "/dev/pts/7".
3270 TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
3272 If MUST_SUCCEED is true, then all errors are fatal. */
3274 struct terminal *
3275 init_tty (char *name, char *terminal_type, int must_succeed)
3277 char *area = NULL;
3278 char **address = &area;
3279 char *buffer = NULL;
3280 int buffer_size = 4096;
3281 register char *p = NULL;
3282 int status;
3283 struct tty_display_info *tty = NULL;
3284 struct terminal *terminal = NULL;
3285 int ctty = 0; /* 1 if asked to open controlling tty. */
3287 if (!terminal_type)
3288 maybe_fatal (must_succeed, 0, 0,
3289 "Unknown terminal type",
3290 "Unknown terminal type");
3292 if (name == NULL)
3293 name = DEV_TTY;
3294 if (!strcmp (name, DEV_TTY))
3295 ctty = 1;
3297 /* If we already have a terminal on the given device, use that. If
3298 all such terminals are suspended, create a new one instead. */
3299 /* XXX Perhaps this should be made explicit by having init_tty
3300 always create a new terminal and separating terminal and frame
3301 creation on Lisp level. */
3302 terminal = get_named_tty (name);
3303 if (terminal)
3304 return terminal;
3306 terminal = create_terminal ();
3307 #ifdef MSDOS
3308 if (been_here > 0)
3309 maybe_fatal (1, 0, 0, "Attempt to create another terminal %s", "",
3310 name, "");
3311 been_here = 1;
3312 tty = &the_only_display_info;
3313 #else
3314 tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info));
3315 #endif
3316 bzero (tty, sizeof (struct tty_display_info));
3317 tty->next = tty_list;
3318 tty_list = tty;
3320 terminal->type = output_termcap;
3321 terminal->display_info.tty = tty;
3322 tty->terminal = terminal;
3324 tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
3325 Wcm_clear (tty);
3327 #ifndef DOS_NT
3328 set_tty_hooks (terminal);
3331 int fd;
3332 FILE *file;
3334 #ifdef O_IGNORE_CTTY
3335 if (!ctty)
3336 /* Open the terminal device. Don't recognize it as our
3337 controlling terminal, and don't make it the controlling tty
3338 if we don't have one at the moment. */
3339 fd = emacs_open (name, O_RDWR | O_IGNORE_CTTY | O_NOCTTY, 0);
3340 else
3341 #else
3342 /* Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
3343 defined on Hurd. On other systems, we need to explicitly
3344 dissociate ourselves from the controlling tty when we want to
3345 open a frame on the same terminal. */
3346 fd = emacs_open (name, O_RDWR | O_NOCTTY, 0);
3347 #endif /* O_IGNORE_CTTY */
3349 if (fd < 0)
3350 maybe_fatal (must_succeed, buffer, terminal,
3351 "Could not open file: %s",
3352 "Could not open file: %s",
3353 name);
3354 if (!isatty (fd))
3356 close (fd);
3357 maybe_fatal (must_succeed, buffer, terminal,
3358 "Not a tty device: %s",
3359 "Not a tty device: %s",
3360 name);
3363 #ifndef O_IGNORE_CTTY
3364 if (!ctty)
3365 dissociate_if_controlling_tty (fd);
3366 #endif
3368 file = fdopen (fd, "w+");
3369 tty->name = xstrdup (name);
3370 terminal->name = xstrdup (name);
3371 tty->input = file;
3372 tty->output = file;
3375 tty->type = xstrdup (terminal_type);
3377 #ifdef subprocesses
3378 add_keyboard_wait_descriptor (fileno (tty->input));
3379 #endif
3381 #endif /* !DOS_NT */
3383 encode_terminal_src_size = 0;
3384 encode_terminal_dst_size = 0;
3386 #ifdef HAVE_GPM
3387 terminal->mouse_position_hook = term_mouse_position;
3388 mouse_face_window = Qnil;
3389 #endif
3391 #ifdef DOS_NT
3392 #ifdef WINDOWSNT
3393 initialize_w32_display (terminal);
3394 #else /* MSDOS */
3395 if (strcmp (terminal_type, "internal") == 0)
3396 terminal->type = output_msdos_raw;
3397 initialize_msdos_display (terminal);
3398 #endif /* MSDOS */
3399 tty->output = stdout;
3400 tty->input = stdin;
3401 /* The following two are inaccessible from w32console.c. */
3402 terminal->delete_frame_hook = &delete_tty_output;
3403 terminal->delete_terminal_hook = &delete_tty;
3405 tty->name = xstrdup (name);
3406 terminal->name = xstrdup (name);
3407 tty->type = xstrdup (terminal_type);
3409 #ifdef subprocesses
3410 add_keyboard_wait_descriptor (0);
3411 #endif
3413 Wcm_clear (tty);
3415 #ifdef WINDOWSNT
3417 struct frame *f = XFRAME (selected_frame);
3419 FrameRows (tty) = FRAME_LINES (f);
3420 FrameCols (tty) = FRAME_COLS (f);
3421 tty->specified_window = FRAME_LINES (f);
3423 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
3424 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
3426 #else /* MSDOS */
3428 int height, width;
3429 get_tty_size (fileno (tty->input), &width, &height);
3430 FrameCols (tty) = width;
3431 FrameRows (tty) = height;
3433 #endif /* MSDOS */
3434 tty->delete_in_insert_mode = 1;
3436 UseTabs (tty) = 0;
3437 terminal->scroll_region_ok = 0;
3439 /* Seems to insert lines when it's not supposed to, messing up the
3440 display. In doing a trace, it didn't seem to be called much, so I
3441 don't think we're losing anything by turning it off. */
3442 terminal->line_ins_del_ok = 0;
3443 #ifdef WINDOWSNT
3444 terminal->char_ins_del_ok = 1;
3445 baud_rate = 19200;
3446 #else /* MSDOS */
3447 terminal->char_ins_del_ok = 0;
3448 init_baud_rate (fileno (tty->input));
3449 #endif /* MSDOS */
3451 tty->TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */
3453 #else /* not DOS_NT */
3455 Wcm_clear (tty);
3457 buffer = (char *) xmalloc (buffer_size);
3459 /* On some systems, tgetent tries to access the controlling
3460 terminal. */
3461 sigblock (sigmask (SIGTTOU));
3462 status = tgetent (buffer, terminal_type);
3463 sigunblock (sigmask (SIGTTOU));
3465 if (status < 0)
3467 #ifdef TERMINFO
3468 maybe_fatal (must_succeed, buffer, terminal,
3469 "Cannot open terminfo database file",
3470 "Cannot open terminfo database file");
3471 #else
3472 maybe_fatal (must_succeed, buffer, terminal,
3473 "Cannot open termcap database file",
3474 "Cannot open termcap database file");
3475 #endif
3477 if (status == 0)
3479 #ifdef TERMINFO
3480 maybe_fatal (must_succeed, buffer, terminal,
3481 "Terminal type %s is not defined",
3482 "Terminal type %s is not defined.\n\
3483 If that is not the actual type of terminal you have,\n\
3484 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3485 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3486 to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
3487 terminal_type);
3488 #else
3489 maybe_fatal (must_succeed, buffer, terminal,
3490 "Terminal type %s is not defined",
3491 "Terminal type %s is not defined.\n\
3492 If that is not the actual type of terminal you have,\n\
3493 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3494 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3495 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
3496 terminal_type);
3497 #endif
3500 #ifndef TERMINFO
3501 if (strlen (buffer) >= buffer_size)
3502 abort ();
3503 buffer_size = strlen (buffer);
3504 #endif
3505 area = (char *) xmalloc (buffer_size);
3507 tty->TS_ins_line = tgetstr ("al", address);
3508 tty->TS_ins_multi_lines = tgetstr ("AL", address);
3509 tty->TS_bell = tgetstr ("bl", address);
3510 BackTab (tty) = tgetstr ("bt", address);
3511 tty->TS_clr_to_bottom = tgetstr ("cd", address);
3512 tty->TS_clr_line = tgetstr ("ce", address);
3513 tty->TS_clr_frame = tgetstr ("cl", address);
3514 ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
3515 AbsPosition (tty) = tgetstr ("cm", address);
3516 CR (tty) = tgetstr ("cr", address);
3517 tty->TS_set_scroll_region = tgetstr ("cs", address);
3518 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
3519 RowPosition (tty) = tgetstr ("cv", address);
3520 tty->TS_del_char = tgetstr ("dc", address);
3521 tty->TS_del_multi_chars = tgetstr ("DC", address);
3522 tty->TS_del_line = tgetstr ("dl", address);
3523 tty->TS_del_multi_lines = tgetstr ("DL", address);
3524 tty->TS_delete_mode = tgetstr ("dm", address);
3525 tty->TS_end_delete_mode = tgetstr ("ed", address);
3526 tty->TS_end_insert_mode = tgetstr ("ei", address);
3527 Home (tty) = tgetstr ("ho", address);
3528 tty->TS_ins_char = tgetstr ("ic", address);
3529 tty->TS_ins_multi_chars = tgetstr ("IC", address);
3530 tty->TS_insert_mode = tgetstr ("im", address);
3531 tty->TS_pad_inserted_char = tgetstr ("ip", address);
3532 tty->TS_end_keypad_mode = tgetstr ("ke", address);
3533 tty->TS_keypad_mode = tgetstr ("ks", address);
3534 LastLine (tty) = tgetstr ("ll", address);
3535 Right (tty) = tgetstr ("nd", address);
3536 Down (tty) = tgetstr ("do", address);
3537 if (!Down (tty))
3538 Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */
3539 if (tgetflag ("bs"))
3540 Left (tty) = "\b"; /* can't possibly be longer! */
3541 else /* (Actually, "bs" is obsolete...) */
3542 Left (tty) = tgetstr ("le", address);
3543 if (!Left (tty))
3544 Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */
3545 tty->TS_pad_char = tgetstr ("pc", address);
3546 tty->TS_repeat = tgetstr ("rp", address);
3547 tty->TS_end_standout_mode = tgetstr ("se", address);
3548 tty->TS_fwd_scroll = tgetstr ("sf", address);
3549 tty->TS_standout_mode = tgetstr ("so", address);
3550 tty->TS_rev_scroll = tgetstr ("sr", address);
3551 tty->Wcm->cm_tab = tgetstr ("ta", address);
3552 tty->TS_end_termcap_modes = tgetstr ("te", address);
3553 tty->TS_termcap_modes = tgetstr ("ti", address);
3554 Up (tty) = tgetstr ("up", address);
3555 tty->TS_visible_bell = tgetstr ("vb", address);
3556 tty->TS_cursor_normal = tgetstr ("ve", address);
3557 tty->TS_cursor_visible = tgetstr ("vs", address);
3558 tty->TS_cursor_invisible = tgetstr ("vi", address);
3559 tty->TS_set_window = tgetstr ("wi", address);
3561 tty->TS_enter_underline_mode = tgetstr ("us", address);
3562 tty->TS_exit_underline_mode = tgetstr ("ue", address);
3563 tty->TS_enter_bold_mode = tgetstr ("md", address);
3564 tty->TS_enter_dim_mode = tgetstr ("mh", address);
3565 tty->TS_enter_blink_mode = tgetstr ("mb", address);
3566 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
3567 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
3568 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
3569 tty->TS_exit_attribute_mode = tgetstr ("me", address);
3571 MultiUp (tty) = tgetstr ("UP", address);
3572 MultiDown (tty) = tgetstr ("DO", address);
3573 MultiLeft (tty) = tgetstr ("LE", address);
3574 MultiRight (tty) = tgetstr ("RI", address);
3576 /* SVr4/ANSI color suppert. If "op" isn't available, don't support
3577 color because we can't switch back to the default foreground and
3578 background. */
3579 tty->TS_orig_pair = tgetstr ("op", address);
3580 if (tty->TS_orig_pair)
3582 tty->TS_set_foreground = tgetstr ("AF", address);
3583 tty->TS_set_background = tgetstr ("AB", address);
3584 if (!tty->TS_set_foreground)
3586 /* SVr4. */
3587 tty->TS_set_foreground = tgetstr ("Sf", address);
3588 tty->TS_set_background = tgetstr ("Sb", address);
3591 tty->TN_max_colors = tgetnum ("Co");
3592 tty->TN_max_pairs = tgetnum ("pa");
3594 tty->TN_no_color_video = tgetnum ("NC");
3595 if (tty->TN_no_color_video == -1)
3596 tty->TN_no_color_video = 0;
3599 tty_default_color_capabilities (tty, 1);
3601 MagicWrap (tty) = tgetflag ("xn");
3602 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
3603 the former flag imply the latter. */
3604 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
3605 terminal->memory_below_frame = tgetflag ("db");
3606 tty->TF_hazeltine = tgetflag ("hz");
3607 terminal->must_write_spaces = tgetflag ("in");
3608 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
3609 tty->TF_insmode_motion = tgetflag ("mi");
3610 tty->TF_standout_motion = tgetflag ("ms");
3611 tty->TF_underscore = tgetflag ("ul");
3612 tty->TF_teleray = tgetflag ("xt");
3614 #endif /* !DOS_NT */
3615 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3616 init_kboard (terminal->kboard);
3617 terminal->kboard->Vwindow_system = Qnil;
3618 terminal->kboard->next_kboard = all_kboards;
3619 all_kboards = terminal->kboard;
3620 terminal->kboard->reference_count++;
3621 /* Don't let the initial kboard remain current longer than necessary.
3622 That would cause problems if a file loaded on startup tries to
3623 prompt in the mini-buffer. */
3624 if (current_kboard == initial_kboard)
3625 current_kboard = terminal->kboard;
3626 #ifndef DOS_NT
3627 term_get_fkeys (address, terminal->kboard);
3629 /* Get frame size from system, or else from termcap. */
3631 int height, width;
3632 get_tty_size (fileno (tty->input), &width, &height);
3633 FrameCols (tty) = width;
3634 FrameRows (tty) = height;
3637 if (FrameCols (tty) <= 0)
3638 FrameCols (tty) = tgetnum ("co");
3639 if (FrameRows (tty) <= 0)
3640 FrameRows (tty) = tgetnum ("li");
3642 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
3643 maybe_fatal (must_succeed, NULL, terminal,
3644 "Screen size %dx%d is too small"
3645 "Screen size %dx%d is too small",
3646 FrameCols (tty), FrameRows (tty));
3648 #if 0 /* This is not used anywhere. */
3649 tty->terminal->min_padding_speed = tgetnum ("pb");
3650 #endif
3652 TabWidth (tty) = tgetnum ("tw");
3654 if (!tty->TS_bell)
3655 tty->TS_bell = "\07";
3657 if (!tty->TS_fwd_scroll)
3658 tty->TS_fwd_scroll = Down (tty);
3660 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
3662 if (TabWidth (tty) < 0)
3663 TabWidth (tty) = 8;
3665 /* Turned off since /etc/termcap seems to have :ta= for most terminals
3666 and newer termcap doc does not seem to say there is a default.
3667 if (!tty->Wcm->cm_tab)
3668 tty->Wcm->cm_tab = "\t";
3671 /* We don't support standout modes that use `magic cookies', so
3672 turn off any that do. */
3673 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
3675 tty->TS_standout_mode = 0;
3676 tty->TS_end_standout_mode = 0;
3678 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
3680 tty->TS_enter_underline_mode = 0;
3681 tty->TS_exit_underline_mode = 0;
3684 /* If there's no standout mode, try to use underlining instead. */
3685 if (tty->TS_standout_mode == 0)
3687 tty->TS_standout_mode = tty->TS_enter_underline_mode;
3688 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
3691 /* If no `se' string, try using a `me' string instead.
3692 If that fails, we can't use standout mode at all. */
3693 if (tty->TS_end_standout_mode == 0)
3695 char *s = tgetstr ("me", address);
3696 if (s != 0)
3697 tty->TS_end_standout_mode = s;
3698 else
3699 tty->TS_standout_mode = 0;
3702 if (tty->TF_teleray)
3704 tty->Wcm->cm_tab = 0;
3705 /* We can't support standout mode, because it uses magic cookies. */
3706 tty->TS_standout_mode = 0;
3707 /* But that means we cannot rely on ^M to go to column zero! */
3708 CR (tty) = 0;
3709 /* LF can't be trusted either -- can alter hpos */
3710 /* if move at column 0 thru a line with TS_standout_mode */
3711 Down (tty) = 0;
3714 /* Special handling for certain terminal types known to need it */
3716 if (!strcmp (terminal_type, "supdup"))
3718 terminal->memory_below_frame = 1;
3719 tty->Wcm->cm_losewrap = 1;
3721 if (!strncmp (terminal_type, "c10", 3)
3722 || !strcmp (terminal_type, "perq"))
3724 /* Supply a makeshift :wi string.
3725 This string is not valid in general since it works only
3726 for windows starting at the upper left corner;
3727 but that is all Emacs uses.
3729 This string works only if the frame is using
3730 the top of the video memory, because addressing is memory-relative.
3731 So first check the :ti string to see if that is true.
3733 It would be simpler if the :wi string could go in the termcap
3734 entry, but it can't because it is not fully valid.
3735 If it were in the termcap entry, it would confuse other programs. */
3736 if (!tty->TS_set_window)
3738 p = tty->TS_termcap_modes;
3739 while (*p && strcmp (p, "\033v "))
3740 p++;
3741 if (*p)
3742 tty->TS_set_window = "\033v%C %C %C %C ";
3744 /* Termcap entry often fails to have :in: flag */
3745 terminal->must_write_spaces = 1;
3746 /* :ti string typically fails to have \E^G! in it */
3747 /* This limits scope of insert-char to one line. */
3748 strcpy (area, tty->TS_termcap_modes);
3749 strcat (area, "\033\007!");
3750 tty->TS_termcap_modes = area;
3751 area += strlen (area) + 1;
3752 p = AbsPosition (tty);
3753 /* Change all %+ parameters to %C, to handle
3754 values above 96 correctly for the C100. */
3755 while (*p)
3757 if (p[0] == '%' && p[1] == '+')
3758 p[1] = 'C';
3759 p++;
3763 tty->specified_window = FrameRows (tty);
3765 if (Wcm_init (tty) == -1) /* can't do cursor motion */
3767 maybe_fatal (must_succeed, NULL, terminal,
3768 "Terminal type \"%s\" is not powerful enough to run Emacs",
3769 # ifdef TERMINFO
3770 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
3771 It lacks the ability to position the cursor.\n\
3772 If that is not the actual type of terminal you have,\n\
3773 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3774 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3775 to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
3776 # else /* TERMCAP */
3777 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
3778 It lacks the ability to position the cursor.\n\
3779 If that is not the actual type of terminal you have,\n\
3780 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3781 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3782 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
3783 # endif /* TERMINFO */
3784 terminal_type);
3787 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
3788 maybe_fatal (must_succeed, NULL, terminal,
3789 "Could not determine the frame size",
3790 "Could not determine the frame size");
3792 tty->delete_in_insert_mode
3793 = tty->TS_delete_mode && tty->TS_insert_mode
3794 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
3796 tty->se_is_so = (tty->TS_standout_mode
3797 && tty->TS_end_standout_mode
3798 && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode));
3800 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
3802 terminal->scroll_region_ok
3803 = (tty->Wcm->cm_abs
3804 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
3806 terminal->line_ins_del_ok
3807 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
3808 && (tty->TS_del_line || tty->TS_del_multi_lines))
3809 || (terminal->scroll_region_ok
3810 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
3812 terminal->char_ins_del_ok
3813 = ((tty->TS_ins_char || tty->TS_insert_mode
3814 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
3815 && (tty->TS_del_char || tty->TS_del_multi_chars));
3817 terminal->fast_clear_end_of_line = tty->TS_clr_line != 0;
3819 init_baud_rate (fileno (tty->input));
3821 /* Don't do this. I think termcap may still need the buffer. */
3822 /* xfree (buffer); */
3824 #endif /* not DOS_NT */
3826 /* Init system terminal modes (RAW or CBREAK, etc.). */
3827 init_sys_modes (tty);
3829 return terminal;
3832 /* Auxiliary error-handling function for init_tty.
3833 Free BUFFER and delete TERMINAL, then call error or fatal
3834 with str1 or str2, respectively, according to MUST_SUCCEED. */
3836 static void
3837 maybe_fatal (must_succeed, buffer, terminal, str1, str2, arg1, arg2)
3838 int must_succeed;
3839 char *buffer;
3840 struct terminal *terminal;
3841 char *str1, *str2, *arg1, *arg2;
3843 xfree (buffer);
3845 if (terminal)
3846 delete_tty (terminal);
3848 if (must_succeed)
3849 fatal (str2, arg1, arg2);
3850 else
3851 error (str1, arg1, arg2);
3853 abort ();
3856 void
3857 fatal (const char *str, ...)
3859 va_list ap;
3860 va_start (ap, str);
3861 fprintf (stderr, "emacs: ");
3862 vfprintf (stderr, str, ap);
3863 va_end (ap);
3864 fflush (stderr);
3865 exit (1);
3870 /* Delete the given tty terminal, closing all frames on it. */
3872 static void
3873 delete_tty (struct terminal *terminal)
3875 struct tty_display_info *tty;
3876 Lisp_Object tail, frame;
3877 int last_terminal;
3879 /* Protect against recursive calls. Fdelete_frame in
3880 delete_terminal calls us back when it deletes our last frame. */
3881 if (!terminal->name)
3882 return;
3884 if (terminal->type != output_termcap)
3885 abort ();
3887 tty = terminal->display_info.tty;
3889 last_terminal = 1;
3890 FOR_EACH_FRAME (tail, frame)
3892 struct frame *f = XFRAME (frame);
3893 if (FRAME_LIVE_P (f) && (!FRAME_TERMCAP_P (f) || FRAME_TTY (f) != tty))
3895 last_terminal = 0;
3896 break;
3899 if (last_terminal)
3900 error ("Attempt to delete the sole terminal device with live frames");
3902 if (tty == tty_list)
3903 tty_list = tty->next;
3904 else
3906 struct tty_display_info *p;
3907 for (p = tty_list; p && p->next != tty; p = p->next)
3910 if (! p)
3911 /* This should not happen. */
3912 abort ();
3914 p->next = tty->next;
3915 tty->next = 0;
3918 /* reset_sys_modes needs a valid device, so this call needs to be
3919 before delete_terminal. */
3920 reset_sys_modes (tty);
3922 delete_terminal (terminal);
3924 xfree (tty->name);
3925 xfree (tty->type);
3927 if (tty->input)
3929 #ifdef subprocesses
3930 delete_keyboard_wait_descriptor (fileno (tty->input));
3931 #endif
3932 if (tty->input != stdin)
3933 fclose (tty->input);
3935 if (tty->output && tty->output != stdout && tty->output != tty->input)
3936 fclose (tty->output);
3937 if (tty->termscript)
3938 fclose (tty->termscript);
3940 xfree (tty->old_tty);
3941 xfree (tty->Wcm);
3943 bzero (tty, sizeof (struct tty_display_info));
3944 xfree (tty);
3949 /* Mark the pointers in the tty_display_info objects.
3950 Called by the Fgarbage_collector. */
3952 void
3953 mark_ttys (void)
3955 struct tty_display_info *tty;
3957 for (tty = tty_list; tty; tty = tty->next)
3958 mark_object (tty->top_frame);
3963 void
3964 syms_of_term ()
3966 DEFVAR_BOOL ("system-uses-terminfo", &system_uses_terminfo,
3967 doc: /* Non-nil means the system uses terminfo rather than termcap.
3968 This variable can be used by terminal emulator packages. */);
3969 #ifdef TERMINFO
3970 system_uses_terminfo = 1;
3971 #else
3972 system_uses_terminfo = 0;
3973 #endif
3975 DEFVAR_LISP ("suspend-tty-functions", &Vsuspend_tty_functions,
3976 doc: /* Functions to be run after suspending a tty.
3977 The functions are run with one argument, the terminal id to be suspended.
3978 See `suspend-tty'. */);
3979 Vsuspend_tty_functions = Qnil;
3982 DEFVAR_LISP ("resume-tty-functions", &Vresume_tty_functions,
3983 doc: /* Functions to be run after resuming a tty.
3984 The functions are run with one argument, the terminal id that was revived.
3985 See `resume-tty'. */);
3986 Vresume_tty_functions = Qnil;
3988 DEFVAR_BOOL ("visible-cursor", &visible_cursor,
3989 doc: /* Non-nil means to make the cursor very visible.
3990 This only has an effect when running in a text terminal.
3991 What means \"very visible\" is up to your terminal. It may make the cursor
3992 bigger, or it may make it blink, or it may do nothing at all. */);
3993 visible_cursor = 1;
3995 defsubr (&Stty_display_color_p);
3996 defsubr (&Stty_display_color_cells);
3997 defsubr (&Stty_no_underline);
3998 defsubr (&Stty_type);
3999 defsubr (&Scontrolling_tty_p);
4000 defsubr (&Ssuspend_tty);
4001 defsubr (&Sresume_tty);
4002 #ifdef HAVE_GPM
4003 defsubr (&Sgpm_mouse_start);
4004 defsubr (&Sgpm_mouse_stop);
4006 staticpro (&mouse_face_window);
4007 #endif /* HAVE_GPM */
4009 #ifndef DOS_NT
4010 default_orig_pair = NULL;
4011 default_set_foreground = NULL;
4012 default_set_background = NULL;
4013 #endif /* !DOS_NT */
4018 /* arch-tag: 498e7449-6f2e-45e2-91dd-b7d4ca488193
4019 (do not change this comment) */