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))
337 switch (XIMAGE_INSTANCE_TYPE (instance))
343 XIMAGE_INSTANCE_TEXT_STRING (instance);
344 Bytecount len = XSTRING_LENGTH (string);
346 /* In the unlikely instance that a garbage-collect
347 occurs during encoding, we at least need to
350 temptemp = (Bufbyte *) alloca (len);
351 memcpy (temptemp, XSTRING_DATA (string), len);
355 /* Now truncate the first rb->object.dglyph.xoffset
357 for (i = 0; i < rb->object.dglyph.xoffset;)
360 Emchar ch = charptr_emchar (temptemp);
361 i += XCHARSET_COLUMNS (CHAR_CHARSET (ch));
363 i++; /* telescope this */
365 INC_CHARPTR (temptemp);
368 /* If we truncated one column too many, then
369 add a space at the beginning. */
370 if (i > rb->object.dglyph.xoffset)
379 tty_output_bufbyte_string (w, dl, temptemp, len,
382 if (xpos >= cursor_start
384 xpos + (bufbyte_string_displayed_columns
387 cmgoto (f, dl->ypos - 1, cursor_start);
392 case IMAGE_MONO_PIXMAP:
393 case IMAGE_COLOR_PIXMAP:
394 case IMAGE_SUBWINDOW:
397 /* just do nothing here */
404 /* nothing is as nothing does */
410 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
411 (XIMAGE_INSTANCE (instance)) = 0;
422 if (Dynarr_length (buf))
423 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
430 /*****************************************************************************
431 tty_output_vertical_divider
433 Draw a vertical divider down the right side of the given window.
434 ****************************************************************************/
436 tty_output_vertical_divider (struct window *w, int clear)
438 /* Divider width can either be 0 or 1 on TTYs */
439 if (window_divider_width (w))
441 struct frame *f = XFRAME (w->frame);
442 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
444 int y_top = WINDOW_TEXT_TOP (w);
445 int y_bot = WINDOW_TEXT_BOTTOM (w);
446 unsigned char divv = '|';
448 tty_turn_on_face (w, MODELINE_INDEX);
449 for (line = y_top; line < y_bot; line++)
451 cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
452 send_string_to_tty_console (c, &divv, 1);
453 TTY_INC_CURSOR_X (c, 1);
456 /* Draw the divider in the modeline. */
457 cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
458 send_string_to_tty_console (c, &divv, 1);
459 TTY_INC_CURSOR_X (c, 1);
460 tty_turn_off_face (w, MODELINE_INDEX);
464 /****************************************************************************
467 Clear the area in the box defined by the given parameters.
468 ****************************************************************************/
470 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
471 face_index findex, int x, int y,
472 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
473 Lisp_Object background_pixmap)
475 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
477 struct window* w = XWINDOW (window);
479 tty_turn_on_face (w, findex);
480 for (line = y; line < y + height; line++)
486 if (window_is_leftmost (w)
487 && window_is_rightmost (w)
488 && TTY_SE (c).clr_to_eol)
490 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
494 unsigned char sp = ' ';
495 /* #### Of course, this is all complete and utter crap. */
496 for (col = x; col < x + width; col++)
497 send_string_to_tty_console (c, &sp, 1);
498 TTY_INC_CURSOR_X (c, width);
501 tty_turn_off_face (w, findex);
505 /*****************************************************************************
506 tty_clear_to_window_end
508 Clear the area between ypos1 and ypos2. Each margin area and the
509 text area is handled separately since they may each have their own
511 ****************************************************************************/
513 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
515 struct frame *f = XFRAME (w->frame);
516 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
519 x = WINDOW_TEXT_LEFT (w);
520 width = WINDOW_TEXT_WIDTH (w);
522 if (window_is_rightmost (w))
524 /* #### Optimize to use clr_to_eol function of tty if available, if
525 the window is the entire width of the frame. */
526 /* #### Is this actually an optimization? */
528 tty_turn_on_face (w, DEFAULT_INDEX);
529 for (line = ypos1; line < ypos2; line++)
531 cmgoto (XFRAME (w->frame), line, x);
532 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
534 tty_turn_off_face (w, DEFAULT_INDEX);
540 XSETWINDOW (window, w);
541 redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
545 /****************************************************************************
548 Clear the entire frame.
549 ****************************************************************************/
551 tty_clear_frame (struct frame *f)
553 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
555 tty_turn_on_frame_face (f, Vdefault_face);
556 if (TTY_SE (c).clr_frame)
558 OUTPUT1 (c, TTY_SE (c).clr_frame);
559 CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
560 CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
562 FRAME_CURSOR_X (f) = 0;
563 FRAME_CURSOR_Y (f) = 0;
569 internal_cursor_to (f, 0, 0);
572 /* #### Not implemented. */
573 stderr_out ("Not yet.\n");
576 tty_turn_off_frame_face (f, Vdefault_face);
580 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
581 Bufbyte *str, Bytecount len, int xpos,
582 face_index findex, int cursor)
584 struct frame *f = XFRAME (w->frame);
585 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
587 /* First position the cursor. */
588 cmgoto (f, dl->ypos - 1, xpos);
590 /* Enable any face properties. */
591 tty_turn_on_face (w, findex);
593 send_string_to_tty_console (c, str, len);
594 TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
596 /* Turn the face properties back off. */
597 tty_turn_off_face (w, findex);
600 static Bufbyte_dynarr *tty_output_emchar_dynarr_dynarr;
602 /*****************************************************************************
603 tty_output_emchar_dynarr
605 Given a string and a starting position, output that string in the
606 given face. If cursor is true, draw a cursor around the string.
607 ****************************************************************************/
609 tty_output_emchar_dynarr (struct window *w, struct display_line *dl,
610 Emchar_dynarr *buf, int xpos, face_index findex,
613 if (!tty_output_emchar_dynarr_dynarr)
614 tty_output_emchar_dynarr_dynarr = Dynarr_new (Bufbyte);
616 Dynarr_reset (tty_output_emchar_dynarr_dynarr);
618 convert_emchar_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
620 tty_output_emchar_dynarr_dynarr);
622 tty_output_bufbyte_string (w, dl,
623 Dynarr_atp (tty_output_emchar_dynarr_dynarr, 0),
624 Dynarr_length (tty_output_emchar_dynarr_dynarr),
625 xpos, findex, cursor);
630 static Bufbyte_dynarr *sidcs_dynarr;
633 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
636 Bufbyte *specdata = XSTRING_DATA (spec);
637 Bytecount speclen = XSTRING_LENGTH (spec);
640 sidcs_dynarr = Dynarr_new (Bufbyte);
642 Dynarr_reset (sidcs_dynarr);
644 for (i = 0; i < speclen; i++)
646 if (specdata[i] == '%' && specdata[i+1] == '%')
648 Dynarr_add (sidcs_dynarr, '%');
651 else if (specdata[i] == '%' && specdata[i+1] == 's')
653 Dynarr_add_many (sidcs_dynarr,
654 XSTRING_DATA (string),
655 XSTRING_LENGTH (string));
659 Dynarr_add (sidcs_dynarr, specdata[i]);
666 set_foreground_to (struct console *c, Lisp_Object sym)
670 Bytecount escseqlen = 0;
672 result = assq_no_quit (sym, Vtty_color_alist);
675 Lisp_Object esc_seq = XCAR (XCDR (result));
676 escseq = XSTRING_DATA (esc_seq);
677 escseqlen = XSTRING_LENGTH (esc_seq);
680 else if (STRINGP (Vtty_dynamic_color_fg))
682 substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
684 escseq = Dynarr_atp (sidcs_dynarr, 0);
685 escseqlen = Dynarr_length (sidcs_dynarr);
691 send_string_to_tty_console (c, escseq, escseqlen);
696 set_background_to (struct console *c, Lisp_Object sym)
700 Bytecount escseqlen = 0;
702 result = assq_no_quit (sym, Vtty_color_alist);
705 Lisp_Object esc_seq = XCDR (XCDR (result));
706 escseq = XSTRING_DATA (esc_seq);
707 escseqlen = XSTRING_LENGTH (esc_seq);
710 else if (STRINGP (Vtty_dynamic_color_bg))
712 substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
714 escseq = Dynarr_atp (sidcs_dynarr, 0);
715 escseqlen = Dynarr_length (sidcs_dynarr);
721 send_string_to_tty_console (c, escseq, escseqlen);
726 tty_turn_on_face_1 (struct console *c, int highlight_p,
727 int blinking_p, int dim_p, int underline_p,
728 int reverse_p, Lisp_Object cinst_fore,
729 Lisp_Object cinst_back)
733 OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
738 OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
743 OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
748 /* #### punt for now if underline mode is glitchy */
749 if (!TTY_FLAGS (c).underline_width)
751 OUTPUT1_IF (c, TTY_SD (c).begin_underline);
757 /* #### punt for now if standout mode is glitchy */
758 if (!TTY_FLAGS (c).standout_width)
760 OUTPUT1_IF (c, TTY_SD (c).begin_standout);
768 Lisp_Object temp = cinst_fore;
769 cinst_fore = cinst_back;
773 if (COLOR_INSTANCEP (cinst_fore)
774 && !EQ (cinst_fore, Vthe_null_color_instance))
775 set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
776 (XCOLOR_INSTANCE (cinst_fore)));
778 if (COLOR_INSTANCEP (cinst_back)
779 && !EQ (cinst_back, Vthe_null_color_instance))
780 set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
781 (XCOLOR_INSTANCE (cinst_back)));
784 /*****************************************************************************
787 Turn on all set properties of the given face.
788 ****************************************************************************/
790 tty_turn_on_face (struct window *w, face_index findex)
792 struct frame *f = XFRAME (w->frame);
793 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
795 tty_turn_on_face_1 (c,
796 WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
797 WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
798 WINDOW_FACE_CACHEL_DIM_P (w, findex),
799 WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
800 WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
801 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
802 WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
805 /*****************************************************************************
808 Turn off all set properties of the given face (revert to default
809 face). We assume that tty_turn_on_face has been called for the given
810 face so that its properties are actually active.
811 ****************************************************************************/
813 tty_turn_off_face (struct window *w, face_index findex)
815 struct frame *f = XFRAME (w->frame);
816 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
818 if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
820 /* #### punt for now if standout mode is glitchy */
821 if (!TTY_FLAGS (c).standout_width)
823 OUTPUT1_IF (c, TTY_SD (c).end_standout);
827 if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
829 /* #### punt for now if underline mode is glitchy */
830 if (!TTY_FLAGS (c).underline_width)
832 OUTPUT1_IF (c, TTY_SD (c).end_underline);
836 if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
837 WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
838 WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
839 !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
840 Vthe_null_color_instance) ||
841 !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
842 Vthe_null_color_instance))
844 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
848 /*****************************************************************************
849 tty_turn_on_frame_face
851 Turn on all set properties of the given face.
852 ****************************************************************************/
854 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
857 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
859 XSETFRAME (frame, f);
860 tty_turn_on_face_1 (c,
861 FACE_HIGHLIGHT_P (face, frame),
862 FACE_BLINKING_P (face, frame),
863 FACE_DIM_P (face, frame),
864 FACE_UNDERLINE_P (face, frame),
865 FACE_REVERSE_P (face, frame),
866 FACE_FOREGROUND (face, frame),
867 FACE_BACKGROUND (face, frame));
870 /*****************************************************************************
871 tty_turn_off_frame_face
873 Turn off all set properties of the given face (revert to default
874 face). We assume that tty_turn_on_face has been called for the given
875 face so that its properties are actually active.
876 ****************************************************************************/
878 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
881 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
883 XSETFRAME (frame, f);
885 if (FACE_REVERSE_P (face, frame))
887 /* #### punt for now if standout mode is glitchy */
888 if (!TTY_FLAGS (c).standout_width)
890 OUTPUT1_IF (c, TTY_SD (c).end_standout);
894 if (FACE_UNDERLINE_P (face, frame))
896 /* #### punt for now if underline mode is glitchy */
897 if (!TTY_FLAGS (c).underline_width)
899 OUTPUT1_IF (c, TTY_SD (c).end_underline);
903 if (FACE_HIGHLIGHT_P (face, frame) ||
904 FACE_BLINKING_P (face, frame) ||
905 FACE_DIM_P (face, frame) ||
906 !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
907 !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
909 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
913 /*****************************************************************************
916 Sets up various parameters on tty modes.
917 ****************************************************************************/
919 set_tty_modes (struct console *c)
921 if (!CONSOLE_TTY_P (c))
924 OUTPUT1_IF (c, TTY_SD (c).init_motion);
925 OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
926 OUTPUT1_IF (c, TTY_SD (c).keypad_on);
929 /*****************************************************************************
932 Restore default state of tty.
933 ****************************************************************************/
935 reset_tty_modes (struct console *c)
937 if (!CONSOLE_TTY_P (c))
940 OUTPUT1_IF (c, TTY_SD (c).orig_pair);
941 OUTPUT1_IF (c, TTY_SD (c).keypad_off);
942 OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
943 OUTPUT1_IF (c, TTY_SD (c).end_motion);
944 tty_output_end (XDEVICE (CONSOLE_SELECTED_DEVICE (c)));
947 /*****************************************************************************
948 tty_redisplay_shutdown
950 Clear the frame and position the cursor properly for exiting.
951 ****************************************************************************/
953 tty_redisplay_shutdown (struct console *c)
955 Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
959 Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
963 struct frame *f = XFRAME (frm);
965 /* Clear the bottom line of the frame. */
966 redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
967 f->height, f->width, 1);
969 /* And then stick the cursor there. */
970 tty_set_final_cursor_coords (f, f->height, 0);
971 tty_output_end (XDEVICE (dev));
977 /* #### Everything below here is old shit. It should either be moved
981 /* FLAGS - these don't need to be console local since only one console
982 can be being updated at a time. */
983 static int insert_mode_on; /* nonzero if in insert mode */
984 static int standout_mode_on; /* nonzero if in standout mode */
985 static int underline_mode_on; /* nonzero if in underline mode */
986 static int alternate_mode_on; /* nonzero if in alternate char set */
987 static int attributes_on; /* nonzero if any attributes on */
991 turn_on_insert (struct frame *f)
993 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
996 OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
1001 turn_off_insert (struct frame *f)
1003 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1006 OUTPUT1 (c, TTY_SE (c).end_ins_mode);
1011 internal_cursor_to (struct frame *f, int row, int col)
1013 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1015 if (!TTY_FLAGS (c).insert_mode_motion)
1016 turn_off_insert (f);
1017 if (!TTY_FLAGS (c).standout_motion)
1019 turn_off_standout (f);
1020 turn_off_underline (f);
1021 turn_off_alternate (f);
1024 cmgoto (f, row, col);
1028 clear_to_end (struct frame *f)
1030 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1032 /* assumes cursor is already positioned */
1033 if (TTY_SE (c).clr_from_cursor)
1035 OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
1039 int line = FRAME_CURSOR_Y (f);
1041 while (line < FRAME_HEIGHT (f))
1043 internal_cursor_to (f, line, 0);
1044 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1052 * clear from last visible line on window to window end (presumably
1053 * the line above window's modeline
1056 tty_clear_window_end (struct window *w, int ystart, int yend)
1058 struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1061 for (line = ystart; line < yend; line++)
1063 cmgoto (XFRAME (w->frame), line, 0);
1064 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1071 tty_flash (struct device *d)
1073 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1074 if (TTY_SD (c).visual_bell)
1076 OUTPUT1 (c, TTY_SD (c).visual_bell);
1077 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1085 * tty_ring_bell - sound an audio beep.
1088 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1090 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1094 OUTPUT1 (c, TTY_SD (c).audio_bell);
1095 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1101 init_tty_for_redisplay (struct device *d, char *terminal_type)
1104 char entry_buffer[2044];
1105 /* char temp_buffer[2044]; */
1107 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1109 /* What we should really do is allocate just enough space for
1110 the actual strings that are stored; but this would require
1111 doing this after all the tgetstr()s and adjusting all the
1113 CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1114 bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1117 /* SIGTT* don't exist under win32 */
1118 EMACS_BLOCK_SIGNAL (SIGTTOU);
1120 status = tgetent (entry_buffer, terminal_type);
1122 EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1126 return TTY_UNABLE_OPEN_DATABASE;
1127 else if (status == 0)
1128 return TTY_TYPE_UNDEFINED;
1130 /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1132 return TTY_TYPE_UNDEFINED;
1135 * Establish the terminal size.
1137 /* First try to get the info from the system. If that fails, check
1138 the termcap entry. */
1139 get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1140 &CONSOLE_TTY_DATA (c)->height);
1142 if (CONSOLE_TTY_DATA (c)->width <= 0)
1143 CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1144 if (CONSOLE_TTY_DATA (c)->height <= 0)
1145 CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1147 if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1148 return TTY_SIZE_UNSPECIFIED;
1151 * Initialize cursor motion information.
1154 /* local cursor movement */
1155 TTY_CM (c).up = tgetstr ("up", &bufptr);
1156 TTY_CM (c).down = tgetstr ("do", &bufptr);
1157 TTY_CM (c).left = tgetstr ("le", &bufptr);
1158 TTY_CM (c).right = tgetstr ("nd", &bufptr);
1159 TTY_CM (c).home = tgetstr ("ho", &bufptr);
1160 TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1161 TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1163 /* absolute cursor motion */
1164 TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1165 TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1166 TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1168 /* Verify that the terminal is powerful enough to run Emacs */
1169 if (!TTY_CM (c).abs)
1171 if (!TTY_CM (c).up || !TTY_CM (c).down
1172 || !TTY_CM (c).left || !TTY_CM (c).right)
1173 return TTY_TYPE_INSUFFICIENT;
1176 /* parameterized local cursor movement */
1177 TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1178 TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1179 TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1180 TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1183 TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1184 TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1185 TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1186 TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1187 TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1191 * Initialize screen editing information.
1194 /* adding to the screen */
1195 TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1196 TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1197 TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1198 TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1199 TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1200 TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1201 TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1202 TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1204 /* deleting from the screen */
1205 TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1206 TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1207 TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1208 TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1209 TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1210 TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1211 TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1212 TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1213 TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1214 TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1218 * Initialize screen display information.
1220 TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1221 TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1222 TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1223 TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1224 TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1225 TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1226 TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1227 TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1228 TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1229 TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1230 TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1231 TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1233 TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1234 TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1235 if (!TTY_SD (c).audio_bell)
1237 /* If audio_bell doesn't get set, then assume C-g. This is gross and
1238 ugly but is what Emacs has done from time immortal. */
1239 TTY_SD (c).audio_bell = "\07";
1242 TTY_SD (c).cursor_visible = tgetstr ("ve", &bufptr);
1243 TTY_SD (c).cursor_normal = tgetstr ("vs", &bufptr);
1244 TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1245 TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1246 TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1247 TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1251 * Initialize additional terminal information.
1253 TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1254 TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1255 TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1256 TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1257 TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1258 TTY_FLAGS (c).standout_width = tgetnum ("sg");
1259 TTY_FLAGS (c).underline_width = tgetnum ("ug");
1261 if (TTY_FLAGS (c).standout_width == -1)
1262 TTY_FLAGS (c).standout_width = 0;
1263 if (TTY_FLAGS (c).underline_width == -1)
1264 TTY_FLAGS (c).underline_width = 0;
1266 TTY_FLAGS (c).meta_key =
1267 eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1271 * Setup the costs tables for this tty console.
1276 * Initialize local flags.
1279 standout_mode_on = 0;
1280 underline_mode_on = 0;
1281 alternate_mode_on = 0;
1285 * Attempt to initialize the function_key_map to
1286 * some kind of sensible value
1289 term_get_fkeys (c->function_key_map, &bufptr);
1292 /* check for ANSI set-foreground and set-background strings,
1293 and assume color if so.
1295 #### we should support the other (non-ANSI) ways of specifying
1298 char *fooptr = foobuf;
1299 if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1300 (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1301 ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1302 DEVICE_CLASS (d) = Qcolor;
1304 DEVICE_CLASS (d) = Qmono;
1307 return TTY_INIT_SUCCESS;
1316 /* Termcap capability names that correspond directly to X keysyms.
1317 Some of these (marked "terminfo") aren't supplied by old-style
1318 (Berkeley) termcap entries. They're listed in X keysym order;
1319 except we put the keypad keys first, so that if they clash with
1320 other keys (as on the IBM PC keyboard) they get overridden.
1323 static struct fkey_table keys[] =
1325 {"kh", "home"}, /* termcap */
1326 {"kl", "left"}, /* termcap */
1327 {"ku", "up"}, /* termcap */
1328 {"kr", "right"}, /* termcap */
1329 {"kd", "down"}, /* termcap */
1330 {"%8", "prior"}, /* terminfo */
1331 {"%5", "next"}, /* terminfo */
1332 {"@7", "end"}, /* terminfo */
1333 {"@1", "begin"}, /* terminfo */
1334 {"*6", "select"}, /* terminfo */
1335 {"%9", "print"}, /* terminfo */
1336 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1338 * "insert" --- see below
1340 {"&8", "undo"}, /* terminfo */
1341 {"%0", "redo"}, /* terminfo */
1342 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1343 {"@0", "find"}, /* terminfo */
1344 {"@2", "cancel"}, /* terminfo */
1345 {"%1", "help"}, /* terminfo */
1347 * "break" goes here, but can't be reliably intercepted with termcap
1349 {"&4", "reset"}, /* terminfo --- actually `restart' */
1351 * "system" and "user" --- no termcaps
1353 {"kE", "clearline"}, /* terminfo */
1354 {"kA", "insertline"}, /* terminfo */
1355 {"kL", "deleteline"}, /* terminfo */
1356 {"kI", "insertchar"}, /* terminfo */
1357 {"kD", "delete"}, /* terminfo */
1358 {"kB", "backtab"}, /* terminfo */
1360 * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1362 {"@8", "kp-enter"}, /* terminfo */
1364 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1365 * "kp-multiply", "kp-add", "kp-separator",
1366 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1367 * --- no termcaps for any of these.
1369 {"K4", "kp-1"}, /* terminfo */
1371 * "kp-2" --- no termcap
1373 {"K5", "kp-3"}, /* terminfo */
1375 * "kp-4" --- no termcap
1377 {"K2", "kp-5"}, /* terminfo */
1379 * "kp-6" --- no termcap
1381 {"K1", "kp-7"}, /* terminfo */
1383 * "kp-8" --- no termcap
1385 {"K3", "kp-9"}, /* terminfo */
1387 * "kp-equal" --- no termcap
1400 static char **term_get_fkeys_arg;
1402 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1403 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1405 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1406 This function scans the termcap function key sequence entries, and
1407 adds entries to Vfunction_key_map for each function key it finds. */
1410 term_get_fkeys (Lisp_Object keymap, char **address)
1412 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1413 errors during the call. The only errors should be from Fdefine_key
1414 when given a key sequence containing an invalid prefix key. If the
1415 termcap defines function keys which use a prefix that is already bound
1416 to a command by the default bindings, we should silently ignore that
1417 function key specification, rather than giving the user an error and
1418 refusing to run at all on such a terminal. */
1420 term_get_fkeys_arg = address;
1422 condition_case_1 (Qerror,
1423 term_get_fkeys_1, keymap,
1424 term_get_fkeys_error, Qnil);
1428 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1434 term_get_fkeys_1 (Lisp_Object function_key_map)
1438 char **address = term_get_fkeys_arg;
1440 for (i = 0; i < countof (keys); i++)
1442 char *sequence = tgetstr (keys[i].cap, address);
1444 Fdefine_key (function_key_map,
1445 build_ext_string (sequence, Qbinary),
1446 vector1 (intern (keys[i].name)));
1449 /* The uses of the "k0" capability are inconsistent; sometimes it
1450 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1451 We will attempt to politely accommodate both systems by testing for
1452 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1455 const char *k_semi = tgetstr ("k;", address);
1456 const char *k0 = tgetstr ("k0", address);
1459 Fdefine_key (function_key_map, build_ext_string (k_semi, Qbinary),
1460 vector1 (intern ("f10")));
1463 Fdefine_key (function_key_map, build_ext_string (k0, Qbinary),
1464 vector1 (intern (k_semi ? "f0" : "f10")));
1467 /* Set up cookies for numbered function keys above f10. */
1469 char fcap[3], fkey[4];
1471 fcap[0] = 'F'; fcap[2] = '\0';
1472 for (i = 11; i < 64; i++)
1475 fcap[1] = '1' + i - 11;
1477 fcap[1] = 'A' + i - 20;
1479 fcap[1] = 'a' + i - 46;
1482 char *sequence = tgetstr (fcap, address);
1485 sprintf (fkey, "f%d", i);
1486 Fdefine_key (function_key_map,
1487 build_ext_string (sequence, Qbinary),
1488 vector1 (intern (fkey)));
1495 * Various mappings to try and get a better fit.
1497 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) do { \
1498 if (!tgetstr (cap1, address)) \
1500 char *sequence = tgetstr (cap2, address); \
1502 Fdefine_key (function_key_map, \
1503 build_ext_string (sequence, Qbinary), \
1504 vector1 (intern (keyname))); \
1508 /* if there's no key_next keycap, map key_npage to `next' keysym */
1509 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1510 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1511 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1512 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1513 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1515 /* IBM has their own non-standard dialect of terminfo.
1516 If the standard name isn't found, try the IBM name. */
1517 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1518 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1519 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1520 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1521 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1522 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1523 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1524 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1525 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1526 #undef CONDITIONAL_REASSIGN
1532 /************************************************************************/
1533 /* initialization */
1534 /************************************************************************/
1537 console_type_create_redisplay_tty (void)
1539 /* redisplay methods */
1540 CONSOLE_HAS_METHOD (tty, text_width);
1541 CONSOLE_HAS_METHOD (tty, output_display_block);
1542 CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1543 CONSOLE_HAS_METHOD (tty, divider_height);
1544 CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1545 CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1546 CONSOLE_HAS_METHOD (tty, clear_region);
1547 CONSOLE_HAS_METHOD (tty, clear_frame);
1548 CONSOLE_HAS_METHOD (tty, output_begin);
1549 CONSOLE_HAS_METHOD (tty, output_end);
1550 CONSOLE_HAS_METHOD (tty, flash);
1551 CONSOLE_HAS_METHOD (tty, ring_bell);
1552 CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);