Resorted; add missing some Morohashi's Daikanwa characters; add
[chise/xemacs-chise.git-] / src / redisplay-tty.c
1 /* Communication module for TTY terminals.
2    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4    Copyright (C) 1995, 1996 Ben Wing.
5    Copyright (C) 1996 Chuck Thompson.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: Not completely synched with FSF.  Mostly divergent
25    from FSF. */
26
27 /* This file has been Mule-ized. */
28
29 /* Written by Chuck Thompson. */
30 /* Color support added by Ben Wing. */
31
32 #include <config.h>
33 #include "lisp.h"
34
35 #include "buffer.h"
36 #include "console-tty.h"
37 #include "events.h"
38 #include "faces.h"
39 #include "frame.h"
40 #include "glyphs.h"
41 #include "lstream.h"
42 #include "objects-tty.h"
43 #include "redisplay.h"
44 #include "sysdep.h"
45 #include "window.h"
46
47 /* These headers #define all kinds of common words like "columns"...
48    What a bunch of losers.  If we were to include them, we'd have to
49    include them last to prevent them from messing up our own header
50    files (struct slot names, etc.).  But it turns out that there are
51    other conflicts as well on some systems, so screw it: we'll just
52    re-declare the routines we use and assume the code in this file is
53    invoking them correctly. */
54 /* # include <curses.h> */
55 /* # include <term.h> */
56 #ifdef __cplusplus
57 extern "C" {
58 #endif
59 extern int tgetent (const char *, const char *);
60 extern int tgetflag (const char *);
61 extern int tgetnum (const char *);
62 extern char *tgetstr (const char *, char **);
63 extern void tputs (const char *, int, void (*)(int));
64 #ifdef __cplusplus
65 }
66 #endif
67 #define FORCE_CURSOR_UPDATE(c) send_string_to_tty_console (c, 0, 0)
68 #define OUTPUTN(c, a, n)                        \
69   do {                                          \
70     cmputc_console = c;                         \
71     FORCE_CURSOR_UPDATE (c);                    \
72     tputs (a, n, cmputc);                       \
73   } while (0)
74 #define OUTPUT1(c, a) OUTPUTN (c, a, 1)
75 #define OUTPUTN_IF(c, a, n)                     \
76   do {                                          \
77     cmputc_console = c;                         \
78     FORCE_CURSOR_UPDATE (c);                    \
79     if (a)                                      \
80       tputs (a, n, cmputc);                     \
81   } while (0)
82 #define OUTPUT1_IF(c, a) OUTPUTN_IF (c, a, 1)
83
84 static void tty_output_charc_dynarr (struct window *w,
85                                      struct display_line *dl,
86                                      Charc_dynarr *buf, int xpos,
87                                      face_index findex,
88                                      int cursor);
89 static void tty_output_bufbyte_string (struct window *w,
90                                        struct display_line *dl,
91                                        Bufbyte *str, Bytecount len,
92                                        int xpos, face_index findex,
93                                        int cursor);
94 static void tty_turn_on_face (struct window *w, face_index findex);
95 static void tty_turn_off_face (struct window *w, face_index findex);
96 static void tty_turn_on_frame_face (struct frame *f, Lisp_Object face);
97 static void tty_turn_off_frame_face (struct frame *f, Lisp_Object face);
98
99 static void term_get_fkeys (Lisp_Object keymap, char **address);
100
101 /*****************************************************************************
102  tty_text_width
103
104  Non-Mule tty's don't have fonts (that we use at least), so everything
105  is considered to be fixed width -- in other words, we return LEN.
106  Under Mule, however, a character can still cover more than one
107  column, so we use charc_string_displayed_columns().
108  ****************************************************************************/
109 static int
110 tty_text_width (struct frame *f, struct face_cachel *cachel,
111                 const Charc *str, Charcount len)
112 {
113   return charc_string_displayed_columns (str, len);
114 }
115
116 /*****************************************************************************
117  tty_divider_height
118
119  Return the width of the horizontal divider.  This is a function
120  because divider_height is a console method.
121  ****************************************************************************/
122 static int
123 tty_divider_height (void)
124 {
125   return 1;
126 }
127
128 /*****************************************************************************
129  tty_eol_cursor_width
130
131  Return the width of the end-of-line cursor.  This is a function
132  because eol_cursor_width is a console method.
133  ****************************************************************************/
134 static int
135 tty_eol_cursor_width (void)
136 {
137   return 1;
138 }
139
140 /*****************************************************************************
141  tty_frame_output_begin
142
143  Perform any necessary initialization prior to an update.
144  ****************************************************************************/
145 #ifdef DEBUG_XEMACS
146 void tty_frame_output_begin (struct frame *f);
147 void
148 #else
149 static void
150 #endif
151 tty_frame_output_begin (struct frame *f)
152 {
153 #ifndef HAVE_TERMIOS
154   /* Termcap requires `ospeed' to be a global variable so we have to
155      always set it for whatever tty console we are actually currently
156      working with. */
157   ospeed = DEVICE_TTY_DATA (XDEVICE (FRAME_DEVICE (f)))->ospeed;
158 #endif
159 }
160
161 /*****************************************************************************
162  tty_frame_output_end
163
164  Perform any necessary flushing of queues when an update has completed.
165  ****************************************************************************/
166 #ifdef DEBUG_XEMACS
167 void tty_frame_output_end (struct frame *f);
168 void
169 #else
170 static void
171 #endif
172 tty_frame_output_end (struct frame *f)
173 {
174   struct device *d = XDEVICE (FRAME_DEVICE (f));
175   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
176
177   CONSOLE_TTY_CURSOR_X (c) = CONSOLE_TTY_FINAL_CURSOR_X (c);
178   CONSOLE_TTY_CURSOR_Y (c) = CONSOLE_TTY_FINAL_CURSOR_Y (c);
179   FORCE_CURSOR_UPDATE (c);
180   Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
181 }
182
183 static void
184 tty_set_final_cursor_coords (struct frame *f, int y, int x)
185 {
186   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
187
188   CONSOLE_TTY_FINAL_CURSOR_X (c) = x;
189   CONSOLE_TTY_FINAL_CURSOR_Y (c) = y;
190 }
191
192 /*****************************************************************************
193  tty_output_display_block
194
195  Given a display line, a block number for that start line, output all
196  runes between start and end in the specified display block.
197  ****************************************************************************/
198 static void
199 tty_output_display_block (struct window *w, struct display_line *dl, int block,
200                           int start, int end, int start_pixpos,
201                           int cursor_start, int cursor_width,
202                           int cursor_height)
203 {
204   struct frame *f = XFRAME (w->frame);
205   Charc_dynarr *buf = Dynarr_new (Charc);
206
207   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
208   rune_dynarr *rba = db->runes;
209   struct rune *rb;
210
211   int elt = start;
212   face_index findex;
213   int xpos;
214
215   rb = Dynarr_atp (rba, elt);
216
217   if (!rb)
218     {
219       /* Nothing to do so don't do anything. */
220       return;
221     }
222   else
223     {
224       findex = rb->findex;
225       xpos = rb->xpos;
226     }
227
228   if (end < 0)
229     end = Dynarr_length (rba);
230
231   Dynarr_reset (buf);
232
233   while (elt < end && Dynarr_atp (rba, elt)->xpos < start_pixpos)
234     {
235       elt++;
236       findex = Dynarr_atp (rba, elt)->findex;
237       xpos = Dynarr_atp (rba, elt)->xpos;
238     }
239
240   while (elt < end)
241     {
242       rb = Dynarr_atp (rba, elt);
243
244       if (rb->findex == findex && rb->type == RUNE_CHAR
245           && (!CHARC_ASCII_EQ (rb->object.cglyph, '\n'))
246           && (rb->cursor_type != CURSOR_ON
247               || NILP (w->text_cursor_visible_p)))
248         {
249           Dynarr_add (buf, rb->object.cglyph);
250           elt++;
251         }
252       else
253         {
254           if (Dynarr_length (buf))
255             {
256               tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
257               xpos = rb->xpos;
258             }
259           Dynarr_reset (buf);
260
261           if (rb->type == RUNE_CHAR)
262             {
263               findex = rb->findex;
264               xpos = rb->xpos;
265
266               if (CHARC_ASCII_EQ (rb->object.cglyph, '\n'))
267                 {
268                   /* Clear in case a cursor was formerly here. */
269                   Dynarr_add (buf, ASCII_TO_CHARC (' '));
270                   tty_output_charc_dynarr (w, dl, buf, rb->xpos,
271                                            DEFAULT_INDEX, 0);
272                   Dynarr_reset (buf);
273
274                   cmgoto (f, dl->ypos - 1, rb->xpos);
275
276                   elt++;
277                 }
278               else if (rb->cursor_type == CURSOR_ON)
279                 {
280                   /* There is not a distinct eol cursor on tty's. */
281
282                   Dynarr_add (buf, rb->object.cglyph);
283                   tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
284                   Dynarr_reset (buf);
285
286                   cmgoto (f, dl->ypos - 1, xpos);
287
288                   xpos += rb->width;
289                   elt++;
290                 }
291             }
292           /* #### RUNE_HLINE is actually a little more complicated than this
293              but at the moment it is only used to draw a turned off
294              modeline and this will suffice for that. */
295           else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
296             {
297               Charc ec_to_add;
298               int size = rb->width;
299
300               if (rb->type == RUNE_BLANK)
301                 ec_to_add = ASCII_TO_CHARC (' ');
302               else
303                 ec_to_add = ASCII_TO_CHARC ('-');
304
305               while (size--)
306                 Dynarr_add (buf, ec_to_add);
307               tty_output_charc_dynarr (w, dl, buf, rb->xpos, findex, 0);
308
309               if (xpos >= cursor_start
310                   && cursor_start < xpos + Dynarr_length (buf))
311                 {
312                   cmgoto (f, dl->ypos - 1, cursor_start);
313                 }
314
315               Dynarr_reset (buf);
316
317               elt++;
318               if (elt < end)
319                 {
320                   rb = Dynarr_atp (rba, elt);
321
322                   findex = rb->findex;
323                   xpos = rb->xpos;
324                 }
325             }
326           else if (rb->type == RUNE_DGLYPH)
327             {
328               Lisp_Object window;
329               Lisp_Object instance;
330
331               XSETWINDOW (window, w);
332               instance = glyph_image_instance (rb->object.dglyph.glyph,
333                                                window, ERROR_ME_NOT, 1);
334
335               if (IMAGE_INSTANCEP (instance))
336                 {
337                   switch (XIMAGE_INSTANCE_TYPE (instance))
338                     {
339                     case IMAGE_MONO_PIXMAP:
340                     case IMAGE_COLOR_PIXMAP:
341                     case IMAGE_SUBWINDOW:
342                     case IMAGE_WIDGET:
343                       /* just do nothing here */
344                       break;
345
346                     case IMAGE_NOTHING:
347                       /* nothing is as nothing does */
348                       break;
349
350                     case IMAGE_TEXT:
351                     case IMAGE_POINTER:
352                     default:
353                       abort ();
354                     }
355                   IMAGE_INSTANCE_OPTIMIZE_OUTPUT
356                     (XIMAGE_INSTANCE (instance)) = 0;
357                 }
358
359               xpos += rb->width;
360               elt++;
361             }
362           else
363             abort ();
364         }
365     }
366
367   if (Dynarr_length (buf))
368     tty_output_charc_dynarr (w, dl, buf, xpos, findex, 0);
369   Dynarr_free (buf);
370
371 }
372
373
374
375 /*****************************************************************************
376  tty_output_vertical_divider
377
378  Draw a vertical divider down the right side of the given window.
379  ****************************************************************************/
380 static void
381 tty_output_vertical_divider (struct window *w, int clear)
382 {
383   /* Divider width can either be 0 or 1 on TTYs */
384   if (window_divider_width (w))
385     {
386       struct frame *f = XFRAME (w->frame);
387       struct console *c = XCONSOLE (FRAME_CONSOLE (f));
388       int line;
389       int y_top = WINDOW_TEXT_TOP (w);
390       int y_bot = WINDOW_TEXT_BOTTOM (w);
391       unsigned char divv = '|';
392
393       tty_turn_on_face (w, MODELINE_INDEX);
394       for (line = y_top; line < y_bot; line++)
395         {
396           cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
397           send_string_to_tty_console (c, &divv, 1);
398           TTY_INC_CURSOR_X (c, 1);
399         }
400
401       /* Draw the divider in the modeline. */
402       cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
403       send_string_to_tty_console (c, &divv, 1);
404       TTY_INC_CURSOR_X (c, 1);
405       tty_turn_off_face (w, MODELINE_INDEX);
406     }
407 }
408
409 /****************************************************************************
410  tty_clear_region
411
412  Clear the area in the box defined by the given parameters.
413  ****************************************************************************/
414 static void
415 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
416                   face_index findex, int x, int y,
417                   int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
418                   Lisp_Object background_pixmap)
419 {
420   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
421   int line;
422   struct window* w = XWINDOW (window);
423
424   tty_turn_on_face (w, findex);
425   for (line = y; line < y + height; line++)
426     {
427       int col;
428
429       cmgoto (f, line, x);
430
431       if (window_is_leftmost (w)
432           && window_is_rightmost (w)
433           && TTY_SE (c).clr_to_eol)
434         {
435           OUTPUT1 (c, TTY_SE (c).clr_to_eol);
436         }
437       else
438         {
439           unsigned char sp = ' ';
440           /* #### Of course, this is all complete and utter crap. */
441           for (col = x; col < x + width; col++)
442             send_string_to_tty_console (c, &sp, 1);
443           TTY_INC_CURSOR_X (c, width);
444         }
445     }
446   tty_turn_off_face (w, findex);
447   cmgoto (f, y, x);
448 }
449
450 /*****************************************************************************
451  tty_clear_to_window_end
452
453  Clear the area between ypos1 and ypos2.  Each margin area and the
454  text area is handled separately since they may each have their own
455  background color.
456  ****************************************************************************/
457 static void
458 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
459 {
460   struct frame *f = XFRAME (w->frame);
461   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
462   int x, width;
463
464   x = WINDOW_TEXT_LEFT (w);
465   width = WINDOW_TEXT_WIDTH (w);
466
467   if (window_is_rightmost (w))
468     {
469       /* #### Optimize to use clr_to_eol function of tty if available, if
470          the window is the entire width of the frame. */
471       /* #### Is this actually an optimization? */
472       int line;
473       tty_turn_on_face (w, DEFAULT_INDEX);
474       for (line = ypos1; line < ypos2; line++)
475         {
476           cmgoto (XFRAME (w->frame), line, x);
477           OUTPUT1 (c, TTY_SE (c).clr_to_eol);
478         }
479       tty_turn_off_face (w, DEFAULT_INDEX);
480     }
481   else
482     {
483       Lisp_Object window;
484
485       XSETWINDOW (window, w);
486       redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
487     }
488 }
489
490 /****************************************************************************
491  tty_clear_frame
492
493  Clear the entire frame.
494  ****************************************************************************/
495 static void
496 tty_clear_frame (struct frame *f)
497 {
498   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
499
500   tty_turn_on_frame_face (f, Vdefault_face);
501   if (TTY_SE (c).clr_frame)
502     {
503       OUTPUT1 (c, TTY_SE (c).clr_frame);
504       CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
505       CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
506 #ifdef NOT_SURE
507       FRAME_CURSOR_X (f) = 0;
508       FRAME_CURSOR_Y (f) = 0;
509 #endif
510     }
511   else
512     {
513 #ifdef NOT_SURE
514       internal_cursor_to (f, 0, 0);
515       clear_to_end (f);
516 #else
517       /* #### Not implemented. */
518       stderr_out ("Not yet.\n");
519 #endif
520     }
521   tty_turn_off_frame_face (f, Vdefault_face);
522 }
523
524 static void
525 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
526                            Bufbyte *str, Bytecount len, int xpos,
527                            face_index findex, int cursor)
528 {
529   struct frame *f = XFRAME (w->frame);
530   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
531
532   /* First position the cursor. */
533   cmgoto (f, dl->ypos - 1, xpos);
534
535   /* Enable any face properties. */
536   tty_turn_on_face (w, findex);
537
538   send_string_to_tty_console (c, str, len);
539   TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
540
541   /* Turn the face properties back off. */
542   tty_turn_off_face (w, findex);
543 }
544
545 static Bufbyte_dynarr *tty_output_charc_dynarr_dynarr;
546
547 /*****************************************************************************
548  tty_output_charc_dynarr
549
550  Given a string and a starting position, output that string in the
551  given face.  If cursor is true, draw a cursor around the string.
552  ****************************************************************************/
553 static void
554 tty_output_charc_dynarr (struct window *w, struct display_line *dl,
555                          Charc_dynarr *buf, int xpos, face_index findex,
556                          int cursor)
557 {
558   if (!tty_output_charc_dynarr_dynarr)
559     tty_output_charc_dynarr_dynarr = Dynarr_new (Bufbyte);
560   else
561     Dynarr_reset (tty_output_charc_dynarr_dynarr);
562
563   convert_charc_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
564                                             Dynarr_length (buf),
565                                             tty_output_charc_dynarr_dynarr);
566
567   tty_output_bufbyte_string (w, dl,
568                              Dynarr_atp (tty_output_charc_dynarr_dynarr, 0),
569                              Dynarr_length (tty_output_charc_dynarr_dynarr),
570                              xpos, findex, cursor);
571 }
572
573 #if 0
574
575 static Bufbyte_dynarr *sidcs_dynarr;
576
577 static void
578 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
579 {
580   int i;
581   Bufbyte *specdata = XSTRING_DATA   (spec);
582   Bytecount speclen = XSTRING_LENGTH (spec);
583
584   if (!sidcs_dynarr)
585     sidcs_dynarr = Dynarr_new (Bufbyte);
586   else
587     Dynarr_reset (sidcs_dynarr);
588
589   for (i = 0; i < speclen; i++)
590     {
591       if (specdata[i] == '%' && specdata[i+1] == '%')
592         {
593           Dynarr_add (sidcs_dynarr, '%');
594           i++;
595         }
596       else if (specdata[i] == '%' && specdata[i+1] == 's')
597         {
598           Dynarr_add_many (sidcs_dynarr,
599                            XSTRING_DATA   (string),
600                            XSTRING_LENGTH (string));
601           i++;
602         }
603       else
604         Dynarr_add (sidcs_dynarr, specdata[i]);
605     }
606 }
607
608 #endif
609
610 static void
611 set_foreground_to (struct console *c, Lisp_Object sym)
612 {
613   Lisp_Object result;
614   Bufbyte *escseq = 0;
615   Bytecount escseqlen = 0;
616
617   result = assq_no_quit (sym, Vtty_color_alist);
618   if (!NILP (result))
619     {
620       Lisp_Object esc_seq = XCAR (XCDR (result));
621       escseq    = XSTRING_DATA   (esc_seq);
622       escseqlen = XSTRING_LENGTH (esc_seq);
623     }
624 #if 0
625   else if (STRINGP (Vtty_dynamic_color_fg))
626     {
627       substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
628                                           Fsymbol_name (sym));
629       escseq = Dynarr_atp (sidcs_dynarr, 0);
630       escseqlen = Dynarr_length (sidcs_dynarr);
631     }
632 #endif
633
634   if (escseq)
635     {
636       send_string_to_tty_console (c, escseq, escseqlen);
637     }
638 }
639
640 static void
641 set_background_to (struct console *c, Lisp_Object sym)
642 {
643   Lisp_Object result;
644   Bufbyte *escseq = 0;
645   Bytecount escseqlen = 0;
646
647   result = assq_no_quit (sym, Vtty_color_alist);
648   if (!NILP (result))
649     {
650       Lisp_Object esc_seq = XCDR (XCDR (result));
651       escseq    = XSTRING_DATA   (esc_seq);
652       escseqlen = XSTRING_LENGTH (esc_seq);
653     }
654 #if 0
655   else if (STRINGP (Vtty_dynamic_color_bg))
656     {
657       substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
658                                           Fsymbol_name (sym));
659       escseq = Dynarr_atp (sidcs_dynarr, 0);
660       escseqlen = Dynarr_length (sidcs_dynarr);
661     }
662 #endif
663
664   if (escseq)
665     {
666       send_string_to_tty_console (c, escseq, escseqlen);
667     }
668 }
669
670 static void
671 tty_turn_on_face_1 (struct console *c, int highlight_p,
672                     int blinking_p, int dim_p, int underline_p,
673                     int reverse_p, Lisp_Object cinst_fore,
674                     Lisp_Object cinst_back)
675 {
676   if (highlight_p)
677     {
678       OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
679     }
680
681   if (blinking_p)
682     {
683       OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
684     }
685
686   if (dim_p)
687     {
688       OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
689     }
690
691   if (underline_p)
692     {
693       /* #### punt for now if underline mode is glitchy */
694       if (!TTY_FLAGS (c).underline_width)
695         {
696           OUTPUT1_IF (c, TTY_SD (c).begin_underline);
697         }
698     }
699
700   if (reverse_p)
701     {
702       /* #### punt for now if standout mode is glitchy */
703       if (!TTY_FLAGS (c).standout_width)
704         {
705           OUTPUT1_IF (c, TTY_SD (c).begin_standout);
706         }
707       else
708         reverse_p = 0;
709     }
710
711   if (reverse_p)
712     {
713       Lisp_Object temp = cinst_fore;
714       cinst_fore = cinst_back;
715       cinst_back = temp;
716     }
717
718   if (COLOR_INSTANCEP (cinst_fore)
719       && !EQ (cinst_fore, Vthe_null_color_instance))
720     set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
721                        (XCOLOR_INSTANCE (cinst_fore)));
722
723   if (COLOR_INSTANCEP (cinst_back)
724       && !EQ (cinst_back, Vthe_null_color_instance))
725     set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
726                        (XCOLOR_INSTANCE (cinst_back)));
727 }
728
729 /*****************************************************************************
730  tty_turn_on_face
731
732  Turn on all set properties of the given face.
733  ****************************************************************************/
734 static void
735 tty_turn_on_face (struct window *w, face_index findex)
736 {
737   struct frame *f = XFRAME (w->frame);
738   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
739
740   tty_turn_on_face_1 (c,
741                       WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
742                       WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
743                       WINDOW_FACE_CACHEL_DIM_P (w, findex),
744                       WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
745                       WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
746                       WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
747                       WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
748 }
749
750 /*****************************************************************************
751  tty_turn_off_face
752
753  Turn off all set properties of the given face (revert to default
754  face).  We assume that tty_turn_on_face has been called for the given
755  face so that its properties are actually active.
756  ****************************************************************************/
757 static void
758 tty_turn_off_face (struct window *w, face_index findex)
759 {
760   struct frame *f = XFRAME (w->frame);
761   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
762
763   if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
764     {
765       /* #### punt for now if standout mode is glitchy */
766       if (!TTY_FLAGS (c).standout_width)
767         {
768           OUTPUT1_IF (c, TTY_SD (c).end_standout);
769         }
770     }
771
772   if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
773     {
774       /* #### punt for now if underline mode is glitchy */
775       if (!TTY_FLAGS (c).underline_width)
776         {
777           OUTPUT1_IF (c, TTY_SD (c).end_underline);
778         }
779     }
780
781   if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
782       WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
783       WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
784       !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
785            Vthe_null_color_instance) ||
786       !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
787            Vthe_null_color_instance))
788     {
789       OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
790     }
791 }
792
793 /*****************************************************************************
794  tty_turn_on_frame_face
795
796  Turn on all set properties of the given face.
797  ****************************************************************************/
798 static void
799 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
800 {
801   Lisp_Object frame;
802   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
803
804   XSETFRAME (frame, f);
805   tty_turn_on_face_1 (c,
806                       FACE_HIGHLIGHT_P (face, frame),
807                       FACE_BLINKING_P (face, frame),
808                       FACE_DIM_P (face, frame),
809                       FACE_UNDERLINE_P (face, frame),
810                       FACE_REVERSE_P (face, frame),
811                       FACE_FOREGROUND (face, frame),
812                       FACE_BACKGROUND (face, frame));
813 }
814
815 /*****************************************************************************
816  tty_turn_off_frame_face
817
818  Turn off all set properties of the given face (revert to default
819  face).  We assume that tty_turn_on_face has been called for the given
820  face so that its properties are actually active.
821  ****************************************************************************/
822 static void
823 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
824 {
825   Lisp_Object frame;
826   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
827
828   XSETFRAME (frame, f);
829
830   if (FACE_REVERSE_P (face, frame))
831     {
832       /* #### punt for now if standout mode is glitchy */
833       if (!TTY_FLAGS (c).standout_width)
834         {
835           OUTPUT1_IF (c, TTY_SD (c).end_standout);
836         }
837     }
838
839   if (FACE_UNDERLINE_P (face, frame))
840     {
841       /* #### punt for now if underline mode is glitchy */
842       if (!TTY_FLAGS (c).underline_width)
843         {
844           OUTPUT1_IF (c, TTY_SD (c).end_underline);
845         }
846     }
847
848   if (FACE_HIGHLIGHT_P (face, frame) ||
849       FACE_BLINKING_P (face, frame) ||
850       FACE_DIM_P (face, frame) ||
851       !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
852       !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
853     {
854       OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
855     }
856 }
857
858 /*****************************************************************************
859  set_tty_modes
860
861  Sets up various parameters on tty modes.
862  ****************************************************************************/
863 void
864 set_tty_modes (struct console *c)
865 {
866   if (!CONSOLE_TTY_P (c))
867     return;
868
869   OUTPUT1_IF (c, TTY_SD (c).init_motion);
870   OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
871   OUTPUT1_IF (c, TTY_SD (c).keypad_on);
872 }
873
874 /*****************************************************************************
875  reset_tty_modes
876
877  Restore default state of tty.
878  ****************************************************************************/
879 void
880 reset_tty_modes (struct console *c)
881 {
882   if (!CONSOLE_TTY_P (c))
883     return;
884
885   OUTPUT1_IF (c, TTY_SD (c).orig_pair);
886   OUTPUT1_IF (c, TTY_SD (c).keypad_off);
887   OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
888   OUTPUT1_IF (c, TTY_SD (c).end_motion);
889   tty_frame_output_end (XFRAME (CONSOLE_SELECTED_FRAME (c)));
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 /* FLAGS - these don't need to be console local since only one console
927            can be being updated at a time. */
928 static int insert_mode_on;              /* nonzero if in insert mode */
929 static int standout_mode_on;            /* nonzero if in standout mode */
930 static int underline_mode_on;           /* nonzero if in underline mode */
931 static int alternate_mode_on;           /* nonzero if in alternate char set */
932 static int attributes_on;               /* nonzero if any attributes on */
933
934 #ifdef NOT_YET
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 #if !defined(WIN32)
1062   /* SIGTT* don't exist under win32 */
1063   EMACS_BLOCK_SIGNAL (SIGTTOU);
1064 #endif
1065   status = tgetent (entry_buffer, terminal_type);
1066 #if !defined(WIN32)
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   /*
1221    * Initialize local flags.
1222    */
1223   insert_mode_on = 0;
1224   standout_mode_on = 0;
1225   underline_mode_on = 0;
1226   alternate_mode_on = 0;
1227   attributes_on = 0;
1228
1229   /*
1230    * Attempt to initialize the function_key_map to
1231    * some kind of sensible value
1232    */
1233
1234   term_get_fkeys (c->function_key_map, &bufptr);
1235
1236   {
1237     /* check for ANSI set-foreground and set-background strings,
1238        and assume color if so.
1239
1240        #### we should support the other (non-ANSI) ways of specifying
1241        color, too. */
1242     char foobuf[500];
1243     char *fooptr = foobuf;
1244     if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1245         (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1246         ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1247       DEVICE_CLASS (d) = Qcolor;
1248     else
1249       DEVICE_CLASS (d) = Qmono;
1250   }
1251
1252   return TTY_INIT_SUCCESS;
1253 }
1254 \f
1255 struct fkey_table
1256 {
1257   const char *cap;
1258   const char *name;
1259 };
1260
1261   /* Termcap capability names that correspond directly to X keysyms.
1262      Some of these (marked "terminfo") aren't supplied by old-style
1263      (Berkeley) termcap entries.  They're listed in X keysym order;
1264      except we put the keypad keys first, so that if they clash with
1265      other keys (as on the IBM PC keyboard) they get overridden.
1266   */
1267
1268 static struct fkey_table keys[] =
1269 {
1270   {"kh", "home"},       /* termcap */
1271   {"kl", "left"},       /* termcap */
1272   {"ku", "up"},         /* termcap */
1273   {"kr", "right"},      /* termcap */
1274   {"kd", "down"},       /* termcap */
1275   {"%8", "prior"},      /* terminfo */
1276   {"%5", "next"},       /* terminfo */
1277   {"@7", "end"},        /* terminfo */
1278   {"@1", "begin"},      /* terminfo */
1279   {"*6", "select"},     /* terminfo */
1280   {"%9", "print"},      /* terminfo */
1281   {"@4", "execute"},    /* terminfo --- actually the `command' key */
1282   /*
1283    * "insert" --- see below
1284    */
1285   {"&8", "undo"},       /* terminfo */
1286   {"%0", "redo"},       /* terminfo */
1287   {"%7", "menu"},       /* terminfo --- actually the `options' key */
1288   {"@0", "find"},       /* terminfo */
1289   {"@2", "cancel"},     /* terminfo */
1290   {"%1", "help"},       /* terminfo */
1291   /*
1292    * "break" goes here, but can't be reliably intercepted with termcap
1293    */
1294   {"&4", "reset"},      /* terminfo --- actually `restart' */
1295   /*
1296    * "system" and "user" --- no termcaps
1297    */
1298   {"kE", "clearline"},  /* terminfo */
1299   {"kA", "insertline"}, /* terminfo */
1300   {"kL", "deleteline"}, /* terminfo */
1301   {"kI", "insertchar"}, /* terminfo */
1302   {"kD", "delete"},     /* terminfo */
1303   {"kB", "backtab"},    /* terminfo */
1304   /*
1305    * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1306    */
1307   {"@8", "kp-enter"},   /* terminfo */
1308   /*
1309    * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1310    * "kp-multiply", "kp-add", "kp-separator",
1311    * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1312    * --- no termcaps for any of these.
1313    */
1314   {"K4", "kp-1"},       /* terminfo */
1315   /*
1316    * "kp-2" --- no termcap
1317    */
1318   {"K5", "kp-3"},       /* terminfo */
1319   /*
1320    * "kp-4" --- no termcap
1321    */
1322   {"K2", "kp-5"},       /* terminfo */
1323   /*
1324    * "kp-6" --- no termcap
1325    */
1326   {"K1", "kp-7"},       /* terminfo */
1327   /*
1328    * "kp-8" --- no termcap
1329    */
1330   {"K3", "kp-9"},       /* terminfo */
1331   /*
1332    * "kp-equal" --- no termcap
1333    */
1334   {"k1", "f1"},
1335   {"k2", "f2"},
1336   {"k3", "f3"},
1337   {"k4", "f4"},
1338   {"k5", "f5"},
1339   {"k6", "f6"},
1340   {"k7", "f7"},
1341   {"k8", "f8"},
1342   {"k9", "f9"},
1343 };
1344
1345 static char **term_get_fkeys_arg;
1346
1347 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1348 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1349
1350 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1351    This function scans the termcap function key sequence entries, and
1352    adds entries to Vfunction_key_map for each function key it finds.  */
1353
1354 static void
1355 term_get_fkeys (Lisp_Object keymap, char **address)
1356 {
1357   /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1358      errors during the call.  The only errors should be from Fdefine_key
1359      when given a key sequence containing an invalid prefix key.  If the
1360      termcap defines function keys which use a prefix that is already bound
1361      to a command by the default bindings, we should silently ignore that
1362      function key specification, rather than giving the user an error and
1363      refusing to run at all on such a terminal.  */
1364
1365   term_get_fkeys_arg = address;
1366
1367   condition_case_1 (Qerror,
1368                     term_get_fkeys_1, keymap,
1369                     term_get_fkeys_error, Qnil);
1370 }
1371
1372 static Lisp_Object
1373 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1374 {
1375   return arg;
1376 }
1377
1378 static Lisp_Object
1379 term_get_fkeys_1 (Lisp_Object function_key_map)
1380 {
1381   int i;
1382
1383   char **address = term_get_fkeys_arg;
1384
1385   for (i = 0; i < countof (keys); i++)
1386     {
1387       char *sequence = tgetstr (keys[i].cap, address);
1388       if (sequence)
1389         Fdefine_key (function_key_map,
1390                      build_ext_string (sequence, Qbinary),
1391                      vector1 (intern (keys[i].name)));
1392     }
1393
1394   /* The uses of the "k0" capability are inconsistent; sometimes it
1395      describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1396      We will attempt to politely accommodate both systems by testing for
1397      "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1398   */
1399   {
1400     const char *k_semi  = tgetstr ("k;", address);
1401     const char *k0      = tgetstr ("k0", address);
1402
1403     if (k_semi)
1404       Fdefine_key (function_key_map, build_ext_string (k_semi, Qbinary),
1405                    vector1 (intern ("f10")));
1406
1407     if (k0)
1408       Fdefine_key (function_key_map, build_ext_string (k0, Qbinary),
1409                    vector1 (intern (k_semi ? "f0" : "f10")));
1410   }
1411
1412   /* Set up cookies for numbered function keys above f10. */
1413   {
1414     char fcap[3], fkey[4];
1415
1416     fcap[0] = 'F'; fcap[2] = '\0';
1417     for (i = 11; i < 64; i++)
1418       {
1419         if (i <= 19)
1420           fcap[1] = '1' + i - 11;
1421         else if (i <= 45)
1422           fcap[1] = 'A' + i - 20;
1423         else
1424           fcap[1] = 'a' + i - 46;
1425
1426         {
1427           char *sequence = tgetstr (fcap, address);
1428           if (sequence)
1429             {
1430               sprintf (fkey, "f%d", i);
1431               Fdefine_key (function_key_map,
1432                            build_ext_string (sequence, Qbinary),
1433                            vector1 (intern (fkey)));
1434             }
1435         }
1436       }
1437   }
1438
1439   /*
1440    * Various mappings to try and get a better fit.
1441    */
1442 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) do {          \
1443     if (!tgetstr (cap1, address))                               \
1444       {                                                         \
1445         char *sequence = tgetstr (cap2, address);               \
1446         if (sequence)                                           \
1447           Fdefine_key (function_key_map,                        \
1448                        build_ext_string (sequence, Qbinary),    \
1449                        vector1 (intern (keyname)));             \
1450       }                                                         \
1451   } while (0)
1452
1453   /* if there's no key_next keycap, map key_npage to `next' keysym */
1454   CONDITIONAL_REASSIGN ("%5", "kN", "next");
1455   /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1456   CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1457   /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1458   CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1459
1460   /* IBM has their own non-standard dialect of terminfo.
1461      If the standard name isn't found, try the IBM name.  */
1462   CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1463   CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1464   CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1465   CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1466   CONDITIONAL_REASSIGN ("@7", "kw", "end");
1467   CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1468   CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1469   CONDITIONAL_REASSIGN ("%1", "kq", "help");
1470   CONDITIONAL_REASSIGN ("*6", "kU", "select");
1471 #undef CONDITIONAL_REASSIGN
1472
1473   return Qnil;
1474 }
1475
1476 \f
1477 /************************************************************************/
1478 /*                            initialization                            */
1479 /************************************************************************/
1480
1481 void
1482 console_type_create_redisplay_tty (void)
1483 {
1484   /* redisplay methods */
1485   CONSOLE_HAS_METHOD (tty, text_width);
1486   CONSOLE_HAS_METHOD (tty, output_display_block);
1487   CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1488   CONSOLE_HAS_METHOD (tty, divider_height);
1489   CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1490   CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1491   CONSOLE_HAS_METHOD (tty, clear_region);
1492   CONSOLE_HAS_METHOD (tty, clear_frame);
1493   CONSOLE_HAS_METHOD (tty, frame_output_begin);
1494   CONSOLE_HAS_METHOD (tty, frame_output_end);
1495   CONSOLE_HAS_METHOD (tty, flash);
1496   CONSOLE_HAS_METHOD (tty, ring_bell);
1497   CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);
1498 }