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