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