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