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_charc_dynarr (struct window *w,
85 struct display_line *dl,
86 Charc_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 charc_string_displayed_columns().
108 ****************************************************************************/
110 tty_text_width (struct frame *f, struct face_cachel *cachel,
111 const Charc *str, Charcount len)
113 return charc_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 /*****************************************************************************
141 tty_frame_output_begin
143 Perform any necessary initialization prior to an update.
144 ****************************************************************************/
146 void tty_frame_output_begin (struct frame *f);
151 tty_frame_output_begin (struct frame *f)
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 (XDEVICE (FRAME_DEVICE (f)))->ospeed;
161 /*****************************************************************************
164 Perform any necessary flushing of queues when an update has completed.
165 ****************************************************************************/
167 void tty_frame_output_end (struct frame *f);
172 tty_frame_output_end (struct frame *f)
174 struct device *d = XDEVICE (FRAME_DEVICE (f));
175 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
177 CONSOLE_TTY_CURSOR_X (c) = CONSOLE_TTY_FINAL_CURSOR_X (c);
178 CONSOLE_TTY_CURSOR_Y (c) = CONSOLE_TTY_FINAL_CURSOR_Y (c);
179 FORCE_CURSOR_UPDATE (c);
180 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
184 tty_set_final_cursor_coords (struct frame *f, int y, int x)
186 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
188 CONSOLE_TTY_FINAL_CURSOR_X (c) = x;
189 CONSOLE_TTY_FINAL_CURSOR_Y (c) = y;
192 /*****************************************************************************
193 tty_output_display_block
195 Given a display line, a block number for that start line, output all
196 runes between start and end in the specified display block.
197 ****************************************************************************/
199 tty_output_display_block (struct window *w, struct display_line *dl, int block,
200 int start, int end, int start_pixpos,
201 int cursor_start, int cursor_width,
204 struct frame *f = XFRAME (w->frame);
205 Charc_dynarr *buf = Dynarr_new (Charc);
207 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
208 rune_dynarr *rba = db->runes;
215 rb = Dynarr_atp (rba, elt);
219 /* Nothing to do so don't do anything. */
229 end = Dynarr_length (rba);
233 while (elt < end && Dynarr_atp (rba, elt)->xpos < start_pixpos)
236 findex = Dynarr_atp (rba, elt)->findex;
237 xpos = Dynarr_atp (rba, elt)->xpos;
242 rb = Dynarr_atp (rba, elt);
244 if (rb->findex == findex && rb->type == RUNE_CHAR
245 && (!EQ (rb->object.cglyph.charset, Vcharset_ascii)
246 || (rb->object.cglyph.code_point != '\n'))
247 && (rb->cursor_type != CURSOR_ON
248 || NILP (w->text_cursor_visible_p)))
250 Dynarr_add (buf, rb->object.cglyph);
255 if (Dynarr_length (buf))
257 tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
262 if (rb->type == RUNE_CHAR)
267 if (EQ (rb->object.cglyph.charset, Vcharset_ascii)
268 && (rb->object.cglyph.code_point == '\n'))
270 /* Clear in case a cursor was formerly here. */
273 ec_space.charset = Vcharset_ascii;
274 ec_space.code_point = ' ';
275 Dynarr_add (buf, ec_space);
276 tty_output_charc_dynarr (w, dl, buf, rb->xpos,
280 cmgoto (f, dl->ypos - 1, rb->xpos);
284 else if (rb->cursor_type == CURSOR_ON)
286 /* There is not a distinct eol cursor on tty's. */
288 Dynarr_add (buf, rb->object.cglyph);
289 tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
292 cmgoto (f, dl->ypos - 1, xpos);
298 /* #### RUNE_HLINE is actually a little more complicated than this
299 but at the moment it is only used to draw a turned off
300 modeline and this will suffice for that. */
301 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
304 int size = rb->width;
306 ec_to_add.charset = Vcharset_ascii;
307 if (rb->type == RUNE_BLANK)
308 ec_to_add.code_point = ' ';
310 ec_to_add.code_point = '-';
313 Dynarr_add (buf, ec_to_add);
314 tty_output_charc_dynarr (w, dl, buf, rb->xpos, findex, 0);
316 if (xpos >= cursor_start
317 && cursor_start < xpos + Dynarr_length (buf))
319 cmgoto (f, dl->ypos - 1, cursor_start);
327 rb = Dynarr_atp (rba, elt);
333 else if (rb->type == RUNE_DGLYPH)
336 Lisp_Object instance;
338 XSETWINDOW (window, w);
339 instance = glyph_image_instance (rb->object.dglyph.glyph,
340 window, ERROR_ME_NOT, 1);
342 if (IMAGE_INSTANCEP (instance))
344 switch (XIMAGE_INSTANCE_TYPE (instance))
346 case IMAGE_MONO_PIXMAP:
347 case IMAGE_COLOR_PIXMAP:
348 case IMAGE_SUBWINDOW:
350 /* just do nothing here */
354 /* nothing is as nothing does */
362 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
363 (XIMAGE_INSTANCE (instance)) = 0;
374 if (Dynarr_length (buf))
375 tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
382 /*****************************************************************************
383 tty_output_vertical_divider
385 Draw a vertical divider down the right side of the given window.
386 ****************************************************************************/
388 tty_output_vertical_divider (struct window *w, int clear)
390 /* Divider width can either be 0 or 1 on TTYs */
391 if (window_divider_width (w))
393 struct frame *f = XFRAME (w->frame);
394 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
396 int y_top = WINDOW_TEXT_TOP (w);
397 int y_bot = WINDOW_TEXT_BOTTOM (w);
398 unsigned char divv = '|';
400 tty_turn_on_face (w, MODELINE_INDEX);
401 for (line = y_top; line < y_bot; line++)
403 cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
404 send_string_to_tty_console (c, &divv, 1);
405 TTY_INC_CURSOR_X (c, 1);
408 /* Draw the divider in the modeline. */
409 cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
410 send_string_to_tty_console (c, &divv, 1);
411 TTY_INC_CURSOR_X (c, 1);
412 tty_turn_off_face (w, MODELINE_INDEX);
416 /****************************************************************************
419 Clear the area in the box defined by the given parameters.
420 ****************************************************************************/
422 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
423 face_index findex, int x, int y,
424 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
425 Lisp_Object background_pixmap)
427 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
429 struct window* w = XWINDOW (window);
431 tty_turn_on_face (w, findex);
432 for (line = y; line < y + height; line++)
438 if (window_is_leftmost (w)
439 && window_is_rightmost (w)
440 && TTY_SE (c).clr_to_eol)
442 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
446 unsigned char sp = ' ';
447 /* #### Of course, this is all complete and utter crap. */
448 for (col = x; col < x + width; col++)
449 send_string_to_tty_console (c, &sp, 1);
450 TTY_INC_CURSOR_X (c, width);
453 tty_turn_off_face (w, findex);
457 /*****************************************************************************
458 tty_clear_to_window_end
460 Clear the area between ypos1 and ypos2. Each margin area and the
461 text area is handled separately since they may each have their own
463 ****************************************************************************/
465 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
467 struct frame *f = XFRAME (w->frame);
468 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
471 x = WINDOW_TEXT_LEFT (w);
472 width = WINDOW_TEXT_WIDTH (w);
474 if (window_is_rightmost (w))
476 /* #### Optimize to use clr_to_eol function of tty if available, if
477 the window is the entire width of the frame. */
478 /* #### Is this actually an optimization? */
480 tty_turn_on_face (w, DEFAULT_INDEX);
481 for (line = ypos1; line < ypos2; line++)
483 cmgoto (XFRAME (w->frame), line, x);
484 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
486 tty_turn_off_face (w, DEFAULT_INDEX);
492 XSETWINDOW (window, w);
493 redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
497 /****************************************************************************
500 Clear the entire frame.
501 ****************************************************************************/
503 tty_clear_frame (struct frame *f)
505 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
507 tty_turn_on_frame_face (f, Vdefault_face);
508 if (TTY_SE (c).clr_frame)
510 OUTPUT1 (c, TTY_SE (c).clr_frame);
511 CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
512 CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
514 FRAME_CURSOR_X (f) = 0;
515 FRAME_CURSOR_Y (f) = 0;
521 internal_cursor_to (f, 0, 0);
524 /* #### Not implemented. */
525 stderr_out ("Not yet.\n");
528 tty_turn_off_frame_face (f, Vdefault_face);
532 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
533 Bufbyte *str, Bytecount len, int xpos,
534 face_index findex, int cursor)
536 struct frame *f = XFRAME (w->frame);
537 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
539 /* First position the cursor. */
540 cmgoto (f, dl->ypos - 1, xpos);
542 /* Enable any face properties. */
543 tty_turn_on_face (w, findex);
545 send_string_to_tty_console (c, str, len);
546 TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
548 /* Turn the face properties back off. */
549 tty_turn_off_face (w, findex);
552 static Bufbyte_dynarr *tty_output_charc_dynarr_dynarr;
554 /*****************************************************************************
555 tty_output_charc_dynarr
557 Given a string and a starting position, output that string in the
558 given face. If cursor is true, draw a cursor around the string.
559 ****************************************************************************/
561 tty_output_charc_dynarr (struct window *w, struct display_line *dl,
562 Charc_dynarr *buf, int xpos, face_index findex,
565 if (!tty_output_charc_dynarr_dynarr)
566 tty_output_charc_dynarr_dynarr = Dynarr_new (Bufbyte);
568 Dynarr_reset (tty_output_charc_dynarr_dynarr);
570 convert_charc_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
572 tty_output_charc_dynarr_dynarr);
574 tty_output_bufbyte_string (w, dl,
575 Dynarr_atp (tty_output_charc_dynarr_dynarr, 0),
576 Dynarr_length (tty_output_charc_dynarr_dynarr),
577 xpos, findex, cursor);
582 static Bufbyte_dynarr *sidcs_dynarr;
585 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
588 Bufbyte *specdata = XSTRING_DATA (spec);
589 Bytecount speclen = XSTRING_LENGTH (spec);
592 sidcs_dynarr = Dynarr_new (Bufbyte);
594 Dynarr_reset (sidcs_dynarr);
596 for (i = 0; i < speclen; i++)
598 if (specdata[i] == '%' && specdata[i+1] == '%')
600 Dynarr_add (sidcs_dynarr, '%');
603 else if (specdata[i] == '%' && specdata[i+1] == 's')
605 Dynarr_add_many (sidcs_dynarr,
606 XSTRING_DATA (string),
607 XSTRING_LENGTH (string));
611 Dynarr_add (sidcs_dynarr, specdata[i]);
618 set_foreground_to (struct console *c, Lisp_Object sym)
622 Bytecount escseqlen = 0;
624 result = assq_no_quit (sym, Vtty_color_alist);
627 Lisp_Object esc_seq = XCAR (XCDR (result));
628 escseq = XSTRING_DATA (esc_seq);
629 escseqlen = XSTRING_LENGTH (esc_seq);
632 else if (STRINGP (Vtty_dynamic_color_fg))
634 substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
636 escseq = Dynarr_atp (sidcs_dynarr, 0);
637 escseqlen = Dynarr_length (sidcs_dynarr);
643 send_string_to_tty_console (c, escseq, escseqlen);
648 set_background_to (struct console *c, Lisp_Object sym)
652 Bytecount escseqlen = 0;
654 result = assq_no_quit (sym, Vtty_color_alist);
657 Lisp_Object esc_seq = XCDR (XCDR (result));
658 escseq = XSTRING_DATA (esc_seq);
659 escseqlen = XSTRING_LENGTH (esc_seq);
662 else if (STRINGP (Vtty_dynamic_color_bg))
664 substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
666 escseq = Dynarr_atp (sidcs_dynarr, 0);
667 escseqlen = Dynarr_length (sidcs_dynarr);
673 send_string_to_tty_console (c, escseq, escseqlen);
678 tty_turn_on_face_1 (struct console *c, int highlight_p,
679 int blinking_p, int dim_p, int underline_p,
680 int reverse_p, Lisp_Object cinst_fore,
681 Lisp_Object cinst_back)
685 OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
690 OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
695 OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
700 /* #### punt for now if underline mode is glitchy */
701 if (!TTY_FLAGS (c).underline_width)
703 OUTPUT1_IF (c, TTY_SD (c).begin_underline);
709 /* #### punt for now if standout mode is glitchy */
710 if (!TTY_FLAGS (c).standout_width)
712 OUTPUT1_IF (c, TTY_SD (c).begin_standout);
720 Lisp_Object temp = cinst_fore;
721 cinst_fore = cinst_back;
725 if (COLOR_INSTANCEP (cinst_fore)
726 && !EQ (cinst_fore, Vthe_null_color_instance))
727 set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
728 (XCOLOR_INSTANCE (cinst_fore)));
730 if (COLOR_INSTANCEP (cinst_back)
731 && !EQ (cinst_back, Vthe_null_color_instance))
732 set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
733 (XCOLOR_INSTANCE (cinst_back)));
736 /*****************************************************************************
739 Turn on all set properties of the given face.
740 ****************************************************************************/
742 tty_turn_on_face (struct window *w, face_index findex)
744 struct frame *f = XFRAME (w->frame);
745 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
747 tty_turn_on_face_1 (c,
748 WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
749 WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
750 WINDOW_FACE_CACHEL_DIM_P (w, findex),
751 WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
752 WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
753 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
754 WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
757 /*****************************************************************************
760 Turn off all set properties of the given face (revert to default
761 face). We assume that tty_turn_on_face has been called for the given
762 face so that its properties are actually active.
763 ****************************************************************************/
765 tty_turn_off_face (struct window *w, face_index findex)
767 struct frame *f = XFRAME (w->frame);
768 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
770 if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
772 /* #### punt for now if standout mode is glitchy */
773 if (!TTY_FLAGS (c).standout_width)
775 OUTPUT1_IF (c, TTY_SD (c).end_standout);
779 if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
781 /* #### punt for now if underline mode is glitchy */
782 if (!TTY_FLAGS (c).underline_width)
784 OUTPUT1_IF (c, TTY_SD (c).end_underline);
788 if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
789 WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
790 WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
791 !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
792 Vthe_null_color_instance) ||
793 !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
794 Vthe_null_color_instance))
796 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
800 /*****************************************************************************
801 tty_turn_on_frame_face
803 Turn on all set properties of the given face.
804 ****************************************************************************/
806 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
809 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
811 XSETFRAME (frame, f);
812 tty_turn_on_face_1 (c,
813 FACE_HIGHLIGHT_P (face, frame),
814 FACE_BLINKING_P (face, frame),
815 FACE_DIM_P (face, frame),
816 FACE_UNDERLINE_P (face, frame),
817 FACE_REVERSE_P (face, frame),
818 FACE_FOREGROUND (face, frame),
819 FACE_BACKGROUND (face, frame));
822 /*****************************************************************************
823 tty_turn_off_frame_face
825 Turn off all set properties of the given face (revert to default
826 face). We assume that tty_turn_on_face has been called for the given
827 face so that its properties are actually active.
828 ****************************************************************************/
830 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
833 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
835 XSETFRAME (frame, f);
837 if (FACE_REVERSE_P (face, frame))
839 /* #### punt for now if standout mode is glitchy */
840 if (!TTY_FLAGS (c).standout_width)
842 OUTPUT1_IF (c, TTY_SD (c).end_standout);
846 if (FACE_UNDERLINE_P (face, frame))
848 /* #### punt for now if underline mode is glitchy */
849 if (!TTY_FLAGS (c).underline_width)
851 OUTPUT1_IF (c, TTY_SD (c).end_underline);
855 if (FACE_HIGHLIGHT_P (face, frame) ||
856 FACE_BLINKING_P (face, frame) ||
857 FACE_DIM_P (face, frame) ||
858 !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
859 !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
861 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
865 /*****************************************************************************
868 Sets up various parameters on tty modes.
869 ****************************************************************************/
871 set_tty_modes (struct console *c)
873 if (!CONSOLE_TTY_P (c))
876 OUTPUT1_IF (c, TTY_SD (c).init_motion);
877 OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
878 OUTPUT1_IF (c, TTY_SD (c).keypad_on);
881 /*****************************************************************************
884 Restore default state of tty.
885 ****************************************************************************/
887 reset_tty_modes (struct console *c)
889 if (!CONSOLE_TTY_P (c))
892 OUTPUT1_IF (c, TTY_SD (c).orig_pair);
893 OUTPUT1_IF (c, TTY_SD (c).keypad_off);
894 OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
895 OUTPUT1_IF (c, TTY_SD (c).end_motion);
896 tty_frame_output_end (XFRAME (CONSOLE_SELECTED_FRAME (c)));
899 /*****************************************************************************
900 tty_redisplay_shutdown
902 Clear the frame and position the cursor properly for exiting.
903 ****************************************************************************/
905 tty_redisplay_shutdown (struct console *c)
907 Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
911 Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
915 struct frame *f = XFRAME (frm);
917 /* Clear the bottom line of the frame. */
918 redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
919 f->height, f->width, 1);
921 /* And then stick the cursor there. */
922 tty_set_final_cursor_coords (f, f->height, 0);
923 tty_frame_output_end (f);
929 /* #### Everything below here is old shit. It should either be moved
933 /* FLAGS - these don't need to be console local since only one console
934 can be being updated at a time. */
935 static int insert_mode_on; /* nonzero if in insert mode */
936 static int standout_mode_on; /* nonzero if in standout mode */
937 static int underline_mode_on; /* nonzero if in underline mode */
938 static int alternate_mode_on; /* nonzero if in alternate char set */
939 static int attributes_on; /* nonzero if any attributes on */
943 turn_on_insert (struct frame *f)
945 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
948 OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
953 turn_off_insert (struct frame *f)
955 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
958 OUTPUT1 (c, TTY_SE (c).end_ins_mode);
963 internal_cursor_to (struct frame *f, int row, int col)
965 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
967 if (!TTY_FLAGS (c).insert_mode_motion)
969 if (!TTY_FLAGS (c).standout_motion)
971 turn_off_standout (f);
972 turn_off_underline (f);
973 turn_off_alternate (f);
976 cmgoto (f, row, col);
980 clear_to_end (struct frame *f)
982 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
984 /* assumes cursor is already positioned */
985 if (TTY_SE (c).clr_from_cursor)
987 OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
991 int line = FRAME_CURSOR_Y (f);
993 while (line < FRAME_HEIGHT (f))
995 internal_cursor_to (f, line, 0);
996 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1004 * clear from last visible line on window to window end (presumably
1005 * the line above window's modeline
1008 tty_clear_window_end (struct window *w, int ystart, int yend)
1010 struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1013 for (line = ystart; line < yend; line++)
1015 cmgoto (XFRAME (w->frame), line, 0);
1016 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1023 tty_flash (struct device *d)
1025 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1026 if (TTY_SD (c).visual_bell)
1028 OUTPUT1 (c, TTY_SD (c).visual_bell);
1029 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1037 * tty_ring_bell - sound an audio beep.
1040 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1042 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1046 OUTPUT1 (c, TTY_SD (c).audio_bell);
1047 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1053 init_tty_for_redisplay (struct device *d, char *terminal_type)
1056 char entry_buffer[2044];
1057 /* char temp_buffer[2044]; */
1059 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1061 /* What we should really do is allocate just enough space for
1062 the actual strings that are stored; but this would require
1063 doing this after all the tgetstr()s and adjusting all the
1065 CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1066 bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1069 /* SIGTT* don't exist under win32 */
1070 EMACS_BLOCK_SIGNAL (SIGTTOU);
1072 status = tgetent (entry_buffer, terminal_type);
1074 EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1078 return TTY_UNABLE_OPEN_DATABASE;
1079 else if (status == 0)
1080 return TTY_TYPE_UNDEFINED;
1082 /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1084 return TTY_TYPE_UNDEFINED;
1087 * Establish the terminal size.
1089 /* First try to get the info from the system. If that fails, check
1090 the termcap entry. */
1091 get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1092 &CONSOLE_TTY_DATA (c)->height);
1094 if (CONSOLE_TTY_DATA (c)->width <= 0)
1095 CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1096 if (CONSOLE_TTY_DATA (c)->height <= 0)
1097 CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1099 if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1100 return TTY_SIZE_UNSPECIFIED;
1103 * Initialize cursor motion information.
1106 /* local cursor movement */
1107 TTY_CM (c).up = tgetstr ("up", &bufptr);
1108 TTY_CM (c).down = tgetstr ("do", &bufptr);
1109 TTY_CM (c).left = tgetstr ("le", &bufptr);
1110 TTY_CM (c).right = tgetstr ("nd", &bufptr);
1111 TTY_CM (c).home = tgetstr ("ho", &bufptr);
1112 TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1113 TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1115 /* absolute cursor motion */
1116 TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1117 TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1118 TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1120 /* Verify that the terminal is powerful enough to run Emacs */
1121 if (!TTY_CM (c).abs)
1123 if (!TTY_CM (c).up || !TTY_CM (c).down
1124 || !TTY_CM (c).left || !TTY_CM (c).right)
1125 return TTY_TYPE_INSUFFICIENT;
1128 /* parameterized local cursor movement */
1129 TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1130 TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1131 TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1132 TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1135 TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1136 TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1137 TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1138 TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1139 TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1143 * Initialize screen editing information.
1146 /* adding to the screen */
1147 TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1148 TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1149 TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1150 TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1151 TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1152 TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1153 TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1154 TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1156 /* deleting from the screen */
1157 TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1158 TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1159 TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1160 TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1161 TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1162 TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1163 TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1164 TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1165 TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1166 TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1170 * Initialize screen display information.
1172 TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1173 TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1174 TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1175 TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1176 TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1177 TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1178 TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1179 TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1180 TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1181 TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1182 TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1183 TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1185 TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1186 TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1187 if (!TTY_SD (c).audio_bell)
1189 /* If audio_bell doesn't get set, then assume C-g. This is gross and
1190 ugly but is what Emacs has done from time immortal. */
1191 TTY_SD (c).audio_bell = "\07";
1194 TTY_SD (c).cursor_visible = tgetstr ("ve", &bufptr);
1195 TTY_SD (c).cursor_normal = tgetstr ("vs", &bufptr);
1196 TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1197 TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1198 TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1199 TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1203 * Initialize additional terminal information.
1205 TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1206 TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1207 TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1208 TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1209 TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1210 TTY_FLAGS (c).standout_width = tgetnum ("sg");
1211 TTY_FLAGS (c).underline_width = tgetnum ("ug");
1213 if (TTY_FLAGS (c).standout_width == -1)
1214 TTY_FLAGS (c).standout_width = 0;
1215 if (TTY_FLAGS (c).underline_width == -1)
1216 TTY_FLAGS (c).underline_width = 0;
1218 TTY_FLAGS (c).meta_key =
1219 eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1223 * Setup the costs tables for this tty console.
1228 * Initialize local flags.
1231 standout_mode_on = 0;
1232 underline_mode_on = 0;
1233 alternate_mode_on = 0;
1237 * Attempt to initialize the function_key_map to
1238 * some kind of sensible value
1241 term_get_fkeys (c->function_key_map, &bufptr);
1244 /* check for ANSI set-foreground and set-background strings,
1245 and assume color if so.
1247 #### we should support the other (non-ANSI) ways of specifying
1250 char *fooptr = foobuf;
1251 if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1252 (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1253 ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1254 DEVICE_CLASS (d) = Qcolor;
1256 DEVICE_CLASS (d) = Qmono;
1259 return TTY_INIT_SUCCESS;
1268 /* Termcap capability names that correspond directly to X keysyms.
1269 Some of these (marked "terminfo") aren't supplied by old-style
1270 (Berkeley) termcap entries. They're listed in X keysym order;
1271 except we put the keypad keys first, so that if they clash with
1272 other keys (as on the IBM PC keyboard) they get overridden.
1275 static struct fkey_table keys[] =
1277 {"kh", "home"}, /* termcap */
1278 {"kl", "left"}, /* termcap */
1279 {"ku", "up"}, /* termcap */
1280 {"kr", "right"}, /* termcap */
1281 {"kd", "down"}, /* termcap */
1282 {"%8", "prior"}, /* terminfo */
1283 {"%5", "next"}, /* terminfo */
1284 {"@7", "end"}, /* terminfo */
1285 {"@1", "begin"}, /* terminfo */
1286 {"*6", "select"}, /* terminfo */
1287 {"%9", "print"}, /* terminfo */
1288 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1290 * "insert" --- see below
1292 {"&8", "undo"}, /* terminfo */
1293 {"%0", "redo"}, /* terminfo */
1294 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1295 {"@0", "find"}, /* terminfo */
1296 {"@2", "cancel"}, /* terminfo */
1297 {"%1", "help"}, /* terminfo */
1299 * "break" goes here, but can't be reliably intercepted with termcap
1301 {"&4", "reset"}, /* terminfo --- actually `restart' */
1303 * "system" and "user" --- no termcaps
1305 {"kE", "clearline"}, /* terminfo */
1306 {"kA", "insertline"}, /* terminfo */
1307 {"kL", "deleteline"}, /* terminfo */
1308 {"kI", "insertchar"}, /* terminfo */
1309 {"kD", "delete"}, /* terminfo */
1310 {"kB", "backtab"}, /* terminfo */
1312 * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1314 {"@8", "kp-enter"}, /* terminfo */
1316 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1317 * "kp-multiply", "kp-add", "kp-separator",
1318 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1319 * --- no termcaps for any of these.
1321 {"K4", "kp-1"}, /* terminfo */
1323 * "kp-2" --- no termcap
1325 {"K5", "kp-3"}, /* terminfo */
1327 * "kp-4" --- no termcap
1329 {"K2", "kp-5"}, /* terminfo */
1331 * "kp-6" --- no termcap
1333 {"K1", "kp-7"}, /* terminfo */
1335 * "kp-8" --- no termcap
1337 {"K3", "kp-9"}, /* terminfo */
1339 * "kp-equal" --- no termcap
1352 static char **term_get_fkeys_arg;
1354 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1355 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1357 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1358 This function scans the termcap function key sequence entries, and
1359 adds entries to Vfunction_key_map for each function key it finds. */
1362 term_get_fkeys (Lisp_Object keymap, char **address)
1364 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1365 errors during the call. The only errors should be from Fdefine_key
1366 when given a key sequence containing an invalid prefix key. If the
1367 termcap defines function keys which use a prefix that is already bound
1368 to a command by the default bindings, we should silently ignore that
1369 function key specification, rather than giving the user an error and
1370 refusing to run at all on such a terminal. */
1372 term_get_fkeys_arg = address;
1374 condition_case_1 (Qerror,
1375 term_get_fkeys_1, keymap,
1376 term_get_fkeys_error, Qnil);
1380 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1386 term_get_fkeys_1 (Lisp_Object function_key_map)
1390 char **address = term_get_fkeys_arg;
1392 for (i = 0; i < countof (keys); i++)
1394 char *sequence = tgetstr (keys[i].cap, address);
1396 Fdefine_key (function_key_map,
1397 build_ext_string (sequence, Qbinary),
1398 vector1 (intern (keys[i].name)));
1401 /* The uses of the "k0" capability are inconsistent; sometimes it
1402 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1403 We will attempt to politely accommodate both systems by testing for
1404 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1407 const char *k_semi = tgetstr ("k;", address);
1408 const char *k0 = tgetstr ("k0", address);
1411 Fdefine_key (function_key_map, build_ext_string (k_semi, Qbinary),
1412 vector1 (intern ("f10")));
1415 Fdefine_key (function_key_map, build_ext_string (k0, Qbinary),
1416 vector1 (intern (k_semi ? "f0" : "f10")));
1419 /* Set up cookies for numbered function keys above f10. */
1421 char fcap[3], fkey[4];
1423 fcap[0] = 'F'; fcap[2] = '\0';
1424 for (i = 11; i < 64; i++)
1427 fcap[1] = '1' + i - 11;
1429 fcap[1] = 'A' + i - 20;
1431 fcap[1] = 'a' + i - 46;
1434 char *sequence = tgetstr (fcap, address);
1437 sprintf (fkey, "f%d", i);
1438 Fdefine_key (function_key_map,
1439 build_ext_string (sequence, Qbinary),
1440 vector1 (intern (fkey)));
1447 * Various mappings to try and get a better fit.
1449 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) do { \
1450 if (!tgetstr (cap1, address)) \
1452 char *sequence = tgetstr (cap2, address); \
1454 Fdefine_key (function_key_map, \
1455 build_ext_string (sequence, Qbinary), \
1456 vector1 (intern (keyname))); \
1460 /* if there's no key_next keycap, map key_npage to `next' keysym */
1461 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1462 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1463 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1464 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1465 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1467 /* IBM has their own non-standard dialect of terminfo.
1468 If the standard name isn't found, try the IBM name. */
1469 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1470 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1471 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1472 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1473 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1474 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1475 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1476 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1477 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1478 #undef CONDITIONAL_REASSIGN
1484 /************************************************************************/
1485 /* initialization */
1486 /************************************************************************/
1489 console_type_create_redisplay_tty (void)
1491 /* redisplay methods */
1492 CONSOLE_HAS_METHOD (tty, text_width);
1493 CONSOLE_HAS_METHOD (tty, output_display_block);
1494 CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1495 CONSOLE_HAS_METHOD (tty, divider_height);
1496 CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1497 CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1498 CONSOLE_HAS_METHOD (tty, clear_region);
1499 CONSOLE_HAS_METHOD (tty, clear_frame);
1500 CONSOLE_HAS_METHOD (tty, frame_output_begin);
1501 CONSOLE_HAS_METHOD (tty, frame_output_end);
1502 CONSOLE_HAS_METHOD (tty, flash);
1503 CONSOLE_HAS_METHOD (tty, ring_bell);
1504 CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);