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 += CHAR_COLUMNS (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:
396 /* just do nothing here */
403 /* nothing is as nothing does */
418 if (Dynarr_length (buf))
419 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
426 /*****************************************************************************
427 tty_output_vertical_divider
429 Draw a vertical divider down the right side of the given window.
430 ****************************************************************************/
432 tty_output_vertical_divider (struct window *w, int clear)
434 /* Divider width can either be 0 or 1 on TTYs */
435 if (window_divider_width (w))
437 struct frame *f = XFRAME (w->frame);
438 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
440 int y_top = WINDOW_TEXT_TOP (w);
441 int y_bot = WINDOW_TEXT_BOTTOM (w);
442 unsigned char divv = '|';
444 tty_turn_on_face (w, MODELINE_INDEX);
445 for (line = y_top; line < y_bot; line++)
447 cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
448 send_string_to_tty_console (c, &divv, 1);
449 TTY_INC_CURSOR_X (c, 1);
452 /* Draw the divider in the modeline. */
453 cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
454 send_string_to_tty_console (c, &divv, 1);
455 TTY_INC_CURSOR_X (c, 1);
456 tty_turn_off_face (w, MODELINE_INDEX);
460 /****************************************************************************
463 Clear the area in the box defined by the given parameters.
464 ****************************************************************************/
466 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
467 face_index findex, int x, int y,
468 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
469 Lisp_Object background_pixmap)
471 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
473 struct window* w = XWINDOW (window);
475 tty_turn_on_face (w, findex);
476 for (line = y; line < y + height; line++)
482 if (window_is_leftmost (w)
483 && window_is_rightmost (w)
484 && TTY_SE (c).clr_to_eol)
486 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
490 unsigned char sp = ' ';
491 /* #### Of course, this is all complete and utter crap. */
492 for (col = x; col < x + width; col++)
493 send_string_to_tty_console (c, &sp, 1);
494 TTY_INC_CURSOR_X (c, width);
497 tty_turn_off_face (w, findex);
501 /*****************************************************************************
502 tty_clear_to_window_end
504 Clear the area between ypos1 and ypos2. Each margin area and the
505 text area is handled separately since they may each have their own
507 ****************************************************************************/
509 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
511 struct frame *f = XFRAME (w->frame);
512 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
515 x = WINDOW_TEXT_LEFT (w);
516 width = WINDOW_TEXT_WIDTH (w);
518 if (window_is_rightmost (w))
520 /* #### Optimize to use clr_to_eol function of tty if available, if
521 the window is the entire width of the frame. */
522 /* #### Is this actually an optimization? */
524 tty_turn_on_face (w, DEFAULT_INDEX);
525 for (line = ypos1; line < ypos2; line++)
527 cmgoto (XFRAME (w->frame), line, x);
528 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
530 tty_turn_off_face (w, DEFAULT_INDEX);
536 XSETWINDOW (window, w);
537 redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
541 /****************************************************************************
544 Clear the entire frame.
545 ****************************************************************************/
547 tty_clear_frame (struct frame *f)
549 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
551 tty_turn_on_frame_face (f, Vdefault_face);
552 if (TTY_SE (c).clr_frame)
554 OUTPUT1 (c, TTY_SE (c).clr_frame);
555 CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
556 CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
558 FRAME_CURSOR_X (f) = 0;
559 FRAME_CURSOR_Y (f) = 0;
565 internal_cursor_to (f, 0, 0);
568 /* #### Not implemented. */
569 fprintf (stderr, "Not yet.\n");
572 tty_turn_off_frame_face (f, Vdefault_face);
576 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
577 Bufbyte *str, Bytecount len, int xpos,
578 face_index findex, int cursor)
580 struct frame *f = XFRAME (w->frame);
581 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
583 /* First position the cursor. */
584 cmgoto (f, dl->ypos - 1, xpos);
586 /* Enable any face properties. */
587 tty_turn_on_face (w, findex);
589 send_string_to_tty_console (c, str, len);
590 TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
592 /* Turn the face properties back off. */
593 tty_turn_off_face (w, findex);
596 static Bufbyte_dynarr *tty_output_emchar_dynarr_dynarr;
598 /*****************************************************************************
599 tty_output_emchar_dynarr
601 Given a string and a starting position, output that string in the
602 given face. If cursor is true, draw a cursor around the string.
603 ****************************************************************************/
605 tty_output_emchar_dynarr (struct window *w, struct display_line *dl,
606 Emchar_dynarr *buf, int xpos, face_index findex,
609 if (!tty_output_emchar_dynarr_dynarr)
610 tty_output_emchar_dynarr_dynarr = Dynarr_new (Bufbyte);
612 Dynarr_reset (tty_output_emchar_dynarr_dynarr);
614 convert_emchar_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
616 tty_output_emchar_dynarr_dynarr);
618 tty_output_bufbyte_string (w, dl,
619 Dynarr_atp (tty_output_emchar_dynarr_dynarr, 0),
620 Dynarr_length (tty_output_emchar_dynarr_dynarr),
621 xpos, findex, cursor);
626 static Bufbyte_dynarr *sidcs_dynarr;
629 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
632 Bufbyte *specdata = XSTRING_DATA (spec);
633 Bytecount speclen = XSTRING_LENGTH (spec);
636 sidcs_dynarr = Dynarr_new (Bufbyte);
638 Dynarr_reset (sidcs_dynarr);
640 for (i = 0; i < speclen; i++)
642 if (specdata[i] == '%' && specdata[i+1] == '%')
644 Dynarr_add (sidcs_dynarr, '%');
647 else if (specdata[i] == '%' && specdata[i+1] == 's')
649 Dynarr_add_many (sidcs_dynarr,
650 XSTRING_DATA (string),
651 XSTRING_LENGTH (string));
655 Dynarr_add (sidcs_dynarr, specdata[i]);
662 set_foreground_to (struct console *c, Lisp_Object sym)
666 Bytecount escseqlen = 0;
668 result = assq_no_quit (sym, Vtty_color_alist);
671 Lisp_Object esc_seq = XCAR (XCDR (result));
672 escseq = XSTRING_DATA (esc_seq);
673 escseqlen = XSTRING_LENGTH (esc_seq);
676 else if (STRINGP (Vtty_dynamic_color_fg))
678 substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
680 escseq = Dynarr_atp (sidcs_dynarr, 0);
681 escseqlen = Dynarr_length (sidcs_dynarr);
687 send_string_to_tty_console (c, escseq, escseqlen);
692 set_background_to (struct console *c, Lisp_Object sym)
696 Bytecount escseqlen = 0;
698 result = assq_no_quit (sym, Vtty_color_alist);
701 Lisp_Object esc_seq = XCDR (XCDR (result));
702 escseq = XSTRING_DATA (esc_seq);
703 escseqlen = XSTRING_LENGTH (esc_seq);
706 else if (STRINGP (Vtty_dynamic_color_bg))
708 substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
710 escseq = Dynarr_atp (sidcs_dynarr, 0);
711 escseqlen = Dynarr_length (sidcs_dynarr);
717 send_string_to_tty_console (c, escseq, escseqlen);
722 tty_turn_on_face_1 (struct console *c, int highlight_p,
723 int blinking_p, int dim_p, int underline_p,
724 int reverse_p, Lisp_Object cinst_fore,
725 Lisp_Object cinst_back)
729 OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
734 OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
739 OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
744 /* #### punt for now if underline mode is glitchy */
745 if (!TTY_FLAGS (c).underline_width)
747 OUTPUT1_IF (c, TTY_SD (c).begin_underline);
753 /* #### punt for now if standout mode is glitchy */
754 if (!TTY_FLAGS (c).standout_width)
756 OUTPUT1_IF (c, TTY_SD (c).begin_standout);
764 Lisp_Object temp = cinst_fore;
765 cinst_fore = cinst_back;
769 if (COLOR_INSTANCEP (cinst_fore)
770 && !EQ (cinst_fore, Vthe_null_color_instance))
771 set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
772 (XCOLOR_INSTANCE (cinst_fore)));
774 if (COLOR_INSTANCEP (cinst_back)
775 && !EQ (cinst_back, Vthe_null_color_instance))
776 set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
777 (XCOLOR_INSTANCE (cinst_back)));
780 /*****************************************************************************
783 Turn on all set properties of the given face.
784 ****************************************************************************/
786 tty_turn_on_face (struct window *w, face_index findex)
788 struct frame *f = XFRAME (w->frame);
789 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
791 tty_turn_on_face_1 (c,
792 WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
793 WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
794 WINDOW_FACE_CACHEL_DIM_P (w, findex),
795 WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
796 WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
797 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
798 WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
801 /*****************************************************************************
804 Turn off all set properties of the given face (revert to default
805 face). We assume that tty_turn_on_face has been called for the given
806 face so that its properties are actually active.
807 ****************************************************************************/
809 tty_turn_off_face (struct window *w, face_index findex)
811 struct frame *f = XFRAME (w->frame);
812 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
814 if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
816 /* #### punt for now if standout mode is glitchy */
817 if (!TTY_FLAGS (c).standout_width)
819 OUTPUT1_IF (c, TTY_SD (c).end_standout);
823 if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
825 /* #### punt for now if underline mode is glitchy */
826 if (!TTY_FLAGS (c).underline_width)
828 OUTPUT1_IF (c, TTY_SD (c).end_underline);
832 if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
833 WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
834 WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
835 !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
836 Vthe_null_color_instance) ||
837 !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
838 Vthe_null_color_instance))
840 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
844 /*****************************************************************************
845 tty_turn_on_frame_face
847 Turn on all set properties of the given face.
848 ****************************************************************************/
850 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
853 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
855 XSETFRAME (frame, f);
856 tty_turn_on_face_1 (c,
857 FACE_HIGHLIGHT_P (face, frame),
858 FACE_BLINKING_P (face, frame),
859 FACE_DIM_P (face, frame),
860 FACE_UNDERLINE_P (face, frame),
861 FACE_REVERSE_P (face, frame),
862 FACE_FOREGROUND (face, frame),
863 FACE_BACKGROUND (face, frame));
866 /*****************************************************************************
867 tty_turn_off_frame_face
869 Turn off all set properties of the given face (revert to default
870 face). We assume that tty_turn_on_face has been called for the given
871 face so that its properties are actually active.
872 ****************************************************************************/
874 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
877 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
879 XSETFRAME (frame, f);
881 if (FACE_REVERSE_P (face, frame))
883 /* #### punt for now if standout mode is glitchy */
884 if (!TTY_FLAGS (c).standout_width)
886 OUTPUT1_IF (c, TTY_SD (c).end_standout);
890 if (FACE_UNDERLINE_P (face, frame))
892 /* #### punt for now if underline mode is glitchy */
893 if (!TTY_FLAGS (c).underline_width)
895 OUTPUT1_IF (c, TTY_SD (c).end_underline);
899 if (FACE_HIGHLIGHT_P (face, frame) ||
900 FACE_BLINKING_P (face, frame) ||
901 FACE_DIM_P (face, frame) ||
902 !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
903 !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
905 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
909 /*****************************************************************************
912 Sets up various parameters on tty modes.
913 ****************************************************************************/
915 set_tty_modes (struct console *c)
917 if (!CONSOLE_TTY_P (c))
920 OUTPUT1_IF (c, TTY_SD (c).init_motion);
921 OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
922 OUTPUT1_IF (c, TTY_SD (c).keypad_on);
925 /*****************************************************************************
928 Restore default state of tty.
929 ****************************************************************************/
931 reset_tty_modes (struct console *c)
933 if (!CONSOLE_TTY_P (c))
936 OUTPUT1_IF (c, TTY_SD (c).orig_pair);
937 OUTPUT1_IF (c, TTY_SD (c).keypad_off);
938 OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
939 OUTPUT1_IF (c, TTY_SD (c).end_motion);
940 tty_output_end (XDEVICE (CONSOLE_SELECTED_DEVICE (c)));
943 /*****************************************************************************
944 tty_redisplay_shutdown
946 Clear the frame and position the cursor properly for exiting.
947 ****************************************************************************/
949 tty_redisplay_shutdown (struct console *c)
951 Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
955 Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
959 struct frame *f = XFRAME (frm);
961 /* Clear the bottom line of the frame. */
962 redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
963 f->height, f->width, 1);
965 /* And then stick the cursor there. */
966 tty_set_final_cursor_coords (f, f->height, 0);
967 tty_output_end (XDEVICE (dev));
973 /* #### Everything below here is old shit. It should either be moved
977 /* FLAGS - these don't need to be console local since only one console
978 can be being updated at a time. */
979 static int insert_mode_on; /* nonzero if in insert mode */
980 static int standout_mode_on; /* nonzero if in standout mode */
981 static int underline_mode_on; /* nonzero if in underline mode */
982 static int alternate_mode_on; /* nonzero if in alternate char set */
983 static int attributes_on; /* nonzero if any attributes on */
987 turn_on_insert (struct frame *f)
989 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
992 OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
997 turn_off_insert (struct frame *f)
999 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1002 OUTPUT1 (c, TTY_SE (c).end_ins_mode);
1007 internal_cursor_to (struct frame *f, int row, int col)
1009 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1011 if (!TTY_FLAGS (c).insert_mode_motion)
1012 turn_off_insert (f);
1013 if (!TTY_FLAGS (c).standout_motion)
1015 turn_off_standout (f);
1016 turn_off_underline (f);
1017 turn_off_alternate (f);
1020 cmgoto (f, row, col);
1024 clear_to_end (struct frame *f)
1026 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1028 /* assumes cursor is already positioned */
1029 if (TTY_SE (c).clr_from_cursor)
1031 OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
1035 int line = FRAME_CURSOR_Y (f);
1037 while (line < FRAME_HEIGHT (f))
1039 internal_cursor_to (f, line, 0);
1040 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1048 * clear from last visible line on window to window end (presumably
1049 * the line above window's modeline
1052 tty_clear_window_end (struct window *w, int ystart, int yend)
1054 struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1057 for (line = ystart; line < yend; line++)
1059 cmgoto (XFRAME (w->frame), line, 0);
1060 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1067 tty_flash (struct device *d)
1069 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1070 if (TTY_SD (c).visual_bell)
1072 OUTPUT1 (c, TTY_SD (c).visual_bell);
1073 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1081 * tty_ring_bell - sound an audio beep.
1084 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1086 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1090 OUTPUT1 (c, TTY_SD (c).audio_bell);
1091 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1097 init_tty_for_redisplay (struct device *d, char *terminal_type)
1100 char entry_buffer[2044];
1101 /* char temp_buffer[2044]; */
1103 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1105 /* What we should really do is allocate just enough space for
1106 the actual strings that are stored; but this would require
1107 doing this after all the tgetstr()s and adjusting all the
1109 CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1110 bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1113 /* SIGTT* don't exist under win32 */
1114 EMACS_BLOCK_SIGNAL (SIGTTOU);
1116 status = tgetent (entry_buffer, terminal_type);
1118 EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1122 return TTY_UNABLE_OPEN_DATABASE;
1123 else if (status == 0)
1124 return TTY_TYPE_UNDEFINED;
1126 /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1128 return TTY_TYPE_UNDEFINED;
1131 * Establish the terminal size.
1133 /* First try to get the info from the system. If that fails, check
1134 the termcap entry. */
1135 get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1136 &CONSOLE_TTY_DATA (c)->height);
1138 if (CONSOLE_TTY_DATA (c)->width <= 0)
1139 CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1140 if (CONSOLE_TTY_DATA (c)->height <= 0)
1141 CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1143 if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1144 return TTY_SIZE_UNSPECIFIED;
1147 * Initialize cursor motion information.
1150 /* local cursor movement */
1151 TTY_CM (c).up = tgetstr ("up", &bufptr);
1152 TTY_CM (c).down = tgetstr ("do", &bufptr);
1153 TTY_CM (c).left = tgetstr ("le", &bufptr);
1154 TTY_CM (c).right = tgetstr ("nd", &bufptr);
1155 TTY_CM (c).home = tgetstr ("ho", &bufptr);
1156 TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1157 TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1159 /* absolute cursor motion */
1160 TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1161 TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1162 TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1164 /* Verify that the terminal is powerful enough to run Emacs */
1165 if (!TTY_CM (c).abs)
1167 if (!TTY_CM (c).up || !TTY_CM (c).down
1168 || !TTY_CM (c).left || !TTY_CM (c).right)
1169 return TTY_TYPE_INSUFFICIENT;
1172 /* parameterized local cursor movement */
1173 TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1174 TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1175 TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1176 TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1179 TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1180 TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1181 TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1182 TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1183 TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1187 * Initialize screen editing information.
1190 /* adding to the screen */
1191 TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1192 TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1193 TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1194 TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1195 TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1196 TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1197 TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1198 TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1200 /* deleting from the screen */
1201 TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1202 TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1203 TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1204 TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1205 TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1206 TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1207 TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1208 TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1209 TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1210 TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1214 * Initialize screen display information.
1216 TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1217 TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1218 TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1219 TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1220 TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1221 TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1222 TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1223 TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1224 TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1225 TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1226 TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1227 TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1229 TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1230 TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1231 if (!TTY_SD (c).audio_bell)
1233 /* If audio_bell doesn't get set, then assume C-g. This is gross and
1234 ugly but is what Emacs has done from time immortal. */
1235 TTY_SD (c).audio_bell = "\07";
1238 TTY_SD (c).cursor_visible = tgetstr ("ve", &bufptr);
1239 TTY_SD (c).cursor_normal = tgetstr ("vs", &bufptr);
1240 TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1241 TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1242 TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1243 TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1247 * Initialize additional terminal information.
1249 TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1250 TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1251 TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1252 TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1253 TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1254 TTY_FLAGS (c).standout_width = tgetnum ("sg");
1255 TTY_FLAGS (c).underline_width = tgetnum ("ug");
1257 if (TTY_FLAGS (c).standout_width == -1)
1258 TTY_FLAGS (c).standout_width = 0;
1259 if (TTY_FLAGS (c).underline_width == -1)
1260 TTY_FLAGS (c).underline_width = 0;
1262 TTY_FLAGS (c).meta_key =
1263 eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1267 * Setup the costs tables for this tty console.
1272 * Initialize local flags.
1275 standout_mode_on = 0;
1276 underline_mode_on = 0;
1277 alternate_mode_on = 0;
1281 * Attempt to initialize the function_key_map to
1282 * some kind of sensible value
1285 term_get_fkeys (c->function_key_map, &bufptr);
1288 /* check for ANSI set-foreground and set-background strings,
1289 and assume color if so.
1291 #### we should support the other (non-ANSI) ways of specifying
1294 char *fooptr = foobuf;
1295 if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1296 (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1297 ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1298 DEVICE_CLASS (d) = Qcolor;
1300 DEVICE_CLASS (d) = Qmono;
1303 return TTY_INIT_SUCCESS;
1312 /* Termcap capability names that correspond directly to X keysyms.
1313 Some of these (marked "terminfo") aren't supplied by old-style
1314 (Berkeley) termcap entries. They're listed in X keysym order;
1315 except we put the keypad keys first, so that if they clash with
1316 other keys (as on the IBM PC keyboard) they get overridden.
1319 static struct fkey_table keys[] =
1321 {"kh", "home"}, /* termcap */
1322 {"kl", "left"}, /* termcap */
1323 {"ku", "up"}, /* termcap */
1324 {"kr", "right"}, /* termcap */
1325 {"kd", "down"}, /* termcap */
1326 {"%8", "prior"}, /* terminfo */
1327 {"%5", "next"}, /* terminfo */
1328 {"@7", "end"}, /* terminfo */
1329 {"@1", "begin"}, /* terminfo */
1330 {"*6", "select"}, /* terminfo */
1331 {"%9", "print"}, /* terminfo */
1332 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1334 * "insert" --- see below
1336 {"&8", "undo"}, /* terminfo */
1337 {"%0", "redo"}, /* terminfo */
1338 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1339 {"@0", "find"}, /* terminfo */
1340 {"@2", "cancel"}, /* terminfo */
1341 {"%1", "help"}, /* terminfo */
1343 * "break" goes here, but can't be reliably intercepted with termcap
1345 {"&4", "reset"}, /* terminfo --- actually `restart' */
1347 * "system" and "user" --- no termcaps
1349 {"kE", "clearline"}, /* terminfo */
1350 {"kA", "insertline"}, /* terminfo */
1351 {"kL", "deleteline"}, /* terminfo */
1352 {"kI", "insertchar"}, /* terminfo */
1353 {"kD", "delete"}, /* terminfo */
1354 {"kB", "backtab"}, /* terminfo */
1356 * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1358 {"@8", "kp-enter"}, /* terminfo */
1360 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1361 * "kp-multiply", "kp-add", "kp-separator",
1362 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1363 * --- no termcaps for any of these.
1365 {"K4", "kp-1"}, /* terminfo */
1367 * "kp-2" --- no termcap
1369 {"K5", "kp-3"}, /* terminfo */
1371 * "kp-4" --- no termcap
1373 {"K2", "kp-5"}, /* terminfo */
1375 * "kp-6" --- no termcap
1377 {"K1", "kp-7"}, /* terminfo */
1379 * "kp-8" --- no termcap
1381 {"K3", "kp-9"}, /* terminfo */
1383 * "kp-equal" --- no termcap
1396 static char **term_get_fkeys_arg;
1398 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1399 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1401 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1402 This function scans the termcap function key sequence entries, and
1403 adds entries to Vfunction_key_map for each function key it finds. */
1406 term_get_fkeys (Lisp_Object keymap, char **address)
1408 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1409 errors during the call. The only errors should be from Fdefine_key
1410 when given a key sequence containing an invalid prefix key. If the
1411 termcap defines function keys which use a prefix that is already bound
1412 to a command by the default bindings, we should silently ignore that
1413 function key specification, rather than giving the user an error and
1414 refusing to run at all on such a terminal. */
1416 term_get_fkeys_arg = address;
1418 condition_case_1 (Qerror,
1419 term_get_fkeys_1, keymap,
1420 term_get_fkeys_error, Qnil);
1424 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1430 term_get_fkeys_1 (Lisp_Object function_key_map)
1434 char **address = term_get_fkeys_arg;
1436 for (i = 0; i < countof (keys); i++)
1438 char *sequence = tgetstr (keys[i].cap, address);
1440 Fdefine_key (function_key_map,
1441 build_ext_string (sequence, FORMAT_BINARY),
1442 vector1 (intern (keys[i].name)));
1445 /* The uses of the "k0" capability are inconsistent; sometimes it
1446 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1447 We will attempt to politely accommodate both systems by testing for
1448 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1451 CONST char *k_semi = tgetstr ("k;", address);
1452 CONST char *k0 = tgetstr ("k0", address);
1455 Fdefine_key (function_key_map, build_ext_string (k_semi, FORMAT_BINARY),
1456 vector1 (intern ("f10")));
1459 Fdefine_key (function_key_map, build_ext_string (k0, FORMAT_BINARY),
1460 vector1 (intern (k_semi ? "f0" : "f10")));
1463 /* Set up cookies for numbered function keys above f10. */
1465 char fcap[3], fkey[4];
1467 fcap[0] = 'F'; fcap[2] = '\0';
1468 for (i = 11; i < 64; i++)
1471 fcap[1] = '1' + i - 11;
1473 fcap[1] = 'A' + i - 20;
1475 fcap[1] = 'a' + i - 46;
1478 char *sequence = tgetstr (fcap, address);
1481 sprintf (fkey, "f%d", i);
1482 Fdefine_key (function_key_map,
1483 build_ext_string (sequence, FORMAT_BINARY),
1484 vector1 (intern (fkey)));
1491 * Various mappings to try and get a better fit.
1493 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) \
1494 if (!tgetstr (cap1, address)) \
1496 char *sequence = tgetstr (cap2, address); \
1498 Fdefine_key (function_key_map, \
1499 build_ext_string (sequence, FORMAT_BINARY), \
1500 vector1 (intern (keyname))); \
1503 /* if there's no key_next keycap, map key_npage to `next' keysym */
1504 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1505 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1506 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1507 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1508 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1510 /* IBM has their own non-standard dialect of terminfo.
1511 If the standard name isn't found, try the IBM name. */
1512 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1513 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1514 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1515 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1516 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1517 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1518 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1519 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1520 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1521 #undef CONDITIONAL_REASSIGN
1527 /************************************************************************/
1528 /* initialization */
1529 /************************************************************************/
1532 console_type_create_redisplay_tty (void)
1534 /* redisplay methods */
1535 CONSOLE_HAS_METHOD (tty, text_width);
1536 CONSOLE_HAS_METHOD (tty, output_display_block);
1537 CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1538 CONSOLE_HAS_METHOD (tty, divider_height);
1539 CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1540 CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1541 CONSOLE_HAS_METHOD (tty, clear_region);
1542 CONSOLE_HAS_METHOD (tty, clear_frame);
1543 CONSOLE_HAS_METHOD (tty, output_begin);
1544 CONSOLE_HAS_METHOD (tty, output_end);
1545 CONSOLE_HAS_METHOD (tty, flash);
1546 CONSOLE_HAS_METHOD (tty, ring_bell);
1547 CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);