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_emchar_dynarr (struct window *w,
80 struct display_line *dl,
81 Emchar_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 emchar_string_displayed_columns().
103 ****************************************************************************/
105 tty_text_width (struct frame *f, struct face_cachel *cachel, const Emchar *str,
108 return emchar_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);
199 Emchar_dynarr *buf = Dynarr_new (Emchar);
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);
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 && rb->object.chr.ch != '\n'
240 && (rb->cursor_type != CURSOR_ON
241 || NILP (w->text_cursor_visible_p)))
243 Dynarr_add (buf, rb->object.chr.ch);
248 if (Dynarr_length (buf))
250 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
255 if (rb->type == RUNE_CHAR)
260 if (rb->object.chr.ch == '\n')
262 /* Clear in case a cursor was formerly here. */
264 Dynarr_add (buf, ' ');
265 tty_output_emchar_dynarr (w, dl, buf, rb->xpos,
269 cmgoto (f, dl->ypos - 1, rb->xpos);
273 else if (rb->cursor_type == CURSOR_ON)
275 /* There is not a distinct eol cursor on tty's. */
277 Dynarr_add (buf, rb->object.chr.ch);
278 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
281 cmgoto (f, dl->ypos - 1, xpos);
287 /* #### RUNE_HLINE is actually a little more complicated than this
288 but at the moment it is only used to draw a turned off
289 modeline and this will suffice for that. */
290 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
293 int size = rb->width;
295 if (rb->type == RUNE_BLANK)
301 Dynarr_add (buf, ch_to_add);
302 tty_output_emchar_dynarr (w, dl, buf, rb->xpos, findex, 0);
304 if (xpos >= cursor_start
305 && cursor_start < xpos + Dynarr_length (buf))
307 cmgoto (f, dl->ypos - 1, cursor_start);
315 rb = Dynarr_atp (rba, elt);
321 else if (rb->type == RUNE_DGLYPH)
324 Lisp_Object instance;
326 XSETWINDOW (window, w);
327 instance = glyph_image_instance (rb->object.dglyph.glyph,
328 window, ERROR_ME_NOT, 1);
330 if (IMAGE_INSTANCEP (instance))
332 switch (XIMAGE_INSTANCE_TYPE (instance))
334 case IMAGE_MONO_PIXMAP:
335 case IMAGE_COLOR_PIXMAP:
336 case IMAGE_SUBWINDOW:
338 /* just do nothing here */
342 /* nothing is as nothing does */
350 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
351 (XIMAGE_INSTANCE (instance)) = 0;
362 if (Dynarr_length (buf))
363 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
370 /*****************************************************************************
371 tty_output_vertical_divider
373 Draw a vertical divider down the right side of the given window.
374 ****************************************************************************/
376 tty_output_vertical_divider (struct window *w, int clear)
378 /* Divider width can either be 0 or 1 on TTYs */
379 if (window_divider_width (w))
381 struct frame *f = XFRAME (w->frame);
382 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
384 int y_top = WINDOW_TEXT_TOP (w);
385 int y_bot = WINDOW_TEXT_BOTTOM (w);
386 unsigned char divv = '|';
388 tty_turn_on_face (w, MODELINE_INDEX);
389 for (line = y_top; line < y_bot; line++)
391 cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
392 send_string_to_tty_console (c, &divv, 1);
393 TTY_INC_CURSOR_X (c, 1);
396 /* Draw the divider in the modeline. */
397 cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
398 send_string_to_tty_console (c, &divv, 1);
399 TTY_INC_CURSOR_X (c, 1);
400 tty_turn_off_face (w, MODELINE_INDEX);
404 /****************************************************************************
407 Clear the area in the box defined by the given parameters.
408 ****************************************************************************/
410 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
411 face_index findex, int x, int y,
412 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
413 Lisp_Object background_pixmap)
415 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
417 struct window* w = XWINDOW (window);
419 tty_turn_on_face (w, findex);
420 for (line = y; line < y + height; line++)
426 if (window_is_leftmost (w)
427 && window_is_rightmost (w)
428 && TTY_SE (c).clr_to_eol)
430 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
434 unsigned char sp = ' ';
435 /* #### Of course, this is all complete and utter crap. */
436 for (col = x; col < x + width; col++)
437 send_string_to_tty_console (c, &sp, 1);
438 TTY_INC_CURSOR_X (c, width);
441 tty_turn_off_face (w, findex);
445 /*****************************************************************************
446 tty_clear_to_window_end
448 Clear the area between ypos1 and ypos2. Each margin area and the
449 text area is handled separately since they may each have their own
451 ****************************************************************************/
453 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
455 struct frame *f = XFRAME (w->frame);
456 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
459 x = WINDOW_TEXT_LEFT (w);
460 width = WINDOW_TEXT_WIDTH (w);
462 if (window_is_rightmost (w))
464 /* #### Optimize to use clr_to_eol function of tty if available, if
465 the window is the entire width of the frame. */
466 /* #### Is this actually an optimization? */
468 tty_turn_on_face (w, DEFAULT_INDEX);
469 for (line = ypos1; line < ypos2; line++)
471 cmgoto (XFRAME (w->frame), line, x);
472 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
474 tty_turn_off_face (w, DEFAULT_INDEX);
480 XSETWINDOW (window, w);
481 redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
485 /****************************************************************************
488 Clear the entire frame.
489 ****************************************************************************/
491 tty_clear_frame (struct frame *f)
493 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
495 tty_turn_on_frame_face (f, Vdefault_face);
496 if (TTY_SE (c).clr_frame)
498 OUTPUT1 (c, TTY_SE (c).clr_frame);
499 CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
500 CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
502 FRAME_CURSOR_X (f) = 0;
503 FRAME_CURSOR_Y (f) = 0;
509 internal_cursor_to (f, 0, 0);
512 /* #### Not implemented. */
513 stderr_out ("Not yet.\n");
516 tty_turn_off_frame_face (f, Vdefault_face);
520 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
521 Bufbyte *str, Bytecount len, int xpos,
522 face_index findex, int cursor)
524 struct frame *f = XFRAME (w->frame);
525 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
527 /* First position the cursor. */
528 cmgoto (f, dl->ypos - 1, xpos);
530 /* Enable any face properties. */
531 tty_turn_on_face (w, findex);
533 send_string_to_tty_console (c, str, len);
534 TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
536 /* Turn the face properties back off. */
537 tty_turn_off_face (w, findex);
540 static Bufbyte_dynarr *tty_output_emchar_dynarr_dynarr;
542 /*****************************************************************************
543 tty_output_emchar_dynarr
545 Given a string and a starting position, output that string in the
546 given face. If cursor is true, draw a cursor around the string.
547 ****************************************************************************/
549 tty_output_emchar_dynarr (struct window *w, struct display_line *dl,
550 Emchar_dynarr *buf, int xpos, face_index findex,
553 if (!tty_output_emchar_dynarr_dynarr)
554 tty_output_emchar_dynarr_dynarr = Dynarr_new (Bufbyte);
556 Dynarr_reset (tty_output_emchar_dynarr_dynarr);
558 convert_emchar_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
560 tty_output_emchar_dynarr_dynarr);
562 tty_output_bufbyte_string (w, dl,
563 Dynarr_atp (tty_output_emchar_dynarr_dynarr, 0),
564 Dynarr_length (tty_output_emchar_dynarr_dynarr),
565 xpos, findex, cursor);
570 static Bufbyte_dynarr *sidcs_dynarr;
573 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
576 Bufbyte *specdata = XSTRING_DATA (spec);
577 Bytecount speclen = XSTRING_LENGTH (spec);
580 sidcs_dynarr = Dynarr_new (Bufbyte);
582 Dynarr_reset (sidcs_dynarr);
584 for (i = 0; i < speclen; i++)
586 if (specdata[i] == '%' && specdata[i+1] == '%')
588 Dynarr_add (sidcs_dynarr, '%');
591 else if (specdata[i] == '%' && specdata[i+1] == 's')
593 Dynarr_add_many (sidcs_dynarr,
594 XSTRING_DATA (string),
595 XSTRING_LENGTH (string));
599 Dynarr_add (sidcs_dynarr, specdata[i]);
606 set_foreground_to (struct console *c, Lisp_Object sym)
610 Bytecount escseqlen = 0;
612 result = assq_no_quit (sym, Vtty_color_alist);
615 Lisp_Object esc_seq = XCAR (XCDR (result));
616 escseq = XSTRING_DATA (esc_seq);
617 escseqlen = XSTRING_LENGTH (esc_seq);
620 else if (STRINGP (Vtty_dynamic_color_fg))
622 substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
624 escseq = Dynarr_atp (sidcs_dynarr, 0);
625 escseqlen = Dynarr_length (sidcs_dynarr);
631 send_string_to_tty_console (c, escseq, escseqlen);
636 set_background_to (struct console *c, Lisp_Object sym)
640 Bytecount escseqlen = 0;
642 result = assq_no_quit (sym, Vtty_color_alist);
645 Lisp_Object esc_seq = XCDR (XCDR (result));
646 escseq = XSTRING_DATA (esc_seq);
647 escseqlen = XSTRING_LENGTH (esc_seq);
650 else if (STRINGP (Vtty_dynamic_color_bg))
652 substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
654 escseq = Dynarr_atp (sidcs_dynarr, 0);
655 escseqlen = Dynarr_length (sidcs_dynarr);
661 send_string_to_tty_console (c, escseq, escseqlen);
666 tty_turn_on_face_1 (struct console *c, int highlight_p,
667 int blinking_p, int dim_p, int underline_p,
668 int reverse_p, Lisp_Object cinst_fore,
669 Lisp_Object cinst_back)
673 OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
678 OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
683 OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
688 /* #### punt for now if underline mode is glitchy */
689 if (!TTY_FLAGS (c).underline_width)
691 OUTPUT1_IF (c, TTY_SD (c).begin_underline);
697 /* #### punt for now if standout mode is glitchy */
698 if (!TTY_FLAGS (c).standout_width)
700 OUTPUT1_IF (c, TTY_SD (c).begin_standout);
708 Lisp_Object temp = cinst_fore;
709 cinst_fore = cinst_back;
713 if (COLOR_INSTANCEP (cinst_fore)
714 && !EQ (cinst_fore, Vthe_null_color_instance))
715 set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
716 (XCOLOR_INSTANCE (cinst_fore)));
718 if (COLOR_INSTANCEP (cinst_back)
719 && !EQ (cinst_back, Vthe_null_color_instance))
720 set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
721 (XCOLOR_INSTANCE (cinst_back)));
724 /*****************************************************************************
727 Turn on all set properties of the given face.
728 ****************************************************************************/
730 tty_turn_on_face (struct window *w, face_index findex)
732 struct frame *f = XFRAME (w->frame);
733 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
735 tty_turn_on_face_1 (c,
736 WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
737 WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
738 WINDOW_FACE_CACHEL_DIM_P (w, findex),
739 WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
740 WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
741 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
742 WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
745 /*****************************************************************************
748 Turn off all set properties of the given face (revert to default
749 face). We assume that tty_turn_on_face has been called for the given
750 face so that its properties are actually active.
751 ****************************************************************************/
753 tty_turn_off_face (struct window *w, face_index findex)
755 struct frame *f = XFRAME (w->frame);
756 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
758 if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
760 /* #### punt for now if standout mode is glitchy */
761 if (!TTY_FLAGS (c).standout_width)
763 OUTPUT1_IF (c, TTY_SD (c).end_standout);
767 if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
769 /* #### punt for now if underline mode is glitchy */
770 if (!TTY_FLAGS (c).underline_width)
772 OUTPUT1_IF (c, TTY_SD (c).end_underline);
776 if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
777 WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
778 WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
779 !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
780 Vthe_null_color_instance) ||
781 !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
782 Vthe_null_color_instance))
784 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
788 /*****************************************************************************
789 tty_turn_on_frame_face
791 Turn on all set properties of the given face.
792 ****************************************************************************/
794 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
797 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
799 XSETFRAME (frame, f);
800 tty_turn_on_face_1 (c,
801 FACE_HIGHLIGHT_P (face, frame),
802 FACE_BLINKING_P (face, frame),
803 FACE_DIM_P (face, frame),
804 FACE_UNDERLINE_P (face, frame),
805 FACE_REVERSE_P (face, frame),
806 FACE_FOREGROUND (face, frame),
807 FACE_BACKGROUND (face, frame));
810 /*****************************************************************************
811 tty_turn_off_frame_face
813 Turn off all set properties of the given face (revert to default
814 face). We assume that tty_turn_on_face has been called for the given
815 face so that its properties are actually active.
816 ****************************************************************************/
818 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
821 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
823 XSETFRAME (frame, f);
825 if (FACE_REVERSE_P (face, frame))
827 /* #### punt for now if standout mode is glitchy */
828 if (!TTY_FLAGS (c).standout_width)
830 OUTPUT1_IF (c, TTY_SD (c).end_standout);
834 if (FACE_UNDERLINE_P (face, frame))
836 /* #### punt for now if underline mode is glitchy */
837 if (!TTY_FLAGS (c).underline_width)
839 OUTPUT1_IF (c, TTY_SD (c).end_underline);
843 if (FACE_HIGHLIGHT_P (face, frame) ||
844 FACE_BLINKING_P (face, frame) ||
845 FACE_DIM_P (face, frame) ||
846 !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
847 !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
849 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
853 /*****************************************************************************
856 Sets up various parameters on tty modes.
857 ****************************************************************************/
859 set_tty_modes (struct console *c)
861 if (!CONSOLE_TTY_P (c))
864 OUTPUT1_IF (c, TTY_SD (c).init_motion);
865 OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
866 OUTPUT1_IF (c, TTY_SD (c).keypad_on);
868 if (TTY_FLAGS (c).auto_margins)
869 OUTPUT1_IF (c, TTY_SD (c).disable_auto_margins);
872 /*****************************************************************************
875 Restore default state of tty.
876 ****************************************************************************/
878 reset_tty_modes (struct console *c)
880 if (!CONSOLE_TTY_P (c))
883 OUTPUT1_IF (c, TTY_SD (c).orig_pair);
884 OUTPUT1_IF (c, TTY_SD (c).keypad_off);
885 OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
886 OUTPUT1_IF (c, TTY_SD (c).end_motion);
888 if (TTY_FLAGS (c).auto_margins)
889 OUTPUT1_IF (c, TTY_SD (c).enable_auto_margins);
892 Lisp_Object frm = CONSOLE_SELECTED_FRAME (c);
895 tty_frame_output_end (XFRAME (frm));
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
934 /* FLAGS - these don't need to be console local since only one console
935 can be being updated at a time. */
936 static int insert_mode_on; /* nonzero if in insert mode */
937 static int standout_mode_on; /* nonzero if in standout mode */
938 static int underline_mode_on; /* nonzero if in underline mode */
939 static int alternate_mode_on; /* nonzero if in alternate char set */
940 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 ("vs", &bufptr);
1195 TTY_SD (c).cursor_normal = tgetstr ("ve", &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);
1200 TTY_SD (c).disable_auto_margins = tgetstr ("RA", &bufptr);
1201 TTY_SD (c).enable_auto_margins = tgetstr ("SA", &bufptr);
1205 * Initialize additional terminal information.
1207 TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1208 TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1209 TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1210 TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1211 TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1212 TTY_FLAGS (c).standout_width = tgetnum ("sg");
1213 TTY_FLAGS (c).underline_width = tgetnum ("ug");
1214 TTY_FLAGS (c).auto_margins = tgetflag ("am");
1216 if (TTY_FLAGS (c).standout_width == -1)
1217 TTY_FLAGS (c).standout_width = 0;
1218 if (TTY_FLAGS (c).underline_width == -1)
1219 TTY_FLAGS (c).underline_width = 0;
1221 TTY_FLAGS (c).meta_key =
1222 eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1226 * Setup the costs tables for this tty console.
1232 * Initialize local flags.
1235 standout_mode_on = 0;
1236 underline_mode_on = 0;
1237 alternate_mode_on = 0;
1242 * Attempt to initialize the function_key_map to
1243 * some kind of sensible value
1246 term_get_fkeys (c->function_key_map, &bufptr);
1249 /* check for ANSI set-foreground and set-background strings,
1250 and assume color if so.
1252 #### we should support the other (non-ANSI) ways of specifying
1255 char *fooptr = foobuf;
1256 if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1257 (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1258 ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1259 DEVICE_CLASS (d) = Qcolor;
1261 DEVICE_CLASS (d) = Qmono;
1264 return TTY_INIT_SUCCESS;
1273 /* Termcap capability names that correspond directly to X keysyms.
1274 Some of these (marked "terminfo") aren't supplied by old-style
1275 (Berkeley) termcap entries. They're listed in X keysym order;
1276 except we put the keypad keys first, so that if they clash with
1277 other keys (as on the IBM PC keyboard) they get overridden.
1280 static struct fkey_table keys[] =
1282 {"kh", "home"}, /* termcap */
1283 {"kl", "left"}, /* termcap */
1284 {"ku", "up"}, /* termcap */
1285 {"kr", "right"}, /* termcap */
1286 {"kd", "down"}, /* termcap */
1287 {"%8", "prior"}, /* terminfo */
1288 {"%5", "next"}, /* terminfo */
1289 {"@7", "end"}, /* terminfo */
1290 {"@1", "begin"}, /* terminfo */
1291 {"*6", "select"}, /* terminfo */
1292 {"%9", "print"}, /* terminfo */
1293 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1295 * "insert" --- see below
1297 {"&8", "undo"}, /* terminfo */
1298 {"%0", "redo"}, /* terminfo */
1299 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1300 {"@0", "find"}, /* terminfo */
1301 {"@2", "cancel"}, /* terminfo */
1302 {"%1", "help"}, /* terminfo */
1304 * "break" goes here, but can't be reliably intercepted with termcap
1306 {"&4", "reset"}, /* terminfo --- actually `restart' */
1308 * "system" and "user" --- no termcaps
1310 {"kE", "clearline"}, /* terminfo */
1311 {"kA", "insertline"}, /* terminfo */
1312 {"kL", "deleteline"}, /* terminfo */
1313 {"kI", "insertchar"}, /* terminfo */
1314 {"kD", "delete"}, /* terminfo */
1315 {"kB", "backtab"}, /* terminfo */
1317 * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1319 {"@8", "kp-enter"}, /* terminfo */
1321 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1322 * "kp-multiply", "kp-add", "kp-separator",
1323 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1324 * --- no termcaps for any of these.
1326 {"K4", "kp-1"}, /* terminfo */
1328 * "kp-2" --- no termcap
1330 {"K5", "kp-3"}, /* terminfo */
1332 * "kp-4" --- no termcap
1334 {"K2", "kp-5"}, /* terminfo */
1336 * "kp-6" --- no termcap
1338 {"K1", "kp-7"}, /* terminfo */
1340 * "kp-8" --- no termcap
1342 {"K3", "kp-9"}, /* terminfo */
1344 * "kp-equal" --- no termcap
1357 static char **term_get_fkeys_arg;
1359 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1360 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1362 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1363 This function scans the termcap function key sequence entries, and
1364 adds entries to Vfunction_key_map for each function key it finds. */
1367 term_get_fkeys (Lisp_Object keymap, char **address)
1369 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1370 errors during the call. The only errors should be from Fdefine_key
1371 when given a key sequence containing an invalid prefix key. If the
1372 termcap defines function keys which use a prefix that is already bound
1373 to a command by the default bindings, we should silently ignore that
1374 function key specification, rather than giving the user an error and
1375 refusing to run at all on such a terminal. */
1377 term_get_fkeys_arg = address;
1379 condition_case_1 (Qerror,
1380 term_get_fkeys_1, keymap,
1381 term_get_fkeys_error, Qnil);
1385 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1391 term_get_fkeys_1 (Lisp_Object function_key_map)
1395 char **address = term_get_fkeys_arg;
1397 for (i = 0; i < countof (keys); i++)
1399 char *sequence = tgetstr (keys[i].cap, address);
1401 Fdefine_key (function_key_map,
1402 build_ext_string (sequence, Qbinary),
1403 vector1 (intern (keys[i].name)));
1406 /* The uses of the "k0" capability are inconsistent; sometimes it
1407 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1408 We will attempt to politely accommodate both systems by testing for
1409 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1412 const char *k_semi = tgetstr ("k;", address);
1413 const char *k0 = tgetstr ("k0", address);
1416 Fdefine_key (function_key_map, build_ext_string (k_semi, Qbinary),
1417 vector1 (intern ("f10")));
1420 Fdefine_key (function_key_map, build_ext_string (k0, Qbinary),
1421 vector1 (intern (k_semi ? "f0" : "f10")));
1424 /* Set up cookies for numbered function keys above f10. */
1426 char fcap[3], fkey[4];
1428 fcap[0] = 'F'; fcap[2] = '\0';
1429 for (i = 11; i < 64; i++)
1432 fcap[1] = '1' + i - 11;
1434 fcap[1] = 'A' + i - 20;
1436 fcap[1] = 'a' + i - 46;
1439 char *sequence = tgetstr (fcap, address);
1442 sprintf (fkey, "f%d", i);
1443 Fdefine_key (function_key_map,
1444 build_ext_string (sequence, Qbinary),
1445 vector1 (intern (fkey)));
1452 * Various mappings to try and get a better fit.
1454 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) do { \
1455 if (!tgetstr (cap1, address)) \
1457 char *sequence = tgetstr (cap2, address); \
1459 Fdefine_key (function_key_map, \
1460 build_ext_string (sequence, Qbinary), \
1461 vector1 (intern (keyname))); \
1465 /* if there's no key_next keycap, map key_npage to `next' keysym */
1466 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1467 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1468 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1469 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1470 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1472 /* IBM has their own non-standard dialect of terminfo.
1473 If the standard name isn't found, try the IBM name. */
1474 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1475 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1476 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1477 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1478 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1479 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1480 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1481 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1482 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1483 #undef CONDITIONAL_REASSIGN
1489 /************************************************************************/
1490 /* initialization */
1491 /************************************************************************/
1494 console_type_create_redisplay_tty (void)
1496 /* redisplay methods */
1497 CONSOLE_HAS_METHOD (tty, text_width);
1498 CONSOLE_HAS_METHOD (tty, output_display_block);
1499 CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1500 CONSOLE_HAS_METHOD (tty, divider_height);
1501 CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1502 CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1503 CONSOLE_HAS_METHOD (tty, clear_region);
1504 CONSOLE_HAS_METHOD (tty, clear_frame);
1505 CONSOLE_HAS_METHOD (tty, frame_output_begin);
1506 CONSOLE_HAS_METHOD (tty, frame_output_end);
1507 CONSOLE_HAS_METHOD (tty, flash);
1508 CONSOLE_HAS_METHOD (tty, ring_bell);
1509 CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);