1 /* Communication module for TTY terminals.
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1995 Sun Microsystems, Inc.
4 Copyright (C) 1995, 1996 Ben Wing.
5 Copyright (C) 1996 Chuck Thompson.
7 This file is part of XEmacs.
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* Synched up with: Not completely synched with FSF. Mostly divergent
27 /* This file has been Mule-ized. */
29 /* Written by Chuck Thompson. */
30 /* Color support added by Ben Wing. */
36 #include "console-tty.h"
42 #include "objects-tty.h"
43 #include "redisplay.h"
47 /* These headers #define all kinds of common words like "columns"...
48 What a bunch of losers. If we were to include them, we'd have to
49 include them last to prevent them from messing up our own header
50 files (struct slot names, etc.). But it turns out that there are
51 other conflicts as well on some systems, so screw it: we'll just
52 re-declare the routines we use and assume the code in this file is
53 invoking them correctly. */
54 /* # include <curses.h> */
55 /* # include <term.h> */
59 extern int tgetent (const char *, const char *);
60 extern int tgetflag (const char *);
61 extern int tgetnum (const char *);
62 extern char *tgetstr (const char *, char **);
63 extern void tputs (const char *, int, void (*)(int));
67 #define FORCE_CURSOR_UPDATE(c) send_string_to_tty_console (c, 0, 0)
68 #define OUTPUTN(c, a, n) \
71 FORCE_CURSOR_UPDATE (c); \
72 tputs (a, n, cmputc); \
74 #define OUTPUT1(c, a) OUTPUTN (c, a, 1)
75 #define OUTPUTN_IF(c, a, n) \
78 FORCE_CURSOR_UPDATE (c); \
80 tputs (a, n, cmputc); \
82 #define OUTPUT1_IF(c, a) OUTPUTN_IF (c, a, 1)
84 static void tty_output_emchar_dynarr (struct window *w,
85 struct display_line *dl,
86 Emchar_dynarr *buf, int xpos,
89 static void tty_output_bufbyte_string (struct window *w,
90 struct display_line *dl,
91 Bufbyte *str, Bytecount len,
92 int xpos, face_index findex,
94 static void tty_turn_on_face (struct window *w, face_index findex);
95 static void tty_turn_off_face (struct window *w, face_index findex);
96 static void tty_turn_on_frame_face (struct frame *f, Lisp_Object face);
97 static void tty_turn_off_frame_face (struct frame *f, Lisp_Object face);
99 static void term_get_fkeys (Lisp_Object keymap, char **address);
101 /*****************************************************************************
104 Non-Mule tty's don't have fonts (that we use at least), so everything
105 is considered to be fixed width -- in other words, we return LEN.
106 Under Mule, however, a character can still cover more than one
107 column, so we use emchar_string_displayed_columns().
108 ****************************************************************************/
110 tty_text_width (struct frame *f, struct face_cachel *cachel, const Emchar *str,
113 return emchar_string_displayed_columns (str, len);
116 /*****************************************************************************
119 Return the width of the horizontal divider. This is a function
120 because divider_height is a console method.
121 ****************************************************************************/
123 tty_divider_height (void)
128 /*****************************************************************************
131 Return the width of the end-of-line cursor. This is a function
132 because eol_cursor_width is a console method.
133 ****************************************************************************/
135 tty_eol_cursor_width (void)
140 /*****************************************************************************
143 Perform any necessary initialization prior to an update.
144 ****************************************************************************/
146 void tty_output_begin (struct device *d);
151 tty_output_begin (struct device *d)
154 /* Termcap requires `ospeed' to be a global variable so we have to
155 always set it for whatever tty console we are actually currently
157 ospeed = DEVICE_TTY_DATA (d)->ospeed;
161 /*****************************************************************************
164 Perform any necessary flushing of queues when an update has completed.
165 ****************************************************************************/
167 void tty_output_end (struct device *d);
172 tty_output_end (struct device *d)
174 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
176 CONSOLE_TTY_CURSOR_X (c) = CONSOLE_TTY_FINAL_CURSOR_X (c);
177 CONSOLE_TTY_CURSOR_Y (c) = CONSOLE_TTY_FINAL_CURSOR_Y (c);
178 FORCE_CURSOR_UPDATE (c);
179 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
183 tty_set_final_cursor_coords (struct frame *f, int y, int x)
185 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
187 CONSOLE_TTY_FINAL_CURSOR_X (c) = x;
188 CONSOLE_TTY_FINAL_CURSOR_Y (c) = y;
191 /*****************************************************************************
192 tty_output_display_block
194 Given a display line, a block number for that start line, output all
195 runes between start and end in the specified display block.
196 ****************************************************************************/
198 tty_output_display_block (struct window *w, struct display_line *dl, int block,
199 int start, int end, int start_pixpos,
200 int cursor_start, int cursor_width,
203 struct frame *f = XFRAME (w->frame);
204 Emchar_dynarr *buf = Dynarr_new (Emchar);
206 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
207 rune_dynarr *rba = db->runes;
214 rb = Dynarr_atp (rba, elt);
218 /* Nothing to do so don't do anything. */
228 end = Dynarr_length (rba);
232 while (elt < end && Dynarr_atp (rba, elt)->xpos < start_pixpos)
235 findex = Dynarr_atp (rba, elt)->findex;
236 xpos = Dynarr_atp (rba, elt)->xpos;
241 rb = Dynarr_atp (rba, elt);
243 if (rb->findex == findex && rb->type == RUNE_CHAR
244 && rb->object.chr.ch != '\n'
245 && (rb->cursor_type != CURSOR_ON
246 || NILP (w->text_cursor_visible_p)))
248 Dynarr_add (buf, rb->object.chr.ch);
253 if (Dynarr_length (buf))
255 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
260 if (rb->type == RUNE_CHAR)
265 if (rb->object.chr.ch == '\n')
267 /* Clear in case a cursor was formerly here. */
269 Dynarr_add (buf, ' ');
270 tty_output_emchar_dynarr (w, dl, buf, rb->xpos,
274 cmgoto (f, dl->ypos - 1, rb->xpos);
278 else if (rb->cursor_type == CURSOR_ON)
280 /* There is not a distinct eol cursor on tty's. */
282 Dynarr_add (buf, rb->object.chr.ch);
283 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
286 cmgoto (f, dl->ypos - 1, xpos);
292 /* #### RUNE_HLINE is actually a little more complicated than this
293 but at the moment it is only used to draw a turned off
294 modeline and this will suffice for that. */
295 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
298 int size = rb->width;
300 if (rb->type == RUNE_BLANK)
306 Dynarr_add (buf, ch_to_add);
307 tty_output_emchar_dynarr (w, dl, buf, rb->xpos, findex, 0);
309 if (xpos >= cursor_start
310 && cursor_start < xpos + Dynarr_length (buf))
312 cmgoto (f, dl->ypos - 1, cursor_start);
320 rb = Dynarr_atp (rba, elt);
326 else if (rb->type == RUNE_DGLYPH)
329 Lisp_Object instance;
331 XSETWINDOW (window, w);
332 instance = glyph_image_instance (rb->object.dglyph.glyph,
333 window, ERROR_ME_NOT, 1);
335 if (IMAGE_INSTANCEP (instance))
337 switch (XIMAGE_INSTANCE_TYPE (instance))
339 case IMAGE_MONO_PIXMAP:
340 case IMAGE_COLOR_PIXMAP:
341 case IMAGE_SUBWINDOW:
344 /* just do nothing here */
348 /* nothing is as nothing does */
356 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
357 (XIMAGE_INSTANCE (instance)) = 0;
368 if (Dynarr_length (buf))
369 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
376 /*****************************************************************************
377 tty_output_vertical_divider
379 Draw a vertical divider down the right side of the given window.
380 ****************************************************************************/
382 tty_output_vertical_divider (struct window *w, int clear)
384 /* Divider width can either be 0 or 1 on TTYs */
385 if (window_divider_width (w))
387 struct frame *f = XFRAME (w->frame);
388 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
390 int y_top = WINDOW_TEXT_TOP (w);
391 int y_bot = WINDOW_TEXT_BOTTOM (w);
392 unsigned char divv = '|';
394 tty_turn_on_face (w, MODELINE_INDEX);
395 for (line = y_top; line < y_bot; line++)
397 cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
398 send_string_to_tty_console (c, &divv, 1);
399 TTY_INC_CURSOR_X (c, 1);
402 /* Draw the divider in the modeline. */
403 cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
404 send_string_to_tty_console (c, &divv, 1);
405 TTY_INC_CURSOR_X (c, 1);
406 tty_turn_off_face (w, MODELINE_INDEX);
410 /****************************************************************************
413 Clear the area in the box defined by the given parameters.
414 ****************************************************************************/
416 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
417 face_index findex, int x, int y,
418 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
419 Lisp_Object background_pixmap)
421 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
423 struct window* w = XWINDOW (window);
425 tty_turn_on_face (w, findex);
426 for (line = y; line < y + height; line++)
432 if (window_is_leftmost (w)
433 && window_is_rightmost (w)
434 && TTY_SE (c).clr_to_eol)
436 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
440 unsigned char sp = ' ';
441 /* #### Of course, this is all complete and utter crap. */
442 for (col = x; col < x + width; col++)
443 send_string_to_tty_console (c, &sp, 1);
444 TTY_INC_CURSOR_X (c, width);
447 tty_turn_off_face (w, findex);
451 /*****************************************************************************
452 tty_clear_to_window_end
454 Clear the area between ypos1 and ypos2. Each margin area and the
455 text area is handled separately since they may each have their own
457 ****************************************************************************/
459 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
461 struct frame *f = XFRAME (w->frame);
462 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
465 x = WINDOW_TEXT_LEFT (w);
466 width = WINDOW_TEXT_WIDTH (w);
468 if (window_is_rightmost (w))
470 /* #### Optimize to use clr_to_eol function of tty if available, if
471 the window is the entire width of the frame. */
472 /* #### Is this actually an optimization? */
474 tty_turn_on_face (w, DEFAULT_INDEX);
475 for (line = ypos1; line < ypos2; line++)
477 cmgoto (XFRAME (w->frame), line, x);
478 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
480 tty_turn_off_face (w, DEFAULT_INDEX);
486 XSETWINDOW (window, w);
487 redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
491 /****************************************************************************
494 Clear the entire frame.
495 ****************************************************************************/
497 tty_clear_frame (struct frame *f)
499 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
501 tty_turn_on_frame_face (f, Vdefault_face);
502 if (TTY_SE (c).clr_frame)
504 OUTPUT1 (c, TTY_SE (c).clr_frame);
505 CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
506 CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
508 FRAME_CURSOR_X (f) = 0;
509 FRAME_CURSOR_Y (f) = 0;
515 internal_cursor_to (f, 0, 0);
518 /* #### Not implemented. */
519 stderr_out ("Not yet.\n");
522 tty_turn_off_frame_face (f, Vdefault_face);
526 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
527 Bufbyte *str, Bytecount len, int xpos,
528 face_index findex, int cursor)
530 struct frame *f = XFRAME (w->frame);
531 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
533 /* First position the cursor. */
534 cmgoto (f, dl->ypos - 1, xpos);
536 /* Enable any face properties. */
537 tty_turn_on_face (w, findex);
539 send_string_to_tty_console (c, str, len);
540 TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
542 /* Turn the face properties back off. */
543 tty_turn_off_face (w, findex);
546 static Bufbyte_dynarr *tty_output_emchar_dynarr_dynarr;
548 /*****************************************************************************
549 tty_output_emchar_dynarr
551 Given a string and a starting position, output that string in the
552 given face. If cursor is true, draw a cursor around the string.
553 ****************************************************************************/
555 tty_output_emchar_dynarr (struct window *w, struct display_line *dl,
556 Emchar_dynarr *buf, int xpos, face_index findex,
559 if (!tty_output_emchar_dynarr_dynarr)
560 tty_output_emchar_dynarr_dynarr = Dynarr_new (Bufbyte);
562 Dynarr_reset (tty_output_emchar_dynarr_dynarr);
564 convert_emchar_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
566 tty_output_emchar_dynarr_dynarr);
568 tty_output_bufbyte_string (w, dl,
569 Dynarr_atp (tty_output_emchar_dynarr_dynarr, 0),
570 Dynarr_length (tty_output_emchar_dynarr_dynarr),
571 xpos, findex, cursor);
576 static Bufbyte_dynarr *sidcs_dynarr;
579 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
582 Bufbyte *specdata = XSTRING_DATA (spec);
583 Bytecount speclen = XSTRING_LENGTH (spec);
586 sidcs_dynarr = Dynarr_new (Bufbyte);
588 Dynarr_reset (sidcs_dynarr);
590 for (i = 0; i < speclen; i++)
592 if (specdata[i] == '%' && specdata[i+1] == '%')
594 Dynarr_add (sidcs_dynarr, '%');
597 else if (specdata[i] == '%' && specdata[i+1] == 's')
599 Dynarr_add_many (sidcs_dynarr,
600 XSTRING_DATA (string),
601 XSTRING_LENGTH (string));
605 Dynarr_add (sidcs_dynarr, specdata[i]);
612 set_foreground_to (struct console *c, Lisp_Object sym)
616 Bytecount escseqlen = 0;
618 result = assq_no_quit (sym, Vtty_color_alist);
621 Lisp_Object esc_seq = XCAR (XCDR (result));
622 escseq = XSTRING_DATA (esc_seq);
623 escseqlen = XSTRING_LENGTH (esc_seq);
626 else if (STRINGP (Vtty_dynamic_color_fg))
628 substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
630 escseq = Dynarr_atp (sidcs_dynarr, 0);
631 escseqlen = Dynarr_length (sidcs_dynarr);
637 send_string_to_tty_console (c, escseq, escseqlen);
642 set_background_to (struct console *c, Lisp_Object sym)
646 Bytecount escseqlen = 0;
648 result = assq_no_quit (sym, Vtty_color_alist);
651 Lisp_Object esc_seq = XCDR (XCDR (result));
652 escseq = XSTRING_DATA (esc_seq);
653 escseqlen = XSTRING_LENGTH (esc_seq);
656 else if (STRINGP (Vtty_dynamic_color_bg))
658 substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
660 escseq = Dynarr_atp (sidcs_dynarr, 0);
661 escseqlen = Dynarr_length (sidcs_dynarr);
667 send_string_to_tty_console (c, escseq, escseqlen);
672 tty_turn_on_face_1 (struct console *c, int highlight_p,
673 int blinking_p, int dim_p, int underline_p,
674 int reverse_p, Lisp_Object cinst_fore,
675 Lisp_Object cinst_back)
679 OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
684 OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
689 OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
694 /* #### punt for now if underline mode is glitchy */
695 if (!TTY_FLAGS (c).underline_width)
697 OUTPUT1_IF (c, TTY_SD (c).begin_underline);
703 /* #### punt for now if standout mode is glitchy */
704 if (!TTY_FLAGS (c).standout_width)
706 OUTPUT1_IF (c, TTY_SD (c).begin_standout);
714 Lisp_Object temp = cinst_fore;
715 cinst_fore = cinst_back;
719 if (COLOR_INSTANCEP (cinst_fore)
720 && !EQ (cinst_fore, Vthe_null_color_instance))
721 set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
722 (XCOLOR_INSTANCE (cinst_fore)));
724 if (COLOR_INSTANCEP (cinst_back)
725 && !EQ (cinst_back, Vthe_null_color_instance))
726 set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
727 (XCOLOR_INSTANCE (cinst_back)));
730 /*****************************************************************************
733 Turn on all set properties of the given face.
734 ****************************************************************************/
736 tty_turn_on_face (struct window *w, face_index findex)
738 struct frame *f = XFRAME (w->frame);
739 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
741 tty_turn_on_face_1 (c,
742 WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
743 WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
744 WINDOW_FACE_CACHEL_DIM_P (w, findex),
745 WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
746 WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
747 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
748 WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
751 /*****************************************************************************
754 Turn off all set properties of the given face (revert to default
755 face). We assume that tty_turn_on_face has been called for the given
756 face so that its properties are actually active.
757 ****************************************************************************/
759 tty_turn_off_face (struct window *w, face_index findex)
761 struct frame *f = XFRAME (w->frame);
762 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
764 if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
766 /* #### punt for now if standout mode is glitchy */
767 if (!TTY_FLAGS (c).standout_width)
769 OUTPUT1_IF (c, TTY_SD (c).end_standout);
773 if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
775 /* #### punt for now if underline mode is glitchy */
776 if (!TTY_FLAGS (c).underline_width)
778 OUTPUT1_IF (c, TTY_SD (c).end_underline);
782 if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
783 WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
784 WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
785 !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
786 Vthe_null_color_instance) ||
787 !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
788 Vthe_null_color_instance))
790 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
794 /*****************************************************************************
795 tty_turn_on_frame_face
797 Turn on all set properties of the given face.
798 ****************************************************************************/
800 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
803 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
805 XSETFRAME (frame, f);
806 tty_turn_on_face_1 (c,
807 FACE_HIGHLIGHT_P (face, frame),
808 FACE_BLINKING_P (face, frame),
809 FACE_DIM_P (face, frame),
810 FACE_UNDERLINE_P (face, frame),
811 FACE_REVERSE_P (face, frame),
812 FACE_FOREGROUND (face, frame),
813 FACE_BACKGROUND (face, frame));
816 /*****************************************************************************
817 tty_turn_off_frame_face
819 Turn off all set properties of the given face (revert to default
820 face). We assume that tty_turn_on_face has been called for the given
821 face so that its properties are actually active.
822 ****************************************************************************/
824 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
827 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
829 XSETFRAME (frame, f);
831 if (FACE_REVERSE_P (face, frame))
833 /* #### punt for now if standout mode is glitchy */
834 if (!TTY_FLAGS (c).standout_width)
836 OUTPUT1_IF (c, TTY_SD (c).end_standout);
840 if (FACE_UNDERLINE_P (face, frame))
842 /* #### punt for now if underline mode is glitchy */
843 if (!TTY_FLAGS (c).underline_width)
845 OUTPUT1_IF (c, TTY_SD (c).end_underline);
849 if (FACE_HIGHLIGHT_P (face, frame) ||
850 FACE_BLINKING_P (face, frame) ||
851 FACE_DIM_P (face, frame) ||
852 !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
853 !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
855 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
859 /*****************************************************************************
862 Sets up various parameters on tty modes.
863 ****************************************************************************/
865 set_tty_modes (struct console *c)
867 if (!CONSOLE_TTY_P (c))
870 OUTPUT1_IF (c, TTY_SD (c).init_motion);
871 OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
872 OUTPUT1_IF (c, TTY_SD (c).keypad_on);
875 /*****************************************************************************
878 Restore default state of tty.
879 ****************************************************************************/
881 reset_tty_modes (struct console *c)
883 if (!CONSOLE_TTY_P (c))
886 OUTPUT1_IF (c, TTY_SD (c).orig_pair);
887 OUTPUT1_IF (c, TTY_SD (c).keypad_off);
888 OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
889 OUTPUT1_IF (c, TTY_SD (c).end_motion);
890 tty_output_end (XDEVICE (CONSOLE_SELECTED_DEVICE (c)));
893 /*****************************************************************************
894 tty_redisplay_shutdown
896 Clear the frame and position the cursor properly for exiting.
897 ****************************************************************************/
899 tty_redisplay_shutdown (struct console *c)
901 Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
905 Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
909 struct frame *f = XFRAME (frm);
911 /* Clear the bottom line of the frame. */
912 redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
913 f->height, f->width, 1);
915 /* And then stick the cursor there. */
916 tty_set_final_cursor_coords (f, f->height, 0);
917 tty_output_end (XDEVICE (dev));
923 /* #### Everything below here is old shit. It should either be moved
927 /* FLAGS - these don't need to be console local since only one console
928 can be being updated at a time. */
929 static int insert_mode_on; /* nonzero if in insert mode */
930 static int standout_mode_on; /* nonzero if in standout mode */
931 static int underline_mode_on; /* nonzero if in underline mode */
932 static int alternate_mode_on; /* nonzero if in alternate char set */
933 static int attributes_on; /* nonzero if any attributes on */
937 turn_on_insert (struct frame *f)
939 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
942 OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
947 turn_off_insert (struct frame *f)
949 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
952 OUTPUT1 (c, TTY_SE (c).end_ins_mode);
957 internal_cursor_to (struct frame *f, int row, int col)
959 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
961 if (!TTY_FLAGS (c).insert_mode_motion)
963 if (!TTY_FLAGS (c).standout_motion)
965 turn_off_standout (f);
966 turn_off_underline (f);
967 turn_off_alternate (f);
970 cmgoto (f, row, col);
974 clear_to_end (struct frame *f)
976 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
978 /* assumes cursor is already positioned */
979 if (TTY_SE (c).clr_from_cursor)
981 OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
985 int line = FRAME_CURSOR_Y (f);
987 while (line < FRAME_HEIGHT (f))
989 internal_cursor_to (f, line, 0);
990 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
998 * clear from last visible line on window to window end (presumably
999 * the line above window's modeline
1002 tty_clear_window_end (struct window *w, int ystart, int yend)
1004 struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1007 for (line = ystart; line < yend; line++)
1009 cmgoto (XFRAME (w->frame), line, 0);
1010 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1017 tty_flash (struct device *d)
1019 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1020 if (TTY_SD (c).visual_bell)
1022 OUTPUT1 (c, TTY_SD (c).visual_bell);
1023 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1031 * tty_ring_bell - sound an audio beep.
1034 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1036 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1040 OUTPUT1 (c, TTY_SD (c).audio_bell);
1041 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1047 init_tty_for_redisplay (struct device *d, char *terminal_type)
1050 char entry_buffer[2044];
1051 /* char temp_buffer[2044]; */
1053 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1055 /* What we should really do is allocate just enough space for
1056 the actual strings that are stored; but this would require
1057 doing this after all the tgetstr()s and adjusting all the
1059 CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1060 bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1063 /* SIGTT* don't exist under win32 */
1064 EMACS_BLOCK_SIGNAL (SIGTTOU);
1066 status = tgetent (entry_buffer, terminal_type);
1068 EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1072 return TTY_UNABLE_OPEN_DATABASE;
1073 else if (status == 0)
1074 return TTY_TYPE_UNDEFINED;
1076 /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1078 return TTY_TYPE_UNDEFINED;
1081 * Establish the terminal size.
1083 /* First try to get the info from the system. If that fails, check
1084 the termcap entry. */
1085 get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1086 &CONSOLE_TTY_DATA (c)->height);
1088 if (CONSOLE_TTY_DATA (c)->width <= 0)
1089 CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1090 if (CONSOLE_TTY_DATA (c)->height <= 0)
1091 CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1093 if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1094 return TTY_SIZE_UNSPECIFIED;
1097 * Initialize cursor motion information.
1100 /* local cursor movement */
1101 TTY_CM (c).up = tgetstr ("up", &bufptr);
1102 TTY_CM (c).down = tgetstr ("do", &bufptr);
1103 TTY_CM (c).left = tgetstr ("le", &bufptr);
1104 TTY_CM (c).right = tgetstr ("nd", &bufptr);
1105 TTY_CM (c).home = tgetstr ("ho", &bufptr);
1106 TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1107 TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1109 /* absolute cursor motion */
1110 TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1111 TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1112 TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1114 /* Verify that the terminal is powerful enough to run Emacs */
1115 if (!TTY_CM (c).abs)
1117 if (!TTY_CM (c).up || !TTY_CM (c).down
1118 || !TTY_CM (c).left || !TTY_CM (c).right)
1119 return TTY_TYPE_INSUFFICIENT;
1122 /* parameterized local cursor movement */
1123 TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1124 TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1125 TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1126 TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1129 TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1130 TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1131 TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1132 TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1133 TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1137 * Initialize screen editing information.
1140 /* adding to the screen */
1141 TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1142 TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1143 TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1144 TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1145 TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1146 TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1147 TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1148 TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1150 /* deleting from the screen */
1151 TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1152 TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1153 TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1154 TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1155 TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1156 TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1157 TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1158 TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1159 TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1160 TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1164 * Initialize screen display information.
1166 TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1167 TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1168 TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1169 TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1170 TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1171 TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1172 TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1173 TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1174 TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1175 TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1176 TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1177 TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1179 TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1180 TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1181 if (!TTY_SD (c).audio_bell)
1183 /* If audio_bell doesn't get set, then assume C-g. This is gross and
1184 ugly but is what Emacs has done from time immortal. */
1185 TTY_SD (c).audio_bell = "\07";
1188 TTY_SD (c).cursor_visible = tgetstr ("ve", &bufptr);
1189 TTY_SD (c).cursor_normal = tgetstr ("vs", &bufptr);
1190 TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1191 TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1192 TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1193 TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1197 * Initialize additional terminal information.
1199 TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1200 TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1201 TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1202 TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1203 TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1204 TTY_FLAGS (c).standout_width = tgetnum ("sg");
1205 TTY_FLAGS (c).underline_width = tgetnum ("ug");
1207 if (TTY_FLAGS (c).standout_width == -1)
1208 TTY_FLAGS (c).standout_width = 0;
1209 if (TTY_FLAGS (c).underline_width == -1)
1210 TTY_FLAGS (c).underline_width = 0;
1212 TTY_FLAGS (c).meta_key =
1213 eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1217 * Setup the costs tables for this tty console.
1222 * Initialize local flags.
1225 standout_mode_on = 0;
1226 underline_mode_on = 0;
1227 alternate_mode_on = 0;
1231 * Attempt to initialize the function_key_map to
1232 * some kind of sensible value
1235 term_get_fkeys (c->function_key_map, &bufptr);
1238 /* check for ANSI set-foreground and set-background strings,
1239 and assume color if so.
1241 #### we should support the other (non-ANSI) ways of specifying
1244 char *fooptr = foobuf;
1245 if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1246 (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1247 ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1248 DEVICE_CLASS (d) = Qcolor;
1250 DEVICE_CLASS (d) = Qmono;
1253 return TTY_INIT_SUCCESS;
1262 /* Termcap capability names that correspond directly to X keysyms.
1263 Some of these (marked "terminfo") aren't supplied by old-style
1264 (Berkeley) termcap entries. They're listed in X keysym order;
1265 except we put the keypad keys first, so that if they clash with
1266 other keys (as on the IBM PC keyboard) they get overridden.
1269 static struct fkey_table keys[] =
1271 {"kh", "home"}, /* termcap */
1272 {"kl", "left"}, /* termcap */
1273 {"ku", "up"}, /* termcap */
1274 {"kr", "right"}, /* termcap */
1275 {"kd", "down"}, /* termcap */
1276 {"%8", "prior"}, /* terminfo */
1277 {"%5", "next"}, /* terminfo */
1278 {"@7", "end"}, /* terminfo */
1279 {"@1", "begin"}, /* terminfo */
1280 {"*6", "select"}, /* terminfo */
1281 {"%9", "print"}, /* terminfo */
1282 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1284 * "insert" --- see below
1286 {"&8", "undo"}, /* terminfo */
1287 {"%0", "redo"}, /* terminfo */
1288 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1289 {"@0", "find"}, /* terminfo */
1290 {"@2", "cancel"}, /* terminfo */
1291 {"%1", "help"}, /* terminfo */
1293 * "break" goes here, but can't be reliably intercepted with termcap
1295 {"&4", "reset"}, /* terminfo --- actually `restart' */
1297 * "system" and "user" --- no termcaps
1299 {"kE", "clearline"}, /* terminfo */
1300 {"kA", "insertline"}, /* terminfo */
1301 {"kL", "deleteline"}, /* terminfo */
1302 {"kI", "insertchar"}, /* terminfo */
1303 {"kD", "delete"}, /* terminfo */
1304 {"kB", "backtab"}, /* terminfo */
1306 * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1308 {"@8", "kp-enter"}, /* terminfo */
1310 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1311 * "kp-multiply", "kp-add", "kp-separator",
1312 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1313 * --- no termcaps for any of these.
1315 {"K4", "kp-1"}, /* terminfo */
1317 * "kp-2" --- no termcap
1319 {"K5", "kp-3"}, /* terminfo */
1321 * "kp-4" --- no termcap
1323 {"K2", "kp-5"}, /* terminfo */
1325 * "kp-6" --- no termcap
1327 {"K1", "kp-7"}, /* terminfo */
1329 * "kp-8" --- no termcap
1331 {"K3", "kp-9"}, /* terminfo */
1333 * "kp-equal" --- no termcap
1346 static char **term_get_fkeys_arg;
1348 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1349 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1351 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1352 This function scans the termcap function key sequence entries, and
1353 adds entries to Vfunction_key_map for each function key it finds. */
1356 term_get_fkeys (Lisp_Object keymap, char **address)
1358 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1359 errors during the call. The only errors should be from Fdefine_key
1360 when given a key sequence containing an invalid prefix key. If the
1361 termcap defines function keys which use a prefix that is already bound
1362 to a command by the default bindings, we should silently ignore that
1363 function key specification, rather than giving the user an error and
1364 refusing to run at all on such a terminal. */
1366 term_get_fkeys_arg = address;
1368 condition_case_1 (Qerror,
1369 term_get_fkeys_1, keymap,
1370 term_get_fkeys_error, Qnil);
1374 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1380 term_get_fkeys_1 (Lisp_Object function_key_map)
1384 char **address = term_get_fkeys_arg;
1386 for (i = 0; i < countof (keys); i++)
1388 char *sequence = tgetstr (keys[i].cap, address);
1390 Fdefine_key (function_key_map,
1391 build_ext_string (sequence, Qbinary),
1392 vector1 (intern (keys[i].name)));
1395 /* The uses of the "k0" capability are inconsistent; sometimes it
1396 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1397 We will attempt to politely accommodate both systems by testing for
1398 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1401 const char *k_semi = tgetstr ("k;", address);
1402 const char *k0 = tgetstr ("k0", address);
1405 Fdefine_key (function_key_map, build_ext_string (k_semi, Qbinary),
1406 vector1 (intern ("f10")));
1409 Fdefine_key (function_key_map, build_ext_string (k0, Qbinary),
1410 vector1 (intern (k_semi ? "f0" : "f10")));
1413 /* Set up cookies for numbered function keys above f10. */
1415 char fcap[3], fkey[4];
1417 fcap[0] = 'F'; fcap[2] = '\0';
1418 for (i = 11; i < 64; i++)
1421 fcap[1] = '1' + i - 11;
1423 fcap[1] = 'A' + i - 20;
1425 fcap[1] = 'a' + i - 46;
1428 char *sequence = tgetstr (fcap, address);
1431 sprintf (fkey, "f%d", i);
1432 Fdefine_key (function_key_map,
1433 build_ext_string (sequence, Qbinary),
1434 vector1 (intern (fkey)));
1441 * Various mappings to try and get a better fit.
1443 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) do { \
1444 if (!tgetstr (cap1, address)) \
1446 char *sequence = tgetstr (cap2, address); \
1448 Fdefine_key (function_key_map, \
1449 build_ext_string (sequence, Qbinary), \
1450 vector1 (intern (keyname))); \
1454 /* if there's no key_next keycap, map key_npage to `next' keysym */
1455 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1456 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1457 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1458 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1459 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1461 /* IBM has their own non-standard dialect of terminfo.
1462 If the standard name isn't found, try the IBM name. */
1463 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1464 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1465 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1466 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1467 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1468 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1469 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1470 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1471 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1472 #undef CONDITIONAL_REASSIGN
1478 /************************************************************************/
1479 /* initialization */
1480 /************************************************************************/
1483 console_type_create_redisplay_tty (void)
1485 /* redisplay methods */
1486 CONSOLE_HAS_METHOD (tty, text_width);
1487 CONSOLE_HAS_METHOD (tty, output_display_block);
1488 CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1489 CONSOLE_HAS_METHOD (tty, divider_height);
1490 CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1491 CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1492 CONSOLE_HAS_METHOD (tty, clear_region);
1493 CONSOLE_HAS_METHOD (tty, clear_frame);
1494 CONSOLE_HAS_METHOD (tty, output_begin);
1495 CONSOLE_HAS_METHOD (tty, output_end);
1496 CONSOLE_HAS_METHOD (tty, flash);
1497 CONSOLE_HAS_METHOD (tty, ring_bell);
1498 CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);