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> */
56 EXTERN_C int tgetent (const char *, const char *);
57 EXTERN_C int tgetflag (const char *);
58 EXTERN_C int tgetnum (const char *);
59 EXTERN_C char *tgetstr (const char *, char **);
60 EXTERN_C void tputs (const char *, int, void (*)(int));
62 #define FORCE_CURSOR_UPDATE(c) send_string_to_tty_console (c, 0, 0)
63 #define OUTPUTN(c, a, n) \
66 FORCE_CURSOR_UPDATE (c); \
67 tputs (a, n, cmputc); \
69 #define OUTPUT1(c, a) OUTPUTN (c, a, 1)
70 #define OUTPUTN_IF(c, a, n) \
73 FORCE_CURSOR_UPDATE (c); \
75 tputs (a, n, cmputc); \
77 #define OUTPUT1_IF(c, a) OUTPUTN_IF (c, a, 1)
79 static void tty_output_charc_dynarr (struct window *w,
80 struct display_line *dl,
81 Charc_dynarr *buf, int xpos,
84 static void tty_output_bufbyte_string (struct window *w,
85 struct display_line *dl,
86 Bufbyte *str, Bytecount len,
87 int xpos, face_index findex,
89 static void tty_turn_on_face (struct window *w, face_index findex);
90 static void tty_turn_off_face (struct window *w, face_index findex);
91 static void tty_turn_on_frame_face (struct frame *f, Lisp_Object face);
92 static void tty_turn_off_frame_face (struct frame *f, Lisp_Object face);
94 static void term_get_fkeys (Lisp_Object keymap, char **address);
96 /*****************************************************************************
99 Non-Mule tty's don't have fonts (that we use at least), so everything
100 is considered to be fixed width -- in other words, we return LEN.
101 Under Mule, however, a character can still cover more than one
102 column, so we use charc_string_displayed_columns().
103 ****************************************************************************/
105 tty_text_width (struct frame *f, struct face_cachel *cachel,
106 const Charc *str, Charcount len)
108 return charc_string_displayed_columns (str, len);
111 /*****************************************************************************
114 Return the width of the horizontal divider. This is a function
115 because divider_height is a console method.
116 ****************************************************************************/
118 tty_divider_height (void)
123 /*****************************************************************************
126 Return the width of the end-of-line cursor. This is a function
127 because eol_cursor_width is a console method.
128 ****************************************************************************/
130 tty_eol_cursor_width (void)
135 /*****************************************************************************
136 tty_frame_output_begin
138 Perform any necessary initialization prior to an update.
139 ****************************************************************************/
141 void tty_frame_output_begin (struct frame *f);
146 tty_frame_output_begin (struct frame *f)
149 /* Termcap requires `ospeed' to be a global variable so we have to
150 always set it for whatever tty console we are actually currently
152 ospeed = DEVICE_TTY_DATA (XDEVICE (FRAME_DEVICE (f)))->ospeed;
156 /*****************************************************************************
159 Perform any necessary flushing of queues when an update has completed.
160 ****************************************************************************/
162 void tty_frame_output_end (struct frame *f);
167 tty_frame_output_end (struct frame *f)
169 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
171 CONSOLE_TTY_CURSOR_X (c) = CONSOLE_TTY_FINAL_CURSOR_X (c);
172 CONSOLE_TTY_CURSOR_Y (c) = CONSOLE_TTY_FINAL_CURSOR_Y (c);
173 FORCE_CURSOR_UPDATE (c);
174 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
178 tty_set_final_cursor_coords (struct frame *f, int y, int x)
180 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
182 CONSOLE_TTY_FINAL_CURSOR_X (c) = x;
183 CONSOLE_TTY_FINAL_CURSOR_Y (c) = y;
186 /*****************************************************************************
187 tty_output_display_block
189 Given a display line, a block number for that start line, output all
190 runes between start and end in the specified display block.
191 ****************************************************************************/
193 tty_output_display_block (struct window *w, struct display_line *dl, int block,
194 int start, int end, int start_pixpos,
195 int cursor_start, int cursor_width,
198 struct frame *f = XFRAME (w->frame);
201 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
202 rune_dynarr *rba = db->runes;
209 rb = Dynarr_atp (rba, elt);
213 /* Nothing to do so don't do anything. */
223 end = Dynarr_length (rba);
225 buf = Dynarr_new (Charc);
227 while (elt < end && Dynarr_atp (rba, elt)->xpos < start_pixpos)
230 findex = Dynarr_atp (rba, elt)->findex;
231 xpos = Dynarr_atp (rba, elt)->xpos;
236 rb = Dynarr_atp (rba, elt);
238 if (rb->findex == findex && rb->type == RUNE_CHAR
239 && (!CHARC_ASCII_EQ (rb->object.cglyph, '\n'))
240 && (rb->cursor_type != CURSOR_ON
241 || NILP (w->text_cursor_visible_p)))
243 Dynarr_add (buf, rb->object.cglyph);
248 if (Dynarr_length (buf))
250 tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
255 if (rb->type == RUNE_CHAR)
260 if (CHARC_ASCII_EQ (rb->object.cglyph, '\n'))
262 /* Clear in case a cursor was formerly here. */
263 Dynarr_add (buf, ASCII_TO_CHARC (' '));
264 tty_output_charc_dynarr (w, dl, buf, rb->xpos,
268 cmgoto (f, dl->ypos - 1, rb->xpos);
272 else if (rb->cursor_type == CURSOR_ON)
274 /* There is not a distinct eol cursor on tty's. */
276 Dynarr_add (buf, rb->object.cglyph);
277 tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
280 cmgoto (f, dl->ypos - 1, xpos);
286 /* #### RUNE_HLINE is actually a little more complicated than this
287 but at the moment it is only used to draw a turned off
288 modeline and this will suffice for that. */
289 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
292 int size = rb->width;
294 if (rb->type == RUNE_BLANK)
295 ec_to_add = ASCII_TO_CHARC (' ');
297 ec_to_add = ASCII_TO_CHARC ('-');
300 Dynarr_add (buf, ec_to_add);
301 tty_output_charc_dynarr (w, dl, buf, rb->xpos, findex, 0);
303 if (xpos >= cursor_start
304 && cursor_start < xpos + Dynarr_length (buf))
306 cmgoto (f, dl->ypos - 1, cursor_start);
314 rb = Dynarr_atp (rba, elt);
320 else if (rb->type == RUNE_DGLYPH)
323 Lisp_Object instance;
325 XSETWINDOW (window, w);
326 instance = glyph_image_instance (rb->object.dglyph.glyph,
327 window, ERROR_ME_NOT, 1);
329 if (IMAGE_INSTANCEP (instance))
331 switch (XIMAGE_INSTANCE_TYPE (instance))
333 case IMAGE_MONO_PIXMAP:
334 case IMAGE_COLOR_PIXMAP:
335 case IMAGE_SUBWINDOW:
337 /* just do nothing here */
341 /* nothing is as nothing does */
349 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
350 (XIMAGE_INSTANCE (instance)) = 0;
361 if (Dynarr_length (buf))
362 tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
369 /*****************************************************************************
370 tty_output_vertical_divider
372 Draw a vertical divider down the right side of the given window.
373 ****************************************************************************/
375 tty_output_vertical_divider (struct window *w, int clear)
377 /* Divider width can either be 0 or 1 on TTYs */
378 if (window_divider_width (w))
380 struct frame *f = XFRAME (w->frame);
381 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
383 int y_top = WINDOW_TEXT_TOP (w);
384 int y_bot = WINDOW_TEXT_BOTTOM (w);
385 unsigned char divv = '|';
387 tty_turn_on_face (w, MODELINE_INDEX);
388 for (line = y_top; line < y_bot; line++)
390 cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
391 send_string_to_tty_console (c, &divv, 1);
392 TTY_INC_CURSOR_X (c, 1);
395 /* Draw the divider in the modeline. */
396 cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
397 send_string_to_tty_console (c, &divv, 1);
398 TTY_INC_CURSOR_X (c, 1);
399 tty_turn_off_face (w, MODELINE_INDEX);
403 /****************************************************************************
406 Clear the area in the box defined by the given parameters.
407 ****************************************************************************/
409 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
410 face_index findex, int x, int y,
411 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
412 Lisp_Object background_pixmap)
414 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
416 struct window* w = XWINDOW (window);
418 tty_turn_on_face (w, findex);
419 for (line = y; line < y + height; line++)
425 if (window_is_leftmost (w)
426 && window_is_rightmost (w)
427 && TTY_SE (c).clr_to_eol)
429 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
433 unsigned char sp = ' ';
434 /* #### Of course, this is all complete and utter crap. */
435 for (col = x; col < x + width; col++)
436 send_string_to_tty_console (c, &sp, 1);
437 TTY_INC_CURSOR_X (c, width);
440 tty_turn_off_face (w, findex);
444 /*****************************************************************************
445 tty_clear_to_window_end
447 Clear the area between ypos1 and ypos2. Each margin area and the
448 text area is handled separately since they may each have their own
450 ****************************************************************************/
452 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
454 struct frame *f = XFRAME (w->frame);
455 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
458 x = WINDOW_TEXT_LEFT (w);
459 width = WINDOW_TEXT_WIDTH (w);
461 if (window_is_rightmost (w))
463 /* #### Optimize to use clr_to_eol function of tty if available, if
464 the window is the entire width of the frame. */
465 /* #### Is this actually an optimization? */
467 tty_turn_on_face (w, DEFAULT_INDEX);
468 for (line = ypos1; line < ypos2; line++)
470 cmgoto (XFRAME (w->frame), line, x);
471 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
473 tty_turn_off_face (w, DEFAULT_INDEX);
479 XSETWINDOW (window, w);
480 redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
484 /****************************************************************************
487 Clear the entire frame.
488 ****************************************************************************/
490 tty_clear_frame (struct frame *f)
492 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
494 tty_turn_on_frame_face (f, Vdefault_face);
495 if (TTY_SE (c).clr_frame)
497 OUTPUT1 (c, TTY_SE (c).clr_frame);
498 CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
499 CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
501 FRAME_CURSOR_X (f) = 0;
502 FRAME_CURSOR_Y (f) = 0;
508 internal_cursor_to (f, 0, 0);
511 /* #### Not implemented. */
512 stderr_out ("Not yet.\n");
515 tty_turn_off_frame_face (f, Vdefault_face);
519 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
520 Bufbyte *str, Bytecount len, int xpos,
521 face_index findex, int cursor)
523 struct frame *f = XFRAME (w->frame);
524 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
526 /* First position the cursor. */
527 cmgoto (f, dl->ypos - 1, xpos);
529 /* Enable any face properties. */
530 tty_turn_on_face (w, findex);
532 send_string_to_tty_console (c, str, len);
533 TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
535 /* Turn the face properties back off. */
536 tty_turn_off_face (w, findex);
539 static Bufbyte_dynarr *tty_output_charc_dynarr_dynarr;
541 /*****************************************************************************
542 tty_output_charc_dynarr
544 Given a string and a starting position, output that string in the
545 given face. If cursor is true, draw a cursor around the string.
546 ****************************************************************************/
548 tty_output_charc_dynarr (struct window *w, struct display_line *dl,
549 Charc_dynarr *buf, int xpos, face_index findex,
552 if (!tty_output_charc_dynarr_dynarr)
553 tty_output_charc_dynarr_dynarr = Dynarr_new (Bufbyte);
555 Dynarr_reset (tty_output_charc_dynarr_dynarr);
557 convert_charc_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
559 tty_output_charc_dynarr_dynarr);
561 tty_output_bufbyte_string (w, dl,
562 Dynarr_atp (tty_output_charc_dynarr_dynarr, 0),
563 Dynarr_length (tty_output_charc_dynarr_dynarr),
564 xpos, findex, cursor);
569 static Bufbyte_dynarr *sidcs_dynarr;
572 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
575 Bufbyte *specdata = XSTRING_DATA (spec);
576 Bytecount speclen = XSTRING_LENGTH (spec);
579 sidcs_dynarr = Dynarr_new (Bufbyte);
581 Dynarr_reset (sidcs_dynarr);
583 for (i = 0; i < speclen; i++)
585 if (specdata[i] == '%' && specdata[i+1] == '%')
587 Dynarr_add (sidcs_dynarr, '%');
590 else if (specdata[i] == '%' && specdata[i+1] == 's')
592 Dynarr_add_many (sidcs_dynarr,
593 XSTRING_DATA (string),
594 XSTRING_LENGTH (string));
598 Dynarr_add (sidcs_dynarr, specdata[i]);
605 set_foreground_to (struct console *c, Lisp_Object sym)
609 Bytecount escseqlen = 0;
611 result = assq_no_quit (sym, Vtty_color_alist);
614 Lisp_Object esc_seq = XCAR (XCDR (result));
615 escseq = XSTRING_DATA (esc_seq);
616 escseqlen = XSTRING_LENGTH (esc_seq);
619 else if (STRINGP (Vtty_dynamic_color_fg))
621 substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
623 escseq = Dynarr_atp (sidcs_dynarr, 0);
624 escseqlen = Dynarr_length (sidcs_dynarr);
630 send_string_to_tty_console (c, escseq, escseqlen);
635 set_background_to (struct console *c, Lisp_Object sym)
639 Bytecount escseqlen = 0;
641 result = assq_no_quit (sym, Vtty_color_alist);
644 Lisp_Object esc_seq = XCDR (XCDR (result));
645 escseq = XSTRING_DATA (esc_seq);
646 escseqlen = XSTRING_LENGTH (esc_seq);
649 else if (STRINGP (Vtty_dynamic_color_bg))
651 substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
653 escseq = Dynarr_atp (sidcs_dynarr, 0);
654 escseqlen = Dynarr_length (sidcs_dynarr);
660 send_string_to_tty_console (c, escseq, escseqlen);
665 tty_turn_on_face_1 (struct console *c, int highlight_p,
666 int blinking_p, int dim_p, int underline_p,
667 int reverse_p, Lisp_Object cinst_fore,
668 Lisp_Object cinst_back)
672 OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
677 OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
682 OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
687 /* #### punt for now if underline mode is glitchy */
688 if (!TTY_FLAGS (c).underline_width)
690 OUTPUT1_IF (c, TTY_SD (c).begin_underline);
696 /* #### punt for now if standout mode is glitchy */
697 if (!TTY_FLAGS (c).standout_width)
699 OUTPUT1_IF (c, TTY_SD (c).begin_standout);
707 Lisp_Object temp = cinst_fore;
708 cinst_fore = cinst_back;
712 if (COLOR_INSTANCEP (cinst_fore)
713 && !EQ (cinst_fore, Vthe_null_color_instance))
714 set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
715 (XCOLOR_INSTANCE (cinst_fore)));
717 if (COLOR_INSTANCEP (cinst_back)
718 && !EQ (cinst_back, Vthe_null_color_instance))
719 set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
720 (XCOLOR_INSTANCE (cinst_back)));
723 /*****************************************************************************
726 Turn on all set properties of the given face.
727 ****************************************************************************/
729 tty_turn_on_face (struct window *w, face_index findex)
731 struct frame *f = XFRAME (w->frame);
732 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
734 tty_turn_on_face_1 (c,
735 WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
736 WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
737 WINDOW_FACE_CACHEL_DIM_P (w, findex),
738 WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
739 WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
740 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
741 WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
744 /*****************************************************************************
747 Turn off all set properties of the given face (revert to default
748 face). We assume that tty_turn_on_face has been called for the given
749 face so that its properties are actually active.
750 ****************************************************************************/
752 tty_turn_off_face (struct window *w, face_index findex)
754 struct frame *f = XFRAME (w->frame);
755 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
757 if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
759 /* #### punt for now if standout mode is glitchy */
760 if (!TTY_FLAGS (c).standout_width)
762 OUTPUT1_IF (c, TTY_SD (c).end_standout);
766 if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
768 /* #### punt for now if underline mode is glitchy */
769 if (!TTY_FLAGS (c).underline_width)
771 OUTPUT1_IF (c, TTY_SD (c).end_underline);
775 if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
776 WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
777 WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
778 !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
779 Vthe_null_color_instance) ||
780 !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
781 Vthe_null_color_instance))
783 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
787 /*****************************************************************************
788 tty_turn_on_frame_face
790 Turn on all set properties of the given face.
791 ****************************************************************************/
793 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
796 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
798 XSETFRAME (frame, f);
799 tty_turn_on_face_1 (c,
800 FACE_HIGHLIGHT_P (face, frame),
801 FACE_BLINKING_P (face, frame),
802 FACE_DIM_P (face, frame),
803 FACE_UNDERLINE_P (face, frame),
804 FACE_REVERSE_P (face, frame),
805 FACE_FOREGROUND (face, frame),
806 FACE_BACKGROUND (face, frame));
809 /*****************************************************************************
810 tty_turn_off_frame_face
812 Turn off all set properties of the given face (revert to default
813 face). We assume that tty_turn_on_face has been called for the given
814 face so that its properties are actually active.
815 ****************************************************************************/
817 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
820 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
822 XSETFRAME (frame, f);
824 if (FACE_REVERSE_P (face, frame))
826 /* #### punt for now if standout mode is glitchy */
827 if (!TTY_FLAGS (c).standout_width)
829 OUTPUT1_IF (c, TTY_SD (c).end_standout);
833 if (FACE_UNDERLINE_P (face, frame))
835 /* #### punt for now if underline mode is glitchy */
836 if (!TTY_FLAGS (c).underline_width)
838 OUTPUT1_IF (c, TTY_SD (c).end_underline);
842 if (FACE_HIGHLIGHT_P (face, frame) ||
843 FACE_BLINKING_P (face, frame) ||
844 FACE_DIM_P (face, frame) ||
845 !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
846 !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
848 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
852 /*****************************************************************************
855 Sets up various parameters on tty modes.
856 ****************************************************************************/
858 set_tty_modes (struct console *c)
860 if (!CONSOLE_TTY_P (c))
863 OUTPUT1_IF (c, TTY_SD (c).init_motion);
864 OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
865 OUTPUT1_IF (c, TTY_SD (c).keypad_on);
867 if (TTY_FLAGS (c).auto_margins)
868 OUTPUT1_IF (c, TTY_SD (c).disable_auto_margins);
871 /*****************************************************************************
874 Restore default state of tty.
875 ****************************************************************************/
877 reset_tty_modes (struct console *c)
879 if (!CONSOLE_TTY_P (c))
882 OUTPUT1_IF (c, TTY_SD (c).orig_pair);
883 OUTPUT1_IF (c, TTY_SD (c).keypad_off);
884 OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
885 OUTPUT1_IF (c, TTY_SD (c).end_motion);
887 if (TTY_FLAGS (c).auto_margins)
888 OUTPUT1_IF (c, TTY_SD (c).enable_auto_margins);
891 Lisp_Object frm = CONSOLE_SELECTED_FRAME (c);
894 tty_frame_output_end (XFRAME (frm));
898 /*****************************************************************************
899 tty_redisplay_shutdown
901 Clear the frame and position the cursor properly for exiting.
902 ****************************************************************************/
904 tty_redisplay_shutdown (struct console *c)
906 Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
910 Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
914 struct frame *f = XFRAME (frm);
916 /* Clear the bottom line of the frame. */
917 redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
918 f->height, f->width, 1);
920 /* And then stick the cursor there. */
921 tty_set_final_cursor_coords (f, f->height, 0);
922 tty_frame_output_end (f);
928 /* #### 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 */
942 turn_on_insert (struct frame *f)
944 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
947 OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
952 turn_off_insert (struct frame *f)
954 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
957 OUTPUT1 (c, TTY_SE (c).end_ins_mode);
962 internal_cursor_to (struct frame *f, int row, int col)
964 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
966 if (!TTY_FLAGS (c).insert_mode_motion)
968 if (!TTY_FLAGS (c).standout_motion)
970 turn_off_standout (f);
971 turn_off_underline (f);
972 turn_off_alternate (f);
975 cmgoto (f, row, col);
979 clear_to_end (struct frame *f)
981 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
983 /* assumes cursor is already positioned */
984 if (TTY_SE (c).clr_from_cursor)
986 OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
990 int line = FRAME_CURSOR_Y (f);
992 while (line < FRAME_HEIGHT (f))
994 internal_cursor_to (f, line, 0);
995 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1003 * clear from last visible line on window to window end (presumably
1004 * the line above window's modeline
1007 tty_clear_window_end (struct window *w, int ystart, int yend)
1009 struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1012 for (line = ystart; line < yend; line++)
1014 cmgoto (XFRAME (w->frame), line, 0);
1015 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1022 tty_flash (struct device *d)
1024 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1025 if (TTY_SD (c).visual_bell)
1027 OUTPUT1 (c, TTY_SD (c).visual_bell);
1028 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1036 * tty_ring_bell - sound an audio beep.
1039 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1041 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1045 OUTPUT1 (c, TTY_SD (c).audio_bell);
1046 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1052 init_tty_for_redisplay (struct device *d, char *terminal_type)
1055 char entry_buffer[2044];
1056 /* char temp_buffer[2044]; */
1058 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1060 /* What we should really do is allocate just enough space for
1061 the actual strings that are stored; but this would require
1062 doing this after all the tgetstr()s and adjusting all the
1064 CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1065 bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1068 /* SIGTT* don't exist under win32 */
1069 EMACS_BLOCK_SIGNAL (SIGTTOU);
1071 status = tgetent (entry_buffer, terminal_type);
1073 EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1077 return TTY_UNABLE_OPEN_DATABASE;
1078 else if (status == 0)
1079 return TTY_TYPE_UNDEFINED;
1081 /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1083 return TTY_TYPE_UNDEFINED;
1086 * Establish the terminal size.
1088 /* First try to get the info from the system. If that fails, check
1089 the termcap entry. */
1090 get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1091 &CONSOLE_TTY_DATA (c)->height);
1093 if (CONSOLE_TTY_DATA (c)->width <= 0)
1094 CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1095 if (CONSOLE_TTY_DATA (c)->height <= 0)
1096 CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1098 if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1099 return TTY_SIZE_UNSPECIFIED;
1102 * Initialize cursor motion information.
1105 /* local cursor movement */
1106 TTY_CM (c).up = tgetstr ("up", &bufptr);
1107 TTY_CM (c).down = tgetstr ("do", &bufptr);
1108 TTY_CM (c).left = tgetstr ("le", &bufptr);
1109 TTY_CM (c).right = tgetstr ("nd", &bufptr);
1110 TTY_CM (c).home = tgetstr ("ho", &bufptr);
1111 TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1112 TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1114 /* absolute cursor motion */
1115 TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1116 TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1117 TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1119 /* Verify that the terminal is powerful enough to run Emacs */
1120 if (!TTY_CM (c).abs)
1122 if (!TTY_CM (c).up || !TTY_CM (c).down
1123 || !TTY_CM (c).left || !TTY_CM (c).right)
1124 return TTY_TYPE_INSUFFICIENT;
1127 /* parameterized local cursor movement */
1128 TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1129 TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1130 TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1131 TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1134 TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1135 TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1136 TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1137 TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1138 TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1142 * Initialize screen editing information.
1145 /* adding to the screen */
1146 TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1147 TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1148 TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1149 TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1150 TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1151 TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1152 TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1153 TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1155 /* deleting from the screen */
1156 TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1157 TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1158 TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1159 TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1160 TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1161 TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1162 TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1163 TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1164 TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1165 TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1169 * Initialize screen display information.
1171 TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1172 TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1173 TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1174 TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1175 TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1176 TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1177 TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1178 TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1179 TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1180 TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1181 TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1182 TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1184 TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1185 TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1186 if (!TTY_SD (c).audio_bell)
1188 /* If audio_bell doesn't get set, then assume C-g. This is gross and
1189 ugly but is what Emacs has done from time immortal. */
1190 TTY_SD (c).audio_bell = "\07";
1193 TTY_SD (c).cursor_visible = tgetstr ("vs", &bufptr);
1194 TTY_SD (c).cursor_normal = tgetstr ("ve", &bufptr);
1195 TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1196 TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1197 TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1198 TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1199 TTY_SD (c).disable_auto_margins = tgetstr ("RA", &bufptr);
1200 TTY_SD (c).enable_auto_margins = tgetstr ("SA", &bufptr);
1204 * Initialize additional terminal information.
1206 TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1207 TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1208 TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1209 TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1210 TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1211 TTY_FLAGS (c).standout_width = tgetnum ("sg");
1212 TTY_FLAGS (c).underline_width = tgetnum ("ug");
1213 TTY_FLAGS (c).auto_margins = tgetflag ("am");
1215 if (TTY_FLAGS (c).standout_width == -1)
1216 TTY_FLAGS (c).standout_width = 0;
1217 if (TTY_FLAGS (c).underline_width == -1)
1218 TTY_FLAGS (c).underline_width = 0;
1220 TTY_FLAGS (c).meta_key =
1221 eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1225 * Setup the costs tables for this tty console.
1231 * Initialize local flags.
1234 standout_mode_on = 0;
1235 underline_mode_on = 0;
1236 alternate_mode_on = 0;
1241 * Attempt to initialize the function_key_map to
1242 * some kind of sensible value
1245 term_get_fkeys (c->function_key_map, &bufptr);
1248 /* check for ANSI set-foreground and set-background strings,
1249 and assume color if so.
1251 #### we should support the other (non-ANSI) ways of specifying
1254 char *fooptr = foobuf;
1255 if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1256 (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1257 ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1258 DEVICE_CLASS (d) = Qcolor;
1260 DEVICE_CLASS (d) = Qmono;
1263 return TTY_INIT_SUCCESS;
1272 /* Termcap capability names that correspond directly to X keysyms.
1273 Some of these (marked "terminfo") aren't supplied by old-style
1274 (Berkeley) termcap entries. They're listed in X keysym order;
1275 except we put the keypad keys first, so that if they clash with
1276 other keys (as on the IBM PC keyboard) they get overridden.
1279 static struct fkey_table keys[] =
1281 {"kh", "home"}, /* termcap */
1282 {"kl", "left"}, /* termcap */
1283 {"ku", "up"}, /* termcap */
1284 {"kr", "right"}, /* termcap */
1285 {"kd", "down"}, /* termcap */
1286 {"%8", "prior"}, /* terminfo */
1287 {"%5", "next"}, /* terminfo */
1288 {"@7", "end"}, /* terminfo */
1289 {"@1", "begin"}, /* terminfo */
1290 {"*6", "select"}, /* terminfo */
1291 {"%9", "print"}, /* terminfo */
1292 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1294 * "insert" --- see below
1296 {"&8", "undo"}, /* terminfo */
1297 {"%0", "redo"}, /* terminfo */
1298 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1299 {"@0", "find"}, /* terminfo */
1300 {"@2", "cancel"}, /* terminfo */
1301 {"%1", "help"}, /* terminfo */
1303 * "break" goes here, but can't be reliably intercepted with termcap
1305 {"&4", "reset"}, /* terminfo --- actually `restart' */
1307 * "system" and "user" --- no termcaps
1309 {"kE", "clearline"}, /* terminfo */
1310 {"kA", "insertline"}, /* terminfo */
1311 {"kL", "deleteline"}, /* terminfo */
1312 {"kI", "insertchar"}, /* terminfo */
1313 {"kD", "delete"}, /* terminfo */
1314 {"kB", "backtab"}, /* terminfo */
1316 * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1318 {"@8", "kp-enter"}, /* terminfo */
1320 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1321 * "kp-multiply", "kp-add", "kp-separator",
1322 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1323 * --- no termcaps for any of these.
1325 {"K4", "kp-1"}, /* terminfo */
1327 * "kp-2" --- no termcap
1329 {"K5", "kp-3"}, /* terminfo */
1331 * "kp-4" --- no termcap
1333 {"K2", "kp-5"}, /* terminfo */
1335 * "kp-6" --- no termcap
1337 {"K1", "kp-7"}, /* terminfo */
1339 * "kp-8" --- no termcap
1341 {"K3", "kp-9"}, /* terminfo */
1343 * "kp-equal" --- no termcap
1356 static char **term_get_fkeys_arg;
1358 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1359 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1361 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1362 This function scans the termcap function key sequence entries, and
1363 adds entries to Vfunction_key_map for each function key it finds. */
1366 term_get_fkeys (Lisp_Object keymap, char **address)
1368 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1369 errors during the call. The only errors should be from Fdefine_key
1370 when given a key sequence containing an invalid prefix key. If the
1371 termcap defines function keys which use a prefix that is already bound
1372 to a command by the default bindings, we should silently ignore that
1373 function key specification, rather than giving the user an error and
1374 refusing to run at all on such a terminal. */
1376 term_get_fkeys_arg = address;
1378 condition_case_1 (Qerror,
1379 term_get_fkeys_1, keymap,
1380 term_get_fkeys_error, Qnil);
1384 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1390 term_get_fkeys_1 (Lisp_Object function_key_map)
1394 char **address = term_get_fkeys_arg;
1396 for (i = 0; i < countof (keys); i++)
1398 char *sequence = tgetstr (keys[i].cap, address);
1400 Fdefine_key (function_key_map,
1401 build_ext_string (sequence, Qbinary),
1402 vector1 (intern (keys[i].name)));
1405 /* The uses of the "k0" capability are inconsistent; sometimes it
1406 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1407 We will attempt to politely accommodate both systems by testing for
1408 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1411 const char *k_semi = tgetstr ("k;", address);
1412 const char *k0 = tgetstr ("k0", address);
1415 Fdefine_key (function_key_map, build_ext_string (k_semi, Qbinary),
1416 vector1 (intern ("f10")));
1419 Fdefine_key (function_key_map, build_ext_string (k0, Qbinary),
1420 vector1 (intern (k_semi ? "f0" : "f10")));
1423 /* Set up cookies for numbered function keys above f10. */
1425 char fcap[3], fkey[4];
1427 fcap[0] = 'F'; fcap[2] = '\0';
1428 for (i = 11; i < 64; i++)
1431 fcap[1] = '1' + i - 11;
1433 fcap[1] = 'A' + i - 20;
1435 fcap[1] = 'a' + i - 46;
1438 char *sequence = tgetstr (fcap, address);
1441 sprintf (fkey, "f%d", i);
1442 Fdefine_key (function_key_map,
1443 build_ext_string (sequence, Qbinary),
1444 vector1 (intern (fkey)));
1451 * Various mappings to try and get a better fit.
1453 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) do { \
1454 if (!tgetstr (cap1, address)) \
1456 char *sequence = tgetstr (cap2, address); \
1458 Fdefine_key (function_key_map, \
1459 build_ext_string (sequence, Qbinary), \
1460 vector1 (intern (keyname))); \
1464 /* if there's no key_next keycap, map key_npage to `next' keysym */
1465 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1466 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1467 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1468 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1469 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1471 /* IBM has their own non-standard dialect of terminfo.
1472 If the standard name isn't found, try the IBM name. */
1473 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1474 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1475 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1476 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1477 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1478 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1479 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1480 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1481 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1482 #undef CONDITIONAL_REASSIGN
1488 /************************************************************************/
1489 /* initialization */
1490 /************************************************************************/
1493 console_type_create_redisplay_tty (void)
1495 /* redisplay methods */
1496 CONSOLE_HAS_METHOD (tty, text_width);
1497 CONSOLE_HAS_METHOD (tty, output_display_block);
1498 CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1499 CONSOLE_HAS_METHOD (tty, divider_height);
1500 CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1501 CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1502 CONSOLE_HAS_METHOD (tty, clear_region);
1503 CONSOLE_HAS_METHOD (tty, clear_frame);
1504 CONSOLE_HAS_METHOD (tty, frame_output_begin);
1505 CONSOLE_HAS_METHOD (tty, frame_output_end);
1506 CONSOLE_HAS_METHOD (tty, flash);
1507 CONSOLE_HAS_METHOD (tty, ring_bell);
1508 CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);