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