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 && (!CHARC_ASCII_EQ (rb->object.cglyph, '\n'))
246 && (rb->cursor_type != CURSOR_ON
247 || NILP (w->text_cursor_visible_p)))
249 Dynarr_add (buf, rb->object.cglyph);
254 if (Dynarr_length (buf))
256 tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
261 if (rb->type == RUNE_CHAR)
266 if (CHARC_ASCII_EQ (rb->object.cglyph, '\n'))
268 /* Clear in case a cursor was formerly here. */
269 Dynarr_add (buf, ASCII_TO_CHARC (' '));
270 tty_output_charc_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.cglyph);
283 tty_output_charc_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)
301 ec_to_add = ASCII_TO_CHARC (' ');
303 ec_to_add = ASCII_TO_CHARC ('-');
306 Dynarr_add (buf, ec_to_add);
307 tty_output_charc_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))
339 case IMAGE_MONO_PIXMAP:
340 case IMAGE_COLOR_PIXMAP:
341 case IMAGE_SUBWINDOW:
343 /* just do nothing here */
347 /* nothing is as nothing does */
355 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
356 (XIMAGE_INSTANCE (instance)) = 0;
367 if (Dynarr_length (buf))
368 tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
375 /*****************************************************************************
376 tty_output_vertical_divider
378 Draw a vertical divider down the right side of the given window.
379 ****************************************************************************/
381 tty_output_vertical_divider (struct window *w, int clear)
383 /* Divider width can either be 0 or 1 on TTYs */
384 if (window_divider_width (w))
386 struct frame *f = XFRAME (w->frame);
387 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
389 int y_top = WINDOW_TEXT_TOP (w);
390 int y_bot = WINDOW_TEXT_BOTTOM (w);
391 unsigned char divv = '|';
393 tty_turn_on_face (w, MODELINE_INDEX);
394 for (line = y_top; line < y_bot; line++)
396 cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
397 send_string_to_tty_console (c, &divv, 1);
398 TTY_INC_CURSOR_X (c, 1);
401 /* Draw the divider in the modeline. */
402 cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
403 send_string_to_tty_console (c, &divv, 1);
404 TTY_INC_CURSOR_X (c, 1);
405 tty_turn_off_face (w, MODELINE_INDEX);
409 /****************************************************************************
412 Clear the area in the box defined by the given parameters.
413 ****************************************************************************/
415 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
416 face_index findex, int x, int y,
417 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
418 Lisp_Object background_pixmap)
420 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
422 struct window* w = XWINDOW (window);
424 tty_turn_on_face (w, findex);
425 for (line = y; line < y + height; line++)
431 if (window_is_leftmost (w)
432 && window_is_rightmost (w)
433 && TTY_SE (c).clr_to_eol)
435 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
439 unsigned char sp = ' ';
440 /* #### Of course, this is all complete and utter crap. */
441 for (col = x; col < x + width; col++)
442 send_string_to_tty_console (c, &sp, 1);
443 TTY_INC_CURSOR_X (c, width);
446 tty_turn_off_face (w, findex);
450 /*****************************************************************************
451 tty_clear_to_window_end
453 Clear the area between ypos1 and ypos2. Each margin area and the
454 text area is handled separately since they may each have their own
456 ****************************************************************************/
458 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
460 struct frame *f = XFRAME (w->frame);
461 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
464 x = WINDOW_TEXT_LEFT (w);
465 width = WINDOW_TEXT_WIDTH (w);
467 if (window_is_rightmost (w))
469 /* #### Optimize to use clr_to_eol function of tty if available, if
470 the window is the entire width of the frame. */
471 /* #### Is this actually an optimization? */
473 tty_turn_on_face (w, DEFAULT_INDEX);
474 for (line = ypos1; line < ypos2; line++)
476 cmgoto (XFRAME (w->frame), line, x);
477 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
479 tty_turn_off_face (w, DEFAULT_INDEX);
485 XSETWINDOW (window, w);
486 redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
490 /****************************************************************************
493 Clear the entire frame.
494 ****************************************************************************/
496 tty_clear_frame (struct frame *f)
498 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
500 tty_turn_on_frame_face (f, Vdefault_face);
501 if (TTY_SE (c).clr_frame)
503 OUTPUT1 (c, TTY_SE (c).clr_frame);
504 CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
505 CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
507 FRAME_CURSOR_X (f) = 0;
508 FRAME_CURSOR_Y (f) = 0;
514 internal_cursor_to (f, 0, 0);
517 /* #### Not implemented. */
518 stderr_out ("Not yet.\n");
521 tty_turn_off_frame_face (f, Vdefault_face);
525 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
526 Bufbyte *str, Bytecount len, int xpos,
527 face_index findex, int cursor)
529 struct frame *f = XFRAME (w->frame);
530 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
532 /* First position the cursor. */
533 cmgoto (f, dl->ypos - 1, xpos);
535 /* Enable any face properties. */
536 tty_turn_on_face (w, findex);
538 send_string_to_tty_console (c, str, len);
539 TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
541 /* Turn the face properties back off. */
542 tty_turn_off_face (w, findex);
545 static Bufbyte_dynarr *tty_output_charc_dynarr_dynarr;
547 /*****************************************************************************
548 tty_output_charc_dynarr
550 Given a string and a starting position, output that string in the
551 given face. If cursor is true, draw a cursor around the string.
552 ****************************************************************************/
554 tty_output_charc_dynarr (struct window *w, struct display_line *dl,
555 Charc_dynarr *buf, int xpos, face_index findex,
558 if (!tty_output_charc_dynarr_dynarr)
559 tty_output_charc_dynarr_dynarr = Dynarr_new (Bufbyte);
561 Dynarr_reset (tty_output_charc_dynarr_dynarr);
563 convert_charc_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
565 tty_output_charc_dynarr_dynarr);
567 tty_output_bufbyte_string (w, dl,
568 Dynarr_atp (tty_output_charc_dynarr_dynarr, 0),
569 Dynarr_length (tty_output_charc_dynarr_dynarr),
570 xpos, findex, cursor);
575 static Bufbyte_dynarr *sidcs_dynarr;
578 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
581 Bufbyte *specdata = XSTRING_DATA (spec);
582 Bytecount speclen = XSTRING_LENGTH (spec);
585 sidcs_dynarr = Dynarr_new (Bufbyte);
587 Dynarr_reset (sidcs_dynarr);
589 for (i = 0; i < speclen; i++)
591 if (specdata[i] == '%' && specdata[i+1] == '%')
593 Dynarr_add (sidcs_dynarr, '%');
596 else if (specdata[i] == '%' && specdata[i+1] == 's')
598 Dynarr_add_many (sidcs_dynarr,
599 XSTRING_DATA (string),
600 XSTRING_LENGTH (string));
604 Dynarr_add (sidcs_dynarr, specdata[i]);
611 set_foreground_to (struct console *c, Lisp_Object sym)
615 Bytecount escseqlen = 0;
617 result = assq_no_quit (sym, Vtty_color_alist);
620 Lisp_Object esc_seq = XCAR (XCDR (result));
621 escseq = XSTRING_DATA (esc_seq);
622 escseqlen = XSTRING_LENGTH (esc_seq);
625 else if (STRINGP (Vtty_dynamic_color_fg))
627 substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
629 escseq = Dynarr_atp (sidcs_dynarr, 0);
630 escseqlen = Dynarr_length (sidcs_dynarr);
636 send_string_to_tty_console (c, escseq, escseqlen);
641 set_background_to (struct console *c, Lisp_Object sym)
645 Bytecount escseqlen = 0;
647 result = assq_no_quit (sym, Vtty_color_alist);
650 Lisp_Object esc_seq = XCDR (XCDR (result));
651 escseq = XSTRING_DATA (esc_seq);
652 escseqlen = XSTRING_LENGTH (esc_seq);
655 else if (STRINGP (Vtty_dynamic_color_bg))
657 substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
659 escseq = Dynarr_atp (sidcs_dynarr, 0);
660 escseqlen = Dynarr_length (sidcs_dynarr);
666 send_string_to_tty_console (c, escseq, escseqlen);
671 tty_turn_on_face_1 (struct console *c, int highlight_p,
672 int blinking_p, int dim_p, int underline_p,
673 int reverse_p, Lisp_Object cinst_fore,
674 Lisp_Object cinst_back)
678 OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
683 OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
688 OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
693 /* #### punt for now if underline mode is glitchy */
694 if (!TTY_FLAGS (c).underline_width)
696 OUTPUT1_IF (c, TTY_SD (c).begin_underline);
702 /* #### punt for now if standout mode is glitchy */
703 if (!TTY_FLAGS (c).standout_width)
705 OUTPUT1_IF (c, TTY_SD (c).begin_standout);
713 Lisp_Object temp = cinst_fore;
714 cinst_fore = cinst_back;
718 if (COLOR_INSTANCEP (cinst_fore)
719 && !EQ (cinst_fore, Vthe_null_color_instance))
720 set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
721 (XCOLOR_INSTANCE (cinst_fore)));
723 if (COLOR_INSTANCEP (cinst_back)
724 && !EQ (cinst_back, Vthe_null_color_instance))
725 set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
726 (XCOLOR_INSTANCE (cinst_back)));
729 /*****************************************************************************
732 Turn on all set properties of the given face.
733 ****************************************************************************/
735 tty_turn_on_face (struct window *w, face_index findex)
737 struct frame *f = XFRAME (w->frame);
738 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
740 tty_turn_on_face_1 (c,
741 WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
742 WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
743 WINDOW_FACE_CACHEL_DIM_P (w, findex),
744 WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
745 WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
746 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
747 WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
750 /*****************************************************************************
753 Turn off all set properties of the given face (revert to default
754 face). We assume that tty_turn_on_face has been called for the given
755 face so that its properties are actually active.
756 ****************************************************************************/
758 tty_turn_off_face (struct window *w, face_index findex)
760 struct frame *f = XFRAME (w->frame);
761 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
763 if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
765 /* #### punt for now if standout mode is glitchy */
766 if (!TTY_FLAGS (c).standout_width)
768 OUTPUT1_IF (c, TTY_SD (c).end_standout);
772 if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
774 /* #### punt for now if underline mode is glitchy */
775 if (!TTY_FLAGS (c).underline_width)
777 OUTPUT1_IF (c, TTY_SD (c).end_underline);
781 if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
782 WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
783 WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
784 !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
785 Vthe_null_color_instance) ||
786 !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
787 Vthe_null_color_instance))
789 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
793 /*****************************************************************************
794 tty_turn_on_frame_face
796 Turn on all set properties of the given face.
797 ****************************************************************************/
799 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
802 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
804 XSETFRAME (frame, f);
805 tty_turn_on_face_1 (c,
806 FACE_HIGHLIGHT_P (face, frame),
807 FACE_BLINKING_P (face, frame),
808 FACE_DIM_P (face, frame),
809 FACE_UNDERLINE_P (face, frame),
810 FACE_REVERSE_P (face, frame),
811 FACE_FOREGROUND (face, frame),
812 FACE_BACKGROUND (face, frame));
815 /*****************************************************************************
816 tty_turn_off_frame_face
818 Turn off all set properties of the given face (revert to default
819 face). We assume that tty_turn_on_face has been called for the given
820 face so that its properties are actually active.
821 ****************************************************************************/
823 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
826 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
828 XSETFRAME (frame, f);
830 if (FACE_REVERSE_P (face, frame))
832 /* #### punt for now if standout mode is glitchy */
833 if (!TTY_FLAGS (c).standout_width)
835 OUTPUT1_IF (c, TTY_SD (c).end_standout);
839 if (FACE_UNDERLINE_P (face, frame))
841 /* #### punt for now if underline mode is glitchy */
842 if (!TTY_FLAGS (c).underline_width)
844 OUTPUT1_IF (c, TTY_SD (c).end_underline);
848 if (FACE_HIGHLIGHT_P (face, frame) ||
849 FACE_BLINKING_P (face, frame) ||
850 FACE_DIM_P (face, frame) ||
851 !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
852 !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
854 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
858 /*****************************************************************************
861 Sets up various parameters on tty modes.
862 ****************************************************************************/
864 set_tty_modes (struct console *c)
866 if (!CONSOLE_TTY_P (c))
869 OUTPUT1_IF (c, TTY_SD (c).init_motion);
870 OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
871 OUTPUT1_IF (c, TTY_SD (c).keypad_on);
874 /*****************************************************************************
877 Restore default state of tty.
878 ****************************************************************************/
880 reset_tty_modes (struct console *c)
882 if (!CONSOLE_TTY_P (c))
885 OUTPUT1_IF (c, TTY_SD (c).orig_pair);
886 OUTPUT1_IF (c, TTY_SD (c).keypad_off);
887 OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
888 OUTPUT1_IF (c, TTY_SD (c).end_motion);
889 tty_frame_output_end (XFRAME (CONSOLE_SELECTED_FRAME (c)));
892 /*****************************************************************************
893 tty_redisplay_shutdown
895 Clear the frame and position the cursor properly for exiting.
896 ****************************************************************************/
898 tty_redisplay_shutdown (struct console *c)
900 Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
904 Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
908 struct frame *f = XFRAME (frm);
910 /* Clear the bottom line of the frame. */
911 redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
912 f->height, f->width, 1);
914 /* And then stick the cursor there. */
915 tty_set_final_cursor_coords (f, f->height, 0);
916 tty_frame_output_end (f);
922 /* #### Everything below here is old shit. It should either be moved
926 /* FLAGS - these don't need to be console local since only one console
927 can be being updated at a time. */
928 static int insert_mode_on; /* nonzero if in insert mode */
929 static int standout_mode_on; /* nonzero if in standout mode */
930 static int underline_mode_on; /* nonzero if in underline mode */
931 static int alternate_mode_on; /* nonzero if in alternate char set */
932 static int attributes_on; /* nonzero if any attributes on */
936 turn_on_insert (struct frame *f)
938 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
941 OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
946 turn_off_insert (struct frame *f)
948 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
951 OUTPUT1 (c, TTY_SE (c).end_ins_mode);
956 internal_cursor_to (struct frame *f, int row, int col)
958 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
960 if (!TTY_FLAGS (c).insert_mode_motion)
962 if (!TTY_FLAGS (c).standout_motion)
964 turn_off_standout (f);
965 turn_off_underline (f);
966 turn_off_alternate (f);
969 cmgoto (f, row, col);
973 clear_to_end (struct frame *f)
975 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
977 /* assumes cursor is already positioned */
978 if (TTY_SE (c).clr_from_cursor)
980 OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
984 int line = FRAME_CURSOR_Y (f);
986 while (line < FRAME_HEIGHT (f))
988 internal_cursor_to (f, line, 0);
989 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
997 * clear from last visible line on window to window end (presumably
998 * the line above window's modeline
1001 tty_clear_window_end (struct window *w, int ystart, int yend)
1003 struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1006 for (line = ystart; line < yend; line++)
1008 cmgoto (XFRAME (w->frame), line, 0);
1009 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1016 tty_flash (struct device *d)
1018 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1019 if (TTY_SD (c).visual_bell)
1021 OUTPUT1 (c, TTY_SD (c).visual_bell);
1022 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1030 * tty_ring_bell - sound an audio beep.
1033 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1035 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1039 OUTPUT1 (c, TTY_SD (c).audio_bell);
1040 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1046 init_tty_for_redisplay (struct device *d, char *terminal_type)
1049 char entry_buffer[2044];
1050 /* char temp_buffer[2044]; */
1052 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1054 /* What we should really do is allocate just enough space for
1055 the actual strings that are stored; but this would require
1056 doing this after all the tgetstr()s and adjusting all the
1058 CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1059 bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1062 /* SIGTT* don't exist under win32 */
1063 EMACS_BLOCK_SIGNAL (SIGTTOU);
1065 status = tgetent (entry_buffer, terminal_type);
1067 EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1071 return TTY_UNABLE_OPEN_DATABASE;
1072 else if (status == 0)
1073 return TTY_TYPE_UNDEFINED;
1075 /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1077 return TTY_TYPE_UNDEFINED;
1080 * Establish the terminal size.
1082 /* First try to get the info from the system. If that fails, check
1083 the termcap entry. */
1084 get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1085 &CONSOLE_TTY_DATA (c)->height);
1087 if (CONSOLE_TTY_DATA (c)->width <= 0)
1088 CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1089 if (CONSOLE_TTY_DATA (c)->height <= 0)
1090 CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1092 if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1093 return TTY_SIZE_UNSPECIFIED;
1096 * Initialize cursor motion information.
1099 /* local cursor movement */
1100 TTY_CM (c).up = tgetstr ("up", &bufptr);
1101 TTY_CM (c).down = tgetstr ("do", &bufptr);
1102 TTY_CM (c).left = tgetstr ("le", &bufptr);
1103 TTY_CM (c).right = tgetstr ("nd", &bufptr);
1104 TTY_CM (c).home = tgetstr ("ho", &bufptr);
1105 TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1106 TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1108 /* absolute cursor motion */
1109 TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1110 TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1111 TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1113 /* Verify that the terminal is powerful enough to run Emacs */
1114 if (!TTY_CM (c).abs)
1116 if (!TTY_CM (c).up || !TTY_CM (c).down
1117 || !TTY_CM (c).left || !TTY_CM (c).right)
1118 return TTY_TYPE_INSUFFICIENT;
1121 /* parameterized local cursor movement */
1122 TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1123 TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1124 TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1125 TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1128 TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1129 TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1130 TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1131 TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1132 TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1136 * Initialize screen editing information.
1139 /* adding to the screen */
1140 TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1141 TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1142 TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1143 TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1144 TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1145 TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1146 TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1147 TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1149 /* deleting from the screen */
1150 TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1151 TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1152 TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1153 TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1154 TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1155 TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1156 TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1157 TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1158 TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1159 TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1163 * Initialize screen display information.
1165 TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1166 TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1167 TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1168 TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1169 TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1170 TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1171 TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1172 TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1173 TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1174 TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1175 TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1176 TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1178 TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1179 TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1180 if (!TTY_SD (c).audio_bell)
1182 /* If audio_bell doesn't get set, then assume C-g. This is gross and
1183 ugly but is what Emacs has done from time immortal. */
1184 TTY_SD (c).audio_bell = "\07";
1187 TTY_SD (c).cursor_visible = tgetstr ("ve", &bufptr);
1188 TTY_SD (c).cursor_normal = tgetstr ("vs", &bufptr);
1189 TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1190 TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1191 TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1192 TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1196 * Initialize additional terminal information.
1198 TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1199 TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1200 TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1201 TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1202 TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1203 TTY_FLAGS (c).standout_width = tgetnum ("sg");
1204 TTY_FLAGS (c).underline_width = tgetnum ("ug");
1206 if (TTY_FLAGS (c).standout_width == -1)
1207 TTY_FLAGS (c).standout_width = 0;
1208 if (TTY_FLAGS (c).underline_width == -1)
1209 TTY_FLAGS (c).underline_width = 0;
1211 TTY_FLAGS (c).meta_key =
1212 eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1216 * Setup the costs tables for this tty console.
1221 * Initialize local flags.
1224 standout_mode_on = 0;
1225 underline_mode_on = 0;
1226 alternate_mode_on = 0;
1230 * Attempt to initialize the function_key_map to
1231 * some kind of sensible value
1234 term_get_fkeys (c->function_key_map, &bufptr);
1237 /* check for ANSI set-foreground and set-background strings,
1238 and assume color if so.
1240 #### we should support the other (non-ANSI) ways of specifying
1243 char *fooptr = foobuf;
1244 if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1245 (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1246 ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1247 DEVICE_CLASS (d) = Qcolor;
1249 DEVICE_CLASS (d) = Qmono;
1252 return TTY_INIT_SUCCESS;
1261 /* Termcap capability names that correspond directly to X keysyms.
1262 Some of these (marked "terminfo") aren't supplied by old-style
1263 (Berkeley) termcap entries. They're listed in X keysym order;
1264 except we put the keypad keys first, so that if they clash with
1265 other keys (as on the IBM PC keyboard) they get overridden.
1268 static struct fkey_table keys[] =
1270 {"kh", "home"}, /* termcap */
1271 {"kl", "left"}, /* termcap */
1272 {"ku", "up"}, /* termcap */
1273 {"kr", "right"}, /* termcap */
1274 {"kd", "down"}, /* termcap */
1275 {"%8", "prior"}, /* terminfo */
1276 {"%5", "next"}, /* terminfo */
1277 {"@7", "end"}, /* terminfo */
1278 {"@1", "begin"}, /* terminfo */
1279 {"*6", "select"}, /* terminfo */
1280 {"%9", "print"}, /* terminfo */
1281 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1283 * "insert" --- see below
1285 {"&8", "undo"}, /* terminfo */
1286 {"%0", "redo"}, /* terminfo */
1287 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1288 {"@0", "find"}, /* terminfo */
1289 {"@2", "cancel"}, /* terminfo */
1290 {"%1", "help"}, /* terminfo */
1292 * "break" goes here, but can't be reliably intercepted with termcap
1294 {"&4", "reset"}, /* terminfo --- actually `restart' */
1296 * "system" and "user" --- no termcaps
1298 {"kE", "clearline"}, /* terminfo */
1299 {"kA", "insertline"}, /* terminfo */
1300 {"kL", "deleteline"}, /* terminfo */
1301 {"kI", "insertchar"}, /* terminfo */
1302 {"kD", "delete"}, /* terminfo */
1303 {"kB", "backtab"}, /* terminfo */
1305 * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1307 {"@8", "kp-enter"}, /* terminfo */
1309 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1310 * "kp-multiply", "kp-add", "kp-separator",
1311 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1312 * --- no termcaps for any of these.
1314 {"K4", "kp-1"}, /* terminfo */
1316 * "kp-2" --- no termcap
1318 {"K5", "kp-3"}, /* terminfo */
1320 * "kp-4" --- no termcap
1322 {"K2", "kp-5"}, /* terminfo */
1324 * "kp-6" --- no termcap
1326 {"K1", "kp-7"}, /* terminfo */
1328 * "kp-8" --- no termcap
1330 {"K3", "kp-9"}, /* terminfo */
1332 * "kp-equal" --- no termcap
1345 static char **term_get_fkeys_arg;
1347 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1348 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1350 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1351 This function scans the termcap function key sequence entries, and
1352 adds entries to Vfunction_key_map for each function key it finds. */
1355 term_get_fkeys (Lisp_Object keymap, char **address)
1357 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1358 errors during the call. The only errors should be from Fdefine_key
1359 when given a key sequence containing an invalid prefix key. If the
1360 termcap defines function keys which use a prefix that is already bound
1361 to a command by the default bindings, we should silently ignore that
1362 function key specification, rather than giving the user an error and
1363 refusing to run at all on such a terminal. */
1365 term_get_fkeys_arg = address;
1367 condition_case_1 (Qerror,
1368 term_get_fkeys_1, keymap,
1369 term_get_fkeys_error, Qnil);
1373 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1379 term_get_fkeys_1 (Lisp_Object function_key_map)
1383 char **address = term_get_fkeys_arg;
1385 for (i = 0; i < countof (keys); i++)
1387 char *sequence = tgetstr (keys[i].cap, address);
1389 Fdefine_key (function_key_map,
1390 build_ext_string (sequence, Qbinary),
1391 vector1 (intern (keys[i].name)));
1394 /* The uses of the "k0" capability are inconsistent; sometimes it
1395 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1396 We will attempt to politely accommodate both systems by testing for
1397 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1400 const char *k_semi = tgetstr ("k;", address);
1401 const char *k0 = tgetstr ("k0", address);
1404 Fdefine_key (function_key_map, build_ext_string (k_semi, Qbinary),
1405 vector1 (intern ("f10")));
1408 Fdefine_key (function_key_map, build_ext_string (k0, Qbinary),
1409 vector1 (intern (k_semi ? "f0" : "f10")));
1412 /* Set up cookies for numbered function keys above f10. */
1414 char fcap[3], fkey[4];
1416 fcap[0] = 'F'; fcap[2] = '\0';
1417 for (i = 11; i < 64; i++)
1420 fcap[1] = '1' + i - 11;
1422 fcap[1] = 'A' + i - 20;
1424 fcap[1] = 'a' + i - 46;
1427 char *sequence = tgetstr (fcap, address);
1430 sprintf (fkey, "f%d", i);
1431 Fdefine_key (function_key_map,
1432 build_ext_string (sequence, Qbinary),
1433 vector1 (intern (fkey)));
1440 * Various mappings to try and get a better fit.
1442 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) do { \
1443 if (!tgetstr (cap1, address)) \
1445 char *sequence = tgetstr (cap2, address); \
1447 Fdefine_key (function_key_map, \
1448 build_ext_string (sequence, Qbinary), \
1449 vector1 (intern (keyname))); \
1453 /* if there's no key_next keycap, map key_npage to `next' keysym */
1454 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1455 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1456 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1457 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1458 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1460 /* IBM has their own non-standard dialect of terminfo.
1461 If the standard name isn't found, try the IBM name. */
1462 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1463 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1464 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1465 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1466 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1467 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1468 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1469 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1470 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1471 #undef CONDITIONAL_REASSIGN
1477 /************************************************************************/
1478 /* initialization */
1479 /************************************************************************/
1482 console_type_create_redisplay_tty (void)
1484 /* redisplay methods */
1485 CONSOLE_HAS_METHOD (tty, text_width);
1486 CONSOLE_HAS_METHOD (tty, output_display_block);
1487 CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1488 CONSOLE_HAS_METHOD (tty, divider_height);
1489 CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1490 CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1491 CONSOLE_HAS_METHOD (tty, clear_region);
1492 CONSOLE_HAS_METHOD (tty, clear_frame);
1493 CONSOLE_HAS_METHOD (tty, frame_output_begin);
1494 CONSOLE_HAS_METHOD (tty, frame_output_end);
1495 CONSOLE_HAS_METHOD (tty, flash);
1496 CONSOLE_HAS_METHOD (tty, ring_bell);
1497 CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);