(bubbles-version): Bump value to "0.5".
[emacs.git] / src / term.c
blob144b14a1e3fbe323a102acd1ff9d1cbdedf65a72
1 /* Terminal control module for terminals described by TERMCAP
2 Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1998, 2000, 2001,
3 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
22 /* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>. */
24 #include <config.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <sys/file.h>
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
35 #if HAVE_TERMIOS_H
36 #include <termios.h> /* For TIOCNOTTY. */
37 #endif
39 #include <signal.h>
41 #include "lisp.h"
42 #include "termchar.h"
43 #include "termopts.h"
44 #include "charset.h"
45 #include "coding.h"
46 #include "keyboard.h"
47 #include "frame.h"
48 #include "disptab.h"
49 #include "termhooks.h"
50 #include "dispextern.h"
51 #include "window.h"
52 #include "keymap.h"
53 #include "blockinput.h"
54 #include "syssignal.h"
55 #include "systty.h"
56 #include "intervals.h"
58 /* For now, don't try to include termcap.h. On some systems,
59 configure finds a non-standard termcap.h that the main build
60 won't find. */
62 #if defined HAVE_TERMCAP_H && 0
63 #include <termcap.h>
64 #else
65 extern void tputs P_ ((const char *, int, int (*)(int)));
66 extern int tgetent P_ ((char *, const char *));
67 extern int tgetflag P_ ((char *id));
68 extern int tgetnum P_ ((char *id));
69 #endif
71 #include "cm.h"
72 #ifdef HAVE_X_WINDOWS
73 #include "xterm.h"
74 #endif
75 #ifdef MAC_OS
76 #include "macterm.h"
77 #endif
79 #ifndef O_RDWR
80 #define O_RDWR 2
81 #endif
83 #ifndef O_NOCTTY
84 #define O_NOCTTY 0
85 #endif
87 static void tty_set_scroll_region P_ ((struct frame *f, int start, int stop));
88 static void turn_on_face P_ ((struct frame *, int face_id));
89 static void turn_off_face P_ ((struct frame *, int face_id));
90 static void tty_show_cursor P_ ((struct tty_display_info *));
91 static void tty_hide_cursor P_ ((struct tty_display_info *));
92 static void tty_background_highlight P_ ((struct tty_display_info *tty));
93 static void clear_tty_hooks P_ ((struct terminal *terminal));
94 static void set_tty_hooks P_ ((struct terminal *terminal));
95 static void dissociate_if_controlling_tty P_ ((int fd));
96 static void delete_tty P_ ((struct terminal *));
98 #define OUTPUT(tty, a) \
99 emacs_tputs ((tty), a, \
100 (int) (FRAME_LINES (XFRAME (selected_frame)) \
101 - curY (tty)), \
102 cmputc)
104 #define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
105 #define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
107 #define OUTPUT_IF(tty, a) \
108 do { \
109 if (a) \
110 emacs_tputs ((tty), a, \
111 (int) (FRAME_LINES (XFRAME (selected_frame)) \
112 - curY (tty) ), \
113 cmputc); \
114 } while (0)
116 #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
118 /* If true, use "vs", otherwise use "ve" to make the cursor visible. */
120 static int visible_cursor;
122 /* Display space properties */
124 extern Lisp_Object Qspace, QCalign_to, QCwidth;
126 /* Functions to call after suspending a tty. */
127 Lisp_Object Vsuspend_tty_functions;
129 /* Functions to call after resuming a tty. */
130 Lisp_Object Vresume_tty_functions;
132 /* Chain of all tty device parameters. */
133 struct tty_display_info *tty_list;
135 /* Nonzero means no need to redraw the entire frame on resuming a
136 suspended Emacs. This is useful on terminals with multiple
137 pages, where one page is used for Emacs and another for all
138 else. */
139 int no_redraw_on_reenter;
141 /* Meaning of bits in no_color_video. Each bit set means that the
142 corresponding attribute cannot be combined with colors. */
144 enum no_color_bit
146 NC_STANDOUT = 1 << 0,
147 NC_UNDERLINE = 1 << 1,
148 NC_REVERSE = 1 << 2,
149 NC_BLINK = 1 << 3,
150 NC_DIM = 1 << 4,
151 NC_BOLD = 1 << 5,
152 NC_INVIS = 1 << 6,
153 NC_PROTECT = 1 << 7,
154 NC_ALT_CHARSET = 1 << 8
157 /* internal state */
159 /* The largest frame width in any call to calculate_costs. */
161 int max_frame_cols;
163 /* The largest frame height in any call to calculate_costs. */
165 int max_frame_lines;
167 /* Non-zero if we have dropped our controlling tty and therefore
168 should not open a frame on stdout. */
169 static int no_controlling_tty;
171 /* Provided for lisp packages. */
173 static int system_uses_terminfo;
175 char *tparam ();
177 extern char *tgetstr ();
179 static void term_clear_mouse_face ();
180 static void term_mouse_highlight (struct frame *f, int x, int y);
183 #ifdef WINDOWSNT
184 /* We aren't X windows, but we aren't termcap either. This makes me
185 uncertain as to what value to use for frame.output_method. For
186 this file, we'll define FRAME_TERMCAP_P to be zero so that our
187 output hooks get called instead of the termcap functions. Probably
188 the best long-term solution is to define an output_windows_nt... */
190 #undef FRAME_TERMCAP_P
191 #define FRAME_TERMCAP_P(_f_) 0
192 #endif /* WINDOWSNT */
194 #ifdef HAVE_GPM
195 #include <sys/fcntl.h>
196 #include "buffer.h"
198 /* Nonzero means mouse is enabled on Linux console. */
199 int term_gpm = 0;
201 /* The id of the terminal device for which we have gpm support. */
202 int gpm_tty;
204 /* These variables describe the range of text currently shown in its
205 mouse-face, together with the window they apply to. As long as
206 the mouse stays within this range, we need not redraw anything on
207 its account. Rows and columns are glyph matrix positions in
208 MOUSE_FACE_WINDOW. */
209 static int mouse_face_beg_row, mouse_face_beg_col;
210 static int mouse_face_end_row, mouse_face_end_col;
211 static int mouse_face_past_end;
212 static Lisp_Object Qmouse_face_window;
213 static int mouse_face_face_id;
215 static int pos_x, pos_y;
216 static int last_mouse_x, last_mouse_y;
217 #endif /* HAVE_GPM */
219 /* Ring the bell on a tty. */
221 static void
222 tty_ring_bell (struct frame *f)
224 struct tty_display_info *tty = FRAME_TTY (f);
226 if (tty->output)
228 OUTPUT (tty, (tty->TS_visible_bell && visible_bell
229 ? tty->TS_visible_bell
230 : tty->TS_bell));
231 fflush (tty->output);
235 /* Set up termcap modes for Emacs. */
237 void
238 tty_set_terminal_modes (struct terminal *terminal)
240 struct tty_display_info *tty = terminal->display_info.tty;
242 if (tty->output)
244 if (tty->TS_termcap_modes)
245 OUTPUT (tty, tty->TS_termcap_modes);
246 else
248 /* Output enough newlines to scroll all the old screen contents
249 off the screen, so it won't be overwritten and lost. */
250 int i;
251 current_tty = tty;
252 for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
253 cmputc ('\n');
256 OUTPUT_IF (tty, tty->TS_termcap_modes);
257 OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
258 OUTPUT_IF (tty, tty->TS_keypad_mode);
259 losecursor (tty);
260 fflush (tty->output);
264 /* Reset termcap modes before exiting Emacs. */
266 void
267 tty_reset_terminal_modes (struct terminal *terminal)
269 struct tty_display_info *tty = terminal->display_info.tty;
271 if (tty->output)
273 tty_turn_off_highlight (tty);
274 tty_turn_off_insert (tty);
275 OUTPUT_IF (tty, tty->TS_end_keypad_mode);
276 OUTPUT_IF (tty, tty->TS_cursor_normal);
277 OUTPUT_IF (tty, tty->TS_end_termcap_modes);
278 OUTPUT_IF (tty, tty->TS_orig_pair);
279 /* Output raw CR so kernel can track the cursor hpos. */
280 current_tty = tty;
281 cmputc ('\r');
282 fflush (tty->output);
286 /* Flag the end of a display update on a termcap terminal. */
288 static void
289 tty_update_end (struct frame *f)
291 struct tty_display_info *tty = FRAME_TTY (f);
293 if (!XWINDOW (selected_window)->cursor_off_p)
294 tty_show_cursor (tty);
295 tty_turn_off_insert (tty);
296 tty_background_highlight (tty);
299 /* The implementation of set_terminal_window for termcap frames. */
301 static void
302 tty_set_terminal_window (struct frame *f, int size)
304 struct tty_display_info *tty = FRAME_TTY (f);
306 tty->specified_window = size ? size : FRAME_LINES (f);
307 if (FRAME_SCROLL_REGION_OK (f))
308 tty_set_scroll_region (f, 0, tty->specified_window);
311 static void
312 tty_set_scroll_region (struct frame *f, int start, int stop)
314 char *buf;
315 struct tty_display_info *tty = FRAME_TTY (f);
317 if (tty->TS_set_scroll_region)
318 buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1);
319 else if (tty->TS_set_scroll_region_1)
320 buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
321 FRAME_LINES (f), start,
322 FRAME_LINES (f) - stop,
323 FRAME_LINES (f));
324 else
325 buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
327 OUTPUT (tty, buf);
328 xfree (buf);
329 losecursor (tty);
333 static void
334 tty_turn_on_insert (struct tty_display_info *tty)
336 if (!tty->insert_mode)
337 OUTPUT (tty, tty->TS_insert_mode);
338 tty->insert_mode = 1;
341 void
342 tty_turn_off_insert (struct tty_display_info *tty)
344 if (tty->insert_mode)
345 OUTPUT (tty, tty->TS_end_insert_mode);
346 tty->insert_mode = 0;
349 /* Handle highlighting. */
351 void
352 tty_turn_off_highlight (struct tty_display_info *tty)
354 if (tty->standout_mode)
355 OUTPUT_IF (tty, tty->TS_end_standout_mode);
356 tty->standout_mode = 0;
359 static void
360 tty_turn_on_highlight (struct tty_display_info *tty)
362 if (!tty->standout_mode)
363 OUTPUT_IF (tty, tty->TS_standout_mode);
364 tty->standout_mode = 1;
367 static void
368 tty_toggle_highlight (struct tty_display_info *tty)
370 if (tty->standout_mode)
371 tty_turn_off_highlight (tty);
372 else
373 tty_turn_on_highlight (tty);
377 /* Make cursor invisible. */
379 static void
380 tty_hide_cursor (struct tty_display_info *tty)
382 if (tty->cursor_hidden == 0)
384 tty->cursor_hidden = 1;
385 OUTPUT_IF (tty, tty->TS_cursor_invisible);
390 /* Ensure that cursor is visible. */
392 static void
393 tty_show_cursor (struct tty_display_info *tty)
395 if (tty->cursor_hidden)
397 tty->cursor_hidden = 0;
398 OUTPUT_IF (tty, tty->TS_cursor_normal);
399 if (visible_cursor)
400 OUTPUT_IF (tty, tty->TS_cursor_visible);
405 /* Set standout mode to the state it should be in for
406 empty space inside windows. What this is,
407 depends on the user option inverse-video. */
409 static void
410 tty_background_highlight (struct tty_display_info *tty)
412 if (inverse_video)
413 tty_turn_on_highlight (tty);
414 else
415 tty_turn_off_highlight (tty);
418 /* Set standout mode to the mode specified for the text to be output. */
420 static void
421 tty_highlight_if_desired (struct tty_display_info *tty)
423 if (inverse_video)
424 tty_turn_on_highlight (tty);
425 else
426 tty_turn_off_highlight (tty);
430 /* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are
431 frame-relative coordinates. */
433 static void
434 tty_cursor_to (struct frame *f, int vpos, int hpos)
436 struct tty_display_info *tty = FRAME_TTY (f);
438 /* Detect the case where we are called from reset_sys_modes
439 and the costs have never been calculated. Do nothing. */
440 if (! tty->costs_set)
441 return;
443 if (curY (tty) == vpos
444 && curX (tty) == hpos)
445 return;
446 if (!tty->TF_standout_motion)
447 tty_background_highlight (tty);
448 if (!tty->TF_insmode_motion)
449 tty_turn_off_insert (tty);
450 cmgoto (tty, vpos, hpos);
453 /* Similar but don't take any account of the wasted characters. */
455 static void
456 tty_raw_cursor_to (struct frame *f, int row, int col)
458 struct tty_display_info *tty = FRAME_TTY (f);
460 if (curY (tty) == row
461 && curX (tty) == col)
462 return;
463 if (!tty->TF_standout_motion)
464 tty_background_highlight (tty);
465 if (!tty->TF_insmode_motion)
466 tty_turn_off_insert (tty);
467 cmgoto (tty, row, col);
470 /* Erase operations */
472 /* Clear from cursor to end of frame on a termcap device. */
474 static void
475 tty_clear_to_end (struct frame *f)
477 register int i;
478 struct tty_display_info *tty = FRAME_TTY (f);
480 if (tty->TS_clr_to_bottom)
482 tty_background_highlight (tty);
483 OUTPUT (tty, tty->TS_clr_to_bottom);
485 else
487 for (i = curY (tty); i < FRAME_LINES (f); i++)
489 cursor_to (f, i, 0);
490 clear_end_of_line (f, FRAME_COLS (f));
495 /* Clear an entire termcap frame. */
497 static void
498 tty_clear_frame (struct frame *f)
500 struct tty_display_info *tty = FRAME_TTY (f);
502 if (tty->TS_clr_frame)
504 tty_background_highlight (tty);
505 OUTPUT (tty, tty->TS_clr_frame);
506 cmat (tty, 0, 0);
508 else
510 cursor_to (f, 0, 0);
511 clear_to_end (f);
515 /* An implementation of clear_end_of_line for termcap frames.
517 Note that the cursor may be moved, on terminals lacking a `ce' string. */
519 static void
520 tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
522 register int i;
523 struct tty_display_info *tty = FRAME_TTY (f);
525 /* Detect the case where we are called from reset_sys_modes
526 and the costs have never been calculated. Do nothing. */
527 if (! tty->costs_set)
528 return;
530 if (curX (tty) >= first_unused_hpos)
531 return;
532 tty_background_highlight (tty);
533 if (tty->TS_clr_line)
535 OUTPUT1 (tty, tty->TS_clr_line);
537 else
538 { /* have to do it the hard way */
539 tty_turn_off_insert (tty);
541 /* Do not write in last row last col with Auto-wrap on. */
542 if (AutoWrap (tty)
543 && curY (tty) == FrameRows (tty) - 1
544 && first_unused_hpos == FrameCols (tty))
545 first_unused_hpos--;
547 for (i = curX (tty); i < first_unused_hpos; i++)
549 if (tty->termscript)
550 fputc (' ', tty->termscript);
551 fputc (' ', tty->output);
553 cmplus (tty, first_unused_hpos - curX (tty));
557 /* Buffer to store the source and result of code conversion for terminal. */
558 static unsigned char *encode_terminal_buf;
559 /* Allocated size of the above buffer. */
560 static int encode_terminal_bufsize;
562 /* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
563 Set CODING->produced to the byte-length of the resulting byte
564 sequence, and return a pointer to that byte sequence. */
566 unsigned char *
567 encode_terminal_code (src, src_len, coding)
568 struct glyph *src;
569 int src_len;
570 struct coding_system *coding;
572 struct glyph *src_end = src + src_len;
573 register GLYPH g;
574 unsigned char *buf;
575 int nchars, nbytes, required;
576 register int tlen = GLYPH_TABLE_LENGTH;
577 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
579 /* Allocate sufficient size of buffer to store all characters in
580 multibyte-form. But, it may be enlarged on demand if
581 Vglyph_table contains a string. */
582 required = MAX_MULTIBYTE_LENGTH * src_len;
583 if (encode_terminal_bufsize < required)
585 if (encode_terminal_bufsize == 0)
586 encode_terminal_buf = xmalloc (required);
587 else
588 encode_terminal_buf = xrealloc (encode_terminal_buf, required);
589 encode_terminal_bufsize = required;
592 buf = encode_terminal_buf;
593 nchars = 0;
594 while (src < src_end)
596 /* We must skip glyphs to be padded for a wide character. */
597 if (! CHAR_GLYPH_PADDING_P (*src))
599 g = GLYPH_FROM_CHAR_GLYPH (src[0]);
601 if (g < 0 || g >= tlen)
603 /* This glyph doesn't has an entry in Vglyph_table. */
604 if (CHAR_VALID_P (src->u.ch, 0))
605 buf += CHAR_STRING (src->u.ch, buf);
606 else
607 *buf++ = SPACEGLYPH;
608 nchars++;
610 else
612 /* This glyph has an entry in Vglyph_table,
613 so process any alias before testing for simpleness. */
614 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
616 if (GLYPH_SIMPLE_P (tbase, tlen, g))
618 int c = FAST_GLYPH_CHAR (g);
620 if (CHAR_VALID_P (c, 0))
621 buf += CHAR_STRING (c, buf);
622 else
623 *buf++ = SPACEGLYPH;
624 nchars++;
626 else
628 /* We have a string in Vglyph_table. */
629 Lisp_Object string;
631 string = tbase[g];
632 if (! STRING_MULTIBYTE (string))
633 string = string_to_multibyte (string);
634 nbytes = buf - encode_terminal_buf;
635 if (encode_terminal_bufsize < nbytes + SBYTES (string))
637 encode_terminal_bufsize = nbytes + SBYTES (string);
638 encode_terminal_buf = xrealloc (encode_terminal_buf,
639 encode_terminal_bufsize);
640 buf = encode_terminal_buf + nbytes;
642 bcopy (SDATA (string), buf, SBYTES (string));
643 buf += SBYTES (string);
644 nchars += SCHARS (string);
648 src++;
651 nbytes = buf - encode_terminal_buf;
652 coding->src_multibyte = 1;
653 coding->dst_multibyte = 0;
654 if (SYMBOLP (coding->pre_write_conversion)
655 && ! NILP (Ffboundp (coding->pre_write_conversion)))
657 run_pre_write_conversin_on_c_str (&encode_terminal_buf,
658 &encode_terminal_bufsize,
659 nchars, nbytes, coding);
660 nchars = coding->produced_char;
661 nbytes = coding->produced;
663 required = nbytes + encoding_buffer_size (coding, nbytes);
664 if (encode_terminal_bufsize < required)
666 encode_terminal_bufsize = required;
667 encode_terminal_buf = xrealloc (encode_terminal_buf, required);
670 encode_coding (coding, encode_terminal_buf, encode_terminal_buf + nbytes,
671 nbytes, encode_terminal_bufsize - nbytes);
672 return encode_terminal_buf + nbytes;
676 /* An implementation of write_glyphs for termcap frames. */
678 static void
679 tty_write_glyphs (struct frame *f, struct glyph *string, int len)
681 unsigned char *conversion_buffer;
682 struct coding_system *coding;
684 struct tty_display_info *tty = FRAME_TTY (f);
686 tty_turn_off_insert (tty);
687 tty_hide_cursor (tty);
689 /* Don't dare write in last column of bottom line, if Auto-Wrap,
690 since that would scroll the whole frame on some terminals. */
692 if (AutoWrap (tty)
693 && curY (tty) + 1 == FRAME_LINES (f)
694 && (curX (tty) + len) == FRAME_COLS (f))
695 len --;
696 if (len <= 0)
697 return;
699 cmplus (tty, len);
701 /* If terminal_coding does any conversion, use it, otherwise use
702 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
703 because it always return 1 if the member src_multibyte is 1. */
704 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
705 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
706 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
707 the tail. */
708 coding->mode &= ~CODING_MODE_LAST_BLOCK;
710 while (len > 0)
712 /* Identify a run of glyphs with the same face. */
713 int face_id = string->face_id;
714 int n;
716 for (n = 1; n < len; ++n)
717 if (string[n].face_id != face_id)
718 break;
720 /* Turn appearance modes of the face of the run on. */
721 tty_highlight_if_desired (tty);
722 turn_on_face (f, face_id);
724 if (n == len)
725 /* This is the last run. */
726 coding->mode |= CODING_MODE_LAST_BLOCK;
727 conversion_buffer = encode_terminal_code (string, n, coding);
728 if (coding->produced > 0)
730 BLOCK_INPUT;
731 fwrite (conversion_buffer, 1, coding->produced, tty->output);
732 if (ferror (tty->output))
733 clearerr (tty->output);
734 if (tty->termscript)
735 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
736 UNBLOCK_INPUT;
738 len -= n;
739 string += n;
741 /* Turn appearance modes off. */
742 turn_off_face (f, face_id);
743 tty_turn_off_highlight (tty);
746 cmcheckmagic (tty);
749 static void
750 tty_write_glyphs_with_face (f, string, len, face_id)
751 register struct frame *f;
752 register struct glyph *string;
753 register int len, face_id;
755 unsigned char *conversion_buffer;
756 struct coding_system *coding;
758 struct tty_display_info *tty = FRAME_TTY (f);
760 tty_turn_off_insert (tty);
761 tty_hide_cursor (tty);
763 /* Don't dare write in last column of bottom line, if Auto-Wrap,
764 since that would scroll the whole frame on some terminals. */
766 if (AutoWrap (tty)
767 && curY (tty) + 1 == FRAME_LINES (f)
768 && (curX (tty) + len) == FRAME_COLS (f))
769 len --;
770 if (len <= 0)
771 return;
773 cmplus (tty, len);
775 /* If terminal_coding does any conversion, use it, otherwise use
776 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
777 because it always return 1 if the member src_multibyte is 1. */
778 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
779 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
780 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
781 the tail. */
782 coding->mode &= ~CODING_MODE_LAST_BLOCK;
784 /* Turn appearance modes of the face. */
785 tty_highlight_if_desired (tty);
786 turn_on_face (f, face_id);
788 coding->mode |= CODING_MODE_LAST_BLOCK;
789 conversion_buffer = encode_terminal_code (string, len, coding);
790 if (coding->produced > 0)
792 BLOCK_INPUT;
793 fwrite (conversion_buffer, 1, coding->produced, tty->output);
794 if (ferror (tty->output))
795 clearerr (tty->output);
796 if (tty->termscript)
797 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
798 UNBLOCK_INPUT;
801 /* Turn appearance modes off. */
802 turn_off_face (f, face_id);
803 tty_turn_off_highlight (tty);
805 cmcheckmagic (tty);
809 /* An implementation of insert_glyphs for termcap frames. */
811 static void
812 tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
814 char *buf;
815 struct glyph *glyph = NULL;
816 unsigned char *conversion_buffer;
817 unsigned char space[1];
818 struct coding_system *coding;
820 struct tty_display_info *tty = FRAME_TTY (f);
822 if (tty->TS_ins_multi_chars)
824 buf = tparam (tty->TS_ins_multi_chars, 0, 0, len);
825 OUTPUT1 (tty, buf);
826 xfree (buf);
827 if (start)
828 write_glyphs (f, start, len);
829 return;
832 tty_turn_on_insert (tty);
833 cmplus (tty, len);
835 if (! start)
836 space[0] = SPACEGLYPH;
838 /* If terminal_coding does any conversion, use it, otherwise use
839 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
840 because it always return 1 if the member src_multibyte is 1. */
841 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
842 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
843 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
844 the tail. */
845 coding->mode &= ~CODING_MODE_LAST_BLOCK;
847 while (len-- > 0)
849 OUTPUT1_IF (tty, tty->TS_ins_char);
850 if (!start)
852 conversion_buffer = space;
853 coding->produced = 1;
855 else
857 tty_highlight_if_desired (tty);
858 turn_on_face (f, start->face_id);
859 glyph = start;
860 ++start;
861 /* We must open sufficient space for a character which
862 occupies more than one column. */
863 while (len && CHAR_GLYPH_PADDING_P (*start))
865 OUTPUT1_IF (tty, tty->TS_ins_char);
866 start++, len--;
869 if (len <= 0)
870 /* This is the last glyph. */
871 coding->mode |= CODING_MODE_LAST_BLOCK;
873 conversion_buffer = encode_terminal_code (glyph, 1, coding);
876 if (coding->produced > 0)
878 BLOCK_INPUT;
879 fwrite (conversion_buffer, 1, coding->produced, tty->output);
880 if (ferror (tty->output))
881 clearerr (tty->output);
882 if (tty->termscript)
883 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
884 UNBLOCK_INPUT;
887 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
888 if (start)
890 turn_off_face (f, glyph->face_id);
891 tty_turn_off_highlight (tty);
895 cmcheckmagic (tty);
898 /* An implementation of delete_glyphs for termcap frames. */
900 static void
901 tty_delete_glyphs (struct frame *f, int n)
903 char *buf;
904 register int i;
906 struct tty_display_info *tty = FRAME_TTY (f);
908 if (tty->delete_in_insert_mode)
910 tty_turn_on_insert (tty);
912 else
914 tty_turn_off_insert (tty);
915 OUTPUT_IF (tty, tty->TS_delete_mode);
918 if (tty->TS_del_multi_chars)
920 buf = tparam (tty->TS_del_multi_chars, 0, 0, n);
921 OUTPUT1 (tty, buf);
922 xfree (buf);
924 else
925 for (i = 0; i < n; i++)
926 OUTPUT1 (tty, tty->TS_del_char);
927 if (!tty->delete_in_insert_mode)
928 OUTPUT_IF (tty, tty->TS_end_delete_mode);
931 /* An implementation of ins_del_lines for termcap frames. */
933 static void
934 tty_ins_del_lines (struct frame *f, int vpos, int n)
936 struct tty_display_info *tty = FRAME_TTY (f);
937 char *multi = n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
938 char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
939 char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
941 register int i = n > 0 ? n : -n;
942 register char *buf;
944 /* If the lines below the insertion are being pushed
945 into the end of the window, this is the same as clearing;
946 and we know the lines are already clear, since the matching
947 deletion has already been done. So can ignore this. */
948 /* If the lines below the deletion are blank lines coming
949 out of the end of the window, don't bother,
950 as there will be a matching inslines later that will flush them. */
951 if (FRAME_SCROLL_REGION_OK (f)
952 && vpos + i >= tty->specified_window)
953 return;
954 if (!FRAME_MEMORY_BELOW_FRAME (f)
955 && vpos + i >= FRAME_LINES (f))
956 return;
958 if (multi)
960 raw_cursor_to (f, vpos, 0);
961 tty_background_highlight (tty);
962 buf = tparam (multi, 0, 0, i);
963 OUTPUT (tty, buf);
964 xfree (buf);
966 else if (single)
968 raw_cursor_to (f, vpos, 0);
969 tty_background_highlight (tty);
970 while (--i >= 0)
971 OUTPUT (tty, single);
972 if (tty->TF_teleray)
973 curX (tty) = 0;
975 else
977 tty_set_scroll_region (f, vpos, tty->specified_window);
978 if (n < 0)
979 raw_cursor_to (f, tty->specified_window - 1, 0);
980 else
981 raw_cursor_to (f, vpos, 0);
982 tty_background_highlight (tty);
983 while (--i >= 0)
984 OUTPUTL (tty, scroll, tty->specified_window - vpos);
985 tty_set_scroll_region (f, 0, tty->specified_window);
988 if (!FRAME_SCROLL_REGION_OK (f)
989 && FRAME_MEMORY_BELOW_FRAME (f)
990 && n < 0)
992 cursor_to (f, FRAME_LINES (f) + n, 0);
993 clear_to_end (f);
997 /* Compute cost of sending "str", in characters,
998 not counting any line-dependent padding. */
1001 string_cost (char *str)
1003 cost = 0;
1004 if (str)
1005 tputs (str, 0, evalcost);
1006 return cost;
1009 /* Compute cost of sending "str", in characters,
1010 counting any line-dependent padding at one line. */
1012 static int
1013 string_cost_one_line (char *str)
1015 cost = 0;
1016 if (str)
1017 tputs (str, 1, evalcost);
1018 return cost;
1021 /* Compute per line amount of line-dependent padding,
1022 in tenths of characters. */
1025 per_line_cost (char *str)
1027 cost = 0;
1028 if (str)
1029 tputs (str, 0, evalcost);
1030 cost = - cost;
1031 if (str)
1032 tputs (str, 10, evalcost);
1033 return cost;
1036 #ifndef old
1037 /* char_ins_del_cost[n] is cost of inserting N characters.
1038 char_ins_del_cost[-n] is cost of deleting N characters.
1039 The length of this vector is based on max_frame_cols. */
1041 int *char_ins_del_vector;
1043 #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_COLS ((f))])
1044 #endif
1046 /* ARGSUSED */
1047 static void
1048 calculate_ins_del_char_costs (struct frame *f)
1050 struct tty_display_info *tty = FRAME_TTY (f);
1051 int ins_startup_cost, del_startup_cost;
1052 int ins_cost_per_char, del_cost_per_char;
1053 register int i;
1054 register int *p;
1056 if (tty->TS_ins_multi_chars)
1058 ins_cost_per_char = 0;
1059 ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars);
1061 else if (tty->TS_ins_char || tty->TS_pad_inserted_char
1062 || (tty->TS_insert_mode && tty->TS_end_insert_mode))
1064 ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode)
1065 + string_cost (tty->TS_end_insert_mode))) / 100;
1066 ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char)
1067 + string_cost_one_line (tty->TS_pad_inserted_char));
1069 else
1071 ins_startup_cost = 9999;
1072 ins_cost_per_char = 0;
1075 if (tty->TS_del_multi_chars)
1077 del_cost_per_char = 0;
1078 del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars);
1080 else if (tty->TS_del_char)
1082 del_startup_cost = (string_cost (tty->TS_delete_mode)
1083 + string_cost (tty->TS_end_delete_mode));
1084 if (tty->delete_in_insert_mode)
1085 del_startup_cost /= 2;
1086 del_cost_per_char = string_cost_one_line (tty->TS_del_char);
1088 else
1090 del_startup_cost = 9999;
1091 del_cost_per_char = 0;
1094 /* Delete costs are at negative offsets */
1095 p = &char_ins_del_cost (f)[0];
1096 for (i = FRAME_COLS (f); --i >= 0;)
1097 *--p = (del_startup_cost += del_cost_per_char);
1099 /* Doing nothing is free */
1100 p = &char_ins_del_cost (f)[0];
1101 *p++ = 0;
1103 /* Insert costs are at positive offsets */
1104 for (i = FRAME_COLS (f); --i >= 0;)
1105 *p++ = (ins_startup_cost += ins_cost_per_char);
1108 void
1109 calculate_costs (struct frame *frame)
1111 FRAME_COST_BAUD_RATE (frame) = baud_rate;
1113 if (FRAME_TERMCAP_P (frame))
1115 struct tty_display_info *tty = FRAME_TTY (frame);
1116 register char *f = (tty->TS_set_scroll_region
1117 ? tty->TS_set_scroll_region
1118 : tty->TS_set_scroll_region_1);
1120 FRAME_SCROLL_REGION_COST (frame) = string_cost (f);
1122 tty->costs_set = 1;
1124 /* These variables are only used for terminal stuff. They are
1125 allocated once for the terminal frame of X-windows emacs, but not
1126 used afterwards.
1128 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1129 X turns off char_ins_del_ok. */
1131 max_frame_lines = max (max_frame_lines, FRAME_LINES (frame));
1132 max_frame_cols = max (max_frame_cols, FRAME_COLS (frame));
1134 if (char_ins_del_vector != 0)
1135 char_ins_del_vector
1136 = (int *) xrealloc (char_ins_del_vector,
1137 (sizeof (int)
1138 + 2 * max_frame_cols * sizeof (int)));
1139 else
1140 char_ins_del_vector
1141 = (int *) xmalloc (sizeof (int)
1142 + 2 * max_frame_cols * sizeof (int));
1144 bzero (char_ins_del_vector, (sizeof (int)
1145 + 2 * max_frame_cols * sizeof (int)));
1148 if (f && (!tty->TS_ins_line && !tty->TS_del_line))
1149 do_line_insertion_deletion_costs (frame,
1150 tty->TS_rev_scroll, tty->TS_ins_multi_lines,
1151 tty->TS_fwd_scroll, tty->TS_del_multi_lines,
1152 f, f, 1);
1153 else
1154 do_line_insertion_deletion_costs (frame,
1155 tty->TS_ins_line, tty->TS_ins_multi_lines,
1156 tty->TS_del_line, tty->TS_del_multi_lines,
1157 0, 0, 1);
1159 calculate_ins_del_char_costs (frame);
1161 /* Don't use TS_repeat if its padding is worse than sending the chars */
1162 if (tty->TS_repeat && per_line_cost (tty->TS_repeat) * baud_rate < 9000)
1163 tty->RPov = string_cost (tty->TS_repeat);
1164 else
1165 tty->RPov = FRAME_COLS (frame) * 2;
1167 cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */
1171 struct fkey_table {
1172 char *cap, *name;
1175 /* Termcap capability names that correspond directly to X keysyms.
1176 Some of these (marked "terminfo") aren't supplied by old-style
1177 (Berkeley) termcap entries. They're listed in X keysym order;
1178 except we put the keypad keys first, so that if they clash with
1179 other keys (as on the IBM PC keyboard) they get overridden.
1182 static struct fkey_table keys[] =
1184 {"kh", "home"}, /* termcap */
1185 {"kl", "left"}, /* termcap */
1186 {"ku", "up"}, /* termcap */
1187 {"kr", "right"}, /* termcap */
1188 {"kd", "down"}, /* termcap */
1189 {"%8", "prior"}, /* terminfo */
1190 {"%5", "next"}, /* terminfo */
1191 {"@7", "end"}, /* terminfo */
1192 {"@1", "begin"}, /* terminfo */
1193 {"*6", "select"}, /* terminfo */
1194 {"%9", "print"}, /* terminfo */
1195 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1197 * "insert" --- see below
1199 {"&8", "undo"}, /* terminfo */
1200 {"%0", "redo"}, /* terminfo */
1201 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1202 {"@0", "find"}, /* terminfo */
1203 {"@2", "cancel"}, /* terminfo */
1204 {"%1", "help"}, /* terminfo */
1206 * "break" goes here, but can't be reliably intercepted with termcap
1208 {"&4", "reset"}, /* terminfo --- actually `restart' */
1210 * "system" and "user" --- no termcaps
1212 {"kE", "clearline"}, /* terminfo */
1213 {"kA", "insertline"}, /* terminfo */
1214 {"kL", "deleteline"}, /* terminfo */
1215 {"kI", "insertchar"}, /* terminfo */
1216 {"kD", "deletechar"}, /* terminfo */
1217 {"kB", "backtab"}, /* terminfo */
1219 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1221 {"@8", "kp-enter"}, /* terminfo */
1223 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1224 * "kp-multiply", "kp-add", "kp-separator",
1225 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1226 * --- no termcaps for any of these.
1228 {"K4", "kp-1"}, /* terminfo */
1230 * "kp-2" --- no termcap
1232 {"K5", "kp-3"}, /* terminfo */
1234 * "kp-4" --- no termcap
1236 {"K2", "kp-5"}, /* terminfo */
1238 * "kp-6" --- no termcap
1240 {"K1", "kp-7"}, /* terminfo */
1242 * "kp-8" --- no termcap
1244 {"K3", "kp-9"}, /* terminfo */
1246 * "kp-equal" --- no termcap
1248 {"k1", "f1"},
1249 {"k2", "f2"},
1250 {"k3", "f3"},
1251 {"k4", "f4"},
1252 {"k5", "f5"},
1253 {"k6", "f6"},
1254 {"k7", "f7"},
1255 {"k8", "f8"},
1256 {"k9", "f9"},
1258 {"&0", "S-cancel"}, /*shifted cancel key*/
1259 {"&9", "S-begin"}, /*shifted begin key*/
1260 {"*0", "S-find"}, /*shifted find key*/
1261 {"*1", "S-execute"}, /*shifted execute? actually shifted command key*/
1262 {"*4", "S-delete"}, /*shifted delete-character key*/
1263 {"*7", "S-end"}, /*shifted end key*/
1264 {"*8", "S-clearline"}, /*shifted clear-to end-of-line key*/
1265 {"#1", "S-help"}, /*shifted help key*/
1266 {"#2", "S-home"}, /*shifted home key*/
1267 {"#3", "S-insert"}, /*shifted insert-character key*/
1268 {"#4", "S-left"}, /*shifted left-arrow key*/
1269 {"%d", "S-menu"}, /*shifted menu? actually shifted options key*/
1270 {"%c", "S-next"}, /*shifted next key*/
1271 {"%e", "S-prior"}, /*shifted previous key*/
1272 {"%f", "S-print"}, /*shifted print key*/
1273 {"%g", "S-redo"}, /*shifted redo key*/
1274 {"%i", "S-right"}, /*shifted right-arrow key*/
1275 {"!3", "S-undo"} /*shifted undo key*/
1278 static char **term_get_fkeys_address;
1279 static KBOARD *term_get_fkeys_kboard;
1280 static Lisp_Object term_get_fkeys_1 ();
1282 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1283 This function scans the termcap function key sequence entries, and
1284 adds entries to Vfunction_key_map for each function key it finds. */
1286 static void
1287 term_get_fkeys (address, kboard)
1288 char **address;
1289 KBOARD *kboard;
1291 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1292 errors during the call. The only errors should be from Fdefine_key
1293 when given a key sequence containing an invalid prefix key. If the
1294 termcap defines function keys which use a prefix that is already bound
1295 to a command by the default bindings, we should silently ignore that
1296 function key specification, rather than giving the user an error and
1297 refusing to run at all on such a terminal. */
1299 extern Lisp_Object Fidentity ();
1300 term_get_fkeys_address = address;
1301 term_get_fkeys_kboard = kboard;
1302 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1305 static Lisp_Object
1306 term_get_fkeys_1 ()
1308 int i;
1310 char **address = term_get_fkeys_address;
1311 KBOARD *kboard = term_get_fkeys_kboard;
1313 /* This can happen if CANNOT_DUMP or with strange options. */
1314 if (!initialized)
1315 kboard->Vlocal_function_key_map = Fmake_sparse_keymap (Qnil);
1317 for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
1319 char *sequence = tgetstr (keys[i].cap, address);
1320 if (sequence)
1321 Fdefine_key (kboard->Vlocal_function_key_map, build_string (sequence),
1322 Fmake_vector (make_number (1),
1323 intern (keys[i].name)));
1326 /* The uses of the "k0" capability are inconsistent; sometimes it
1327 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1328 We will attempt to politely accommodate both systems by testing for
1329 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1332 char *k_semi = tgetstr ("k;", address);
1333 char *k0 = tgetstr ("k0", address);
1334 char *k0_name = "f10";
1336 if (k_semi)
1338 if (k0)
1339 /* Define f0 first, so that f10 takes precedence in case the
1340 key sequences happens to be the same. */
1341 Fdefine_key (kboard->Vlocal_function_key_map, build_string (k0),
1342 Fmake_vector (make_number (1), intern ("f0")));
1343 Fdefine_key (kboard->Vlocal_function_key_map, build_string (k_semi),
1344 Fmake_vector (make_number (1), intern ("f10")));
1346 else if (k0)
1347 Fdefine_key (kboard->Vlocal_function_key_map, build_string (k0),
1348 Fmake_vector (make_number (1), intern (k0_name)));
1351 /* Set up cookies for numbered function keys above f10. */
1353 char fcap[3], fkey[4];
1355 fcap[0] = 'F'; fcap[2] = '\0';
1356 for (i = 11; i < 64; i++)
1358 if (i <= 19)
1359 fcap[1] = '1' + i - 11;
1360 else if (i <= 45)
1361 fcap[1] = 'A' + i - 20;
1362 else
1363 fcap[1] = 'a' + i - 46;
1366 char *sequence = tgetstr (fcap, address);
1367 if (sequence)
1369 sprintf (fkey, "f%d", i);
1370 Fdefine_key (kboard->Vlocal_function_key_map, build_string (sequence),
1371 Fmake_vector (make_number (1),
1372 intern (fkey)));
1379 * Various mappings to try and get a better fit.
1382 #define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1383 if (!tgetstr (cap1, address)) \
1385 char *sequence = tgetstr (cap2, address); \
1386 if (sequence) \
1387 Fdefine_key (kboard->Vlocal_function_key_map, build_string (sequence), \
1388 Fmake_vector (make_number (1), \
1389 intern (sym))); \
1392 /* if there's no key_next keycap, map key_npage to `next' keysym */
1393 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1394 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1395 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1396 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1397 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1398 /* if there's no key_end keycap, map key_ll to 'end' keysym */
1399 CONDITIONAL_REASSIGN ("@7", "kH", "end");
1401 /* IBM has their own non-standard dialect of terminfo.
1402 If the standard name isn't found, try the IBM name. */
1403 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1404 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1405 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1406 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1407 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1408 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1409 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1410 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1411 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1412 #undef CONDITIONAL_REASSIGN
1415 return Qnil;
1419 /***********************************************************************
1420 Character Display Information
1421 ***********************************************************************/
1423 /* Avoid name clash with functions defined in xterm.c */
1424 #ifdef static
1425 #define append_glyph append_glyph_term
1426 #define produce_stretch_glyph produce_stretch_glyph_term
1427 #endif
1429 static void append_glyph P_ ((struct it *));
1430 static void produce_stretch_glyph P_ ((struct it *));
1433 /* Append glyphs to IT's glyph_row. Called from produce_glyphs for
1434 terminal frames if IT->glyph_row != NULL. IT->char_to_display is
1435 the character for which to produce glyphs; IT->face_id contains the
1436 character's face. Padding glyphs are appended if IT->c has a
1437 IT->pixel_width > 1. */
1439 static void
1440 append_glyph (it)
1441 struct it *it;
1443 struct glyph *glyph, *end;
1444 int i;
1446 xassert (it->glyph_row);
1447 glyph = (it->glyph_row->glyphs[it->area]
1448 + it->glyph_row->used[it->area]);
1449 end = it->glyph_row->glyphs[1 + it->area];
1451 for (i = 0;
1452 i < it->pixel_width && glyph < end;
1453 ++i)
1455 glyph->type = CHAR_GLYPH;
1456 glyph->pixel_width = 1;
1457 glyph->u.ch = it->char_to_display;
1458 glyph->face_id = it->face_id;
1459 glyph->padding_p = i > 0;
1460 glyph->charpos = CHARPOS (it->position);
1461 glyph->object = it->object;
1463 ++it->glyph_row->used[it->area];
1464 ++glyph;
1469 /* Produce glyphs for the display element described by IT. *IT
1470 specifies what we want to produce a glyph for (character, image, ...),
1471 and where in the glyph matrix we currently are (glyph row and hpos).
1472 produce_glyphs fills in output fields of *IT with information such as the
1473 pixel width and height of a character, and maybe output actual glyphs at
1474 the same time if IT->glyph_row is non-null. See the explanation of
1475 struct display_iterator in dispextern.h for an overview.
1477 produce_glyphs also stores the result of glyph width, ascent
1478 etc. computations in *IT.
1480 IT->glyph_row may be null, in which case produce_glyphs does not
1481 actually fill in the glyphs. This is used in the move_* functions
1482 in xdisp.c for text width and height computations.
1484 Callers usually don't call produce_glyphs directly;
1485 instead they use the macro PRODUCE_GLYPHS. */
1487 void
1488 produce_glyphs (it)
1489 struct it *it;
1491 /* If a hook is installed, let it do the work. */
1492 xassert (it->what == IT_CHARACTER
1493 || it->what == IT_COMPOSITION
1494 || it->what == IT_STRETCH);
1496 if (it->what == IT_STRETCH)
1498 produce_stretch_glyph (it);
1499 goto done;
1502 /* Nothing but characters are supported on terminal frames. For a
1503 composition sequence, it->c is the first character of the
1504 sequence. */
1505 xassert (it->what == IT_CHARACTER
1506 || it->what == IT_COMPOSITION);
1508 /* Maybe translate single-byte characters to multibyte. */
1509 it->char_to_display = it->c;
1511 if (it->c >= 040 && it->c < 0177)
1513 it->pixel_width = it->nglyphs = 1;
1514 if (it->glyph_row)
1515 append_glyph (it);
1517 else if (it->c == '\n')
1518 it->pixel_width = it->nglyphs = 0;
1519 else if (it->c == '\t')
1521 int absolute_x = (it->current_x
1522 + it->continuation_lines_width);
1523 int next_tab_x
1524 = (((1 + absolute_x + it->tab_width - 1)
1525 / it->tab_width)
1526 * it->tab_width);
1527 int nspaces;
1529 /* If part of the TAB has been displayed on the previous line
1530 which is continued now, continuation_lines_width will have
1531 been incremented already by the part that fitted on the
1532 continued line. So, we will get the right number of spaces
1533 here. */
1534 nspaces = next_tab_x - absolute_x;
1536 if (it->glyph_row)
1538 int n = nspaces;
1540 it->char_to_display = ' ';
1541 it->pixel_width = it->len = 1;
1543 while (n--)
1544 append_glyph (it);
1547 it->pixel_width = nspaces;
1548 it->nglyphs = nspaces;
1550 else if (SINGLE_BYTE_CHAR_P (it->c))
1552 if (unibyte_display_via_language_environment
1553 && (it->c >= 0240
1554 || !NILP (Vnonascii_translation_table)))
1556 int charset;
1558 it->char_to_display = unibyte_char_to_multibyte (it->c);
1559 charset = CHAR_CHARSET (it->char_to_display);
1560 it->pixel_width = CHARSET_WIDTH (charset);
1561 it->nglyphs = it->pixel_width;
1562 if (it->glyph_row)
1563 append_glyph (it);
1565 else
1567 /* Coming here means that it->c is from display table, thus we
1568 must send the code as is to the terminal. Although there's
1569 no way to know how many columns it occupies on a screen, it
1570 is a good assumption that a single byte code has 1-column
1571 width. */
1572 it->pixel_width = it->nglyphs = 1;
1573 if (it->glyph_row)
1574 append_glyph (it);
1577 else
1579 /* A multi-byte character. The display width is fixed for all
1580 characters of the set. Some of the glyphs may have to be
1581 ignored because they are already displayed in a continued
1582 line. */
1583 int charset = CHAR_CHARSET (it->c);
1585 it->pixel_width = CHARSET_WIDTH (charset);
1586 it->nglyphs = it->pixel_width;
1588 if (it->glyph_row)
1589 append_glyph (it);
1592 done:
1593 /* Advance current_x by the pixel width as a convenience for
1594 the caller. */
1595 if (it->area == TEXT_AREA)
1596 it->current_x += it->pixel_width;
1597 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1598 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
1602 /* Produce a stretch glyph for iterator IT. IT->object is the value
1603 of the glyph property displayed. The value must be a list
1604 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1605 being recognized:
1607 1. `:width WIDTH' specifies that the space should be WIDTH *
1608 canonical char width wide. WIDTH may be an integer or floating
1609 point number.
1611 2. `:align-to HPOS' specifies that the space should be wide enough
1612 to reach HPOS, a value in canonical character units. */
1614 static void
1615 produce_stretch_glyph (it)
1616 struct it *it;
1618 /* (space :width WIDTH ...) */
1619 Lisp_Object prop, plist;
1620 int width = 0, align_to = -1;
1621 int zero_width_ok_p = 0;
1622 double tem;
1624 /* List should start with `space'. */
1625 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1626 plist = XCDR (it->object);
1628 /* Compute the width of the stretch. */
1629 if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
1630 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, 0))
1632 /* Absolute width `:width WIDTH' specified and valid. */
1633 zero_width_ok_p = 1;
1634 width = (int)(tem + 0.5);
1636 else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
1637 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, &align_to))
1639 if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
1640 align_to = (align_to < 0
1642 : align_to - window_box_left_offset (it->w, TEXT_AREA));
1643 else if (align_to < 0)
1644 align_to = window_box_left_offset (it->w, TEXT_AREA);
1645 width = max (0, (int)(tem + 0.5) + align_to - it->current_x);
1646 zero_width_ok_p = 1;
1648 else
1649 /* Nothing specified -> width defaults to canonical char width. */
1650 width = FRAME_COLUMN_WIDTH (it->f);
1652 if (width <= 0 && (width < 0 || !zero_width_ok_p))
1653 width = 1;
1655 if (width > 0 && it->glyph_row)
1657 Lisp_Object o_object = it->object;
1658 Lisp_Object object = it->stack[it->sp - 1].string;
1659 int n = width;
1661 if (!STRINGP (object))
1662 object = it->w->buffer;
1663 it->object = object;
1664 it->char_to_display = ' ';
1665 it->pixel_width = it->len = 1;
1666 while (n--)
1667 append_glyph (it);
1668 it->object = o_object;
1670 it->pixel_width = width;
1671 it->nglyphs = width;
1675 /* Get information about special display element WHAT in an
1676 environment described by IT. WHAT is one of IT_TRUNCATION or
1677 IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a
1678 non-null glyph_row member. This function ensures that fields like
1679 face_id, c, len of IT are left untouched. */
1681 void
1682 produce_special_glyphs (it, what)
1683 struct it *it;
1684 enum display_element_type what;
1686 struct it temp_it;
1687 GLYPH glyph;
1689 temp_it = *it;
1690 temp_it.dp = NULL;
1691 temp_it.what = IT_CHARACTER;
1692 temp_it.len = 1;
1693 temp_it.object = make_number (0);
1694 bzero (&temp_it.current, sizeof temp_it.current);
1696 if (what == IT_CONTINUATION)
1698 /* Continuation glyph. */
1699 if (it->dp
1700 && INTEGERP (DISP_CONTINUE_GLYPH (it->dp))
1701 && GLYPH_CHAR_VALID_P (XINT (DISP_CONTINUE_GLYPH (it->dp))))
1703 glyph = XINT (DISP_CONTINUE_GLYPH (it->dp));
1704 glyph = spec_glyph_lookup_face (XWINDOW (it->window), glyph);
1706 else
1707 glyph = '\\';
1709 else if (what == IT_TRUNCATION)
1711 /* Truncation glyph. */
1712 if (it->dp
1713 && INTEGERP (DISP_TRUNC_GLYPH (it->dp))
1714 && GLYPH_CHAR_VALID_P (XINT (DISP_TRUNC_GLYPH (it->dp))))
1716 glyph = XINT (DISP_TRUNC_GLYPH (it->dp));
1717 glyph = spec_glyph_lookup_face (XWINDOW (it->window), glyph);
1719 else
1720 glyph = '$';
1722 else
1723 abort ();
1725 temp_it.c = FAST_GLYPH_CHAR (glyph);
1726 temp_it.face_id = FAST_GLYPH_FACE (glyph);
1727 temp_it.len = CHAR_BYTES (temp_it.c);
1729 produce_glyphs (&temp_it);
1730 it->pixel_width = temp_it.pixel_width;
1731 it->nglyphs = temp_it.pixel_width;
1736 /***********************************************************************
1737 Faces
1738 ***********************************************************************/
1740 /* Value is non-zero if attribute ATTR may be used. ATTR should be
1741 one of the enumerators from enum no_color_bit, or a bit set built
1742 from them. Some display attributes may not be used together with
1743 color; the termcap capability `NC' specifies which ones. */
1745 #define MAY_USE_WITH_COLORS_P(tty, ATTR) \
1746 (tty->TN_max_colors > 0 \
1747 ? (tty->TN_no_color_video & (ATTR)) == 0 \
1748 : 1)
1750 /* Turn appearances of face FACE_ID on tty frame F on.
1751 FACE_ID is a realized face ID number, in the face cache. */
1753 static void
1754 turn_on_face (f, face_id)
1755 struct frame *f;
1756 int face_id;
1758 struct face *face = FACE_FROM_ID (f, face_id);
1759 long fg = face->foreground;
1760 long bg = face->background;
1761 struct tty_display_info *tty = FRAME_TTY (f);
1763 /* Do this first because TS_end_standout_mode may be the same
1764 as TS_exit_attribute_mode, which turns all appearances off. */
1765 if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE))
1767 if (tty->TN_max_colors > 0)
1769 if (fg >= 0 && bg >= 0)
1771 /* If the terminal supports colors, we can set them
1772 below without using reverse video. The face's fg
1773 and bg colors are set as they should appear on
1774 the screen, i.e. they take the inverse-video'ness
1775 of the face already into account. */
1777 else if (inverse_video)
1779 if (fg == FACE_TTY_DEFAULT_FG_COLOR
1780 || bg == FACE_TTY_DEFAULT_BG_COLOR)
1781 tty_toggle_highlight (tty);
1783 else
1785 if (fg == FACE_TTY_DEFAULT_BG_COLOR
1786 || bg == FACE_TTY_DEFAULT_FG_COLOR)
1787 tty_toggle_highlight (tty);
1790 else
1792 /* If we can't display colors, use reverse video
1793 if the face specifies that. */
1794 if (inverse_video)
1796 if (fg == FACE_TTY_DEFAULT_FG_COLOR
1797 || bg == FACE_TTY_DEFAULT_BG_COLOR)
1798 tty_toggle_highlight (tty);
1800 else
1802 if (fg == FACE_TTY_DEFAULT_BG_COLOR
1803 || bg == FACE_TTY_DEFAULT_FG_COLOR)
1804 tty_toggle_highlight (tty);
1809 if (face->tty_bold_p)
1811 if (MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
1812 OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
1814 else if (face->tty_dim_p)
1815 if (MAY_USE_WITH_COLORS_P (tty, NC_DIM))
1816 OUTPUT1_IF (tty, tty->TS_enter_dim_mode);
1818 /* Alternate charset and blinking not yet used. */
1819 if (face->tty_alt_charset_p
1820 && MAY_USE_WITH_COLORS_P (tty, NC_ALT_CHARSET))
1821 OUTPUT1_IF (tty, tty->TS_enter_alt_charset_mode);
1823 if (face->tty_blinking_p
1824 && MAY_USE_WITH_COLORS_P (tty, NC_BLINK))
1825 OUTPUT1_IF (tty, tty->TS_enter_blink_mode);
1827 if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
1828 OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
1830 if (tty->TN_max_colors > 0)
1832 char *ts, *p;
1834 ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
1835 if (fg >= 0 && ts)
1837 p = tparam (ts, NULL, 0, (int) fg);
1838 OUTPUT (tty, p);
1839 xfree (p);
1842 ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
1843 if (bg >= 0 && ts)
1845 p = tparam (ts, NULL, 0, (int) bg);
1846 OUTPUT (tty, p);
1847 xfree (p);
1853 /* Turn off appearances of face FACE_ID on tty frame F. */
1855 static void
1856 turn_off_face (f, face_id)
1857 struct frame *f;
1858 int face_id;
1860 struct face *face = FACE_FROM_ID (f, face_id);
1861 struct tty_display_info *tty = FRAME_TTY (f);
1863 xassert (face != NULL);
1865 if (tty->TS_exit_attribute_mode)
1867 /* Capability "me" will turn off appearance modes double-bright,
1868 half-bright, reverse-video, standout, underline. It may or
1869 may not turn off alt-char-mode. */
1870 if (face->tty_bold_p
1871 || face->tty_dim_p
1872 || face->tty_reverse_p
1873 || face->tty_alt_charset_p
1874 || face->tty_blinking_p
1875 || face->tty_underline_p)
1877 OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
1878 if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0)
1879 tty->standout_mode = 0;
1882 if (face->tty_alt_charset_p)
1883 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
1885 else
1887 /* If we don't have "me" we can only have those appearances
1888 that have exit sequences defined. */
1889 if (face->tty_alt_charset_p)
1890 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
1892 if (face->tty_underline_p)
1893 OUTPUT_IF (tty, tty->TS_exit_underline_mode);
1896 /* Switch back to default colors. */
1897 if (tty->TN_max_colors > 0
1898 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
1899 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
1900 || (face->background != FACE_TTY_DEFAULT_COLOR
1901 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
1902 OUTPUT1_IF (tty, tty->TS_orig_pair);
1906 /* Return non-zero if the terminal on frame F supports all of the
1907 capabilities in CAPS simultaneously, with foreground and background
1908 colors FG and BG. */
1911 tty_capable_p (tty, caps, fg, bg)
1912 struct tty_display_info *tty;
1913 unsigned caps;
1914 unsigned long fg, bg;
1916 #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
1917 if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
1918 return 0;
1920 TTY_CAPABLE_P_TRY (tty, TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE);
1921 TTY_CAPABLE_P_TRY (tty, TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode, NC_UNDERLINE);
1922 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
1923 TTY_CAPABLE_P_TRY (tty, TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM);
1924 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BLINK, tty->TS_enter_blink_mode, NC_BLINK);
1925 TTY_CAPABLE_P_TRY (tty, TTY_CAP_ALT_CHARSET, tty->TS_enter_alt_charset_mode, NC_ALT_CHARSET);
1927 /* We can do it! */
1928 return 1;
1931 /* Return non-zero if the terminal is capable to display colors. */
1933 DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
1934 0, 1, 0,
1935 doc: /* Return non-nil if the tty device TERMINAL can display colors.
1937 TERMINAL can be a terminal id, a frame or nil (meaning the selected
1938 frame's terminal). This function always returns nil if TERMINAL
1939 is not on a tty device. */)
1940 (terminal)
1941 Lisp_Object terminal;
1943 struct terminal *t = get_tty_terminal (terminal, 0);
1944 if (!t)
1945 return Qnil;
1946 else
1947 return t->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
1950 /* Return the number of supported colors. */
1951 DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
1952 Stty_display_color_cells, 0, 1, 0,
1953 doc: /* Return the number of colors supported by the tty device TERMINAL.
1955 TERMINAL can be a terminal id, a frame or nil (meaning the selected
1956 frame's terminal). This function always returns 0 if TERMINAL
1957 is not on a tty device. */)
1958 (terminal)
1959 Lisp_Object terminal;
1961 struct terminal *t = get_tty_terminal (terminal, 0);
1962 if (!t)
1963 return make_number (0);
1964 else
1965 return make_number (t->display_info.tty->TN_max_colors);
1968 #ifndef WINDOWSNT
1970 /* Declare here rather than in the function, as in the rest of Emacs,
1971 to work around an HPUX compiler bug (?). See
1972 http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00410.html */
1973 static int default_max_colors;
1974 static int default_max_pairs;
1975 static int default_no_color_video;
1976 static char *default_orig_pair;
1977 static char *default_set_foreground;
1978 static char *default_set_background;
1980 /* Save or restore the default color-related capabilities of this
1981 terminal. */
1982 static void
1983 tty_default_color_capabilities (struct tty_display_info *tty, int save)
1986 if (save)
1988 if (default_orig_pair)
1989 xfree (default_orig_pair);
1990 default_orig_pair = tty->TS_orig_pair ? xstrdup (tty->TS_orig_pair) : NULL;
1992 if (default_set_foreground)
1993 xfree (default_set_foreground);
1994 default_set_foreground = tty->TS_set_foreground ? xstrdup (tty->TS_set_foreground)
1995 : NULL;
1997 if (default_set_background)
1998 xfree (default_set_background);
1999 default_set_background = tty->TS_set_background ? xstrdup (tty->TS_set_background)
2000 : NULL;
2002 default_max_colors = tty->TN_max_colors;
2003 default_max_pairs = tty->TN_max_pairs;
2004 default_no_color_video = tty->TN_no_color_video;
2006 else
2008 tty->TS_orig_pair = default_orig_pair;
2009 tty->TS_set_foreground = default_set_foreground;
2010 tty->TS_set_background = default_set_background;
2011 tty->TN_max_colors = default_max_colors;
2012 tty->TN_max_pairs = default_max_pairs;
2013 tty->TN_no_color_video = default_no_color_video;
2017 /* Setup one of the standard tty color schemes according to MODE.
2018 MODE's value is generally the number of colors which we want to
2019 support; zero means set up for the default capabilities, the ones
2020 we saw at init_tty time; -1 means turn off color support. */
2021 static void
2022 tty_setup_colors (struct tty_display_info *tty, int mode)
2024 /* Canonicalize all negative values of MODE. */
2025 if (mode < -1)
2026 mode = -1;
2028 switch (mode)
2030 case -1: /* no colors at all */
2031 tty->TN_max_colors = 0;
2032 tty->TN_max_pairs = 0;
2033 tty->TN_no_color_video = 0;
2034 tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL;
2035 break;
2036 case 0: /* default colors, if any */
2037 default:
2038 tty_default_color_capabilities (tty, 0);
2039 break;
2040 case 8: /* 8 standard ANSI colors */
2041 tty->TS_orig_pair = "\033[0m";
2042 #ifdef TERMINFO
2043 tty->TS_set_foreground = "\033[3%p1%dm";
2044 tty->TS_set_background = "\033[4%p1%dm";
2045 #else
2046 tty->TS_set_foreground = "\033[3%dm";
2047 tty->TS_set_background = "\033[4%dm";
2048 #endif
2049 tty->TN_max_colors = 8;
2050 tty->TN_max_pairs = 64;
2051 tty->TN_no_color_video = 0;
2052 break;
2056 void
2057 set_tty_color_mode (f, val)
2058 struct frame *f;
2059 Lisp_Object val;
2061 Lisp_Object color_mode_spec, current_mode_spec;
2062 Lisp_Object color_mode, current_mode;
2063 int mode, old_mode;
2064 extern Lisp_Object Qtty_color_mode;
2065 Lisp_Object tty_color_mode_alist;
2067 tty_color_mode_alist = Fintern_soft (build_string ("tty-color-mode-alist"),
2068 Qnil);
2070 if (INTEGERP (val))
2071 color_mode = val;
2072 else
2074 if (NILP (tty_color_mode_alist))
2075 color_mode_spec = Qnil;
2076 else
2077 color_mode_spec = Fassq (val, XSYMBOL (tty_color_mode_alist)->value);
2079 if (CONSP (color_mode_spec))
2080 color_mode = XCDR (color_mode_spec);
2081 else
2082 color_mode = Qnil;
2085 current_mode_spec = assq_no_quit (Qtty_color_mode, f->param_alist);
2087 if (CONSP (current_mode_spec))
2088 current_mode = XCDR (current_mode_spec);
2089 else
2090 current_mode = Qnil;
2091 if (INTEGERP (color_mode))
2092 mode = XINT (color_mode);
2093 else
2094 mode = 0; /* meaning default */
2095 if (INTEGERP (current_mode))
2096 old_mode = XINT (current_mode);
2097 else
2098 old_mode = 0;
2100 if (mode != old_mode)
2102 tty_setup_colors (FRAME_TTY (f), mode);
2103 /* This recomputes all the faces given the new color
2104 definitions. */
2105 call0 (intern ("tty-set-up-initial-frame-faces"));
2106 redraw_frame (f);
2110 #endif /* !WINDOWSNT */
2114 /* Return the tty display object specified by TERMINAL. */
2116 struct terminal *
2117 get_tty_terminal (Lisp_Object terminal, int throw)
2119 struct terminal *t = get_terminal (terminal, throw);
2121 if (t && t->type == output_initial)
2122 return NULL;
2124 if (t && t->type != output_termcap)
2126 if (throw)
2127 error ("Device %d is not a termcap terminal device", t->id);
2128 else
2129 return NULL;
2132 return t;
2135 /* Return an active termcap device that uses the tty device with the
2136 given name.
2138 This function ignores suspended devices.
2140 Returns NULL if the named terminal device is not opened. */
2142 struct terminal *
2143 get_named_tty (name)
2144 char *name;
2146 struct terminal *t;
2148 if (!name)
2149 abort ();
2151 for (t = terminal_list; t; t = t->next_terminal)
2153 if (t->type == output_termcap
2154 && !strcmp (t->display_info.tty->name, name)
2155 && TERMINAL_ACTIVE_P (t))
2156 return t;
2159 return 0;
2163 DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
2164 doc: /* Return the type of the tty device that TERMINAL uses.
2165 Returns nil if TERMINAL is not on a tty device.
2167 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2168 frame's terminal). */)
2169 (terminal)
2170 Lisp_Object terminal;
2172 struct terminal *t = get_terminal (terminal, 1);
2174 if (t->type != output_termcap)
2175 return Qnil;
2177 if (t->display_info.tty->type)
2178 return build_string (t->display_info.tty->type);
2179 else
2180 return Qnil;
2183 DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
2184 doc: /* Return non-nil if TERMINAL is on the controlling tty of the Emacs process.
2186 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2187 frame's terminal). This function always returns nil if TERMINAL
2188 is not on a tty device. */)
2189 (terminal)
2190 Lisp_Object terminal;
2192 struct terminal *t = get_terminal (terminal, 1);
2194 if (t->type != output_termcap || strcmp (t->display_info.tty->name, "/dev/tty"))
2195 return Qnil;
2196 else
2197 return Qt;
2200 DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
2201 doc: /* Declare that the tty used by TERMINAL does not handle underlining.
2202 This is used to override the terminfo data, for certain terminals that
2203 do not really do underlining, but say that they do. This function has
2204 no effect if used on a non-tty terminal.
2206 TERMINAL can be a terminal id, a frame or nil (meaning the selected
2207 frame's terminal). This function always returns nil if TERMINAL
2208 is not on a tty device. */)
2209 (terminal)
2210 Lisp_Object terminal;
2212 struct terminal *t = get_terminal (terminal, 1);
2214 if (t->type == output_termcap)
2215 t->display_info.tty->TS_enter_underline_mode = 0;
2216 return Qnil;
2221 DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
2222 doc: /* Suspend the terminal device TTY.
2224 The device is restored to its default state, and Emacs ceases all
2225 access to the tty device. Frames that use the device are not deleted,
2226 but input is not read from them and if they change, their display is
2227 not updated.
2229 TTY may be a terminal id, a frame, or nil for the terminal device of
2230 the currently selected frame.
2232 This function runs `suspend-tty-functions' after suspending the
2233 device. The functions are run with one arg, the id of the suspended
2234 terminal device.
2236 `suspend-tty' does nothing if it is called on a device that is already
2237 suspended.
2239 A suspended tty may be resumed by calling `resume-tty' on it. */)
2240 (tty)
2241 Lisp_Object tty;
2243 struct terminal *t = get_tty_terminal (tty, 1);
2244 FILE *f;
2246 if (!t)
2247 error ("Unknown tty device");
2249 f = t->display_info.tty->input;
2251 if (f)
2253 reset_sys_modes (t->display_info.tty);
2255 delete_keyboard_wait_descriptor (fileno (f));
2257 fclose (f);
2258 if (f != t->display_info.tty->output)
2259 fclose (t->display_info.tty->output);
2261 t->display_info.tty->input = 0;
2262 t->display_info.tty->output = 0;
2264 if (FRAMEP (t->display_info.tty->top_frame))
2265 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
2267 /* Run `suspend-tty-functions'. */
2268 if (!NILP (Vrun_hooks))
2270 Lisp_Object args[2];
2271 args[0] = intern ("suspend-tty-functions");
2272 args[1] = make_number (t->id);
2273 Frun_hook_with_args (2, args);
2277 /* Clear display hooks to prevent further output. */
2278 clear_tty_hooks (t);
2280 return Qnil;
2283 DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
2284 doc: /* Resume the previously suspended terminal device TTY.
2285 The terminal is opened and reinitialized. Frames that are on the
2286 suspended terminal are revived.
2288 It is an error to resume a terminal while another terminal is active
2289 on the same device.
2291 This function runs `resume-tty-functions' after resuming the terminal.
2292 The functions are run with one arg, the id of the resumed terminal
2293 device.
2295 `resume-tty' does nothing if it is called on a device that is not
2296 suspended.
2298 TTY may be a terminal id, a frame, or nil for the terminal device of
2299 the currently selected frame. */)
2300 (tty)
2301 Lisp_Object tty;
2303 struct terminal *t = get_tty_terminal (tty, 1);
2304 int fd;
2306 if (!t)
2307 error ("Unknown tty device");
2309 if (!t->display_info.tty->input)
2311 if (get_named_tty (t->display_info.tty->name))
2312 error ("Cannot resume display while another display is active on the same device");
2314 fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
2316 if (fd == -1)
2317 error ("Can not reopen tty device %s: %s", t->display_info.tty->name, strerror (errno));
2319 if (strcmp (t->display_info.tty->name, "/dev/tty"))
2320 dissociate_if_controlling_tty (fd);
2322 t->display_info.tty->output = fdopen (fd, "w+");
2323 t->display_info.tty->input = t->display_info.tty->output;
2325 add_keyboard_wait_descriptor (fd);
2327 if (FRAMEP (t->display_info.tty->top_frame))
2328 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
2330 init_sys_modes (t->display_info.tty);
2332 /* Run `resume-tty-functions'. */
2333 if (!NILP (Vrun_hooks))
2335 Lisp_Object args[2];
2336 args[0] = intern ("resume-tty-functions");
2337 args[1] = make_number (t->id);
2338 Frun_hook_with_args (2, args);
2342 set_tty_hooks (t);
2344 return Qnil;
2348 /***********************************************************************
2349 Mouse
2350 ***********************************************************************/
2352 #ifdef HAVE_GPM
2353 void
2354 term_mouse_moveto (int x, int y)
2356 /* TODO: how to set mouse position?
2357 const char *name;
2358 int fd;
2359 name = (const char *) ttyname (0);
2360 fd = open (name, O_WRONLY);
2361 SOME_FUNCTION (x, y, fd);
2362 close (fd);
2363 last_mouse_x = x;
2364 last_mouse_y = y; */
2367 static void
2368 term_show_mouse_face (enum draw_glyphs_face draw)
2370 struct window *w = XWINDOW (Qmouse_face_window);
2371 int save_x, save_y;
2372 int i;
2374 struct frame *f = XFRAME (w->frame);
2375 struct tty_display_info *tty = FRAME_TTY (f);
2377 if (/* If window is in the process of being destroyed, don't bother
2378 to do anything. */
2379 w->current_matrix != NULL
2380 /* Recognize when we are called to operate on rows that don't exist
2381 anymore. This can happen when a window is split. */
2382 && mouse_face_end_row < w->current_matrix->nrows)
2384 /* write_glyphs writes at cursor position, so we need to
2385 temporarily move cursor coordinates to the beginning of
2386 the highlight region. */
2388 /* Save current cursor co-ordinates */
2389 save_y = curY (tty);
2390 save_x = curX (tty);
2392 /* Note that mouse_face_beg_row etc. are window relative. */
2393 for (i = mouse_face_beg_row; i <= mouse_face_end_row; i++)
2395 int start_hpos, end_hpos, nglyphs;
2396 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
2398 /* Don't do anything if row doesn't have valid contents. */
2399 if (!row->enabled_p)
2400 continue;
2402 /* For all but the first row, the highlight starts at column 0. */
2403 if (i == mouse_face_beg_row)
2404 start_hpos = mouse_face_beg_col;
2405 else
2406 start_hpos = 0;
2408 if (i == mouse_face_end_row)
2409 end_hpos = mouse_face_end_col;
2410 else
2412 end_hpos = row->used[TEXT_AREA];
2413 if (draw == DRAW_NORMAL_TEXT)
2414 row->fill_line_p = 1; /* Clear to end of line */
2417 if (end_hpos <= start_hpos)
2418 continue;
2419 /* Record that some glyphs of this row are displayed in
2420 mouse-face. */
2421 row->mouse_face_p = draw > 0;
2423 nglyphs = end_hpos - start_hpos;
2425 if (end_hpos >= row->used[TEXT_AREA])
2426 nglyphs = row->used[TEXT_AREA] - start_hpos;
2428 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
2429 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos
2430 + WINDOW_LEFT_EDGE_X (w);
2432 cursor_to (f, pos_y, pos_x);
2434 if (draw == DRAW_MOUSE_FACE)
2436 tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
2437 nglyphs, mouse_face_face_id);
2439 else /* draw == DRAW_NORMAL_TEXT */
2440 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
2442 cursor_to (f, save_y, save_x);
2446 static void
2447 term_clear_mouse_face ()
2449 if (!NILP (Qmouse_face_window))
2450 term_show_mouse_face (DRAW_NORMAL_TEXT);
2452 mouse_face_beg_row = mouse_face_beg_col = -1;
2453 mouse_face_end_row = mouse_face_end_col = -1;
2454 Qmouse_face_window = Qnil;
2457 /* Find the glyph matrix position of buffer position POS in window W.
2458 *HPOS and *VPOS are set to the positions found. W's current glyphs
2459 must be up to date. If POS is above window start return (0, 0).
2460 If POS is after end of W, return end of last line in W.
2461 - taken from msdos.c */
2462 static int
2463 fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
2465 int i, lastcol, line_start_position, maybe_next_line_p = 0;
2466 int yb = window_text_bottom_y (w);
2467 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
2469 while (row->y < yb)
2471 if (row->used[TEXT_AREA])
2472 line_start_position = row->glyphs[TEXT_AREA]->charpos;
2473 else
2474 line_start_position = 0;
2476 if (line_start_position > pos)
2477 break;
2478 /* If the position sought is the end of the buffer,
2479 don't include the blank lines at the bottom of the window. */
2480 else if (line_start_position == pos
2481 && pos == BUF_ZV (XBUFFER (w->buffer)))
2483 maybe_next_line_p = 1;
2484 break;
2486 else if (line_start_position > 0)
2487 best_row = row;
2489 /* Don't overstep the last matrix row, lest we get into the
2490 never-never land... */
2491 if (row->y + 1 >= yb)
2492 break;
2494 ++row;
2497 /* Find the right column within BEST_ROW. */
2498 lastcol = 0;
2499 row = best_row;
2500 for (i = 0; i < row->used[TEXT_AREA]; i++)
2502 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
2503 int charpos;
2505 charpos = glyph->charpos;
2506 if (charpos == pos)
2508 *hpos = i;
2509 *vpos = row->y;
2510 return 1;
2512 else if (charpos > pos)
2513 break;
2514 else if (charpos > 0)
2515 lastcol = i;
2518 /* If we're looking for the end of the buffer,
2519 and we didn't find it in the line we scanned,
2520 use the start of the following line. */
2521 if (maybe_next_line_p)
2523 ++row;
2524 lastcol = 0;
2527 *vpos = row->y;
2528 *hpos = lastcol + 1;
2529 return 0;
2532 static void
2533 term_mouse_highlight (struct frame *f, int x, int y)
2535 enum window_part part;
2536 Lisp_Object window;
2537 struct window *w;
2538 struct buffer *b;
2540 if (NILP (Vmouse_highlight)
2541 || !f->glyphs_initialized_p)
2542 return;
2544 /* Which window is that in? */
2545 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
2547 /* Not on a window -> return. */
2548 if (!WINDOWP (window))
2549 return;
2551 if (!EQ (window, Qmouse_face_window))
2552 term_clear_mouse_face ();
2554 w = XWINDOW (window);
2556 /* Are we in a window whose display is up to date?
2557 And verify the buffer's text has not changed. */
2558 b = XBUFFER (w->buffer);
2559 if (part == ON_TEXT
2560 && EQ (w->window_end_valid, w->buffer)
2561 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
2562 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
2564 int pos, i, nrows = w->current_matrix->nrows;
2565 struct glyph_row *row;
2566 struct glyph *glyph;
2568 /* Find the glyph under X/Y. */
2569 glyph = NULL;
2570 if (y >= 0 && y < nrows)
2572 row = MATRIX_ROW (w->current_matrix, y);
2573 /* Give up if some row before the one we are looking for is
2574 not enabled. */
2575 for (i = 0; i <= y; i++)
2576 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
2577 break;
2578 if (i > y /* all rows upto and including the one at Y are enabled */
2579 && row->displays_text_p
2580 && x < window_box_width (w, TEXT_AREA))
2582 glyph = row->glyphs[TEXT_AREA];
2583 if (x >= row->used[TEXT_AREA])
2584 glyph = NULL;
2585 else
2587 glyph += x;
2588 if (!BUFFERP (glyph->object))
2589 glyph = NULL;
2594 /* Clear mouse face if X/Y not over text. */
2595 if (glyph == NULL)
2597 term_clear_mouse_face ();
2598 return;
2601 if (!BUFFERP (glyph->object))
2602 abort ();
2603 pos = glyph->charpos;
2605 /* Check for mouse-face. */
2607 extern Lisp_Object Qmouse_face;
2608 Lisp_Object mouse_face, overlay, position, *overlay_vec;
2609 int noverlays, obegv, ozv;
2610 struct buffer *obuf;
2612 /* If we get an out-of-range value, return now; avoid an error. */
2613 if (pos > BUF_Z (b))
2614 return;
2616 /* Make the window's buffer temporarily current for
2617 overlays_at and compute_char_face. */
2618 obuf = current_buffer;
2619 current_buffer = b;
2620 obegv = BEGV;
2621 ozv = ZV;
2622 BEGV = BEG;
2623 ZV = Z;
2625 /* Is this char mouse-active? */
2626 XSETINT (position, pos);
2628 /* Put all the overlays we want in a vector in overlay_vec. */
2629 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
2630 /* Sort overlays into increasing priority order. */
2631 noverlays = sort_overlays (overlay_vec, noverlays, w);
2633 /* Check mouse-face highlighting. */
2634 if (!(EQ (window, Qmouse_face_window)
2635 && y >= mouse_face_beg_row
2636 && y <= mouse_face_end_row
2637 && (y > mouse_face_beg_row
2638 || x >= mouse_face_beg_col)
2639 && (y < mouse_face_end_row
2640 || x < mouse_face_end_col
2641 || mouse_face_past_end)))
2643 /* Clear the display of the old active region, if any. */
2644 term_clear_mouse_face ();
2646 /* Find the highest priority overlay that has a mouse-face
2647 property. */
2648 overlay = Qnil;
2649 for (i = noverlays - 1; i >= 0; --i)
2651 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
2652 if (!NILP (mouse_face))
2654 overlay = overlay_vec[i];
2655 break;
2659 /* If no overlay applies, get a text property. */
2660 if (NILP (overlay))
2661 mouse_face = Fget_text_property (position, Qmouse_face,
2662 w->buffer);
2664 /* Handle the overlay case. */
2665 if (!NILP (overlay))
2667 /* Find the range of text around this char that
2668 should be active. */
2669 Lisp_Object before, after;
2670 int ignore;
2673 before = Foverlay_start (overlay);
2674 after = Foverlay_end (overlay);
2675 /* Record this as the current active region. */
2676 fast_find_position (w, XFASTINT (before),
2677 &mouse_face_beg_col,
2678 &mouse_face_beg_row);
2680 mouse_face_past_end
2681 = !fast_find_position (w, XFASTINT (after),
2682 &mouse_face_end_col,
2683 &mouse_face_end_row);
2684 Qmouse_face_window = window;
2686 mouse_face_face_id
2687 = face_at_buffer_position (w, pos, 0, 0,
2688 &ignore, pos + 1, 1);
2690 /* Display it as active. */
2691 term_show_mouse_face (DRAW_MOUSE_FACE);
2693 /* Handle the text property case. */
2694 else if (!NILP (mouse_face))
2696 /* Find the range of text around this char that
2697 should be active. */
2698 Lisp_Object before, after, beginning, end;
2699 int ignore;
2701 beginning = Fmarker_position (w->start);
2702 XSETINT (end, (BUF_Z (b) - XFASTINT (w->window_end_pos)));
2703 before
2704 = Fprevious_single_property_change (make_number (pos + 1),
2705 Qmouse_face,
2706 w->buffer, beginning);
2707 after
2708 = Fnext_single_property_change (position, Qmouse_face,
2709 w->buffer, end);
2711 /* Record this as the current active region. */
2712 fast_find_position (w, XFASTINT (before),
2713 &mouse_face_beg_col,
2714 &mouse_face_beg_row);
2715 mouse_face_past_end
2716 = !fast_find_position (w, XFASTINT (after),
2717 &mouse_face_end_col,
2718 &mouse_face_end_row);
2719 Qmouse_face_window = window;
2721 mouse_face_face_id
2722 = face_at_buffer_position (w, pos, 0, 0,
2723 &ignore, pos + 1, 1);
2725 /* Display it as active. */
2726 term_show_mouse_face (DRAW_MOUSE_FACE);
2730 /* Look for a `help-echo' property. */
2732 Lisp_Object help;
2733 extern Lisp_Object Qhelp_echo;
2735 /* Check overlays first. */
2736 help = Qnil;
2737 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
2739 overlay = overlay_vec[i];
2740 help = Foverlay_get (overlay, Qhelp_echo);
2743 if (!NILP (help))
2745 help_echo_string = help;
2746 help_echo_window = window;
2747 help_echo_object = overlay;
2748 help_echo_pos = pos;
2750 /* Try text properties. */
2751 else if (NILP (help)
2752 && ((STRINGP (glyph->object)
2753 && glyph->charpos >= 0
2754 && glyph->charpos < SCHARS (glyph->object))
2755 || (BUFFERP (glyph->object)
2756 && glyph->charpos >= BEGV
2757 && glyph->charpos < ZV)))
2759 help = Fget_text_property (make_number (glyph->charpos),
2760 Qhelp_echo, glyph->object);
2761 if (!NILP (help))
2763 help_echo_string = help;
2764 help_echo_window = window;
2765 help_echo_object = glyph->object;
2766 help_echo_pos = glyph->charpos;
2771 BEGV = obegv;
2772 ZV = ozv;
2773 current_buffer = obuf;
2778 static int
2779 term_mouse_movement (FRAME_PTR frame, Gpm_Event *event)
2781 /* Has the mouse moved off the glyph it was on at the last sighting? */
2782 if (event->x != last_mouse_x || event->y != last_mouse_y)
2784 frame->mouse_moved = 1;
2785 term_mouse_highlight (frame, event->x, event->y);
2786 /* Remember which glyph we're now on. */
2787 last_mouse_x = event->x;
2788 last_mouse_y = event->y;
2789 return 1;
2791 return 0;
2794 /* Return the current position of the mouse.
2796 Set *f to the frame the mouse is in, or zero if the mouse is in no
2797 Emacs frame. If it is set to zero, all the other arguments are
2798 garbage.
2800 Set *bar_window to Qnil, and *x and *y to the column and
2801 row of the character cell the mouse is over.
2803 Set *time to the time the mouse was at the returned position.
2805 This clears mouse_moved until the next motion
2806 event arrives. */
2807 static void
2808 term_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window,
2809 enum scroll_bar_part *part, Lisp_Object *x,
2810 Lisp_Object *y, unsigned long *time)
2812 struct timeval now;
2814 *fp = SELECTED_FRAME ();
2815 (*fp)->mouse_moved = 0;
2817 *bar_window = Qnil;
2818 *part = 0;
2820 XSETINT (*x, last_mouse_x);
2821 XSETINT (*y, last_mouse_y);
2822 gettimeofday(&now, 0);
2823 *time = (now.tv_sec * 1000) + (now.tv_usec / 1000);
2826 /* Prepare a mouse-event in *RESULT for placement in the input queue.
2828 If the event is a button press, then note that we have grabbed
2829 the mouse. */
2831 static Lisp_Object
2832 term_mouse_click (struct input_event *result, Gpm_Event *event,
2833 struct frame *f)
2835 struct timeval now;
2836 int i, j;
2838 result->kind = GPM_CLICK_EVENT;
2839 for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
2841 if (event->buttons & j) {
2842 result->code = i; /* button number */
2843 break;
2846 gettimeofday(&now, 0);
2847 result->timestamp = (now.tv_sec * 1000) + (now.tv_usec / 1000);
2849 if (event->type & GPM_UP)
2850 result->modifiers = up_modifier;
2851 else if (event->type & GPM_DOWN)
2852 result->modifiers = down_modifier;
2853 else
2854 result->modifiers = 0;
2856 if (event->type & GPM_SINGLE)
2857 result->modifiers |= click_modifier;
2859 if (event->type & GPM_DOUBLE)
2860 result->modifiers |= double_modifier;
2862 if (event->type & GPM_TRIPLE)
2863 result->modifiers |= triple_modifier;
2865 if (event->type & GPM_DRAG)
2866 result->modifiers |= drag_modifier;
2868 if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
2870 /* 1 << KG_SHIFT */
2871 if (event->modifiers & (1 << 0))
2872 result->modifiers |= shift_modifier;
2874 /* 1 << KG_CTRL */
2875 if (event->modifiers & (1 << 2))
2876 result->modifiers |= ctrl_modifier;
2878 /* 1 << KG_ALT || KG_ALTGR */
2879 if (event->modifiers & (1 << 3)
2880 || event->modifiers & (1 << 1))
2881 result->modifiers |= meta_modifier;
2884 XSETINT (result->x, event->x);
2885 XSETINT (result->y, event->y);
2886 XSETFRAME (result->frame_or_window, f);
2887 result->arg = Qnil;
2888 return Qnil;
2891 int
2892 handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event, struct input_event* hold_quit)
2894 struct frame *f = XFRAME (tty->top_frame);
2895 int fd;
2896 struct input_event ie;
2897 int do_help = 0;
2898 int count = 0;
2900 EVENT_INIT (ie);
2901 ie.kind = NO_EVENT;
2902 ie.arg = Qnil;
2904 if (event->type & (GPM_MOVE | GPM_DRAG)) {
2905 unsigned char buf[6 * sizeof (short)];
2906 unsigned short *arg = (unsigned short *) buf + 1;
2907 const char *name;
2909 previous_help_echo_string = help_echo_string;
2910 help_echo_string = Qnil;
2912 /* Display mouse pointer */
2913 buf[sizeof(short) - 1] = 2; /* set selection */
2915 arg[0] = arg[2] = (unsigned short) event->x + gpm_zerobased;
2916 arg[1] = arg[3] = (unsigned short) event->y + gpm_zerobased;
2917 arg[4] = (unsigned short) 3;
2919 name = ttyname (0);
2920 fd = open (name, O_WRONLY);
2921 ioctl (fd, TIOCLINUX, buf + sizeof (short) - 1);
2922 close (fd);
2924 if (!term_mouse_movement (f, event))
2925 help_echo_string = previous_help_echo_string;
2927 /* If the contents of the global variable help_echo_string
2928 has changed, generate a HELP_EVENT. */
2929 if (!NILP (help_echo_string)
2930 || !NILP (previous_help_echo_string))
2931 do_help = 1;
2933 goto done;
2935 else {
2936 f->mouse_moved = 0;
2937 term_mouse_click (&ie, event, f);
2940 done:
2941 if (ie.kind != NO_EVENT)
2943 kbd_buffer_store_event_hold (&ie, hold_quit);
2944 count++;
2947 if (do_help
2948 && !(hold_quit && hold_quit->kind != NO_EVENT))
2950 Lisp_Object frame;
2952 if (f)
2953 XSETFRAME (frame, f);
2954 else
2955 frame = Qnil;
2957 gen_help_event (help_echo_string, frame, help_echo_window,
2958 help_echo_object, help_echo_pos);
2959 count++;
2962 return count;
2965 DEFUN ("term-open-connection", Fterm_open_connection, Sterm_open_connection,
2966 0, 0, 0,
2967 doc: /* Open a connection to Gpm. */)
2970 struct tty_display_info *tty = FRAME_TTY (SELECTED_FRAME ());
2971 Gpm_Connect connection;
2973 connection.eventMask = ~0;
2974 connection.defaultMask = ~GPM_HARD;
2975 connection.maxMod = ~0;
2976 connection.minMod = 0;
2977 gpm_zerobased = 1;
2979 /* We only support GPM on the controlling tty. */
2980 if (term_gpm || tty->terminal->id > 1
2981 || Gpm_Open (&connection, 0) < 0)
2982 return Qnil;
2983 else
2985 term_gpm = 1;
2986 gpm_tty = tty->terminal->id;
2987 reset_sys_modes (tty);
2988 init_sys_modes (tty);
2989 add_gpm_wait_descriptor (gpm_fd);
2990 return Qt;
2994 DEFUN ("term-close-connection", Fterm_close_connection, Sterm_close_connection,
2995 0, 0, 0,
2996 doc: /* Close a connection to Gpm. */)
2999 delete_gpm_wait_descriptor (gpm_fd);
3000 while (Gpm_Close()); /* close all the stack */
3001 term_gpm = 0;
3002 return Qnil;
3004 #endif /* HAVE_GPM */
3007 /***********************************************************************
3008 Initialization
3009 ***********************************************************************/
3011 /* Initialize the tty-dependent part of frame F. The frame must
3012 already have its device initialized. */
3014 void
3015 create_tty_output (struct frame *f)
3017 struct tty_output *t;
3019 if (! FRAME_TERMCAP_P (f))
3020 abort ();
3022 t = xmalloc (sizeof (struct tty_output));
3023 bzero (t, sizeof (struct tty_output));
3025 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
3027 f->output_data.tty = t;
3030 /* Delete the tty-dependent part of frame F. */
3032 static void
3033 delete_tty_output (struct frame *f)
3035 if (! FRAME_TERMCAP_P (f))
3036 abort ();
3038 xfree (f->output_data.tty);
3042 /* Reset the hooks in TERMINAL. */
3044 static void
3045 clear_tty_hooks (struct terminal *terminal)
3047 terminal->rif = 0;
3048 terminal->cursor_to_hook = 0;
3049 terminal->raw_cursor_to_hook = 0;
3050 terminal->clear_to_end_hook = 0;
3051 terminal->clear_frame_hook = 0;
3052 terminal->clear_end_of_line_hook = 0;
3053 terminal->ins_del_lines_hook = 0;
3054 terminal->insert_glyphs_hook = 0;
3055 terminal->write_glyphs_hook = 0;
3056 terminal->delete_glyphs_hook = 0;
3057 terminal->ring_bell_hook = 0;
3058 terminal->reset_terminal_modes_hook = 0;
3059 terminal->set_terminal_modes_hook = 0;
3060 terminal->update_begin_hook = 0;
3061 terminal->update_end_hook = 0;
3062 terminal->set_terminal_window_hook = 0;
3063 terminal->mouse_position_hook = 0;
3064 terminal->frame_rehighlight_hook = 0;
3065 terminal->frame_raise_lower_hook = 0;
3066 terminal->fullscreen_hook = 0;
3067 terminal->set_vertical_scroll_bar_hook = 0;
3068 terminal->condemn_scroll_bars_hook = 0;
3069 terminal->redeem_scroll_bar_hook = 0;
3070 terminal->judge_scroll_bars_hook = 0;
3071 terminal->read_socket_hook = 0;
3072 terminal->frame_up_to_date_hook = 0;
3074 /* Leave these two set, or suspended frames are not deleted
3075 correctly. */
3076 terminal->delete_frame_hook = &delete_tty_output;
3077 terminal->delete_terminal_hook = &delete_tty;
3080 /* Initialize hooks in TERMINAL with the values needed for a tty. */
3082 static void
3083 set_tty_hooks (struct terminal *terminal)
3085 terminal->rif = 0; /* ttys don't support window-based redisplay. */
3087 terminal->cursor_to_hook = &tty_cursor_to;
3088 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
3090 terminal->clear_to_end_hook = &tty_clear_to_end;
3091 terminal->clear_frame_hook = &tty_clear_frame;
3092 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
3094 terminal->ins_del_lines_hook = &tty_ins_del_lines;
3096 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3097 terminal->write_glyphs_hook = &tty_write_glyphs;
3098 terminal->delete_glyphs_hook = &tty_delete_glyphs;
3100 terminal->ring_bell_hook = &tty_ring_bell;
3102 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3103 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
3104 terminal->update_begin_hook = 0; /* Not needed. */
3105 terminal->update_end_hook = &tty_update_end;
3106 terminal->set_terminal_window_hook = &tty_set_terminal_window;
3108 terminal->mouse_position_hook = 0; /* Not needed. */
3109 terminal->frame_rehighlight_hook = 0; /* Not needed. */
3110 terminal->frame_raise_lower_hook = 0; /* Not needed. */
3112 terminal->set_vertical_scroll_bar_hook = 0; /* Not needed. */
3113 terminal->condemn_scroll_bars_hook = 0; /* Not needed. */
3114 terminal->redeem_scroll_bar_hook = 0; /* Not needed. */
3115 terminal->judge_scroll_bars_hook = 0; /* Not needed. */
3117 terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
3118 terminal->frame_up_to_date_hook = 0; /* Not needed. */
3120 terminal->delete_frame_hook = &delete_tty_output;
3121 terminal->delete_terminal_hook = &delete_tty;
3124 /* Drop the controlling terminal if fd is the same device. */
3125 static void
3126 dissociate_if_controlling_tty (int fd)
3128 #ifndef WINDOWSNT
3129 int pgid;
3130 EMACS_GET_TTY_PGRP (fd, &pgid); /* If tcgetpgrp succeeds, fd is the ctty. */
3131 if (pgid != -1)
3133 #if defined (USG) && !defined (BSD_PGRPS)
3134 setpgrp ();
3135 no_controlling_tty = 1;
3136 #elif defined (CYGWIN)
3137 setsid ();
3138 no_controlling_tty = 1;
3139 #else
3140 #ifdef TIOCNOTTY /* Try BSD ioctls. */
3141 sigblock (sigmask (SIGTTOU));
3142 fd = emacs_open ("/dev/tty", O_RDWR, 0);
3143 if (fd != -1 && ioctl (fd, TIOCNOTTY, 0) != -1)
3145 no_controlling_tty = 1;
3147 if (fd != -1)
3148 emacs_close (fd);
3149 sigunblock (sigmask (SIGTTOU));
3150 #else
3151 /* Unknown system. */
3152 croak ();
3153 #endif /* ! TIOCNOTTY */
3154 #endif /* ! USG */
3156 #endif
3159 static void maybe_fatal();
3161 /* Create a termcap display on the tty device with the given name and
3162 type.
3164 If NAME is NULL, then use the controlling tty, i.e., "/dev/tty".
3165 Otherwise NAME should be a path to the tty device file,
3166 e.g. "/dev/pts/7".
3168 TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
3170 If MUST_SUCCEED is true, then all errors are fatal. */
3172 struct terminal *
3173 init_tty (char *name, char *terminal_type, int must_succeed)
3175 char *area = NULL;
3176 char **address = &area;
3177 char *buffer = NULL;
3178 int buffer_size = 4096;
3179 register char *p = NULL;
3180 int status;
3181 struct tty_display_info *tty = NULL;
3182 struct terminal *terminal = NULL;
3183 int ctty = 0; /* 1 if asked to open controlling tty. */
3185 if (!terminal_type)
3186 maybe_fatal (must_succeed, 0, 0,
3187 "Unknown terminal type",
3188 "Unknown terminal type");
3190 #ifndef WINDOWSNT
3191 if (name == NULL)
3192 name = "/dev/tty";
3193 if (!strcmp (name, "/dev/tty"))
3194 ctty = 1;
3196 /* If we already have a terminal on the given device, use that. If
3197 all such terminals are suspended, create a new one instead. */
3198 /* XXX Perhaps this should be made explicit by having init_tty
3199 always create a new terminal and separating terminal and frame
3200 creation on Lisp level. */
3201 terminal = get_named_tty (name);
3202 if (terminal)
3203 return terminal;
3204 #endif
3206 terminal = create_terminal ();
3207 tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info));
3208 bzero (tty, sizeof (struct tty_display_info));
3209 tty->next = tty_list;
3210 tty_list = tty;
3212 terminal->type = output_termcap;
3213 terminal->display_info.tty = tty;
3214 tty->terminal = terminal;
3216 tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
3217 Wcm_clear (tty);
3219 #ifndef WINDOWSNT
3220 set_tty_hooks (terminal);
3223 int fd;
3224 FILE *file;
3226 #ifdef O_IGNORE_CTTY
3227 if (!ctty)
3228 /* Open the terminal device. Don't recognize it as our
3229 controlling terminal, and don't make it the controlling tty
3230 if we don't have one at the moment. */
3231 fd = emacs_open (name, O_RDWR | O_IGNORE_CTTY | O_NOCTTY, 0);
3232 else
3233 #else
3234 /* Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
3235 defined on Hurd. On other systems, we need to explicitly
3236 dissociate ourselves from the controlling tty when we want to
3237 open a frame on the same terminal. */
3238 fd = emacs_open (name, O_RDWR | O_NOCTTY, 0);
3239 #endif /* O_IGNORE_CTTY */
3241 if (fd < 0)
3242 maybe_fatal (must_succeed, buffer, terminal,
3243 "Could not open file: %s",
3244 "Could not open file: %s",
3245 name);
3246 if (!isatty (fd))
3248 close (fd);
3249 maybe_fatal (must_succeed, buffer, terminal,
3250 "Not a tty device: %s",
3251 "Not a tty device: %s",
3252 name);
3255 #ifndef O_IGNORE_CTTY
3256 if (!ctty)
3257 dissociate_if_controlling_tty (fd);
3258 #endif
3260 file = fdopen (fd, "w+");
3261 tty->name = xstrdup (name);
3262 terminal->name = xstrdup (name);
3263 tty->input = file;
3264 tty->output = file;
3267 tty->type = xstrdup (terminal_type);
3269 add_keyboard_wait_descriptor (fileno (tty->input));
3271 #endif
3273 encode_terminal_bufsize = 0;
3275 #ifdef HAVE_GPM
3276 terminal->mouse_position_hook = term_mouse_position;
3277 Qmouse_face_window = Qnil;
3278 #endif
3280 #ifdef WINDOWSNT
3281 initialize_w32_display (terminal);
3282 /* The following two are inaccessible from w32console.c. */
3283 terminal->delete_frame_hook = &delete_tty_output;
3284 terminal->delete_terminal_hook = &delete_tty;
3286 /* XXX Can this be non-null? */
3287 if (name)
3289 tty->name = xstrdup (name);
3290 terminal->name = xstrdup (name);
3292 tty->type = xstrdup (terminal_type);
3294 tty->output = stdout;
3295 tty->input = stdin;
3296 add_keyboard_wait_descriptor (0);
3298 Wcm_clear (tty);
3301 struct frame *f = XFRAME (selected_frame);
3303 FrameRows (tty) = FRAME_LINES (f);
3304 FrameCols (tty) = FRAME_COLS (f);
3305 tty->specified_window = FRAME_LINES (f);
3307 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
3308 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
3310 tty->delete_in_insert_mode = 1;
3312 UseTabs (tty) = 0;
3313 terminal->scroll_region_ok = 0;
3315 /* Seems to insert lines when it's not supposed to, messing up the
3316 display. In doing a trace, it didn't seem to be called much, so I
3317 don't think we're losing anything by turning it off. */
3318 terminal->line_ins_del_ok = 0;
3319 terminal->char_ins_del_ok = 1;
3321 baud_rate = 19200;
3323 tty->TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */
3325 #else /* not WINDOWSNT */
3327 Wcm_clear (tty);
3329 buffer = (char *) xmalloc (buffer_size);
3331 /* On some systems, tgetent tries to access the controlling
3332 terminal. */
3333 sigblock (sigmask (SIGTTOU));
3334 status = tgetent (buffer, terminal_type);
3335 sigunblock (sigmask (SIGTTOU));
3337 if (status < 0)
3339 #ifdef TERMINFO
3340 maybe_fatal (must_succeed, buffer, terminal,
3341 "Cannot open terminfo database file",
3342 "Cannot open terminfo database file");
3343 #else
3344 maybe_fatal (must_succeed, buffer, terminal,
3345 "Cannot open termcap database file",
3346 "Cannot open termcap database file");
3347 #endif
3349 if (status == 0)
3351 #ifdef TERMINFO
3352 maybe_fatal (must_succeed, buffer, terminal,
3353 "Terminal type %s is not defined",
3354 "Terminal type %s is not defined.\n\
3355 If that is not the actual type of terminal you have,\n\
3356 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3357 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3358 to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
3359 terminal_type);
3360 #else
3361 maybe_fatal (must_succeed, buffer, terminal,
3362 "Terminal type %s is not defined",
3363 "Terminal type %s is not defined.\n\
3364 If that is not the actual type of terminal you have,\n\
3365 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3366 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3367 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
3368 terminal_type);
3369 #endif
3372 #ifndef TERMINFO
3373 if (strlen (buffer) >= buffer_size)
3374 abort ();
3375 buffer_size = strlen (buffer);
3376 #endif
3377 area = (char *) xmalloc (buffer_size);
3379 tty->TS_ins_line = tgetstr ("al", address);
3380 tty->TS_ins_multi_lines = tgetstr ("AL", address);
3381 tty->TS_bell = tgetstr ("bl", address);
3382 BackTab (tty) = tgetstr ("bt", address);
3383 tty->TS_clr_to_bottom = tgetstr ("cd", address);
3384 tty->TS_clr_line = tgetstr ("ce", address);
3385 tty->TS_clr_frame = tgetstr ("cl", address);
3386 ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
3387 AbsPosition (tty) = tgetstr ("cm", address);
3388 CR (tty) = tgetstr ("cr", address);
3389 tty->TS_set_scroll_region = tgetstr ("cs", address);
3390 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
3391 RowPosition (tty) = tgetstr ("cv", address);
3392 tty->TS_del_char = tgetstr ("dc", address);
3393 tty->TS_del_multi_chars = tgetstr ("DC", address);
3394 tty->TS_del_line = tgetstr ("dl", address);
3395 tty->TS_del_multi_lines = tgetstr ("DL", address);
3396 tty->TS_delete_mode = tgetstr ("dm", address);
3397 tty->TS_end_delete_mode = tgetstr ("ed", address);
3398 tty->TS_end_insert_mode = tgetstr ("ei", address);
3399 Home (tty) = tgetstr ("ho", address);
3400 tty->TS_ins_char = tgetstr ("ic", address);
3401 tty->TS_ins_multi_chars = tgetstr ("IC", address);
3402 tty->TS_insert_mode = tgetstr ("im", address);
3403 tty->TS_pad_inserted_char = tgetstr ("ip", address);
3404 tty->TS_end_keypad_mode = tgetstr ("ke", address);
3405 tty->TS_keypad_mode = tgetstr ("ks", address);
3406 LastLine (tty) = tgetstr ("ll", address);
3407 Right (tty) = tgetstr ("nd", address);
3408 Down (tty) = tgetstr ("do", address);
3409 if (!Down (tty))
3410 Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */
3411 #ifdef VMS
3412 /* VMS puts a carriage return before each linefeed,
3413 so it is not safe to use linefeeds. */
3414 if (Down (tty) && Down (tty)[0] == '\n' && Down (tty)[1] == '\0')
3415 Down (tty) = 0;
3416 #endif /* VMS */
3417 if (tgetflag ("bs"))
3418 Left (tty) = "\b"; /* can't possibly be longer! */
3419 else /* (Actually, "bs" is obsolete...) */
3420 Left (tty) = tgetstr ("le", address);
3421 if (!Left (tty))
3422 Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */
3423 tty->TS_pad_char = tgetstr ("pc", address);
3424 tty->TS_repeat = tgetstr ("rp", address);
3425 tty->TS_end_standout_mode = tgetstr ("se", address);
3426 tty->TS_fwd_scroll = tgetstr ("sf", address);
3427 tty->TS_standout_mode = tgetstr ("so", address);
3428 tty->TS_rev_scroll = tgetstr ("sr", address);
3429 tty->Wcm->cm_tab = tgetstr ("ta", address);
3430 tty->TS_end_termcap_modes = tgetstr ("te", address);
3431 tty->TS_termcap_modes = tgetstr ("ti", address);
3432 Up (tty) = tgetstr ("up", address);
3433 tty->TS_visible_bell = tgetstr ("vb", address);
3434 tty->TS_cursor_normal = tgetstr ("ve", address);
3435 tty->TS_cursor_visible = tgetstr ("vs", address);
3436 tty->TS_cursor_invisible = tgetstr ("vi", address);
3437 tty->TS_set_window = tgetstr ("wi", address);
3439 tty->TS_enter_underline_mode = tgetstr ("us", address);
3440 tty->TS_exit_underline_mode = tgetstr ("ue", address);
3441 tty->TS_enter_bold_mode = tgetstr ("md", address);
3442 tty->TS_enter_dim_mode = tgetstr ("mh", address);
3443 tty->TS_enter_blink_mode = tgetstr ("mb", address);
3444 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
3445 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
3446 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
3447 tty->TS_exit_attribute_mode = tgetstr ("me", address);
3449 MultiUp (tty) = tgetstr ("UP", address);
3450 MultiDown (tty) = tgetstr ("DO", address);
3451 MultiLeft (tty) = tgetstr ("LE", address);
3452 MultiRight (tty) = tgetstr ("RI", address);
3454 /* SVr4/ANSI color suppert. If "op" isn't available, don't support
3455 color because we can't switch back to the default foreground and
3456 background. */
3457 tty->TS_orig_pair = tgetstr ("op", address);
3458 if (tty->TS_orig_pair)
3460 tty->TS_set_foreground = tgetstr ("AF", address);
3461 tty->TS_set_background = tgetstr ("AB", address);
3462 if (!tty->TS_set_foreground)
3464 /* SVr4. */
3465 tty->TS_set_foreground = tgetstr ("Sf", address);
3466 tty->TS_set_background = tgetstr ("Sb", address);
3469 tty->TN_max_colors = tgetnum ("Co");
3470 tty->TN_max_pairs = tgetnum ("pa");
3472 tty->TN_no_color_video = tgetnum ("NC");
3473 if (tty->TN_no_color_video == -1)
3474 tty->TN_no_color_video = 0;
3477 tty_default_color_capabilities (tty, 1);
3479 MagicWrap (tty) = tgetflag ("xn");
3480 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
3481 the former flag imply the latter. */
3482 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
3483 terminal->memory_below_frame = tgetflag ("db");
3484 tty->TF_hazeltine = tgetflag ("hz");
3485 terminal->must_write_spaces = tgetflag ("in");
3486 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
3487 tty->TF_insmode_motion = tgetflag ("mi");
3488 tty->TF_standout_motion = tgetflag ("ms");
3489 tty->TF_underscore = tgetflag ("ul");
3490 tty->TF_teleray = tgetflag ("xt");
3492 #endif /* !WINDOWSNT */
3493 #ifdef MULTI_KBOARD
3494 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3495 init_kboard (terminal->kboard);
3496 terminal->kboard->next_kboard = all_kboards;
3497 all_kboards = terminal->kboard;
3498 terminal->kboard->reference_count++;
3499 /* Don't let the initial kboard remain current longer than necessary.
3500 That would cause problems if a file loaded on startup tries to
3501 prompt in the mini-buffer. */
3502 if (current_kboard == initial_kboard)
3503 current_kboard = terminal->kboard;
3504 #ifndef WINDOWSNT
3505 term_get_fkeys (address, terminal->kboard);
3506 #endif
3507 #endif
3509 #ifndef WINDOWSNT
3510 /* Get frame size from system, or else from termcap. */
3512 int height, width;
3513 get_tty_size (fileno (tty->input), &width, &height);
3514 FrameCols (tty) = width;
3515 FrameRows (tty) = height;
3518 if (FrameCols (tty) <= 0)
3519 FrameCols (tty) = tgetnum ("co");
3520 if (FrameRows (tty) <= 0)
3521 FrameRows (tty) = tgetnum ("li");
3523 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
3524 maybe_fatal (must_succeed, NULL, terminal,
3525 "Screen size %dx%d is too small"
3526 "Screen size %dx%d is too small",
3527 FrameCols (tty), FrameRows (tty));
3529 #if 0 /* This is not used anywhere. */
3530 tty->terminal->min_padding_speed = tgetnum ("pb");
3531 #endif
3533 TabWidth (tty) = tgetnum ("tw");
3535 #ifdef VMS
3536 /* These capabilities commonly use ^J.
3537 I don't know why, but sending them on VMS does not work;
3538 it causes following spaces to be lost, sometimes.
3539 For now, the simplest fix is to avoid using these capabilities ever. */
3540 if (Down (tty) && Down (tty)[0] == '\n')
3541 Down (tty) = 0;
3542 #endif /* VMS */
3544 if (!tty->TS_bell)
3545 tty->TS_bell = "\07";
3547 if (!tty->TS_fwd_scroll)
3548 tty->TS_fwd_scroll = Down (tty);
3550 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
3552 if (TabWidth (tty) < 0)
3553 TabWidth (tty) = 8;
3555 /* Turned off since /etc/termcap seems to have :ta= for most terminals
3556 and newer termcap doc does not seem to say there is a default.
3557 if (!tty->Wcm->cm_tab)
3558 tty->Wcm->cm_tab = "\t";
3561 /* We don't support standout modes that use `magic cookies', so
3562 turn off any that do. */
3563 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
3565 tty->TS_standout_mode = 0;
3566 tty->TS_end_standout_mode = 0;
3568 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
3570 tty->TS_enter_underline_mode = 0;
3571 tty->TS_exit_underline_mode = 0;
3574 /* If there's no standout mode, try to use underlining instead. */
3575 if (tty->TS_standout_mode == 0)
3577 tty->TS_standout_mode = tty->TS_enter_underline_mode;
3578 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
3581 /* If no `se' string, try using a `me' string instead.
3582 If that fails, we can't use standout mode at all. */
3583 if (tty->TS_end_standout_mode == 0)
3585 char *s = tgetstr ("me", address);
3586 if (s != 0)
3587 tty->TS_end_standout_mode = s;
3588 else
3589 tty->TS_standout_mode = 0;
3592 if (tty->TF_teleray)
3594 tty->Wcm->cm_tab = 0;
3595 /* We can't support standout mode, because it uses magic cookies. */
3596 tty->TS_standout_mode = 0;
3597 /* But that means we cannot rely on ^M to go to column zero! */
3598 CR (tty) = 0;
3599 /* LF can't be trusted either -- can alter hpos */
3600 /* if move at column 0 thru a line with TS_standout_mode */
3601 Down (tty) = 0;
3604 /* Special handling for certain terminal types known to need it */
3606 if (!strcmp (terminal_type, "supdup"))
3608 terminal->memory_below_frame = 1;
3609 tty->Wcm->cm_losewrap = 1;
3611 if (!strncmp (terminal_type, "c10", 3)
3612 || !strcmp (terminal_type, "perq"))
3614 /* Supply a makeshift :wi string.
3615 This string is not valid in general since it works only
3616 for windows starting at the upper left corner;
3617 but that is all Emacs uses.
3619 This string works only if the frame is using
3620 the top of the video memory, because addressing is memory-relative.
3621 So first check the :ti string to see if that is true.
3623 It would be simpler if the :wi string could go in the termcap
3624 entry, but it can't because it is not fully valid.
3625 If it were in the termcap entry, it would confuse other programs. */
3626 if (!tty->TS_set_window)
3628 p = tty->TS_termcap_modes;
3629 while (*p && strcmp (p, "\033v "))
3630 p++;
3631 if (*p)
3632 tty->TS_set_window = "\033v%C %C %C %C ";
3634 /* Termcap entry often fails to have :in: flag */
3635 terminal->must_write_spaces = 1;
3636 /* :ti string typically fails to have \E^G! in it */
3637 /* This limits scope of insert-char to one line. */
3638 strcpy (area, tty->TS_termcap_modes);
3639 strcat (area, "\033\007!");
3640 tty->TS_termcap_modes = area;
3641 area += strlen (area) + 1;
3642 p = AbsPosition (tty);
3643 /* Change all %+ parameters to %C, to handle
3644 values above 96 correctly for the C100. */
3645 while (*p)
3647 if (p[0] == '%' && p[1] == '+')
3648 p[1] = 'C';
3649 p++;
3653 tty->specified_window = FrameRows (tty);
3655 if (Wcm_init (tty) == -1) /* can't do cursor motion */
3657 maybe_fatal (must_succeed, NULL, terminal,
3658 "Terminal type \"%s\" is not powerful enough to run Emacs",
3659 #ifdef VMS
3660 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
3661 It lacks the ability to position the cursor.\n\
3662 If that is not the actual type of terminal you have, use either the\n\
3663 DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
3664 or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.",
3665 #else /* not VMS */
3666 # ifdef TERMINFO
3667 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
3668 It lacks the ability to position the cursor.\n\
3669 If that is not the actual type of terminal you have,\n\
3670 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3671 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3672 to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
3673 # else /* TERMCAP */
3674 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
3675 It lacks the ability to position the cursor.\n\
3676 If that is not the actual type of terminal you have,\n\
3677 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3678 `setenv TERM ...') to specify the correct type. It may be necessary\n\
3679 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
3680 # endif /* TERMINFO */
3681 #endif /*VMS */
3682 terminal_type);
3685 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
3686 maybe_fatal (must_succeed, NULL, terminal,
3687 "Could not determine the frame size",
3688 "Could not determine the frame size");
3690 tty->delete_in_insert_mode
3691 = tty->TS_delete_mode && tty->TS_insert_mode
3692 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
3694 tty->se_is_so = (tty->TS_standout_mode
3695 && tty->TS_end_standout_mode
3696 && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode));
3698 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
3700 terminal->scroll_region_ok
3701 = (tty->Wcm->cm_abs
3702 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
3704 terminal->line_ins_del_ok
3705 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
3706 && (tty->TS_del_line || tty->TS_del_multi_lines))
3707 || (terminal->scroll_region_ok
3708 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
3710 terminal->char_ins_del_ok
3711 = ((tty->TS_ins_char || tty->TS_insert_mode
3712 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
3713 && (tty->TS_del_char || tty->TS_del_multi_chars));
3715 terminal->fast_clear_end_of_line = tty->TS_clr_line != 0;
3717 init_baud_rate (fileno (tty->input));
3719 #ifdef AIXHFT
3720 /* The HFT system on AIX doesn't optimize for scrolling, so it's
3721 really ugly at times. */
3722 terminal->line_ins_del_ok = 0;
3723 terminal->char_ins_del_ok = 0;
3724 #endif
3726 /* Don't do this. I think termcap may still need the buffer. */
3727 /* xfree (buffer); */
3729 /* Init system terminal modes (RAW or CBREAK, etc.). */
3730 init_sys_modes (tty);
3731 #endif /* not WINDOWSNT */
3733 return terminal;
3736 /* Auxiliary error-handling function for init_tty.
3737 Free BUFFER and delete TERMINAL, then call error or fatal
3738 with str1 or str2, respectively, according to MUST_SUCCEED. */
3740 static void
3741 maybe_fatal (must_succeed, buffer, terminal, str1, str2, arg1, arg2)
3742 int must_succeed;
3743 char *buffer;
3744 struct terminal *terminal;
3745 char *str1, *str2, *arg1, *arg2;
3747 if (buffer)
3748 xfree (buffer);
3750 if (terminal)
3751 delete_tty (terminal);
3753 if (must_succeed)
3754 fatal (str2, arg1, arg2);
3755 else
3756 error (str1, arg1, arg2);
3758 abort ();
3761 /* VARARGS 1 */
3762 void
3763 fatal (str, arg1, arg2)
3764 char *str, *arg1, *arg2;
3766 fprintf (stderr, "emacs: ");
3767 fprintf (stderr, str, arg1, arg2);
3768 fprintf (stderr, "\n");
3769 fflush (stderr);
3770 exit (1);
3775 /* Delete the given tty terminal, closing all frames on it. */
3777 static void
3778 delete_tty (struct terminal *terminal)
3780 struct tty_display_info *tty;
3781 Lisp_Object tail, frame;
3782 int last_terminal;
3784 /* Protect against recursive calls. Fdelete_frame in
3785 delete_terminal calls us back when it deletes our last frame. */
3786 if (terminal->deleted)
3787 return;
3789 if (terminal->type != output_termcap)
3790 abort ();
3792 tty = terminal->display_info.tty;
3794 last_terminal = 1;
3795 FOR_EACH_FRAME (tail, frame)
3797 struct frame *f = XFRAME (frame);
3798 if (FRAME_LIVE_P (f) && (!FRAME_TERMCAP_P (f) || FRAME_TTY (f) != tty))
3800 last_terminal = 0;
3801 break;
3804 if (last_terminal)
3805 error ("Attempt to delete the sole terminal device with live frames");
3807 if (tty == tty_list)
3808 tty_list = tty->next;
3809 else
3811 struct tty_display_info *p;
3812 for (p = tty_list; p && p->next != tty; p = p->next)
3815 if (! p)
3816 /* This should not happen. */
3817 abort ();
3819 p->next = tty->next;
3820 tty->next = 0;
3823 /* reset_sys_modes needs a valid device, so this call needs to be
3824 before delete_terminal. */
3825 reset_sys_modes (tty);
3827 delete_terminal (terminal);
3829 if (tty->name)
3830 xfree (tty->name);
3832 if (tty->type)
3833 xfree (tty->type);
3835 if (tty->input)
3837 delete_keyboard_wait_descriptor (fileno (tty->input));
3838 if (tty->input != stdin)
3839 fclose (tty->input);
3841 if (tty->output && tty->output != stdout && tty->output != tty->input)
3842 fclose (tty->output);
3843 if (tty->termscript)
3844 fclose (tty->termscript);
3846 if (tty->old_tty)
3847 xfree (tty->old_tty);
3849 if (tty->Wcm)
3850 xfree (tty->Wcm);
3852 bzero (tty, sizeof (struct tty_display_info));
3853 xfree (tty);
3858 /* Mark the pointers in the tty_display_info objects.
3859 Called by the Fgarbage_collector. */
3861 void
3862 mark_ttys (void)
3864 struct tty_display_info *tty;
3866 for (tty = tty_list; tty; tty = tty->next)
3867 mark_object (tty->top_frame);
3872 void
3873 syms_of_term ()
3875 DEFVAR_BOOL ("system-uses-terminfo", &system_uses_terminfo,
3876 doc: /* Non-nil means the system uses terminfo rather than termcap.
3877 This variable can be used by terminal emulator packages. */);
3878 #ifdef TERMINFO
3879 system_uses_terminfo = 1;
3880 #else
3881 system_uses_terminfo = 0;
3882 #endif
3884 DEFVAR_LISP ("suspend-tty-functions", &Vsuspend_tty_functions,
3885 doc: /* Functions to be run after suspending a tty.
3886 The functions are run with one argument, the terminal id to be suspended.
3887 See `suspend-tty'. */);
3888 Vsuspend_tty_functions = Qnil;
3891 DEFVAR_LISP ("resume-tty-functions", &Vresume_tty_functions,
3892 doc: /* Functions to be run after resuming a tty.
3893 The functions are run with one argument, the terminal id that was revived.
3894 See `resume-tty'. */);
3895 Vresume_tty_functions = Qnil;
3897 DEFVAR_BOOL ("visible-cursor", &visible_cursor,
3898 doc: /* Non-nil means to make the cursor very visible.
3899 This only has an effect when running in a text terminal.
3900 What means \"very visible\" is up to your terminal. It may make the cursor
3901 bigger, or it may make it blink, or it may do nothing at all. */);
3902 visible_cursor = 1;
3904 defsubr (&Stty_display_color_p);
3905 defsubr (&Stty_display_color_cells);
3906 defsubr (&Stty_no_underline);
3907 defsubr (&Stty_type);
3908 defsubr (&Scontrolling_tty_p);
3909 defsubr (&Ssuspend_tty);
3910 defsubr (&Sresume_tty);
3911 #ifdef HAVE_GPM
3912 defsubr (&Sterm_open_connection);
3913 defsubr (&Sterm_close_connection);
3915 staticpro (&Qmouse_face_window);
3916 #endif /* HAVE_GPM */
3921 /* arch-tag: 498e7449-6f2e-45e2-91dd-b7d4ca488193
3922 (do not change this comment) */