1 /* Communication module for TTY terminals.
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1995 Sun Microsystems, Inc.
4 Copyright (C) 1995, 1996 Ben Wing.
5 Copyright (C) 1996 Chuck Thompson.
7 This file is part of XEmacs.
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* Synched up with: Not completely synched with FSF. Mostly divergent
27 /* This file has been Mule-ized. */
29 /* Written by Chuck Thompson. */
30 /* Color support added by Ben Wing. */
36 #include "console-tty.h"
42 #include "objects-tty.h"
43 #include "redisplay.h"
47 /* These headers #define all kinds of common words like "columns"...
48 What a bunch of losers. If we were to include them, we'd have to
49 include them last to prevent them from messing up our own header
50 files (struct slot names, etc.). But it turns out that there are
51 other conflicts as well on some systems, so screw it: we'll just
52 re-declare the routines we use and assume the code in this file is
53 invoking them correctly. */
54 /* # include <curses.h> */
55 /* # include <term.h> */
59 extern int tgetent (CONST char *, CONST char *);
60 extern int tgetflag (CONST char *);
61 extern int tgetnum (CONST char *);
62 extern char *tgetstr (CONST char *, char **);
63 extern void tputs (CONST char *, int, void (*)(int));
67 #define FORCE_CURSOR_UPDATE(c) send_string_to_tty_console (c, 0, 0)
68 #define OUTPUTN(c, a, n) \
71 FORCE_CURSOR_UPDATE (c); \
72 tputs (a, n, cmputc); \
74 #define OUTPUT1(c, a) OUTPUTN (c, a, 1)
75 #define OUTPUTN_IF(c, a, n) \
78 FORCE_CURSOR_UPDATE (c); \
80 tputs (a, n, cmputc); \
82 #define OUTPUT1_IF(c, a) OUTPUTN_IF (c, a, 1)
84 static void tty_output_emchar_dynarr (struct window *w,
85 struct display_line *dl,
86 Emchar_dynarr *buf, int xpos,
89 static void tty_output_bufbyte_string (struct window *w,
90 struct display_line *dl,
91 Bufbyte *str, Bytecount len,
92 int xpos, face_index findex,
94 static void tty_turn_on_face (struct window *w, face_index findex);
95 static void tty_turn_off_face (struct window *w, face_index findex);
96 static void tty_turn_on_frame_face (struct frame *f, Lisp_Object face);
97 static void tty_turn_off_frame_face (struct frame *f, Lisp_Object face);
99 static void term_get_fkeys (Lisp_Object keymap, char **address);
101 /*****************************************************************************
104 Non-Mule tty's don't have fonts (that we use at least), so everything
105 is considered to be fixed width -- in other words, we return LEN.
106 Under Mule, however, a character can still cover more than one
107 column, so we use emchar_string_displayed_columns().
108 ****************************************************************************/
110 tty_text_width (struct frame *f, struct face_cachel *cachel, CONST Emchar *str,
113 return emchar_string_displayed_columns (str, len);
116 /*****************************************************************************
119 Return the width of the horizontal divider. This is a function
120 because divider_height is a console method.
121 ****************************************************************************/
123 tty_divider_height (void)
128 /*****************************************************************************
131 Return the width of the end-of-line cursor. This is a function
132 because eol_cursor_width is a console method.
133 ****************************************************************************/
135 tty_eol_cursor_width (void)
140 /*****************************************************************************
143 Perform any necessary initialization prior to an update.
144 ****************************************************************************/
146 void tty_output_begin (struct device *d);
151 tty_output_begin (struct device *d)
154 /* Termcap requires `ospeed' to be a global variable so we have to
155 always set it for whatever tty console we are actually currently
157 ospeed = DEVICE_TTY_DATA (d)->ospeed;
161 /*****************************************************************************
164 Perform any necessary flushing of queues when an update has completed.
165 ****************************************************************************/
167 void tty_output_end (struct device *d);
172 tty_output_end (struct device *d)
174 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
176 CONSOLE_TTY_CURSOR_X (c) = CONSOLE_TTY_FINAL_CURSOR_X (c);
177 CONSOLE_TTY_CURSOR_Y (c) = CONSOLE_TTY_FINAL_CURSOR_Y (c);
178 FORCE_CURSOR_UPDATE (c);
179 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
183 tty_set_final_cursor_coords (struct frame *f, int y, int x)
185 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
187 CONSOLE_TTY_FINAL_CURSOR_X (c) = x;
188 CONSOLE_TTY_FINAL_CURSOR_Y (c) = y;
191 /*****************************************************************************
192 tty_output_display_block
194 Given a display line, a block number for that start line, output all
195 runes between start and end in the specified display block.
196 ****************************************************************************/
198 tty_output_display_block (struct window *w, struct display_line *dl, int block,
199 int start, int end, int start_pixpos,
200 int cursor_start, int cursor_width,
203 struct frame *f = XFRAME (w->frame);
204 Emchar_dynarr *buf = Dynarr_new (Emchar);
206 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
207 rune_dynarr *rba = db->runes;
214 rb = Dynarr_atp (rba, elt);
218 /* Nothing to do so don't do anything. */
228 end = Dynarr_length (rba);
232 while (elt < end && Dynarr_atp (rba, elt)->xpos < start_pixpos)
235 findex = Dynarr_atp (rba, elt)->findex;
236 xpos = Dynarr_atp (rba, elt)->xpos;
241 rb = Dynarr_atp (rba, elt);
243 if (rb->findex == findex && rb->type == RUNE_CHAR
244 && rb->object.chr.ch != '\n'
245 && (rb->cursor_type != CURSOR_ON
246 || NILP (w->text_cursor_visible_p)))
248 Dynarr_add (buf, rb->object.chr.ch);
253 if (Dynarr_length (buf))
255 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
260 if (rb->type == RUNE_CHAR)
265 if (rb->object.chr.ch == '\n')
267 /* Clear in case a cursor was formerly here. */
269 Dynarr_add (buf, ' ');
270 tty_output_emchar_dynarr (w, dl, buf, rb->xpos,
274 cmgoto (f, dl->ypos - 1, rb->xpos);
278 else if (rb->cursor_type == CURSOR_ON)
280 /* There is not a distinct eol cursor on tty's. */
282 Dynarr_add (buf, rb->object.chr.ch);
283 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
286 cmgoto (f, dl->ypos - 1, xpos);
292 /* #### RUNE_HLINE is actually a little more complicated than this
293 but at the moment it is only used to draw a turned off
294 modeline and this will suffice for that. */
295 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
298 int size = rb->width;
300 if (rb->type == RUNE_BLANK)
306 Dynarr_add (buf, ch_to_add);
307 tty_output_emchar_dynarr (w, dl, buf, rb->xpos, findex, 0);
309 if (xpos >= cursor_start
310 && cursor_start < xpos + Dynarr_length (buf))
312 cmgoto (f, dl->ypos - 1, cursor_start);
320 rb = Dynarr_atp (rba, elt);
326 else if (rb->type == RUNE_DGLYPH)
329 Lisp_Object instance;
331 XSETWINDOW (window, w);
332 instance = glyph_image_instance (rb->object.dglyph.glyph,
333 window, ERROR_ME_NOT, 1);
335 if (IMAGE_INSTANCEP (instance))
336 switch (XIMAGE_INSTANCE_TYPE (instance))
342 XIMAGE_INSTANCE_TEXT_STRING (instance);
343 Bytecount len = XSTRING_LENGTH (string);
345 /* In the unlikely instance that a garbage-collect
346 occurs during encoding, we at least need to
349 temptemp = (Bufbyte *) alloca (len);
350 memcpy (temptemp, XSTRING_DATA (string), len);
354 /* Now truncate the first rb->object.dglyph.xoffset
356 for (i = 0; i < rb->object.dglyph.xoffset;)
359 Emchar ch = charptr_emchar (temptemp);
360 i += XCHARSET_COLUMNS (CHAR_CHARSET (ch));
362 i++; /* telescope this */
364 INC_CHARPTR (temptemp);
367 /* If we truncated one column too many, then
368 add a space at the beginning. */
369 if (i > rb->object.dglyph.xoffset)
378 tty_output_bufbyte_string (w, dl, temptemp, len,
381 if (xpos >= cursor_start
383 xpos + (bufbyte_string_displayed_columns
386 cmgoto (f, dl->ypos - 1, cursor_start);
391 case IMAGE_MONO_PIXMAP:
392 case IMAGE_COLOR_PIXMAP:
393 case IMAGE_SUBWINDOW:
395 /* just do nothing here */
402 /* nothing is as nothing does */
417 if (Dynarr_length (buf))
418 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
425 /*****************************************************************************
426 tty_output_vertical_divider
428 Draw a vertical divider down the right side of the given window.
429 ****************************************************************************/
431 tty_output_vertical_divider (struct window *w, int clear)
433 /* Divider width can either be 0 or 1 on TTYs */
434 if (window_divider_width (w))
436 struct frame *f = XFRAME (w->frame);
437 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
439 int y_top = WINDOW_TEXT_TOP (w);
440 int y_bot = WINDOW_TEXT_BOTTOM (w);
441 unsigned char divv = '|';
443 tty_turn_on_face (w, MODELINE_INDEX);
444 for (line = y_top; line < y_bot; line++)
446 cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
447 send_string_to_tty_console (c, &divv, 1);
448 TTY_INC_CURSOR_X (c, 1);
451 /* Draw the divider in the modeline. */
452 cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
453 send_string_to_tty_console (c, &divv, 1);
454 TTY_INC_CURSOR_X (c, 1);
455 tty_turn_off_face (w, MODELINE_INDEX);
459 /****************************************************************************
462 Clear the area in the box defined by the given parameters.
463 ****************************************************************************/
465 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
466 face_index findex, int x, int y,
467 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
468 Lisp_Object background_pixmap)
470 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
472 struct window* w = XWINDOW (window);
474 tty_turn_on_face (w, findex);
475 for (line = y; line < y + height; line++)
481 if (window_is_leftmost (w)
482 && window_is_rightmost (w)
483 && TTY_SE (c).clr_to_eol)
485 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
489 unsigned char sp = ' ';
490 /* #### Of course, this is all complete and utter crap. */
491 for (col = x; col < x + width; col++)
492 send_string_to_tty_console (c, &sp, 1);
493 TTY_INC_CURSOR_X (c, width);
496 tty_turn_off_face (w, findex);
500 /*****************************************************************************
501 tty_clear_to_window_end
503 Clear the area between ypos1 and ypos2. Each margin area and the
504 text area is handled separately since they may each have their own
506 ****************************************************************************/
508 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
510 struct frame *f = XFRAME (w->frame);
511 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
514 x = WINDOW_TEXT_LEFT (w);
515 width = WINDOW_TEXT_WIDTH (w);
517 if (window_is_rightmost (w))
519 /* #### Optimize to use clr_to_eol function of tty if available, if
520 the window is the entire width of the frame. */
521 /* #### Is this actually an optimization? */
523 tty_turn_on_face (w, DEFAULT_INDEX);
524 for (line = ypos1; line < ypos2; line++)
526 cmgoto (XFRAME (w->frame), line, x);
527 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
529 tty_turn_off_face (w, DEFAULT_INDEX);
535 XSETWINDOW (window, w);
536 redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
540 /****************************************************************************
543 Clear the entire frame.
544 ****************************************************************************/
546 tty_clear_frame (struct frame *f)
548 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
550 tty_turn_on_frame_face (f, Vdefault_face);
551 if (TTY_SE (c).clr_frame)
553 OUTPUT1 (c, TTY_SE (c).clr_frame);
554 CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
555 CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
557 FRAME_CURSOR_X (f) = 0;
558 FRAME_CURSOR_Y (f) = 0;
564 internal_cursor_to (f, 0, 0);
567 /* #### Not implemented. */
568 fprintf (stderr, "Not yet.\n");
571 tty_turn_off_frame_face (f, Vdefault_face);
575 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
576 Bufbyte *str, Bytecount len, int xpos,
577 face_index findex, int cursor)
579 struct frame *f = XFRAME (w->frame);
580 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
582 /* First position the cursor. */
583 cmgoto (f, dl->ypos - 1, xpos);
585 /* Enable any face properties. */
586 tty_turn_on_face (w, findex);
588 send_string_to_tty_console (c, str, len);
589 TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
591 /* Turn the face properties back off. */
592 tty_turn_off_face (w, findex);
595 static Bufbyte_dynarr *tty_output_emchar_dynarr_dynarr;
597 /*****************************************************************************
598 tty_output_emchar_dynarr
600 Given a string and a starting position, output that string in the
601 given face. If cursor is true, draw a cursor around the string.
602 ****************************************************************************/
604 tty_output_emchar_dynarr (struct window *w, struct display_line *dl,
605 Emchar_dynarr *buf, int xpos, face_index findex,
608 if (!tty_output_emchar_dynarr_dynarr)
609 tty_output_emchar_dynarr_dynarr = Dynarr_new (Bufbyte);
611 Dynarr_reset (tty_output_emchar_dynarr_dynarr);
613 convert_emchar_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
615 tty_output_emchar_dynarr_dynarr);
617 tty_output_bufbyte_string (w, dl,
618 Dynarr_atp (tty_output_emchar_dynarr_dynarr, 0),
619 Dynarr_length (tty_output_emchar_dynarr_dynarr),
620 xpos, findex, cursor);
625 static Bufbyte_dynarr *sidcs_dynarr;
628 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
631 Bufbyte *specdata = XSTRING_DATA (spec);
632 Bytecount speclen = XSTRING_LENGTH (spec);
635 sidcs_dynarr = Dynarr_new (Bufbyte);
637 Dynarr_reset (sidcs_dynarr);
639 for (i = 0; i < speclen; i++)
641 if (specdata[i] == '%' && specdata[i+1] == '%')
643 Dynarr_add (sidcs_dynarr, '%');
646 else if (specdata[i] == '%' && specdata[i+1] == 's')
648 Dynarr_add_many (sidcs_dynarr,
649 XSTRING_DATA (string),
650 XSTRING_LENGTH (string));
654 Dynarr_add (sidcs_dynarr, specdata[i]);
661 set_foreground_to (struct console *c, Lisp_Object sym)
665 Bytecount escseqlen = 0;
667 result = assq_no_quit (sym, Vtty_color_alist);
670 Lisp_Object esc_seq = XCAR (XCDR (result));
671 escseq = XSTRING_DATA (esc_seq);
672 escseqlen = XSTRING_LENGTH (esc_seq);
675 else if (STRINGP (Vtty_dynamic_color_fg))
677 substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
679 escseq = Dynarr_atp (sidcs_dynarr, 0);
680 escseqlen = Dynarr_length (sidcs_dynarr);
686 send_string_to_tty_console (c, escseq, escseqlen);
691 set_background_to (struct console *c, Lisp_Object sym)
695 Bytecount escseqlen = 0;
697 result = assq_no_quit (sym, Vtty_color_alist);
700 Lisp_Object esc_seq = XCDR (XCDR (result));
701 escseq = XSTRING_DATA (esc_seq);
702 escseqlen = XSTRING_LENGTH (esc_seq);
705 else if (STRINGP (Vtty_dynamic_color_bg))
707 substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
709 escseq = Dynarr_atp (sidcs_dynarr, 0);
710 escseqlen = Dynarr_length (sidcs_dynarr);
716 send_string_to_tty_console (c, escseq, escseqlen);
721 tty_turn_on_face_1 (struct console *c, int highlight_p,
722 int blinking_p, int dim_p, int underline_p,
723 int reverse_p, Lisp_Object cinst_fore,
724 Lisp_Object cinst_back)
728 OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
733 OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
738 OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
743 /* #### punt for now if underline mode is glitchy */
744 if (!TTY_FLAGS (c).underline_width)
746 OUTPUT1_IF (c, TTY_SD (c).begin_underline);
752 /* #### punt for now if standout mode is glitchy */
753 if (!TTY_FLAGS (c).standout_width)
755 OUTPUT1_IF (c, TTY_SD (c).begin_standout);
763 Lisp_Object temp = cinst_fore;
764 cinst_fore = cinst_back;
768 if (COLOR_INSTANCEP (cinst_fore)
769 && !EQ (cinst_fore, Vthe_null_color_instance))
770 set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
771 (XCOLOR_INSTANCE (cinst_fore)));
773 if (COLOR_INSTANCEP (cinst_back)
774 && !EQ (cinst_back, Vthe_null_color_instance))
775 set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
776 (XCOLOR_INSTANCE (cinst_back)));
779 /*****************************************************************************
782 Turn on all set properties of the given face.
783 ****************************************************************************/
785 tty_turn_on_face (struct window *w, face_index findex)
787 struct frame *f = XFRAME (w->frame);
788 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
790 tty_turn_on_face_1 (c,
791 WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
792 WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
793 WINDOW_FACE_CACHEL_DIM_P (w, findex),
794 WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
795 WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
796 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
797 WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
800 /*****************************************************************************
803 Turn off all set properties of the given face (revert to default
804 face). We assume that tty_turn_on_face has been called for the given
805 face so that its properties are actually active.
806 ****************************************************************************/
808 tty_turn_off_face (struct window *w, face_index findex)
810 struct frame *f = XFRAME (w->frame);
811 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
813 if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
815 /* #### punt for now if standout mode is glitchy */
816 if (!TTY_FLAGS (c).standout_width)
818 OUTPUT1_IF (c, TTY_SD (c).end_standout);
822 if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
824 /* #### punt for now if underline mode is glitchy */
825 if (!TTY_FLAGS (c).underline_width)
827 OUTPUT1_IF (c, TTY_SD (c).end_underline);
831 if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
832 WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
833 WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
834 !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
835 Vthe_null_color_instance) ||
836 !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
837 Vthe_null_color_instance))
839 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
843 /*****************************************************************************
844 tty_turn_on_frame_face
846 Turn on all set properties of the given face.
847 ****************************************************************************/
849 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
852 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
854 XSETFRAME (frame, f);
855 tty_turn_on_face_1 (c,
856 FACE_HIGHLIGHT_P (face, frame),
857 FACE_BLINKING_P (face, frame),
858 FACE_DIM_P (face, frame),
859 FACE_UNDERLINE_P (face, frame),
860 FACE_REVERSE_P (face, frame),
861 FACE_FOREGROUND (face, frame),
862 FACE_BACKGROUND (face, frame));
865 /*****************************************************************************
866 tty_turn_off_frame_face
868 Turn off all set properties of the given face (revert to default
869 face). We assume that tty_turn_on_face has been called for the given
870 face so that its properties are actually active.
871 ****************************************************************************/
873 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
876 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
878 XSETFRAME (frame, f);
880 if (FACE_REVERSE_P (face, frame))
882 /* #### punt for now if standout mode is glitchy */
883 if (!TTY_FLAGS (c).standout_width)
885 OUTPUT1_IF (c, TTY_SD (c).end_standout);
889 if (FACE_UNDERLINE_P (face, frame))
891 /* #### punt for now if underline mode is glitchy */
892 if (!TTY_FLAGS (c).underline_width)
894 OUTPUT1_IF (c, TTY_SD (c).end_underline);
898 if (FACE_HIGHLIGHT_P (face, frame) ||
899 FACE_BLINKING_P (face, frame) ||
900 FACE_DIM_P (face, frame) ||
901 !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
902 !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
904 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
908 /*****************************************************************************
911 Sets up various parameters on tty modes.
912 ****************************************************************************/
914 set_tty_modes (struct console *c)
916 if (!CONSOLE_TTY_P (c))
919 OUTPUT1_IF (c, TTY_SD (c).init_motion);
920 OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
921 OUTPUT1_IF (c, TTY_SD (c).keypad_on);
924 /*****************************************************************************
927 Restore default state of tty.
928 ****************************************************************************/
930 reset_tty_modes (struct console *c)
932 if (!CONSOLE_TTY_P (c))
935 OUTPUT1_IF (c, TTY_SD (c).orig_pair);
936 OUTPUT1_IF (c, TTY_SD (c).keypad_off);
937 OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
938 OUTPUT1_IF (c, TTY_SD (c).end_motion);
939 tty_output_end (XDEVICE (CONSOLE_SELECTED_DEVICE (c)));
942 /*****************************************************************************
943 tty_redisplay_shutdown
945 Clear the frame and position the cursor properly for exiting.
946 ****************************************************************************/
948 tty_redisplay_shutdown (struct console *c)
950 Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
954 Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
958 struct frame *f = XFRAME (frm);
960 /* Clear the bottom line of the frame. */
961 redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
962 f->height, f->width, 1);
964 /* And then stick the cursor there. */
965 tty_set_final_cursor_coords (f, f->height, 0);
966 tty_output_end (XDEVICE (dev));
972 /* #### Everything below here is old shit. It should either be moved
976 /* FLAGS - these don't need to be console local since only one console
977 can be being updated at a time. */
978 static int insert_mode_on; /* nonzero if in insert mode */
979 static int standout_mode_on; /* nonzero if in standout mode */
980 static int underline_mode_on; /* nonzero if in underline mode */
981 static int alternate_mode_on; /* nonzero if in alternate char set */
982 static int attributes_on; /* nonzero if any attributes on */
986 turn_on_insert (struct frame *f)
988 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
991 OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
996 turn_off_insert (struct frame *f)
998 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1001 OUTPUT1 (c, TTY_SE (c).end_ins_mode);
1006 internal_cursor_to (struct frame *f, int row, int col)
1008 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1010 if (!TTY_FLAGS (c).insert_mode_motion)
1011 turn_off_insert (f);
1012 if (!TTY_FLAGS (c).standout_motion)
1014 turn_off_standout (f);
1015 turn_off_underline (f);
1016 turn_off_alternate (f);
1019 cmgoto (f, row, col);
1023 clear_to_end (struct frame *f)
1025 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1027 /* assumes cursor is already positioned */
1028 if (TTY_SE (c).clr_from_cursor)
1030 OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
1034 int line = FRAME_CURSOR_Y (f);
1036 while (line < FRAME_HEIGHT (f))
1038 internal_cursor_to (f, line, 0);
1039 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1047 * clear from last visible line on window to window end (presumably
1048 * the line above window's modeline
1051 tty_clear_window_end (struct window *w, int ystart, int yend)
1053 struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1056 for (line = ystart; line < yend; line++)
1058 cmgoto (XFRAME (w->frame), line, 0);
1059 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1066 tty_flash (struct device *d)
1068 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1069 if (TTY_SD (c).visual_bell)
1071 OUTPUT1 (c, TTY_SD (c).visual_bell);
1072 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1080 * tty_ring_bell - sound an audio beep.
1083 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1085 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1089 OUTPUT1 (c, TTY_SD (c).audio_bell);
1090 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1096 init_tty_for_redisplay (struct device *d, char *terminal_type)
1099 char entry_buffer[2044];
1100 /* char temp_buffer[2044]; */
1102 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1104 /* What we should really do is allocate just enough space for
1105 the actual strings that are stored; but this would require
1106 doing this after all the tgetstr()s and adjusting all the
1108 CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1109 bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1112 /* SIGTT* don't exist under win32 */
1113 EMACS_BLOCK_SIGNAL (SIGTTOU);
1115 status = tgetent (entry_buffer, terminal_type);
1117 EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1121 return TTY_UNABLE_OPEN_DATABASE;
1122 else if (status == 0)
1123 return TTY_TYPE_UNDEFINED;
1125 /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1127 return TTY_TYPE_UNDEFINED;
1130 * Establish the terminal size.
1132 /* First try to get the info from the system. If that fails, check
1133 the termcap entry. */
1134 get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1135 &CONSOLE_TTY_DATA (c)->height);
1137 if (CONSOLE_TTY_DATA (c)->width <= 0)
1138 CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1139 if (CONSOLE_TTY_DATA (c)->height <= 0)
1140 CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1142 if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1143 return TTY_SIZE_UNSPECIFIED;
1146 * Initialize cursor motion information.
1149 /* local cursor movement */
1150 TTY_CM (c).up = tgetstr ("up", &bufptr);
1151 TTY_CM (c).down = tgetstr ("do", &bufptr);
1152 TTY_CM (c).left = tgetstr ("le", &bufptr);
1153 TTY_CM (c).right = tgetstr ("nd", &bufptr);
1154 TTY_CM (c).home = tgetstr ("ho", &bufptr);
1155 TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1156 TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1158 /* absolute cursor motion */
1159 TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1160 TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1161 TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1163 /* Verify that the terminal is powerful enough to run Emacs */
1164 if (!TTY_CM (c).abs)
1166 if (!TTY_CM (c).up || !TTY_CM (c).down
1167 || !TTY_CM (c).left || !TTY_CM (c).right)
1168 return TTY_TYPE_INSUFFICIENT;
1171 /* parameterized local cursor movement */
1172 TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1173 TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1174 TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1175 TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1178 TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1179 TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1180 TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1181 TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1182 TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1186 * Initialize screen editing information.
1189 /* adding to the screen */
1190 TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1191 TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1192 TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1193 TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1194 TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1195 TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1196 TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1197 TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1199 /* deleting from the screen */
1200 TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1201 TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1202 TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1203 TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1204 TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1205 TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1206 TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1207 TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1208 TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1209 TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1213 * Initialize screen display information.
1215 TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1216 TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1217 TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1218 TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1219 TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1220 TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1221 TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1222 TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1223 TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1224 TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1225 TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1226 TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1228 TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1229 TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1230 if (!TTY_SD (c).audio_bell)
1232 /* If audio_bell doesn't get set, then assume C-g. This is gross and
1233 ugly but is what Emacs has done from time immortal. */
1234 TTY_SD (c).audio_bell = "\07";
1237 TTY_SD (c).cursor_visible = tgetstr ("ve", &bufptr);
1238 TTY_SD (c).cursor_normal = tgetstr ("vs", &bufptr);
1239 TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1240 TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1241 TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1242 TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1246 * Initialize additional terminal information.
1248 TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1249 TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1250 TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1251 TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1252 TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1253 TTY_FLAGS (c).standout_width = tgetnum ("sg");
1254 TTY_FLAGS (c).underline_width = tgetnum ("ug");
1256 if (TTY_FLAGS (c).standout_width == -1)
1257 TTY_FLAGS (c).standout_width = 0;
1258 if (TTY_FLAGS (c).underline_width == -1)
1259 TTY_FLAGS (c).underline_width = 0;
1261 TTY_FLAGS (c).meta_key =
1262 eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1266 * Setup the costs tables for this tty console.
1271 * Initialize local flags.
1274 standout_mode_on = 0;
1275 underline_mode_on = 0;
1276 alternate_mode_on = 0;
1280 * Attempt to initialize the function_key_map to
1281 * some kind of sensible value
1284 term_get_fkeys (c->function_key_map, &bufptr);
1287 /* check for ANSI set-foreground and set-background strings,
1288 and assume color if so.
1290 #### we should support the other (non-ANSI) ways of specifying
1293 char *fooptr = foobuf;
1294 if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1295 (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1296 ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1297 DEVICE_CLASS (d) = Qcolor;
1299 DEVICE_CLASS (d) = Qmono;
1302 return TTY_INIT_SUCCESS;
1307 CONST char *cap, *name;
1310 /* Termcap capability names that correspond directly to X keysyms.
1311 Some of these (marked "terminfo") aren't supplied by old-style
1312 (Berkeley) termcap entries. They're listed in X keysym order;
1313 except we put the keypad keys first, so that if they clash with
1314 other keys (as on the IBM PC keyboard) they get overridden.
1317 static struct fkey_table keys[] =
1319 {"kh", "home"}, /* termcap */
1320 {"kl", "left"}, /* termcap */
1321 {"ku", "up"}, /* termcap */
1322 {"kr", "right"}, /* termcap */
1323 {"kd", "down"}, /* termcap */
1324 {"%8", "prior"}, /* terminfo */
1325 {"%5", "next"}, /* terminfo */
1326 {"@7", "end"}, /* terminfo */
1327 {"@1", "begin"}, /* terminfo */
1328 {"*6", "select"}, /* terminfo */
1329 {"%9", "print"}, /* terminfo */
1330 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1332 * "insert" --- see below
1334 {"&8", "undo"}, /* terminfo */
1335 {"%0", "redo"}, /* terminfo */
1336 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1337 {"@0", "find"}, /* terminfo */
1338 {"@2", "cancel"}, /* terminfo */
1339 {"%1", "help"}, /* terminfo */
1341 * "break" goes here, but can't be reliably intercepted with termcap
1343 {"&4", "reset"}, /* terminfo --- actually `restart' */
1345 * "system" and "user" --- no termcaps
1347 {"kE", "clearline"}, /* terminfo */
1348 {"kA", "insertline"}, /* terminfo */
1349 {"kL", "deleteline"}, /* terminfo */
1350 {"kI", "insertchar"}, /* terminfo */
1351 {"kD", "delete"}, /* terminfo */
1352 {"kB", "backtab"}, /* terminfo */
1354 * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1356 {"@8", "kp-enter"}, /* terminfo */
1358 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1359 * "kp-multiply", "kp-add", "kp-separator",
1360 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1361 * --- no termcaps for any of these.
1363 {"K4", "kp-1"}, /* terminfo */
1365 * "kp-2" --- no termcap
1367 {"K5", "kp-3"}, /* terminfo */
1369 * "kp-4" --- no termcap
1371 {"K2", "kp-5"}, /* terminfo */
1373 * "kp-6" --- no termcap
1375 {"K1", "kp-7"}, /* terminfo */
1377 * "kp-8" --- no termcap
1379 {"K3", "kp-9"}, /* terminfo */
1381 * "kp-equal" --- no termcap
1394 static char **term_get_fkeys_arg;
1396 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1397 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1399 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1400 This function scans the termcap function key sequence entries, and
1401 adds entries to Vfunction_key_map for each function key it finds. */
1404 term_get_fkeys (Lisp_Object keymap, char **address)
1406 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1407 errors during the call. The only errors should be from Fdefine_key
1408 when given a key sequence containing an invalid prefix key. If the
1409 termcap defines function keys which use a prefix that is already bound
1410 to a command by the default bindings, we should silently ignore that
1411 function key specification, rather than giving the user an error and
1412 refusing to run at all on such a terminal. */
1414 term_get_fkeys_arg = address;
1416 condition_case_1 (Qerror,
1417 term_get_fkeys_1, keymap,
1418 term_get_fkeys_error, Qnil);
1422 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1428 term_get_fkeys_1 (Lisp_Object function_key_map)
1432 char **address = term_get_fkeys_arg;
1434 for (i = 0; i < countof (keys); i++)
1436 char *sequence = tgetstr (keys[i].cap, address);
1438 Fdefine_key (function_key_map,
1439 build_ext_string (sequence, FORMAT_BINARY),
1440 vector1 (intern (keys[i].name)));
1443 /* The uses of the "k0" capability are inconsistent; sometimes it
1444 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1445 We will attempt to politely accommodate both systems by testing for
1446 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1449 char *k_semi = tgetstr ("k;", address);
1450 char *k0 = tgetstr ("k0", address);
1451 CONST char *k0_name = "f10";
1455 Fdefine_key (function_key_map, build_ext_string (k_semi, FORMAT_BINARY),
1456 vector1 (intern ("f10")));
1461 Fdefine_key (function_key_map, build_ext_string (k0, FORMAT_BINARY),
1462 vector1 (intern (k0_name)));
1465 /* Set up cookies for numbered function keys above f10. */
1467 char fcap[3], fkey[4];
1469 fcap[0] = 'F'; fcap[2] = '\0';
1470 for (i = 11; i < 64; i++)
1473 fcap[1] = '1' + i - 11;
1475 fcap[1] = 'A' + i - 20;
1477 fcap[1] = 'a' + i - 46;
1480 char *sequence = tgetstr (fcap, address);
1483 sprintf (fkey, "f%d", i);
1484 Fdefine_key (function_key_map,
1485 build_ext_string (sequence, FORMAT_BINARY),
1486 vector1 (intern (fkey)));
1493 * Various mappings to try and get a better fit.
1496 #define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1497 if (!tgetstr (cap1, address)) \
1499 char *sequence = tgetstr (cap2, address); \
1501 Fdefine_key (function_key_map, \
1502 build_ext_string (sequence, FORMAT_BINARY), \
1503 vector1 (intern (sym))); \
1506 /* if there's no key_next keycap, map key_npage to `next' keysym */
1507 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1508 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1509 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1510 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1511 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1513 /* IBM has their own non-standard dialect of terminfo.
1514 If the standard name isn't found, try the IBM name. */
1515 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1516 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1517 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1518 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1519 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1520 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1521 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1522 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1523 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1524 #undef CONDITIONAL_REASSIGN
1531 /************************************************************************/
1532 /* initialization */
1533 /************************************************************************/
1536 console_type_create_redisplay_tty (void)
1538 /* redisplay methods */
1539 CONSOLE_HAS_METHOD (tty, text_width);
1540 CONSOLE_HAS_METHOD (tty, output_display_block);
1541 CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1542 CONSOLE_HAS_METHOD (tty, divider_height);
1543 CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1544 CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1545 CONSOLE_HAS_METHOD (tty, clear_region);
1546 CONSOLE_HAS_METHOD (tty, clear_frame);
1547 CONSOLE_HAS_METHOD (tty, output_begin);
1548 CONSOLE_HAS_METHOD (tty, output_end);
1549 CONSOLE_HAS_METHOD (tty, flash);
1550 CONSOLE_HAS_METHOD (tty, ring_bell);
1551 CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);