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