XEmacs 21.2.20 "Yoko".
[chise/xemacs-chise.git.1] / src / redisplay-tty.c
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.
6
7 This file is part of XEmacs.
8
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
12 later version.
13
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
17 for more details.
18
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.  */
23
24 /* Synched up with: Not completely synched with FSF.  Mostly divergent
25    from FSF. */
26
27 /* This file has been Mule-ized. */
28
29 /* Written by Chuck Thompson. */
30 /* Color support added by Ben Wing. */
31
32 #include <config.h>
33 #include "lisp.h"
34
35 #include "buffer.h"
36 #include "console-tty.h"
37 #include "events.h"
38 #include "faces.h"
39 #include "frame.h"
40 #include "glyphs.h"
41 #include "lstream.h"
42 #include "objects-tty.h"
43 #include "redisplay.h"
44 #include "sysdep.h"
45 #include "window.h"
46
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 #ifdef __cplusplus
57 extern "C" {
58 #endif
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));
64 #ifdef __cplusplus
65 }
66 #endif
67 #define FORCE_CURSOR_UPDATE(c) send_string_to_tty_console (c, 0, 0)
68 #define OUTPUTN(c, a, n)                        \
69   do {                                          \
70     cmputc_console = c;                         \
71     FORCE_CURSOR_UPDATE (c);                    \
72     tputs (a, n, cmputc);                       \
73   } while (0)
74 #define OUTPUT1(c, a) OUTPUTN (c, a, 1)
75 #define OUTPUTN_IF(c, a, n)                     \
76   do {                                          \
77     cmputc_console = c;                         \
78     FORCE_CURSOR_UPDATE (c);                    \
79     if (a)                                      \
80       tputs (a, n, cmputc);                     \
81   } while (0)
82 #define OUTPUT1_IF(c, a) OUTPUTN_IF (c, a, 1)
83
84 static void tty_output_emchar_dynarr (struct window *w,
85                                       struct display_line *dl,
86                                       Emchar_dynarr *buf, int xpos,
87                                       face_index findex,
88                                       int cursor);
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,
93                                        int cursor);
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);
98
99 static void term_get_fkeys (Lisp_Object keymap, char **address);
100
101 /*****************************************************************************
102  tty_text_width
103
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  ****************************************************************************/
109 static int
110 tty_text_width (struct frame *f, struct face_cachel *cachel, CONST Emchar *str,
111                 Charcount len)
112 {
113   return emchar_string_displayed_columns (str, len);
114 }
115
116 /*****************************************************************************
117  tty_divider_height
118
119  Return the width of the horizontal divider.  This is a function
120  because divider_height is a console method.
121  ****************************************************************************/
122 static int
123 tty_divider_height (void)
124 {
125   return 1;
126 }
127
128 /*****************************************************************************
129  tty_eol_cursor_width
130
131  Return the width of the end-of-line cursor.  This is a function
132  because eol_cursor_width is a console method.
133  ****************************************************************************/
134 static int
135 tty_eol_cursor_width (void)
136 {
137   return 1;
138 }
139
140 /*****************************************************************************
141  tty_output_begin
142
143  Perform any necessary initialization prior to an update.
144  ****************************************************************************/
145 #ifdef DEBUG_XEMACS
146 void tty_output_begin (struct device *d);
147 void
148 #else
149 static void
150 #endif
151 tty_output_begin (struct device *d)
152 {
153 #ifndef HAVE_TERMIOS
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
156      working with. */
157   ospeed = DEVICE_TTY_DATA (d)->ospeed;
158 #endif
159 }
160
161 /*****************************************************************************
162  tty_output_end
163
164  Perform any necessary flushing of queues when an update has completed.
165  ****************************************************************************/
166 #ifdef DEBUG_XEMACS
167 void tty_output_end (struct device *d);
168 void
169 #else
170 static void
171 #endif
172 tty_output_end (struct device *d)
173 {
174   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
175
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));
180 }
181
182 static void
183 tty_set_final_cursor_coords (struct frame *f, int y, int x)
184 {
185   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
186
187   CONSOLE_TTY_FINAL_CURSOR_X (c) = x;
188   CONSOLE_TTY_FINAL_CURSOR_Y (c) = y;
189 }
190
191 /*****************************************************************************
192  tty_output_display_block
193
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  ****************************************************************************/
197 static void
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,
201                           int cursor_height)
202 {
203   struct frame *f = XFRAME (w->frame);
204   Emchar_dynarr *buf = Dynarr_new (Emchar);
205
206   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
207   rune_dynarr *rba = db->runes;
208   struct rune *rb;
209
210   int elt = start;
211   face_index findex;
212   int xpos;
213
214   rb = Dynarr_atp (rba, elt);
215
216   if (!rb)
217     {
218       /* Nothing to do so don't do anything. */
219       return;
220     }
221   else
222     {
223       findex = rb->findex;
224       xpos = rb->xpos;
225     }
226
227   if (end < 0)
228     end = Dynarr_length (rba);
229
230   Dynarr_reset (buf);
231
232   while (elt < end && Dynarr_atp (rba, elt)->xpos < start_pixpos)
233     {
234       elt++;
235       findex = Dynarr_atp (rba, elt)->findex;
236       xpos = Dynarr_atp (rba, elt)->xpos;
237     }
238
239   while (elt < end)
240     {
241       rb = Dynarr_atp (rba, elt);
242
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)))
247         {
248           Dynarr_add (buf, rb->object.chr.ch);
249           elt++;
250         }
251       else
252         {
253           if (Dynarr_length (buf))
254             {
255               tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
256               xpos = rb->xpos;
257             }
258           Dynarr_reset (buf);
259
260           if (rb->type == RUNE_CHAR)
261             {
262               findex = rb->findex;
263               xpos = rb->xpos;
264
265               if (rb->object.chr.ch == '\n')
266                 {
267                   /* Clear in case a cursor was formerly here. */
268
269                   Dynarr_add (buf, ' ');
270                   tty_output_emchar_dynarr (w, dl, buf, rb->xpos,
271                                             DEFAULT_INDEX, 0);
272                   Dynarr_reset (buf);
273
274                   cmgoto (f, dl->ypos - 1, rb->xpos);
275
276                   elt++;
277                 }
278               else if (rb->cursor_type == CURSOR_ON)
279                 {
280                   /* There is not a distinct eol cursor on tty's. */
281
282                   Dynarr_add (buf, rb->object.chr.ch);
283                   tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
284                   Dynarr_reset (buf);
285
286                   cmgoto (f, dl->ypos - 1, xpos);
287
288                   xpos += rb->width;
289                   elt++;
290                 }
291             }
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)
296             {
297               Emchar ch_to_add;
298               int size = rb->width;
299
300               if (rb->type == RUNE_BLANK)
301                 ch_to_add = ' ';
302               else
303                 ch_to_add = '-';
304
305               while (size--)
306                 Dynarr_add (buf, ch_to_add);
307               tty_output_emchar_dynarr (w, dl, buf, rb->xpos, findex, 0);
308
309               if (xpos >= cursor_start
310                   && cursor_start < xpos + Dynarr_length (buf))
311                 {
312                   cmgoto (f, dl->ypos - 1, cursor_start);
313                 }
314
315               Dynarr_reset (buf);
316
317               elt++;
318               if (elt < end)
319                 {
320                   rb = Dynarr_atp (rba, elt);
321
322                   findex = rb->findex;
323                   xpos = rb->xpos;
324                 }
325             }
326           else if (rb->type == RUNE_DGLYPH)
327             {
328               Lisp_Object window;
329               Lisp_Object instance;
330
331               XSETWINDOW (window, w);
332               instance = glyph_image_instance (rb->object.dglyph.glyph,
333                                                window, ERROR_ME_NOT, 1);
334
335               if (IMAGE_INSTANCEP (instance))
336                 switch (XIMAGE_INSTANCE_TYPE (instance))
337                   {
338                   case IMAGE_TEXT:
339                     {
340                       Bufbyte *temptemp;
341                       Lisp_Object string =
342                         XIMAGE_INSTANCE_TEXT_STRING (instance);
343                       Bytecount len = XSTRING_LENGTH (string);
344
345                       /* In the unlikely instance that a garbage-collect
346                          occurs during encoding, we at least need to
347                          copy the string.
348                          */
349                       temptemp = (Bufbyte *) alloca (len);
350                       memcpy (temptemp, XSTRING_DATA (string), len);
351                       {
352                         int i;
353
354                         /* Now truncate the first rb->object.dglyph.xoffset
355                            columns. */
356                         for (i = 0; i < rb->object.dglyph.xoffset;)
357                           {
358 #ifdef MULE
359                             Emchar ch = charptr_emchar (temptemp);
360                             i += XCHARSET_COLUMNS (CHAR_CHARSET (ch));
361 #else
362                             i++; /* telescope this */
363 #endif
364                             INC_CHARPTR (temptemp);
365                           }
366
367                         /* If we truncated one column too many, then
368                            add a space at the beginning. */
369                         if (i > rb->object.dglyph.xoffset)
370                           {
371                             assert (i > 0);
372                             *--temptemp = ' ';
373                             i--;
374                           }
375                         len -= i;
376                       }
377
378                       tty_output_bufbyte_string (w, dl, temptemp, len,
379                                                  xpos, findex, 0);
380
381                       if (xpos >= cursor_start
382                           && (cursor_start <
383                               xpos + (bufbyte_string_displayed_columns
384                                       (temptemp, len))))
385                         {
386                           cmgoto (f, dl->ypos - 1, cursor_start);
387                         }
388                     }
389                     break;
390
391                   case IMAGE_MONO_PIXMAP:
392                   case IMAGE_COLOR_PIXMAP:
393                   case IMAGE_SUBWINDOW:
394                   case IMAGE_WIDGET:
395                   case IMAGE_LAYOUT:
396                     /* just do nothing here */
397                     break;
398
399                   case IMAGE_POINTER:
400                     abort ();
401
402                   case IMAGE_NOTHING:
403                     /* nothing is as nothing does */
404                     break;
405
406                   default:
407                     abort ();
408                   }
409
410               xpos += rb->width;
411               elt++;
412             }
413           else
414             abort ();
415         }
416     }
417
418   if (Dynarr_length (buf))
419     tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
420   Dynarr_free (buf);
421
422 }
423
424
425
426 /*****************************************************************************
427  tty_output_vertical_divider
428
429  Draw a vertical divider down the right side of the given window.
430  ****************************************************************************/
431 static void
432 tty_output_vertical_divider (struct window *w, int clear)
433 {
434   /* Divider width can either be 0 or 1 on TTYs */
435   if (window_divider_width (w))
436     {
437       struct frame *f = XFRAME (w->frame);
438       struct console *c = XCONSOLE (FRAME_CONSOLE (f));
439       int line;
440       int y_top = WINDOW_TEXT_TOP (w);
441       int y_bot = WINDOW_TEXT_BOTTOM (w);
442       unsigned char divv = '|';
443
444       tty_turn_on_face (w, MODELINE_INDEX);
445       for (line = y_top; line < y_bot; line++)
446         {
447           cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
448           send_string_to_tty_console (c, &divv, 1);
449           TTY_INC_CURSOR_X (c, 1);
450         }
451
452       /* Draw the divider in the modeline. */
453       cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
454       send_string_to_tty_console (c, &divv, 1);
455       TTY_INC_CURSOR_X (c, 1);
456       tty_turn_off_face (w, MODELINE_INDEX);
457     }
458 }
459
460 /****************************************************************************
461  tty_clear_region
462
463  Clear the area in the box defined by the given parameters.
464  ****************************************************************************/
465 static void
466 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
467                   face_index findex, int x, int y,
468                   int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
469                   Lisp_Object background_pixmap)
470 {
471   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
472   int line;
473   struct window* w = XWINDOW (window);
474
475   tty_turn_on_face (w, findex);
476   for (line = y; line < y + height; line++)
477     {
478       int col;
479
480       cmgoto (f, line, x);
481
482       if (window_is_leftmost (w)
483           && window_is_rightmost (w)
484           && TTY_SE (c).clr_to_eol)
485         {
486           OUTPUT1 (c, TTY_SE (c).clr_to_eol);
487         }
488       else
489         {
490           unsigned char sp = ' ';
491           /* #### Of course, this is all complete and utter crap. */
492           for (col = x; col < x + width; col++)
493             send_string_to_tty_console (c, &sp, 1);
494           TTY_INC_CURSOR_X (c, width);
495         }
496     }
497   tty_turn_off_face (w, findex);
498   cmgoto (f, y, x);
499 }
500
501 /*****************************************************************************
502  tty_clear_to_window_end
503
504  Clear the area between ypos1 and ypos2.  Each margin area and the
505  text area is handled separately since they may each have their own
506  background color.
507  ****************************************************************************/
508 static void
509 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
510 {
511   struct frame *f = XFRAME (w->frame);
512   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
513   int x, width;
514
515   x = WINDOW_TEXT_LEFT (w);
516   width = WINDOW_TEXT_WIDTH (w);
517
518   if (window_is_rightmost (w))
519     {
520       /* #### Optimize to use clr_to_eol function of tty if available, if
521          the window is the entire width of the frame. */
522       /* #### Is this actually an optimization? */
523       int line;
524       tty_turn_on_face (w, DEFAULT_INDEX);
525       for (line = ypos1; line < ypos2; line++)
526         {
527           cmgoto (XFRAME (w->frame), line, x);
528           OUTPUT1 (c, TTY_SE (c).clr_to_eol);
529         }
530       tty_turn_off_face (w, DEFAULT_INDEX);
531     }
532   else
533     {
534       Lisp_Object window;
535
536       XSETWINDOW (window, w);
537       redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
538     }
539 }
540
541 /****************************************************************************
542  tty_clear_frame
543
544  Clear the entire frame.
545  ****************************************************************************/
546 static void
547 tty_clear_frame (struct frame *f)
548 {
549   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
550
551   tty_turn_on_frame_face (f, Vdefault_face);
552   if (TTY_SE (c).clr_frame)
553     {
554       OUTPUT1 (c, TTY_SE (c).clr_frame);
555       CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
556       CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
557 #ifdef NOT_SURE
558       FRAME_CURSOR_X (f) = 0;
559       FRAME_CURSOR_Y (f) = 0;
560 #endif
561     }
562   else
563     {
564 #ifdef NOT_SURE
565       internal_cursor_to (f, 0, 0);
566       clear_to_end (f);
567 #else
568       /* #### Not implemented. */
569       fprintf (stderr, "Not yet.\n");
570 #endif
571     }
572   tty_turn_off_frame_face (f, Vdefault_face);
573 }
574
575 static void
576 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
577                            Bufbyte *str, Bytecount len, int xpos,
578                            face_index findex, int cursor)
579 {
580   struct frame *f = XFRAME (w->frame);
581   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
582
583   /* First position the cursor. */
584   cmgoto (f, dl->ypos - 1, xpos);
585
586   /* Enable any face properties. */
587   tty_turn_on_face (w, findex);
588
589   send_string_to_tty_console (c, str, len);
590   TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
591
592   /* Turn the face properties back off. */
593   tty_turn_off_face (w, findex);
594 }
595
596 static Bufbyte_dynarr *tty_output_emchar_dynarr_dynarr;
597
598 /*****************************************************************************
599  tty_output_emchar_dynarr
600
601  Given a string and a starting position, output that string in the
602  given face.  If cursor is true, draw a cursor around the string.
603  ****************************************************************************/
604 static void
605 tty_output_emchar_dynarr (struct window *w, struct display_line *dl,
606                           Emchar_dynarr *buf, int xpos, face_index findex,
607                           int cursor)
608 {
609   if (!tty_output_emchar_dynarr_dynarr)
610     tty_output_emchar_dynarr_dynarr = Dynarr_new (Bufbyte);
611   else
612     Dynarr_reset (tty_output_emchar_dynarr_dynarr);
613
614   convert_emchar_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
615                                             Dynarr_length (buf),
616                                             tty_output_emchar_dynarr_dynarr);
617
618   tty_output_bufbyte_string (w, dl,
619                              Dynarr_atp (tty_output_emchar_dynarr_dynarr, 0),
620                              Dynarr_length (tty_output_emchar_dynarr_dynarr),
621                              xpos, findex, cursor);
622 }
623
624 #if 0
625
626 static Bufbyte_dynarr *sidcs_dynarr;
627
628 static void
629 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
630 {
631   int i;
632   Bufbyte *specdata = XSTRING_DATA   (spec);
633   Bytecount speclen = XSTRING_LENGTH (spec);
634
635   if (!sidcs_dynarr)
636     sidcs_dynarr = Dynarr_new (Bufbyte);
637   else
638     Dynarr_reset (sidcs_dynarr);
639
640   for (i = 0; i < speclen; i++)
641     {
642       if (specdata[i] == '%' && specdata[i+1] == '%')
643         {
644           Dynarr_add (sidcs_dynarr, '%');
645           i++;
646         }
647       else if (specdata[i] == '%' && specdata[i+1] == 's')
648         {
649           Dynarr_add_many (sidcs_dynarr,
650                            XSTRING_DATA   (string),
651                            XSTRING_LENGTH (string));
652           i++;
653         }
654       else
655         Dynarr_add (sidcs_dynarr, specdata[i]);
656     }
657 }
658
659 #endif
660
661 static void
662 set_foreground_to (struct console *c, Lisp_Object sym)
663 {
664   Lisp_Object result;
665   Bufbyte *escseq = 0;
666   Bytecount escseqlen = 0;
667
668   result = assq_no_quit (sym, Vtty_color_alist);
669   if (!NILP (result))
670     {
671       Lisp_Object esc_seq = XCAR (XCDR (result));
672       escseq    = XSTRING_DATA   (esc_seq);
673       escseqlen = XSTRING_LENGTH (esc_seq);
674     }
675 #if 0
676   else if (STRINGP (Vtty_dynamic_color_fg))
677     {
678       substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
679                                           Fsymbol_name (sym));
680       escseq = Dynarr_atp (sidcs_dynarr, 0);
681       escseqlen = Dynarr_length (sidcs_dynarr);
682     }
683 #endif
684
685   if (escseq)
686     {
687       send_string_to_tty_console (c, escseq, escseqlen);
688     }
689 }
690
691 static void
692 set_background_to (struct console *c, Lisp_Object sym)
693 {
694   Lisp_Object result;
695   Bufbyte *escseq = 0;
696   Bytecount escseqlen = 0;
697
698   result = assq_no_quit (sym, Vtty_color_alist);
699   if (!NILP (result))
700     {
701       Lisp_Object esc_seq = XCDR (XCDR (result));
702       escseq    = XSTRING_DATA   (esc_seq);
703       escseqlen = XSTRING_LENGTH (esc_seq);
704     }
705 #if 0
706   else if (STRINGP (Vtty_dynamic_color_bg))
707     {
708       substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
709                                           Fsymbol_name (sym));
710       escseq = Dynarr_atp (sidcs_dynarr, 0);
711       escseqlen = Dynarr_length (sidcs_dynarr);
712     }
713 #endif
714
715   if (escseq)
716     {
717       send_string_to_tty_console (c, escseq, escseqlen);
718     }
719 }
720
721 static void
722 tty_turn_on_face_1 (struct console *c, int highlight_p,
723                     int blinking_p, int dim_p, int underline_p,
724                     int reverse_p, Lisp_Object cinst_fore,
725                     Lisp_Object cinst_back)
726 {
727   if (highlight_p)
728     {
729       OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
730     }
731
732   if (blinking_p)
733     {
734       OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
735     }
736
737   if (dim_p)
738     {
739       OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
740     }
741
742   if (underline_p)
743     {
744       /* #### punt for now if underline mode is glitchy */
745       if (!TTY_FLAGS (c).underline_width)
746         {
747           OUTPUT1_IF (c, TTY_SD (c).begin_underline);
748         }
749     }
750
751   if (reverse_p)
752     {
753       /* #### punt for now if standout mode is glitchy */
754       if (!TTY_FLAGS (c).standout_width)
755         {
756           OUTPUT1_IF (c, TTY_SD (c).begin_standout);
757         }
758       else
759         reverse_p = 0;
760     }
761
762   if (reverse_p)
763     {
764       Lisp_Object temp = cinst_fore;
765       cinst_fore = cinst_back;
766       cinst_back = temp;
767     }
768
769   if (COLOR_INSTANCEP (cinst_fore)
770       && !EQ (cinst_fore, Vthe_null_color_instance))
771     set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
772                        (XCOLOR_INSTANCE (cinst_fore)));
773
774   if (COLOR_INSTANCEP (cinst_back)
775       && !EQ (cinst_back, Vthe_null_color_instance))
776     set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
777                        (XCOLOR_INSTANCE (cinst_back)));
778 }
779
780 /*****************************************************************************
781  tty_turn_on_face
782
783  Turn on all set properties of the given face.
784  ****************************************************************************/
785 static void
786 tty_turn_on_face (struct window *w, face_index findex)
787 {
788   struct frame *f = XFRAME (w->frame);
789   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
790
791   tty_turn_on_face_1 (c,
792                       WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
793                       WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
794                       WINDOW_FACE_CACHEL_DIM_P (w, findex),
795                       WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
796                       WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
797                       WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
798                       WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
799 }
800
801 /*****************************************************************************
802  tty_turn_off_face
803
804  Turn off all set properties of the given face (revert to default
805  face).  We assume that tty_turn_on_face has been called for the given
806  face so that its properties are actually active.
807  ****************************************************************************/
808 static void
809 tty_turn_off_face (struct window *w, face_index findex)
810 {
811   struct frame *f = XFRAME (w->frame);
812   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
813
814   if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
815     {
816       /* #### punt for now if standout mode is glitchy */
817       if (!TTY_FLAGS (c).standout_width)
818         {
819           OUTPUT1_IF (c, TTY_SD (c).end_standout);
820         }
821     }
822
823   if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
824     {
825       /* #### punt for now if underline mode is glitchy */
826       if (!TTY_FLAGS (c).underline_width)
827         {
828           OUTPUT1_IF (c, TTY_SD (c).end_underline);
829         }
830     }
831
832   if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
833       WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
834       WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
835       !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
836            Vthe_null_color_instance) ||
837       !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
838            Vthe_null_color_instance))
839     {
840       OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
841     }
842 }
843
844 /*****************************************************************************
845  tty_turn_on_frame_face
846
847  Turn on all set properties of the given face.
848  ****************************************************************************/
849 static void
850 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
851 {
852   Lisp_Object frame;
853   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
854
855   XSETFRAME (frame, f);
856   tty_turn_on_face_1 (c,
857                       FACE_HIGHLIGHT_P (face, frame),
858                       FACE_BLINKING_P (face, frame),
859                       FACE_DIM_P (face, frame),
860                       FACE_UNDERLINE_P (face, frame),
861                       FACE_REVERSE_P (face, frame),
862                       FACE_FOREGROUND (face, frame),
863                       FACE_BACKGROUND (face, frame));
864 }
865
866 /*****************************************************************************
867  tty_turn_off_frame_face
868
869  Turn off all set properties of the given face (revert to default
870  face).  We assume that tty_turn_on_face has been called for the given
871  face so that its properties are actually active.
872  ****************************************************************************/
873 static void
874 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
875 {
876   Lisp_Object frame;
877   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
878
879   XSETFRAME (frame, f);
880
881   if (FACE_REVERSE_P (face, frame))
882     {
883       /* #### punt for now if standout mode is glitchy */
884       if (!TTY_FLAGS (c).standout_width)
885         {
886           OUTPUT1_IF (c, TTY_SD (c).end_standout);
887         }
888     }
889
890   if (FACE_UNDERLINE_P (face, frame))
891     {
892       /* #### punt for now if underline mode is glitchy */
893       if (!TTY_FLAGS (c).underline_width)
894         {
895           OUTPUT1_IF (c, TTY_SD (c).end_underline);
896         }
897     }
898
899   if (FACE_HIGHLIGHT_P (face, frame) ||
900       FACE_BLINKING_P (face, frame) ||
901       FACE_DIM_P (face, frame) ||
902       !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
903       !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
904     {
905       OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
906     }
907 }
908
909 /*****************************************************************************
910  set_tty_modes
911
912  Sets up various parameters on tty modes.
913  ****************************************************************************/
914 void
915 set_tty_modes (struct console *c)
916 {
917   if (!CONSOLE_TTY_P (c))
918     return;
919
920   OUTPUT1_IF (c, TTY_SD (c).init_motion);
921   OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
922   OUTPUT1_IF (c, TTY_SD (c).keypad_on);
923 }
924
925 /*****************************************************************************
926  reset_tty_modes
927
928  Restore default state of tty.
929  ****************************************************************************/
930 void
931 reset_tty_modes (struct console *c)
932 {
933   if (!CONSOLE_TTY_P (c))
934     return;
935
936   OUTPUT1_IF (c, TTY_SD (c).orig_pair);
937   OUTPUT1_IF (c, TTY_SD (c).keypad_off);
938   OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
939   OUTPUT1_IF (c, TTY_SD (c).end_motion);
940   tty_output_end (XDEVICE (CONSOLE_SELECTED_DEVICE (c)));
941 }
942
943 /*****************************************************************************
944  tty_redisplay_shutdown
945
946  Clear the frame and position the cursor properly for exiting.
947  ****************************************************************************/
948 void
949 tty_redisplay_shutdown (struct console *c)
950 {
951   Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
952
953   if (!NILP (dev))
954     {
955       Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
956
957       if (!NILP (frm))
958         {
959           struct frame *f = XFRAME (frm);
960
961           /* Clear the bottom line of the frame. */
962           redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
963                             f->height, f->width, 1);
964
965           /* And then stick the cursor there. */
966           tty_set_final_cursor_coords (f, f->height, 0);
967           tty_output_end (XDEVICE (dev));
968         }
969     }
970 }
971
972
973 /* #### Everything below here is old shit.  It should either be moved
974    up or removed. */
975
976
977 /* FLAGS - these don't need to be console local since only one console
978            can be being updated at a time. */
979 static int insert_mode_on;              /* nonzero if in insert mode */
980 static int standout_mode_on;            /* nonzero if in standout mode */
981 static int underline_mode_on;           /* nonzero if in underline mode */
982 static int alternate_mode_on;           /* nonzero if in alternate char set */
983 static int attributes_on;               /* nonzero if any attributes on */
984
985 #ifdef NOT_YET
986 static void
987 turn_on_insert (struct frame *f)
988 {
989   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
990
991   if (!insert_mode_on)
992     OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
993   insert_mode_on = 1;
994 }
995
996 static void
997 turn_off_insert (struct frame *f)
998 {
999   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1000
1001   if (insert_mode_on)
1002     OUTPUT1 (c, TTY_SE (c).end_ins_mode);
1003   insert_mode_on = 0;
1004 }
1005
1006 static void
1007 internal_cursor_to (struct frame *f, int row, int col)
1008 {
1009   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1010
1011   if (!TTY_FLAGS (c).insert_mode_motion)
1012     turn_off_insert (f);
1013   if (!TTY_FLAGS (c).standout_motion)
1014     {
1015       turn_off_standout (f);
1016       turn_off_underline (f);
1017       turn_off_alternate (f);
1018     }
1019
1020   cmgoto (f, row, col);
1021 }
1022
1023 static void
1024 clear_to_end (struct frame *f)
1025 {
1026   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
1027
1028   /* assumes cursor is already positioned */
1029   if (TTY_SE (c).clr_from_cursor)
1030     {
1031       OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
1032     }
1033   else
1034     {
1035       int line = FRAME_CURSOR_Y (f);
1036
1037       while (line < FRAME_HEIGHT (f))
1038         {
1039           internal_cursor_to (f, line, 0);
1040           OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1041         }
1042     }
1043 }
1044 #endif /* 0 */
1045 \f
1046 #if 0
1047 /*
1048  *  clear from last visible line on window to window end (presumably
1049  *  the line above window's modeline
1050  */
1051 static void
1052 tty_clear_window_end (struct window *w, int ystart, int yend)
1053 {
1054   struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1055   int line;
1056
1057   for (line = ystart; line < yend; line++)
1058     {
1059       cmgoto (XFRAME (w->frame), line, 0);
1060       OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1061     }
1062 }
1063
1064 #endif /* 0 */
1065
1066 static int
1067 tty_flash (struct device *d)
1068 {
1069   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1070   if (TTY_SD (c).visual_bell)
1071     {
1072       OUTPUT1 (c, TTY_SD (c).visual_bell);
1073       Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1074       return 1;
1075     }
1076   else
1077     return 0;
1078 }
1079
1080 /*
1081  * tty_ring_bell - sound an audio beep.
1082  */
1083 static void
1084 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1085 {
1086   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1087
1088   if (volume)
1089     {
1090       OUTPUT1 (c, TTY_SD (c).audio_bell);
1091       Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1092     }
1093 }
1094
1095
1096 int
1097 init_tty_for_redisplay (struct device *d, char *terminal_type)
1098 {
1099   int status;
1100   char entry_buffer[2044];
1101   /* char temp_buffer[2044]; */
1102   char *bufptr;
1103   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1104
1105   /* What we should really do is allocate just enough space for
1106      the actual strings that are stored; but this would require
1107      doing this after all the tgetstr()s and adjusting all the
1108      pointers. */
1109   CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1110   bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1111
1112 #if !defined(WIN32)
1113   /* SIGTT* don't exist under win32 */
1114   EMACS_BLOCK_SIGNAL (SIGTTOU);
1115 #endif
1116   status = tgetent (entry_buffer, terminal_type);
1117 #if !defined(WIN32)
1118   EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1119 #endif
1120 #if 0
1121   if (status < 0)
1122     return TTY_UNABLE_OPEN_DATABASE;
1123   else if (status == 0)
1124     return TTY_TYPE_UNDEFINED;
1125 #endif
1126   /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1127   if (status <= 0)
1128     return TTY_TYPE_UNDEFINED;
1129
1130   /*
1131    * Establish the terminal size.
1132    */
1133   /* First try to get the info from the system.  If that fails, check
1134      the termcap entry. */
1135   get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1136                        &CONSOLE_TTY_DATA (c)->height);
1137
1138   if (CONSOLE_TTY_DATA (c)->width <= 0)
1139     CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1140   if (CONSOLE_TTY_DATA (c)->height <= 0)
1141     CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1142
1143   if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1144     return TTY_SIZE_UNSPECIFIED;
1145
1146   /*
1147    * Initialize cursor motion information.
1148    */
1149
1150   /* local cursor movement */
1151   TTY_CM (c).up = tgetstr ("up", &bufptr);
1152   TTY_CM (c).down = tgetstr ("do", &bufptr);
1153   TTY_CM (c).left = tgetstr ("le", &bufptr);
1154   TTY_CM (c).right = tgetstr ("nd", &bufptr);
1155   TTY_CM (c).home = tgetstr ("ho", &bufptr);
1156   TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1157   TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1158
1159   /* absolute cursor motion */
1160   TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1161   TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1162   TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1163
1164   /* Verify that the terminal is powerful enough to run Emacs */
1165   if (!TTY_CM (c).abs)
1166     {
1167       if (!TTY_CM (c).up || !TTY_CM (c).down
1168           || !TTY_CM (c).left || !TTY_CM (c).right)
1169         return TTY_TYPE_INSUFFICIENT;
1170     }
1171
1172   /* parameterized local cursor movement */
1173   TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1174   TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1175   TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1176   TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1177
1178   /* scrolling */
1179   TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1180   TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1181   TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1182   TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1183   TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1184
1185
1186   /*
1187    * Initialize screen editing information.
1188    */
1189
1190   /* adding to the screen */
1191   TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1192   TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1193   TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1194   TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1195   TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1196   TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1197   TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1198   TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1199
1200   /* deleting from the screen */
1201   TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1202   TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1203   TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1204   TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1205   TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1206   TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1207   TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1208   TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1209   TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1210   TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1211
1212
1213   /*
1214    * Initialize screen display information.
1215    */
1216   TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1217   TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1218   TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1219   TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1220   TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1221   TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1222   TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1223   TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1224   TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1225   TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1226   TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1227   TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1228
1229   TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1230   TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1231   if (!TTY_SD (c).audio_bell)
1232     {
1233       /* If audio_bell doesn't get set, then assume C-g.  This is gross and
1234          ugly but is what Emacs has done from time immortal. */
1235       TTY_SD (c).audio_bell = "\07";
1236     }
1237
1238   TTY_SD (c).cursor_visible = tgetstr ("ve", &bufptr);
1239   TTY_SD (c).cursor_normal = tgetstr ("vs", &bufptr);
1240   TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1241   TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1242   TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1243   TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1244
1245
1246   /*
1247    * Initialize additional terminal information.
1248    */
1249   TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1250   TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1251   TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1252   TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1253   TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1254   TTY_FLAGS (c).standout_width = tgetnum ("sg");
1255   TTY_FLAGS (c).underline_width = tgetnum ("ug");
1256
1257   if (TTY_FLAGS (c).standout_width == -1)
1258     TTY_FLAGS (c).standout_width = 0;
1259   if (TTY_FLAGS (c).underline_width == -1)
1260     TTY_FLAGS (c).underline_width = 0;
1261
1262    TTY_FLAGS (c).meta_key =
1263      eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1264
1265
1266   /*
1267    * Setup the costs tables for this tty console.
1268    */
1269   cm_cost_init (c);
1270
1271   /*
1272    * Initialize local flags.
1273    */
1274   insert_mode_on = 0;
1275   standout_mode_on = 0;
1276   underline_mode_on = 0;
1277   alternate_mode_on = 0;
1278   attributes_on = 0;
1279
1280   /*
1281    * Attempt to initialize the function_key_map to
1282    * some kind of sensible value
1283    */
1284
1285   term_get_fkeys (c->function_key_map, &bufptr);
1286
1287   {
1288     /* check for ANSI set-foreground and set-background strings,
1289        and assume color if so.
1290
1291        #### we should support the other (non-ANSI) ways of specifying
1292        color, too. */
1293     char foobuf[500];
1294     char *fooptr = foobuf;
1295     if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1296         (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1297         ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1298       DEVICE_CLASS (d) = Qcolor;
1299     else
1300       DEVICE_CLASS (d) = Qmono;
1301   }
1302
1303   return TTY_INIT_SUCCESS;
1304 }
1305 \f
1306 struct fkey_table
1307 {
1308   CONST char *cap;
1309   CONST char *name;
1310 };
1311
1312   /* Termcap capability names that correspond directly to X keysyms.
1313      Some of these (marked "terminfo") aren't supplied by old-style
1314      (Berkeley) termcap entries.  They're listed in X keysym order;
1315      except we put the keypad keys first, so that if they clash with
1316      other keys (as on the IBM PC keyboard) they get overridden.
1317   */
1318
1319 static struct fkey_table keys[] =
1320 {
1321   {"kh", "home"},       /* termcap */
1322   {"kl", "left"},       /* termcap */
1323   {"ku", "up"},         /* termcap */
1324   {"kr", "right"},      /* termcap */
1325   {"kd", "down"},       /* termcap */
1326   {"%8", "prior"},      /* terminfo */
1327   {"%5", "next"},       /* terminfo */
1328   {"@7", "end"},        /* terminfo */
1329   {"@1", "begin"},      /* terminfo */
1330   {"*6", "select"},     /* terminfo */
1331   {"%9", "print"},      /* terminfo */
1332   {"@4", "execute"},    /* terminfo --- actually the `command' key */
1333   /*
1334    * "insert" --- see below
1335    */
1336   {"&8", "undo"},       /* terminfo */
1337   {"%0", "redo"},       /* terminfo */
1338   {"%7", "menu"},       /* terminfo --- actually the `options' key */
1339   {"@0", "find"},       /* terminfo */
1340   {"@2", "cancel"},     /* terminfo */
1341   {"%1", "help"},       /* terminfo */
1342   /*
1343    * "break" goes here, but can't be reliably intercepted with termcap
1344    */
1345   {"&4", "reset"},      /* terminfo --- actually `restart' */
1346   /*
1347    * "system" and "user" --- no termcaps
1348    */
1349   {"kE", "clearline"},  /* terminfo */
1350   {"kA", "insertline"}, /* terminfo */
1351   {"kL", "deleteline"}, /* terminfo */
1352   {"kI", "insertchar"}, /* terminfo */
1353   {"kD", "delete"},     /* terminfo */
1354   {"kB", "backtab"},    /* terminfo */
1355   /*
1356    * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1357    */
1358   {"@8", "kp-enter"},   /* terminfo */
1359   /*
1360    * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1361    * "kp-multiply", "kp-add", "kp-separator",
1362    * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1363    * --- no termcaps for any of these.
1364    */
1365   {"K4", "kp-1"},       /* terminfo */
1366   /*
1367    * "kp-2" --- no termcap
1368    */
1369   {"K5", "kp-3"},       /* terminfo */
1370   /*
1371    * "kp-4" --- no termcap
1372    */
1373   {"K2", "kp-5"},       /* terminfo */
1374   /*
1375    * "kp-6" --- no termcap
1376    */
1377   {"K1", "kp-7"},       /* terminfo */
1378   /*
1379    * "kp-8" --- no termcap
1380    */
1381   {"K3", "kp-9"},       /* terminfo */
1382   /*
1383    * "kp-equal" --- no termcap
1384    */
1385   {"k1", "f1"},
1386   {"k2", "f2"},
1387   {"k3", "f3"},
1388   {"k4", "f4"},
1389   {"k5", "f5"},
1390   {"k6", "f6"},
1391   {"k7", "f7"},
1392   {"k8", "f8"},
1393   {"k9", "f9"},
1394 };
1395
1396 static char **term_get_fkeys_arg;
1397
1398 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1399 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1400
1401 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1402    This function scans the termcap function key sequence entries, and
1403    adds entries to Vfunction_key_map for each function key it finds.  */
1404
1405 static void
1406 term_get_fkeys (Lisp_Object keymap, char **address)
1407 {
1408   /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1409      errors during the call.  The only errors should be from Fdefine_key
1410      when given a key sequence containing an invalid prefix key.  If the
1411      termcap defines function keys which use a prefix that is already bound
1412      to a command by the default bindings, we should silently ignore that
1413      function key specification, rather than giving the user an error and
1414      refusing to run at all on such a terminal.  */
1415
1416   term_get_fkeys_arg = address;
1417
1418   condition_case_1 (Qerror,
1419                     term_get_fkeys_1, keymap,
1420                     term_get_fkeys_error, Qnil);
1421 }
1422
1423 static Lisp_Object
1424 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1425 {
1426   return arg;
1427 }
1428
1429 static Lisp_Object
1430 term_get_fkeys_1 (Lisp_Object function_key_map)
1431 {
1432   int i;
1433
1434   char **address = term_get_fkeys_arg;
1435
1436   for (i = 0; i < countof (keys); i++)
1437     {
1438       char *sequence = tgetstr (keys[i].cap, address);
1439       if (sequence)
1440         Fdefine_key (function_key_map,
1441                      build_ext_string (sequence, FORMAT_BINARY),
1442                      vector1 (intern (keys[i].name)));
1443     }
1444
1445   /* The uses of the "k0" capability are inconsistent; sometimes it
1446      describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1447      We will attempt to politely accommodate both systems by testing for
1448      "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1449   */
1450   {
1451     CONST char *k_semi  = tgetstr ("k;", address);
1452     CONST char *k0      = tgetstr ("k0", address);
1453
1454     if (k_semi)
1455       Fdefine_key (function_key_map, build_ext_string (k_semi, FORMAT_BINARY),
1456                    vector1 (intern ("f10")));
1457
1458     if (k0)
1459       Fdefine_key (function_key_map, build_ext_string (k0, FORMAT_BINARY),
1460                    vector1 (intern (k_semi ? "f0" : "f10")));
1461   }
1462
1463   /* Set up cookies for numbered function keys above f10. */
1464   {
1465     char fcap[3], fkey[4];
1466
1467     fcap[0] = 'F'; fcap[2] = '\0';
1468     for (i = 11; i < 64; i++)
1469       {
1470         if (i <= 19)
1471           fcap[1] = '1' + i - 11;
1472         else if (i <= 45)
1473           fcap[1] = 'A' + i - 20;
1474         else
1475           fcap[1] = 'a' + i - 46;
1476
1477         {
1478           char *sequence = tgetstr (fcap, address);
1479           if (sequence)
1480             {
1481               sprintf (fkey, "f%d", i);
1482               Fdefine_key (function_key_map,
1483                            build_ext_string (sequence, FORMAT_BINARY),
1484                            vector1 (intern (fkey)));
1485             }
1486         }
1487       }
1488   }
1489
1490   /*
1491    * Various mappings to try and get a better fit.
1492    */
1493 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname)                       \
1494   if (!tgetstr (cap1, address))                                         \
1495     {                                                                   \
1496       char *sequence = tgetstr (cap2, address);                         \
1497       if (sequence)                                                     \
1498         Fdefine_key (function_key_map,                                  \
1499                      build_ext_string (sequence, FORMAT_BINARY),        \
1500                      vector1 (intern (keyname)));                               \
1501     }
1502
1503   /* if there's no key_next keycap, map key_npage to `next' keysym */
1504   CONDITIONAL_REASSIGN ("%5", "kN", "next");
1505   /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1506   CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1507   /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1508   CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1509
1510   /* IBM has their own non-standard dialect of terminfo.
1511      If the standard name isn't found, try the IBM name.  */
1512   CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1513   CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1514   CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1515   CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1516   CONDITIONAL_REASSIGN ("@7", "kw", "end");
1517   CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1518   CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1519   CONDITIONAL_REASSIGN ("%1", "kq", "help");
1520   CONDITIONAL_REASSIGN ("*6", "kU", "select");
1521 #undef CONDITIONAL_REASSIGN
1522
1523   return Qnil;
1524 }
1525
1526 \f
1527 /************************************************************************/
1528 /*                            initialization                            */
1529 /************************************************************************/
1530
1531 void
1532 console_type_create_redisplay_tty (void)
1533 {
1534   /* redisplay methods */
1535   CONSOLE_HAS_METHOD (tty, text_width);
1536   CONSOLE_HAS_METHOD (tty, output_display_block);
1537   CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1538   CONSOLE_HAS_METHOD (tty, divider_height);
1539   CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1540   CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1541   CONSOLE_HAS_METHOD (tty, clear_region);
1542   CONSOLE_HAS_METHOD (tty, clear_frame);
1543   CONSOLE_HAS_METHOD (tty, output_begin);
1544   CONSOLE_HAS_METHOD (tty, output_end);
1545   CONSOLE_HAS_METHOD (tty, flash);
1546   CONSOLE_HAS_METHOD (tty, ring_bell);
1547   CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);
1548 }