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 device *d = XDEVICE (FRAME_DEVICE (f));
170 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
172 CONSOLE_TTY_CURSOR_X (c) = CONSOLE_TTY_FINAL_CURSOR_X (c);
173 CONSOLE_TTY_CURSOR_Y (c) = CONSOLE_TTY_FINAL_CURSOR_Y (c);
174 FORCE_CURSOR_UPDATE (c);
175 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
179 tty_set_final_cursor_coords (struct frame *f, int y, int x)
181 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
183 CONSOLE_TTY_FINAL_CURSOR_X (c) = x;
184 CONSOLE_TTY_FINAL_CURSOR_Y (c) = y;
187 /*****************************************************************************
188 tty_output_display_block
190 Given a display line, a block number for that start line, output all
191 runes between start and end in the specified display block.
192 ****************************************************************************/
194 tty_output_display_block (struct window *w, struct display_line *dl, int block,
195 int start, int end, int start_pixpos,
196 int cursor_start, int cursor_width,
199 struct frame *f = XFRAME (w->frame);
200 Emchar_dynarr *buf = Dynarr_new (Emchar);
202 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
203 rune_dynarr *rba = db->runes;
210 rb = Dynarr_atp (rba, elt);
214 /* Nothing to do so don't do anything. */
224 end = Dynarr_length (rba);
228 while (elt < end && Dynarr_atp (rba, elt)->xpos < start_pixpos)
231 findex = Dynarr_atp (rba, elt)->findex;
232 xpos = Dynarr_atp (rba, elt)->xpos;
237 rb = Dynarr_atp (rba, elt);
239 if (rb->findex == findex && rb->type == RUNE_CHAR
240 && rb->object.chr.ch != '\n'
241 && (rb->cursor_type != CURSOR_ON
242 || NILP (w->text_cursor_visible_p)))
244 Dynarr_add (buf, rb->object.chr.ch);
249 if (Dynarr_length (buf))
251 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
256 if (rb->type == RUNE_CHAR)
261 if (rb->object.chr.ch == '\n')
263 /* Clear in case a cursor was formerly here. */
265 Dynarr_add (buf, ' ');
266 tty_output_emchar_dynarr (w, dl, buf, rb->xpos,
270 cmgoto (f, dl->ypos - 1, rb->xpos);
274 else if (rb->cursor_type == CURSOR_ON)
276 /* There is not a distinct eol cursor on tty's. */
278 Dynarr_add (buf, rb->object.chr.ch);
279 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
282 cmgoto (f, dl->ypos - 1, xpos);
288 /* #### RUNE_HLINE is actually a little more complicated than this
289 but at the moment it is only used to draw a turned off
290 modeline and this will suffice for that. */
291 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
294 int size = rb->width;
296 if (rb->type == RUNE_BLANK)
302 Dynarr_add (buf, ch_to_add);
303 tty_output_emchar_dynarr (w, dl, buf, rb->xpos, findex, 0);
305 if (xpos >= cursor_start
306 && cursor_start < xpos + Dynarr_length (buf))
308 cmgoto (f, dl->ypos - 1, cursor_start);
316 rb = Dynarr_atp (rba, elt);
322 else if (rb->type == RUNE_DGLYPH)
325 Lisp_Object instance;
327 XSETWINDOW (window, w);
328 instance = glyph_image_instance (rb->object.dglyph.glyph,
329 window, ERROR_ME_NOT, 1);
331 if (IMAGE_INSTANCEP (instance))
333 switch (XIMAGE_INSTANCE_TYPE (instance))
335 case IMAGE_MONO_PIXMAP:
336 case IMAGE_COLOR_PIXMAP:
337 case IMAGE_SUBWINDOW:
339 /* just do nothing here */
343 /* nothing is as nothing does */
351 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
352 (XIMAGE_INSTANCE (instance)) = 0;
363 if (Dynarr_length (buf))
364 tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
371 /*****************************************************************************
372 tty_output_vertical_divider
374 Draw a vertical divider down the right side of the given window.
375 ****************************************************************************/
377 tty_output_vertical_divider (struct window *w, int clear)
379 /* Divider width can either be 0 or 1 on TTYs */
380 if (window_divider_width (w))
382 struct frame *f = XFRAME (w->frame);
383 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
385 int y_top = WINDOW_TEXT_TOP (w);
386 int y_bot = WINDOW_TEXT_BOTTOM (w);
387 unsigned char divv = '|';
389 tty_turn_on_face (w, MODELINE_INDEX);
390 for (line = y_top; line < y_bot; line++)
392 cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
393 send_string_to_tty_console (c, &divv, 1);
394 TTY_INC_CURSOR_X (c, 1);
397 /* Draw the divider in the modeline. */
398 cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
399 send_string_to_tty_console (c, &divv, 1);
400 TTY_INC_CURSOR_X (c, 1);
401 tty_turn_off_face (w, MODELINE_INDEX);
405 /****************************************************************************
408 Clear the area in the box defined by the given parameters.
409 ****************************************************************************/
411 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
412 face_index findex, int x, int y,
413 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
414 Lisp_Object background_pixmap)
416 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
418 struct window* w = XWINDOW (window);
420 tty_turn_on_face (w, findex);
421 for (line = y; line < y + height; line++)
427 if (window_is_leftmost (w)
428 && window_is_rightmost (w)
429 && TTY_SE (c).clr_to_eol)
431 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
435 unsigned char sp = ' ';
436 /* #### Of course, this is all complete and utter crap. */
437 for (col = x; col < x + width; col++)
438 send_string_to_tty_console (c, &sp, 1);
439 TTY_INC_CURSOR_X (c, width);
442 tty_turn_off_face (w, findex);
446 /*****************************************************************************
447 tty_clear_to_window_end
449 Clear the area between ypos1 and ypos2. Each margin area and the
450 text area is handled separately since they may each have their own
452 ****************************************************************************/
454 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
456 struct frame *f = XFRAME (w->frame);
457 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
460 x = WINDOW_TEXT_LEFT (w);
461 width = WINDOW_TEXT_WIDTH (w);
463 if (window_is_rightmost (w))
465 /* #### Optimize to use clr_to_eol function of tty if available, if
466 the window is the entire width of the frame. */
467 /* #### Is this actually an optimization? */
469 tty_turn_on_face (w, DEFAULT_INDEX);
470 for (line = ypos1; line < ypos2; line++)
472 cmgoto (XFRAME (w->frame), line, x);
473 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
475 tty_turn_off_face (w, DEFAULT_INDEX);
481 XSETWINDOW (window, w);
482 redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
486 /****************************************************************************
489 Clear the entire frame.
490 ****************************************************************************/
492 tty_clear_frame (struct frame *f)
494 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
496 tty_turn_on_frame_face (f, Vdefault_face);
497 if (TTY_SE (c).clr_frame)
499 OUTPUT1 (c, TTY_SE (c).clr_frame);
500 CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
501 CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
503 FRAME_CURSOR_X (f) = 0;
504 FRAME_CURSOR_Y (f) = 0;
510 internal_cursor_to (f, 0, 0);
513 /* #### Not implemented. */
514 stderr_out ("Not yet.\n");
517 tty_turn_off_frame_face (f, Vdefault_face);
521 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
522 Bufbyte *str, Bytecount len, int xpos,
523 face_index findex, int cursor)
525 struct frame *f = XFRAME (w->frame);
526 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
528 /* First position the cursor. */
529 cmgoto (f, dl->ypos - 1, xpos);
531 /* Enable any face properties. */
532 tty_turn_on_face (w, findex);
534 send_string_to_tty_console (c, str, len);
535 TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
537 /* Turn the face properties back off. */
538 tty_turn_off_face (w, findex);
541 static Bufbyte_dynarr *tty_output_emchar_dynarr_dynarr;
543 /*****************************************************************************
544 tty_output_emchar_dynarr
546 Given a string and a starting position, output that string in the
547 given face. If cursor is true, draw a cursor around the string.
548 ****************************************************************************/
550 tty_output_emchar_dynarr (struct window *w, struct display_line *dl,
551 Emchar_dynarr *buf, int xpos, face_index findex,
554 if (!tty_output_emchar_dynarr_dynarr)
555 tty_output_emchar_dynarr_dynarr = Dynarr_new (Bufbyte);
557 Dynarr_reset (tty_output_emchar_dynarr_dynarr);
559 convert_emchar_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
561 tty_output_emchar_dynarr_dynarr);
563 tty_output_bufbyte_string (w, dl,
564 Dynarr_atp (tty_output_emchar_dynarr_dynarr, 0),
565 Dynarr_length (tty_output_emchar_dynarr_dynarr),
566 xpos, findex, cursor);
571 static Bufbyte_dynarr *sidcs_dynarr;
574 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
577 Bufbyte *specdata = XSTRING_DATA (spec);
578 Bytecount speclen = XSTRING_LENGTH (spec);
581 sidcs_dynarr = Dynarr_new (Bufbyte);
583 Dynarr_reset (sidcs_dynarr);
585 for (i = 0; i < speclen; i++)
587 if (specdata[i] == '%' && specdata[i+1] == '%')
589 Dynarr_add (sidcs_dynarr, '%');
592 else if (specdata[i] == '%' && specdata[i+1] == 's')
594 Dynarr_add_many (sidcs_dynarr,
595 XSTRING_DATA (string),
596 XSTRING_LENGTH (string));
600 Dynarr_add (sidcs_dynarr, specdata[i]);
607 set_foreground_to (struct console *c, Lisp_Object sym)
611 Bytecount escseqlen = 0;
613 result = assq_no_quit (sym, Vtty_color_alist);
616 Lisp_Object esc_seq = XCAR (XCDR (result));
617 escseq = XSTRING_DATA (esc_seq);
618 escseqlen = XSTRING_LENGTH (esc_seq);
621 else if (STRINGP (Vtty_dynamic_color_fg))
623 substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
625 escseq = Dynarr_atp (sidcs_dynarr, 0);
626 escseqlen = Dynarr_length (sidcs_dynarr);
632 send_string_to_tty_console (c, escseq, escseqlen);
637 set_background_to (struct console *c, Lisp_Object sym)
641 Bytecount escseqlen = 0;
643 result = assq_no_quit (sym, Vtty_color_alist);
646 Lisp_Object esc_seq = XCDR (XCDR (result));
647 escseq = XSTRING_DATA (esc_seq);
648 escseqlen = XSTRING_LENGTH (esc_seq);
651 else if (STRINGP (Vtty_dynamic_color_bg))
653 substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
655 escseq = Dynarr_atp (sidcs_dynarr, 0);
656 escseqlen = Dynarr_length (sidcs_dynarr);
662 send_string_to_tty_console (c, escseq, escseqlen);
667 tty_turn_on_face_1 (struct console *c, int highlight_p,
668 int blinking_p, int dim_p, int underline_p,
669 int reverse_p, Lisp_Object cinst_fore,
670 Lisp_Object cinst_back)
674 OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
679 OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
684 OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
689 /* #### punt for now if underline mode is glitchy */
690 if (!TTY_FLAGS (c).underline_width)
692 OUTPUT1_IF (c, TTY_SD (c).begin_underline);
698 /* #### punt for now if standout mode is glitchy */
699 if (!TTY_FLAGS (c).standout_width)
701 OUTPUT1_IF (c, TTY_SD (c).begin_standout);
709 Lisp_Object temp = cinst_fore;
710 cinst_fore = cinst_back;
714 if (COLOR_INSTANCEP (cinst_fore)
715 && !EQ (cinst_fore, Vthe_null_color_instance))
716 set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
717 (XCOLOR_INSTANCE (cinst_fore)));
719 if (COLOR_INSTANCEP (cinst_back)
720 && !EQ (cinst_back, Vthe_null_color_instance))
721 set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
722 (XCOLOR_INSTANCE (cinst_back)));
725 /*****************************************************************************
728 Turn on all set properties of the given face.
729 ****************************************************************************/
731 tty_turn_on_face (struct window *w, face_index findex)
733 struct frame *f = XFRAME (w->frame);
734 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
736 tty_turn_on_face_1 (c,
737 WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
738 WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
739 WINDOW_FACE_CACHEL_DIM_P (w, findex),
740 WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
741 WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
742 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
743 WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
746 /*****************************************************************************
749 Turn off all set properties of the given face (revert to default
750 face). We assume that tty_turn_on_face has been called for the given
751 face so that its properties are actually active.
752 ****************************************************************************/
754 tty_turn_off_face (struct window *w, face_index findex)
756 struct frame *f = XFRAME (w->frame);
757 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
759 if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
761 /* #### punt for now if standout mode is glitchy */
762 if (!TTY_FLAGS (c).standout_width)
764 OUTPUT1_IF (c, TTY_SD (c).end_standout);
768 if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
770 /* #### punt for now if underline mode is glitchy */
771 if (!TTY_FLAGS (c).underline_width)
773 OUTPUT1_IF (c, TTY_SD (c).end_underline);
777 if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
778 WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
779 WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
780 !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
781 Vthe_null_color_instance) ||
782 !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
783 Vthe_null_color_instance))
785 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
789 /*****************************************************************************
790 tty_turn_on_frame_face
792 Turn on all set properties of the given face.
793 ****************************************************************************/
795 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
798 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
800 XSETFRAME (frame, f);
801 tty_turn_on_face_1 (c,
802 FACE_HIGHLIGHT_P (face, frame),
803 FACE_BLINKING_P (face, frame),
804 FACE_DIM_P (face, frame),
805 FACE_UNDERLINE_P (face, frame),
806 FACE_REVERSE_P (face, frame),
807 FACE_FOREGROUND (face, frame),
808 FACE_BACKGROUND (face, frame));
811 /*****************************************************************************
812 tty_turn_off_frame_face
814 Turn off all set properties of the given face (revert to default
815 face). We assume that tty_turn_on_face has been called for the given
816 face so that its properties are actually active.
817 ****************************************************************************/
819 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
822 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
824 XSETFRAME (frame, f);
826 if (FACE_REVERSE_P (face, frame))
828 /* #### punt for now if standout mode is glitchy */
829 if (!TTY_FLAGS (c).standout_width)
831 OUTPUT1_IF (c, TTY_SD (c).end_standout);
835 if (FACE_UNDERLINE_P (face, frame))
837 /* #### punt for now if underline mode is glitchy */
838 if (!TTY_FLAGS (c).underline_width)
840 OUTPUT1_IF (c, TTY_SD (c).end_underline);
844 if (FACE_HIGHLIGHT_P (face, frame) ||
845 FACE_BLINKING_P (face, frame) ||
846 FACE_DIM_P (face, frame) ||
847 !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
848 !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
850 OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
854 /*****************************************************************************
857 Sets up various parameters on tty modes.
858 ****************************************************************************/
860 set_tty_modes (struct console *c)
862 if (!CONSOLE_TTY_P (c))
865 OUTPUT1_IF (c, TTY_SD (c).init_motion);
866 OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
867 OUTPUT1_IF (c, TTY_SD (c).keypad_on);
870 /*****************************************************************************
873 Restore default state of tty.
874 ****************************************************************************/
876 reset_tty_modes (struct console *c)
878 if (!CONSOLE_TTY_P (c))
881 OUTPUT1_IF (c, TTY_SD (c).orig_pair);
882 OUTPUT1_IF (c, TTY_SD (c).keypad_off);
883 OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
884 OUTPUT1_IF (c, TTY_SD (c).end_motion);
885 tty_frame_output_end (XFRAME (CONSOLE_SELECTED_FRAME (c)));
888 /*****************************************************************************
889 tty_redisplay_shutdown
891 Clear the frame and position the cursor properly for exiting.
892 ****************************************************************************/
894 tty_redisplay_shutdown (struct console *c)
896 Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
900 Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
904 struct frame *f = XFRAME (frm);
906 /* Clear the bottom line of the frame. */
907 redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
908 f->height, f->width, 1);
910 /* And then stick the cursor there. */
911 tty_set_final_cursor_coords (f, f->height, 0);
912 tty_frame_output_end (f);
918 /* #### Everything below here is old shit. It should either be moved
922 /* FLAGS - these don't need to be console local since only one console
923 can be being updated at a time. */
924 static int insert_mode_on; /* nonzero if in insert mode */
925 static int standout_mode_on; /* nonzero if in standout mode */
926 static int underline_mode_on; /* nonzero if in underline mode */
927 static int alternate_mode_on; /* nonzero if in alternate char set */
928 static int attributes_on; /* nonzero if any attributes on */
932 turn_on_insert (struct frame *f)
934 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
937 OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
942 turn_off_insert (struct frame *f)
944 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
947 OUTPUT1 (c, TTY_SE (c).end_ins_mode);
952 internal_cursor_to (struct frame *f, int row, int col)
954 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
956 if (!TTY_FLAGS (c).insert_mode_motion)
958 if (!TTY_FLAGS (c).standout_motion)
960 turn_off_standout (f);
961 turn_off_underline (f);
962 turn_off_alternate (f);
965 cmgoto (f, row, col);
969 clear_to_end (struct frame *f)
971 struct console *c = XCONSOLE (FRAME_CONSOLE (f));
973 /* assumes cursor is already positioned */
974 if (TTY_SE (c).clr_from_cursor)
976 OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
980 int line = FRAME_CURSOR_Y (f);
982 while (line < FRAME_HEIGHT (f))
984 internal_cursor_to (f, line, 0);
985 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
993 * clear from last visible line on window to window end (presumably
994 * the line above window's modeline
997 tty_clear_window_end (struct window *w, int ystart, int yend)
999 struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1002 for (line = ystart; line < yend; line++)
1004 cmgoto (XFRAME (w->frame), line, 0);
1005 OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1012 tty_flash (struct device *d)
1014 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1015 if (TTY_SD (c).visual_bell)
1017 OUTPUT1 (c, TTY_SD (c).visual_bell);
1018 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1026 * tty_ring_bell - sound an audio beep.
1029 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1031 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1035 OUTPUT1 (c, TTY_SD (c).audio_bell);
1036 Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1042 init_tty_for_redisplay (struct device *d, char *terminal_type)
1045 char entry_buffer[2044];
1046 /* char temp_buffer[2044]; */
1048 struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1050 /* What we should really do is allocate just enough space for
1051 the actual strings that are stored; but this would require
1052 doing this after all the tgetstr()s and adjusting all the
1054 CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1055 bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1058 /* SIGTT* don't exist under win32 */
1059 EMACS_BLOCK_SIGNAL (SIGTTOU);
1061 status = tgetent (entry_buffer, terminal_type);
1063 EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1067 return TTY_UNABLE_OPEN_DATABASE;
1068 else if (status == 0)
1069 return TTY_TYPE_UNDEFINED;
1071 /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1073 return TTY_TYPE_UNDEFINED;
1076 * Establish the terminal size.
1078 /* First try to get the info from the system. If that fails, check
1079 the termcap entry. */
1080 get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1081 &CONSOLE_TTY_DATA (c)->height);
1083 if (CONSOLE_TTY_DATA (c)->width <= 0)
1084 CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1085 if (CONSOLE_TTY_DATA (c)->height <= 0)
1086 CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1088 if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1089 return TTY_SIZE_UNSPECIFIED;
1092 * Initialize cursor motion information.
1095 /* local cursor movement */
1096 TTY_CM (c).up = tgetstr ("up", &bufptr);
1097 TTY_CM (c).down = tgetstr ("do", &bufptr);
1098 TTY_CM (c).left = tgetstr ("le", &bufptr);
1099 TTY_CM (c).right = tgetstr ("nd", &bufptr);
1100 TTY_CM (c).home = tgetstr ("ho", &bufptr);
1101 TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1102 TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1104 /* absolute cursor motion */
1105 TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1106 TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1107 TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1109 /* Verify that the terminal is powerful enough to run Emacs */
1110 if (!TTY_CM (c).abs)
1112 if (!TTY_CM (c).up || !TTY_CM (c).down
1113 || !TTY_CM (c).left || !TTY_CM (c).right)
1114 return TTY_TYPE_INSUFFICIENT;
1117 /* parameterized local cursor movement */
1118 TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1119 TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1120 TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1121 TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1124 TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1125 TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1126 TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1127 TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1128 TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1132 * Initialize screen editing information.
1135 /* adding to the screen */
1136 TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1137 TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1138 TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1139 TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1140 TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1141 TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1142 TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1143 TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1145 /* deleting from the screen */
1146 TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1147 TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1148 TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1149 TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1150 TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1151 TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1152 TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1153 TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1154 TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1155 TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1159 * Initialize screen display information.
1161 TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1162 TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1163 TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1164 TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1165 TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1166 TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1167 TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1168 TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1169 TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1170 TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1171 TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1172 TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1174 TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1175 TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1176 if (!TTY_SD (c).audio_bell)
1178 /* If audio_bell doesn't get set, then assume C-g. This is gross and
1179 ugly but is what Emacs has done from time immortal. */
1180 TTY_SD (c).audio_bell = "\07";
1183 TTY_SD (c).cursor_visible = tgetstr ("ve", &bufptr);
1184 TTY_SD (c).cursor_normal = tgetstr ("vs", &bufptr);
1185 TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1186 TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1187 TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1188 TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1192 * Initialize additional terminal information.
1194 TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1195 TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1196 TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1197 TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1198 TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1199 TTY_FLAGS (c).standout_width = tgetnum ("sg");
1200 TTY_FLAGS (c).underline_width = tgetnum ("ug");
1202 if (TTY_FLAGS (c).standout_width == -1)
1203 TTY_FLAGS (c).standout_width = 0;
1204 if (TTY_FLAGS (c).underline_width == -1)
1205 TTY_FLAGS (c).underline_width = 0;
1207 TTY_FLAGS (c).meta_key =
1208 eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1212 * Setup the costs tables for this tty console.
1217 * Initialize local flags.
1220 standout_mode_on = 0;
1221 underline_mode_on = 0;
1222 alternate_mode_on = 0;
1226 * Attempt to initialize the function_key_map to
1227 * some kind of sensible value
1230 term_get_fkeys (c->function_key_map, &bufptr);
1233 /* check for ANSI set-foreground and set-background strings,
1234 and assume color if so.
1236 #### we should support the other (non-ANSI) ways of specifying
1239 char *fooptr = foobuf;
1240 if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1241 (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1242 ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1243 DEVICE_CLASS (d) = Qcolor;
1245 DEVICE_CLASS (d) = Qmono;
1248 return TTY_INIT_SUCCESS;
1257 /* Termcap capability names that correspond directly to X keysyms.
1258 Some of these (marked "terminfo") aren't supplied by old-style
1259 (Berkeley) termcap entries. They're listed in X keysym order;
1260 except we put the keypad keys first, so that if they clash with
1261 other keys (as on the IBM PC keyboard) they get overridden.
1264 static struct fkey_table keys[] =
1266 {"kh", "home"}, /* termcap */
1267 {"kl", "left"}, /* termcap */
1268 {"ku", "up"}, /* termcap */
1269 {"kr", "right"}, /* termcap */
1270 {"kd", "down"}, /* termcap */
1271 {"%8", "prior"}, /* terminfo */
1272 {"%5", "next"}, /* terminfo */
1273 {"@7", "end"}, /* terminfo */
1274 {"@1", "begin"}, /* terminfo */
1275 {"*6", "select"}, /* terminfo */
1276 {"%9", "print"}, /* terminfo */
1277 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1279 * "insert" --- see below
1281 {"&8", "undo"}, /* terminfo */
1282 {"%0", "redo"}, /* terminfo */
1283 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1284 {"@0", "find"}, /* terminfo */
1285 {"@2", "cancel"}, /* terminfo */
1286 {"%1", "help"}, /* terminfo */
1288 * "break" goes here, but can't be reliably intercepted with termcap
1290 {"&4", "reset"}, /* terminfo --- actually `restart' */
1292 * "system" and "user" --- no termcaps
1294 {"kE", "clearline"}, /* terminfo */
1295 {"kA", "insertline"}, /* terminfo */
1296 {"kL", "deleteline"}, /* terminfo */
1297 {"kI", "insertchar"}, /* terminfo */
1298 {"kD", "delete"}, /* terminfo */
1299 {"kB", "backtab"}, /* terminfo */
1301 * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1303 {"@8", "kp-enter"}, /* terminfo */
1305 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1306 * "kp-multiply", "kp-add", "kp-separator",
1307 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1308 * --- no termcaps for any of these.
1310 {"K4", "kp-1"}, /* terminfo */
1312 * "kp-2" --- no termcap
1314 {"K5", "kp-3"}, /* terminfo */
1316 * "kp-4" --- no termcap
1318 {"K2", "kp-5"}, /* terminfo */
1320 * "kp-6" --- no termcap
1322 {"K1", "kp-7"}, /* terminfo */
1324 * "kp-8" --- no termcap
1326 {"K3", "kp-9"}, /* terminfo */
1328 * "kp-equal" --- no termcap
1341 static char **term_get_fkeys_arg;
1343 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1344 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1346 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1347 This function scans the termcap function key sequence entries, and
1348 adds entries to Vfunction_key_map for each function key it finds. */
1351 term_get_fkeys (Lisp_Object keymap, char **address)
1353 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1354 errors during the call. The only errors should be from Fdefine_key
1355 when given a key sequence containing an invalid prefix key. If the
1356 termcap defines function keys which use a prefix that is already bound
1357 to a command by the default bindings, we should silently ignore that
1358 function key specification, rather than giving the user an error and
1359 refusing to run at all on such a terminal. */
1361 term_get_fkeys_arg = address;
1363 condition_case_1 (Qerror,
1364 term_get_fkeys_1, keymap,
1365 term_get_fkeys_error, Qnil);
1369 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1375 term_get_fkeys_1 (Lisp_Object function_key_map)
1379 char **address = term_get_fkeys_arg;
1381 for (i = 0; i < countof (keys); i++)
1383 char *sequence = tgetstr (keys[i].cap, address);
1385 Fdefine_key (function_key_map,
1386 build_ext_string (sequence, Qbinary),
1387 vector1 (intern (keys[i].name)));
1390 /* The uses of the "k0" capability are inconsistent; sometimes it
1391 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1392 We will attempt to politely accommodate both systems by testing for
1393 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1396 const char *k_semi = tgetstr ("k;", address);
1397 const char *k0 = tgetstr ("k0", address);
1400 Fdefine_key (function_key_map, build_ext_string (k_semi, Qbinary),
1401 vector1 (intern ("f10")));
1404 Fdefine_key (function_key_map, build_ext_string (k0, Qbinary),
1405 vector1 (intern (k_semi ? "f0" : "f10")));
1408 /* Set up cookies for numbered function keys above f10. */
1410 char fcap[3], fkey[4];
1412 fcap[0] = 'F'; fcap[2] = '\0';
1413 for (i = 11; i < 64; i++)
1416 fcap[1] = '1' + i - 11;
1418 fcap[1] = 'A' + i - 20;
1420 fcap[1] = 'a' + i - 46;
1423 char *sequence = tgetstr (fcap, address);
1426 sprintf (fkey, "f%d", i);
1427 Fdefine_key (function_key_map,
1428 build_ext_string (sequence, Qbinary),
1429 vector1 (intern (fkey)));
1436 * Various mappings to try and get a better fit.
1438 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) do { \
1439 if (!tgetstr (cap1, address)) \
1441 char *sequence = tgetstr (cap2, address); \
1443 Fdefine_key (function_key_map, \
1444 build_ext_string (sequence, Qbinary), \
1445 vector1 (intern (keyname))); \
1449 /* if there's no key_next keycap, map key_npage to `next' keysym */
1450 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1451 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1452 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1453 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1454 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1456 /* IBM has their own non-standard dialect of terminfo.
1457 If the standard name isn't found, try the IBM name. */
1458 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1459 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1460 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1461 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1462 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1463 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1464 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1465 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1466 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1467 #undef CONDITIONAL_REASSIGN
1473 /************************************************************************/
1474 /* initialization */
1475 /************************************************************************/
1478 console_type_create_redisplay_tty (void)
1480 /* redisplay methods */
1481 CONSOLE_HAS_METHOD (tty, text_width);
1482 CONSOLE_HAS_METHOD (tty, output_display_block);
1483 CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1484 CONSOLE_HAS_METHOD (tty, divider_height);
1485 CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1486 CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1487 CONSOLE_HAS_METHOD (tty, clear_region);
1488 CONSOLE_HAS_METHOD (tty, clear_frame);
1489 CONSOLE_HAS_METHOD (tty, frame_output_begin);
1490 CONSOLE_HAS_METHOD (tty, frame_output_end);
1491 CONSOLE_HAS_METHOD (tty, flash);
1492 CONSOLE_HAS_METHOD (tty, ring_bell);
1493 CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);