update.
[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 = Dynarr_new (Charc);
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   Dynarr_reset (buf);
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
868 /*****************************************************************************
869  reset_tty_modes
870
871  Restore default state of tty.
872  ****************************************************************************/
873 void
874 reset_tty_modes (struct console *c)
875 {
876   if (!CONSOLE_TTY_P (c))
877     return;
878
879   OUTPUT1_IF (c, TTY_SD (c).orig_pair);
880   OUTPUT1_IF (c, TTY_SD (c).keypad_off);
881   OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
882   OUTPUT1_IF (c, TTY_SD (c).end_motion);
883
884   {
885     Lisp_Object frm = CONSOLE_SELECTED_FRAME (c);
886
887     if (!NILP (frm))
888       tty_frame_output_end (XFRAME (frm));
889   }
890 }
891
892 /*****************************************************************************
893  tty_redisplay_shutdown
894
895  Clear the frame and position the cursor properly for exiting.
896  ****************************************************************************/
897 void
898 tty_redisplay_shutdown (struct console *c)
899 {
900   Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
901
902   if (!NILP (dev))
903     {
904       Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
905
906       if (!NILP (frm))
907         {
908           struct frame *f = XFRAME (frm);
909
910           /* Clear the bottom line of the frame. */
911           redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
912                             f->height, f->width, 1);
913
914           /* And then stick the cursor there. */
915           tty_set_final_cursor_coords (f, f->height, 0);
916           tty_frame_output_end (f);
917         }
918     }
919 }
920
921
922 /* #### Everything below here is old shit.  It should either be moved
923    up or removed. */
924
925
926 #ifdef NOT_YET
927 /* FLAGS - these don't need to be console local since only one console
928            can be being updated at a time. */
929 static int insert_mode_on;              /* nonzero if in insert mode */
930 static int standout_mode_on;            /* nonzero if in standout mode */
931 static int underline_mode_on;           /* nonzero if in underline mode */
932 static int alternate_mode_on;           /* nonzero if in alternate char set */
933 static int attributes_on;               /* nonzero if any attributes on */
934
935 static void
936 turn_on_insert (struct frame *f)
937 {
938   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
939
940   if (!insert_mode_on)
941     OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
942   insert_mode_on = 1;
943 }
944
945 static void
946 turn_off_insert (struct frame *f)
947 {
948   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
949
950   if (insert_mode_on)
951     OUTPUT1 (c, TTY_SE (c).end_ins_mode);
952   insert_mode_on = 0;
953 }
954
955 static void
956 internal_cursor_to (struct frame *f, int row, int col)
957 {
958   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
959
960   if (!TTY_FLAGS (c).insert_mode_motion)
961     turn_off_insert (f);
962   if (!TTY_FLAGS (c).standout_motion)
963     {
964       turn_off_standout (f);
965       turn_off_underline (f);
966       turn_off_alternate (f);
967     }
968
969   cmgoto (f, row, col);
970 }
971
972 static void
973 clear_to_end (struct frame *f)
974 {
975   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
976
977   /* assumes cursor is already positioned */
978   if (TTY_SE (c).clr_from_cursor)
979     {
980       OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
981     }
982   else
983     {
984       int line = FRAME_CURSOR_Y (f);
985
986       while (line < FRAME_HEIGHT (f))
987         {
988           internal_cursor_to (f, line, 0);
989           OUTPUT1 (c, TTY_SE (c).clr_to_eol);
990         }
991     }
992 }
993 #endif /* 0 */
994 \f
995 #if 0
996 /*
997  *  clear from last visible line on window to window end (presumably
998  *  the line above window's modeline
999  */
1000 static void
1001 tty_clear_window_end (struct window *w, int ystart, int yend)
1002 {
1003   struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1004   int line;
1005
1006   for (line = ystart; line < yend; line++)
1007     {
1008       cmgoto (XFRAME (w->frame), line, 0);
1009       OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1010     }
1011 }
1012
1013 #endif /* 0 */
1014
1015 static int
1016 tty_flash (struct device *d)
1017 {
1018   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1019   if (TTY_SD (c).visual_bell)
1020     {
1021       OUTPUT1 (c, TTY_SD (c).visual_bell);
1022       Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1023       return 1;
1024     }
1025   else
1026     return 0;
1027 }
1028
1029 /*
1030  * tty_ring_bell - sound an audio beep.
1031  */
1032 static void
1033 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1034 {
1035   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1036
1037   if (volume)
1038     {
1039       OUTPUT1 (c, TTY_SD (c).audio_bell);
1040       Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1041     }
1042 }
1043
1044
1045 int
1046 init_tty_for_redisplay (struct device *d, char *terminal_type)
1047 {
1048   int status;
1049   char entry_buffer[2044];
1050   /* char temp_buffer[2044]; */
1051   char *bufptr;
1052   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1053
1054   /* What we should really do is allocate just enough space for
1055      the actual strings that are stored; but this would require
1056      doing this after all the tgetstr()s and adjusting all the
1057      pointers. */
1058   CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1059   bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1060
1061 #ifdef SIGTTOU
1062   /* SIGTT* don't exist under win32 */
1063   EMACS_BLOCK_SIGNAL (SIGTTOU);
1064 #endif
1065   status = tgetent (entry_buffer, terminal_type);
1066 #ifdef SIGTTOU
1067   EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1068 #endif
1069 #if 0
1070   if (status < 0)
1071     return TTY_UNABLE_OPEN_DATABASE;
1072   else if (status == 0)
1073     return TTY_TYPE_UNDEFINED;
1074 #endif
1075   /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1076   if (status <= 0)
1077     return TTY_TYPE_UNDEFINED;
1078
1079   /*
1080    * Establish the terminal size.
1081    */
1082   /* First try to get the info from the system.  If that fails, check
1083      the termcap entry. */
1084   get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1085                        &CONSOLE_TTY_DATA (c)->height);
1086
1087   if (CONSOLE_TTY_DATA (c)->width <= 0)
1088     CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1089   if (CONSOLE_TTY_DATA (c)->height <= 0)
1090     CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1091
1092   if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1093     return TTY_SIZE_UNSPECIFIED;
1094
1095   /*
1096    * Initialize cursor motion information.
1097    */
1098
1099   /* local cursor movement */
1100   TTY_CM (c).up = tgetstr ("up", &bufptr);
1101   TTY_CM (c).down = tgetstr ("do", &bufptr);
1102   TTY_CM (c).left = tgetstr ("le", &bufptr);
1103   TTY_CM (c).right = tgetstr ("nd", &bufptr);
1104   TTY_CM (c).home = tgetstr ("ho", &bufptr);
1105   TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1106   TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1107
1108   /* absolute cursor motion */
1109   TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1110   TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1111   TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1112
1113   /* Verify that the terminal is powerful enough to run Emacs */
1114   if (!TTY_CM (c).abs)
1115     {
1116       if (!TTY_CM (c).up || !TTY_CM (c).down
1117           || !TTY_CM (c).left || !TTY_CM (c).right)
1118         return TTY_TYPE_INSUFFICIENT;
1119     }
1120
1121   /* parameterized local cursor movement */
1122   TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1123   TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1124   TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1125   TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1126
1127   /* scrolling */
1128   TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1129   TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1130   TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1131   TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1132   TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1133
1134
1135   /*
1136    * Initialize screen editing information.
1137    */
1138
1139   /* adding to the screen */
1140   TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1141   TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1142   TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1143   TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1144   TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1145   TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1146   TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1147   TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1148
1149   /* deleting from the screen */
1150   TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1151   TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1152   TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1153   TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1154   TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1155   TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1156   TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1157   TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1158   TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1159   TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1160
1161
1162   /*
1163    * Initialize screen display information.
1164    */
1165   TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1166   TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1167   TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1168   TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1169   TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1170   TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1171   TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1172   TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1173   TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1174   TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1175   TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1176   TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1177
1178   TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1179   TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1180   if (!TTY_SD (c).audio_bell)
1181     {
1182       /* If audio_bell doesn't get set, then assume C-g.  This is gross and
1183          ugly but is what Emacs has done from time immortal. */
1184       TTY_SD (c).audio_bell = "\07";
1185     }
1186
1187   TTY_SD (c).cursor_visible = tgetstr ("ve", &bufptr);
1188   TTY_SD (c).cursor_normal = tgetstr ("vs", &bufptr);
1189   TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1190   TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1191   TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1192   TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1193
1194
1195   /*
1196    * Initialize additional terminal information.
1197    */
1198   TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1199   TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1200   TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1201   TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1202   TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1203   TTY_FLAGS (c).standout_width = tgetnum ("sg");
1204   TTY_FLAGS (c).underline_width = tgetnum ("ug");
1205
1206   if (TTY_FLAGS (c).standout_width == -1)
1207     TTY_FLAGS (c).standout_width = 0;
1208   if (TTY_FLAGS (c).underline_width == -1)
1209     TTY_FLAGS (c).underline_width = 0;
1210
1211    TTY_FLAGS (c).meta_key =
1212      eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1213
1214
1215   /*
1216    * Setup the costs tables for this tty console.
1217    */
1218   cm_cost_init (c);
1219
1220 #ifdef NOT_YET
1221   /*
1222    * Initialize local flags.
1223    */
1224   insert_mode_on = 0;
1225   standout_mode_on = 0;
1226   underline_mode_on = 0;
1227   alternate_mode_on = 0;
1228   attributes_on = 0;
1229 #endif
1230
1231   /*
1232    * Attempt to initialize the function_key_map to
1233    * some kind of sensible value
1234    */
1235
1236   term_get_fkeys (c->function_key_map, &bufptr);
1237
1238   {
1239     /* check for ANSI set-foreground and set-background strings,
1240        and assume color if so.
1241
1242        #### we should support the other (non-ANSI) ways of specifying
1243        color, too. */
1244     char foobuf[500];
1245     char *fooptr = foobuf;
1246     if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1247         (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1248         ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1249       DEVICE_CLASS (d) = Qcolor;
1250     else
1251       DEVICE_CLASS (d) = Qmono;
1252   }
1253
1254   return TTY_INIT_SUCCESS;
1255 }
1256 \f
1257 struct fkey_table
1258 {
1259   const char *cap;
1260   const char *name;
1261 };
1262
1263   /* Termcap capability names that correspond directly to X keysyms.
1264      Some of these (marked "terminfo") aren't supplied by old-style
1265      (Berkeley) termcap entries.  They're listed in X keysym order;
1266      except we put the keypad keys first, so that if they clash with
1267      other keys (as on the IBM PC keyboard) they get overridden.
1268   */
1269
1270 static struct fkey_table keys[] =
1271 {
1272   {"kh", "home"},       /* termcap */
1273   {"kl", "left"},       /* termcap */
1274   {"ku", "up"},         /* termcap */
1275   {"kr", "right"},      /* termcap */
1276   {"kd", "down"},       /* termcap */
1277   {"%8", "prior"},      /* terminfo */
1278   {"%5", "next"},       /* terminfo */
1279   {"@7", "end"},        /* terminfo */
1280   {"@1", "begin"},      /* terminfo */
1281   {"*6", "select"},     /* terminfo */
1282   {"%9", "print"},      /* terminfo */
1283   {"@4", "execute"},    /* terminfo --- actually the `command' key */
1284   /*
1285    * "insert" --- see below
1286    */
1287   {"&8", "undo"},       /* terminfo */
1288   {"%0", "redo"},       /* terminfo */
1289   {"%7", "menu"},       /* terminfo --- actually the `options' key */
1290   {"@0", "find"},       /* terminfo */
1291   {"@2", "cancel"},     /* terminfo */
1292   {"%1", "help"},       /* terminfo */
1293   /*
1294    * "break" goes here, but can't be reliably intercepted with termcap
1295    */
1296   {"&4", "reset"},      /* terminfo --- actually `restart' */
1297   /*
1298    * "system" and "user" --- no termcaps
1299    */
1300   {"kE", "clearline"},  /* terminfo */
1301   {"kA", "insertline"}, /* terminfo */
1302   {"kL", "deleteline"}, /* terminfo */
1303   {"kI", "insertchar"}, /* terminfo */
1304   {"kD", "delete"},     /* terminfo */
1305   {"kB", "backtab"},    /* terminfo */
1306   /*
1307    * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1308    */
1309   {"@8", "kp-enter"},   /* terminfo */
1310   /*
1311    * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1312    * "kp-multiply", "kp-add", "kp-separator",
1313    * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1314    * --- no termcaps for any of these.
1315    */
1316   {"K4", "kp-1"},       /* terminfo */
1317   /*
1318    * "kp-2" --- no termcap
1319    */
1320   {"K5", "kp-3"},       /* terminfo */
1321   /*
1322    * "kp-4" --- no termcap
1323    */
1324   {"K2", "kp-5"},       /* terminfo */
1325   /*
1326    * "kp-6" --- no termcap
1327    */
1328   {"K1", "kp-7"},       /* terminfo */
1329   /*
1330    * "kp-8" --- no termcap
1331    */
1332   {"K3", "kp-9"},       /* terminfo */
1333   /*
1334    * "kp-equal" --- no termcap
1335    */
1336   {"k1", "f1"},
1337   {"k2", "f2"},
1338   {"k3", "f3"},
1339   {"k4", "f4"},
1340   {"k5", "f5"},
1341   {"k6", "f6"},
1342   {"k7", "f7"},
1343   {"k8", "f8"},
1344   {"k9", "f9"},
1345 };
1346
1347 static char **term_get_fkeys_arg;
1348
1349 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1350 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1351
1352 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1353    This function scans the termcap function key sequence entries, and
1354    adds entries to Vfunction_key_map for each function key it finds.  */
1355
1356 static void
1357 term_get_fkeys (Lisp_Object keymap, char **address)
1358 {
1359   /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1360      errors during the call.  The only errors should be from Fdefine_key
1361      when given a key sequence containing an invalid prefix key.  If the
1362      termcap defines function keys which use a prefix that is already bound
1363      to a command by the default bindings, we should silently ignore that
1364      function key specification, rather than giving the user an error and
1365      refusing to run at all on such a terminal.  */
1366
1367   term_get_fkeys_arg = address;
1368
1369   condition_case_1 (Qerror,
1370                     term_get_fkeys_1, keymap,
1371                     term_get_fkeys_error, Qnil);
1372 }
1373
1374 static Lisp_Object
1375 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1376 {
1377   return arg;
1378 }
1379
1380 static Lisp_Object
1381 term_get_fkeys_1 (Lisp_Object function_key_map)
1382 {
1383   int i;
1384
1385   char **address = term_get_fkeys_arg;
1386
1387   for (i = 0; i < countof (keys); i++)
1388     {
1389       char *sequence = tgetstr (keys[i].cap, address);
1390       if (sequence)
1391         Fdefine_key (function_key_map,
1392                      build_ext_string (sequence, Qbinary),
1393                      vector1 (intern (keys[i].name)));
1394     }
1395
1396   /* The uses of the "k0" capability are inconsistent; sometimes it
1397      describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1398      We will attempt to politely accommodate both systems by testing for
1399      "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1400   */
1401   {
1402     const char *k_semi  = tgetstr ("k;", address);
1403     const char *k0      = tgetstr ("k0", address);
1404
1405     if (k_semi)
1406       Fdefine_key (function_key_map, build_ext_string (k_semi, Qbinary),
1407                    vector1 (intern ("f10")));
1408
1409     if (k0)
1410       Fdefine_key (function_key_map, build_ext_string (k0, Qbinary),
1411                    vector1 (intern (k_semi ? "f0" : "f10")));
1412   }
1413
1414   /* Set up cookies for numbered function keys above f10. */
1415   {
1416     char fcap[3], fkey[4];
1417
1418     fcap[0] = 'F'; fcap[2] = '\0';
1419     for (i = 11; i < 64; i++)
1420       {
1421         if (i <= 19)
1422           fcap[1] = '1' + i - 11;
1423         else if (i <= 45)
1424           fcap[1] = 'A' + i - 20;
1425         else
1426           fcap[1] = 'a' + i - 46;
1427
1428         {
1429           char *sequence = tgetstr (fcap, address);
1430           if (sequence)
1431             {
1432               sprintf (fkey, "f%d", i);
1433               Fdefine_key (function_key_map,
1434                            build_ext_string (sequence, Qbinary),
1435                            vector1 (intern (fkey)));
1436             }
1437         }
1438       }
1439   }
1440
1441   /*
1442    * Various mappings to try and get a better fit.
1443    */
1444 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) do {          \
1445     if (!tgetstr (cap1, address))                               \
1446       {                                                         \
1447         char *sequence = tgetstr (cap2, address);               \
1448         if (sequence)                                           \
1449           Fdefine_key (function_key_map,                        \
1450                        build_ext_string (sequence, Qbinary),    \
1451                        vector1 (intern (keyname)));             \
1452       }                                                         \
1453   } while (0)
1454
1455   /* if there's no key_next keycap, map key_npage to `next' keysym */
1456   CONDITIONAL_REASSIGN ("%5", "kN", "next");
1457   /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1458   CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1459   /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1460   CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1461
1462   /* IBM has their own non-standard dialect of terminfo.
1463      If the standard name isn't found, try the IBM name.  */
1464   CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1465   CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1466   CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1467   CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1468   CONDITIONAL_REASSIGN ("@7", "kw", "end");
1469   CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1470   CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1471   CONDITIONAL_REASSIGN ("%1", "kq", "help");
1472   CONDITIONAL_REASSIGN ("*6", "kU", "select");
1473 #undef CONDITIONAL_REASSIGN
1474
1475   return Qnil;
1476 }
1477
1478 \f
1479 /************************************************************************/
1480 /*                            initialization                            */
1481 /************************************************************************/
1482
1483 void
1484 console_type_create_redisplay_tty (void)
1485 {
1486   /* redisplay methods */
1487   CONSOLE_HAS_METHOD (tty, text_width);
1488   CONSOLE_HAS_METHOD (tty, output_display_block);
1489   CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1490   CONSOLE_HAS_METHOD (tty, divider_height);
1491   CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1492   CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1493   CONSOLE_HAS_METHOD (tty, clear_region);
1494   CONSOLE_HAS_METHOD (tty, clear_frame);
1495   CONSOLE_HAS_METHOD (tty, frame_output_begin);
1496   CONSOLE_HAS_METHOD (tty, frame_output_end);
1497   CONSOLE_HAS_METHOD (tty, flash);
1498   CONSOLE_HAS_METHOD (tty, ring_bell);
1499   CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);
1500 }