197036925c8460f4bdf6edf9cc78026b8ef6ba0a
[chise/xemacs-chise.git.1] / src / redisplay-tty.c
1 /* Communication module for TTY terminals.
2    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4    Copyright (C) 1995, 1996 Ben Wing.
5    Copyright (C) 1996 Chuck Thompson.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: Not completely synched with FSF.  Mostly divergent
25    from FSF. */
26
27 /* This file has been Mule-ized. */
28
29 /* Written by Chuck Thompson. */
30 /* Color support added by Ben Wing. */
31
32 #include <config.h>
33 #include "lisp.h"
34
35 #include "buffer.h"
36 #include "console-tty.h"
37 #include "events.h"
38 #include "faces.h"
39 #include "frame.h"
40 #include "glyphs.h"
41 #include "lstream.h"
42 #include "objects-tty.h"
43 #include "redisplay.h"
44 #include "sysdep.h"
45 #include "window.h"
46
47 /* These headers #define all kinds of common words like "columns"...
48    What a bunch of losers.  If we were to include them, we'd have to
49    include them last to prevent them from messing up our own header
50    files (struct slot names, etc.).  But it turns out that there are
51    other conflicts as well on some systems, so screw it: we'll just
52    re-declare the routines we use and assume the code in this file is
53    invoking them correctly. */
54 /* # include <curses.h> */
55 /* # include <term.h> */
56 EXTERN_C int tgetent (const char *, const char *);
57 EXTERN_C int tgetflag (const char *);
58 EXTERN_C int tgetnum (const char *);
59 EXTERN_C char *tgetstr (const char *, char **);
60 EXTERN_C void tputs (const char *, int, void (*)(int));
61
62 #define FORCE_CURSOR_UPDATE(c) send_string_to_tty_console (c, 0, 0)
63 #define OUTPUTN(c, a, n)                        \
64   do {                                          \
65     cmputc_console = c;                         \
66     FORCE_CURSOR_UPDATE (c);                    \
67     tputs (a, n, cmputc);                       \
68   } while (0)
69 #define OUTPUT1(c, a) OUTPUTN (c, a, 1)
70 #define OUTPUTN_IF(c, a, n)                     \
71   do {                                          \
72     cmputc_console = c;                         \
73     FORCE_CURSOR_UPDATE (c);                    \
74     if (a)                                      \
75       tputs (a, n, cmputc);                     \
76   } while (0)
77 #define OUTPUT1_IF(c, a) OUTPUTN_IF (c, a, 1)
78
79 static void tty_output_emchar_dynarr (struct window *w,
80                                       struct display_line *dl,
81                                       Emchar_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 emchar_string_displayed_columns().
103  ****************************************************************************/
104 static int
105 tty_text_width (struct frame *f, struct face_cachel *cachel, const Emchar *str,
106                 Charcount len)
107 {
108   return emchar_string_displayed_columns (str, len);
109 }
110
111 /*****************************************************************************
112  tty_divider_height
113
114  Return the width of the horizontal divider.  This is a function
115  because divider_height is a console method.
116  ****************************************************************************/
117 static int
118 tty_divider_height (void)
119 {
120   return 1;
121 }
122
123 /*****************************************************************************
124  tty_eol_cursor_width
125
126  Return the width of the end-of-line cursor.  This is a function
127  because eol_cursor_width is a console method.
128  ****************************************************************************/
129 static int
130 tty_eol_cursor_width (void)
131 {
132   return 1;
133 }
134
135 /*****************************************************************************
136  tty_frame_output_begin
137
138  Perform any necessary initialization prior to an update.
139  ****************************************************************************/
140 #ifdef DEBUG_XEMACS
141 void tty_frame_output_begin (struct frame *f);
142 void
143 #else
144 static void
145 #endif
146 tty_frame_output_begin (struct frame *f)
147 {
148 #ifndef HAVE_TERMIOS
149   /* Termcap requires `ospeed' to be a global variable so we have to
150      always set it for whatever tty console we are actually currently
151      working with. */
152   ospeed = DEVICE_TTY_DATA (XDEVICE (FRAME_DEVICE (f)))->ospeed;
153 #endif
154 }
155
156 /*****************************************************************************
157  tty_frame_output_end
158
159  Perform any necessary flushing of queues when an update has completed.
160  ****************************************************************************/
161 #ifdef DEBUG_XEMACS
162 void tty_frame_output_end (struct frame *f);
163 void
164 #else
165 static void
166 #endif
167 tty_frame_output_end (struct frame *f)
168 {
169   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
170
171   CONSOLE_TTY_CURSOR_X (c) = CONSOLE_TTY_FINAL_CURSOR_X (c);
172   CONSOLE_TTY_CURSOR_Y (c) = CONSOLE_TTY_FINAL_CURSOR_Y (c);
173   FORCE_CURSOR_UPDATE (c);
174   Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
175 }
176
177 static void
178 tty_set_final_cursor_coords (struct frame *f, int y, int x)
179 {
180   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
181
182   CONSOLE_TTY_FINAL_CURSOR_X (c) = x;
183   CONSOLE_TTY_FINAL_CURSOR_Y (c) = y;
184 }
185
186 /*****************************************************************************
187  tty_output_display_block
188
189  Given a display line, a block number for that start line, output all
190  runes between start and end in the specified display block.
191  ****************************************************************************/
192 static void
193 tty_output_display_block (struct window *w, struct display_line *dl, int block,
194                           int start, int end, int start_pixpos,
195                           int cursor_start, int cursor_width,
196                           int cursor_height)
197 {
198   struct frame *f = XFRAME (w->frame);
199   Emchar_dynarr *buf = Dynarr_new (Emchar);
200
201   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
202   rune_dynarr *rba = db->runes;
203   struct rune *rb;
204
205   int elt = start;
206   face_index findex;
207   int xpos;
208
209   rb = Dynarr_atp (rba, elt);
210
211   if (!rb)
212     {
213       /* Nothing to do so don't do anything. */
214       return;
215     }
216   else
217     {
218       findex = rb->findex;
219       xpos = rb->xpos;
220     }
221
222   if (end < 0)
223     end = Dynarr_length (rba);
224
225   Dynarr_reset (buf);
226
227   while (elt < end && Dynarr_atp (rba, elt)->xpos < start_pixpos)
228     {
229       elt++;
230       findex = Dynarr_atp (rba, elt)->findex;
231       xpos = Dynarr_atp (rba, elt)->xpos;
232     }
233
234   while (elt < end)
235     {
236       rb = Dynarr_atp (rba, elt);
237
238       if (rb->findex == findex && rb->type == RUNE_CHAR
239           && rb->object.chr.ch != '\n'
240           && (rb->cursor_type != CURSOR_ON
241               || NILP (w->text_cursor_visible_p)))
242         {
243           Dynarr_add (buf, rb->object.chr.ch);
244           elt++;
245         }
246       else
247         {
248           if (Dynarr_length (buf))
249             {
250               tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
251               xpos = rb->xpos;
252             }
253           Dynarr_reset (buf);
254
255           if (rb->type == RUNE_CHAR)
256             {
257               findex = rb->findex;
258               xpos = rb->xpos;
259
260               if (rb->object.chr.ch == '\n')
261                 {
262                   /* Clear in case a cursor was formerly here. */
263
264                   Dynarr_add (buf, ' ');
265                   tty_output_emchar_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.chr.ch);
278                   tty_output_emchar_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               Emchar ch_to_add;
293               int size = rb->width;
294
295               if (rb->type == RUNE_BLANK)
296                 ch_to_add = ' ';
297               else
298                 ch_to_add = '-';
299
300               while (size--)
301                 Dynarr_add (buf, ch_to_add);
302               tty_output_emchar_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_emchar_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_emchar_dynarr_dynarr;
541
542 /*****************************************************************************
543  tty_output_emchar_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_emchar_dynarr (struct window *w, struct display_line *dl,
550                           Emchar_dynarr *buf, int xpos, face_index findex,
551                           int cursor)
552 {
553   if (!tty_output_emchar_dynarr_dynarr)
554     tty_output_emchar_dynarr_dynarr = Dynarr_new (Bufbyte);
555   else
556     Dynarr_reset (tty_output_emchar_dynarr_dynarr);
557
558   convert_emchar_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
559                                             Dynarr_length (buf),
560                                             tty_output_emchar_dynarr_dynarr);
561
562   tty_output_bufbyte_string (w, dl,
563                              Dynarr_atp (tty_output_emchar_dynarr_dynarr, 0),
564                              Dynarr_length (tty_output_emchar_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   if (TTY_FLAGS (c).auto_margins)
869     OUTPUT1_IF (c, TTY_SD (c).disable_auto_margins);
870 }
871
872 /*****************************************************************************
873  reset_tty_modes
874
875  Restore default state of tty.
876  ****************************************************************************/
877 void
878 reset_tty_modes (struct console *c)
879 {
880   if (!CONSOLE_TTY_P (c))
881     return;
882
883   OUTPUT1_IF (c, TTY_SD (c).orig_pair);
884   OUTPUT1_IF (c, TTY_SD (c).keypad_off);
885   OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
886   OUTPUT1_IF (c, TTY_SD (c).end_motion);
887
888   if (TTY_FLAGS (c).auto_margins)
889     OUTPUT1_IF (c, TTY_SD (c).enable_auto_margins);
890
891   {
892     Lisp_Object frm = CONSOLE_SELECTED_FRAME (c);
893
894     if (!NILP (frm))
895       tty_frame_output_end (XFRAME (frm));
896   }
897 }
898
899 /*****************************************************************************
900  tty_redisplay_shutdown
901
902  Clear the frame and position the cursor properly for exiting.
903  ****************************************************************************/
904 void
905 tty_redisplay_shutdown (struct console *c)
906 {
907   Lisp_Object dev = CONSOLE_SELECTED_DEVICE (c);
908
909   if (!NILP (dev))
910     {
911       Lisp_Object frm = DEVICE_SELECTED_FRAME (XDEVICE (dev));
912
913       if (!NILP (frm))
914         {
915           struct frame *f = XFRAME (frm);
916
917           /* Clear the bottom line of the frame. */
918           redisplay_clear_region (FRAME_SELECTED_WINDOW (f), DEFAULT_INDEX, 0,
919                             f->height, f->width, 1);
920
921           /* And then stick the cursor there. */
922           tty_set_final_cursor_coords (f, f->height, 0);
923           tty_frame_output_end (f);
924         }
925     }
926 }
927
928
929 /* #### Everything below here is old shit.  It should either be moved
930    up or removed. */
931
932
933 #ifdef NOT_YET
934 /* FLAGS - these don't need to be console local since only one console
935            can be being updated at a time. */
936 static int insert_mode_on;              /* nonzero if in insert mode */
937 static int standout_mode_on;            /* nonzero if in standout mode */
938 static int underline_mode_on;           /* nonzero if in underline mode */
939 static int alternate_mode_on;           /* nonzero if in alternate char set */
940 static int attributes_on;               /* nonzero if any attributes on */
941
942 static void
943 turn_on_insert (struct frame *f)
944 {
945   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
946
947   if (!insert_mode_on)
948     OUTPUT1_IF (c, TTY_SE (c).begin_ins_mode);
949   insert_mode_on = 1;
950 }
951
952 static void
953 turn_off_insert (struct frame *f)
954 {
955   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
956
957   if (insert_mode_on)
958     OUTPUT1 (c, TTY_SE (c).end_ins_mode);
959   insert_mode_on = 0;
960 }
961
962 static void
963 internal_cursor_to (struct frame *f, int row, int col)
964 {
965   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
966
967   if (!TTY_FLAGS (c).insert_mode_motion)
968     turn_off_insert (f);
969   if (!TTY_FLAGS (c).standout_motion)
970     {
971       turn_off_standout (f);
972       turn_off_underline (f);
973       turn_off_alternate (f);
974     }
975
976   cmgoto (f, row, col);
977 }
978
979 static void
980 clear_to_end (struct frame *f)
981 {
982   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
983
984   /* assumes cursor is already positioned */
985   if (TTY_SE (c).clr_from_cursor)
986     {
987       OUTPUT1 (c, TTY_SE (c).clr_from_cursor);
988     }
989   else
990     {
991       int line = FRAME_CURSOR_Y (f);
992
993       while (line < FRAME_HEIGHT (f))
994         {
995           internal_cursor_to (f, line, 0);
996           OUTPUT1 (c, TTY_SE (c).clr_to_eol);
997         }
998     }
999 }
1000 #endif /* 0 */
1001 \f
1002 #if 0
1003 /*
1004  *  clear from last visible line on window to window end (presumably
1005  *  the line above window's modeline
1006  */
1007 static void
1008 tty_clear_window_end (struct window *w, int ystart, int yend)
1009 {
1010   struct console *c = XCONSOLE (WINDOW_CONSOLE (w));
1011   int line;
1012
1013   for (line = ystart; line < yend; line++)
1014     {
1015       cmgoto (XFRAME (w->frame), line, 0);
1016       OUTPUT1 (c, TTY_SE (c).clr_to_eol);
1017     }
1018 }
1019
1020 #endif /* 0 */
1021
1022 static int
1023 tty_flash (struct device *d)
1024 {
1025   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1026   if (TTY_SD (c).visual_bell)
1027     {
1028       OUTPUT1 (c, TTY_SD (c).visual_bell);
1029       Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1030       return 1;
1031     }
1032   else
1033     return 0;
1034 }
1035
1036 /*
1037  * tty_ring_bell - sound an audio beep.
1038  */
1039 static void
1040 tty_ring_bell (struct device *d, int volume, int pitch, int duration)
1041 {
1042   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1043
1044   if (volume)
1045     {
1046       OUTPUT1 (c, TTY_SD (c).audio_bell);
1047       Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
1048     }
1049 }
1050
1051
1052 int
1053 init_tty_for_redisplay (struct device *d, char *terminal_type)
1054 {
1055   int status;
1056   char entry_buffer[2044];
1057   /* char temp_buffer[2044]; */
1058   char *bufptr;
1059   struct console *c = XCONSOLE (DEVICE_CONSOLE (d));
1060
1061   /* What we should really do is allocate just enough space for
1062      the actual strings that are stored; but this would require
1063      doing this after all the tgetstr()s and adjusting all the
1064      pointers. */
1065   CONSOLE_TTY_DATA (c)->term_entry_buffer = (char *) xmalloc (2044);
1066   bufptr = CONSOLE_TTY_DATA (c)->term_entry_buffer;
1067
1068 #ifdef SIGTTOU
1069   /* SIGTT* don't exist under win32 */
1070   EMACS_BLOCK_SIGNAL (SIGTTOU);
1071 #endif
1072   status = tgetent (entry_buffer, terminal_type);
1073 #ifdef SIGTTOU
1074   EMACS_UNBLOCK_SIGNAL (SIGTTOU);
1075 #endif
1076 #if 0
1077   if (status < 0)
1078     return TTY_UNABLE_OPEN_DATABASE;
1079   else if (status == 0)
1080     return TTY_TYPE_UNDEFINED;
1081 #endif
1082   /* Under Linux at least, <0 is returned for TTY_TYPE_UNDEFINED. --ben */
1083   if (status <= 0)
1084     return TTY_TYPE_UNDEFINED;
1085
1086   /*
1087    * Establish the terminal size.
1088    */
1089   /* First try to get the info from the system.  If that fails, check
1090      the termcap entry. */
1091   get_tty_device_size (d, &CONSOLE_TTY_DATA (c)->width,
1092                        &CONSOLE_TTY_DATA (c)->height);
1093
1094   if (CONSOLE_TTY_DATA (c)->width <= 0)
1095     CONSOLE_TTY_DATA (c)->width = tgetnum ("co");
1096   if (CONSOLE_TTY_DATA (c)->height <= 0)
1097     CONSOLE_TTY_DATA (c)->height = tgetnum ("li");
1098
1099   if (CONSOLE_TTY_DATA (c)->width <= 0 || CONSOLE_TTY_DATA (c)->height <= 0)
1100     return TTY_SIZE_UNSPECIFIED;
1101
1102   /*
1103    * Initialize cursor motion information.
1104    */
1105
1106   /* local cursor movement */
1107   TTY_CM (c).up = tgetstr ("up", &bufptr);
1108   TTY_CM (c).down = tgetstr ("do", &bufptr);
1109   TTY_CM (c).left = tgetstr ("le", &bufptr);
1110   TTY_CM (c).right = tgetstr ("nd", &bufptr);
1111   TTY_CM (c).home = tgetstr ("ho", &bufptr);
1112   TTY_CM (c).low_left = tgetstr ("ll", &bufptr);
1113   TTY_CM (c).car_return = tgetstr ("cr", &bufptr);
1114
1115   /* absolute cursor motion */
1116   TTY_CM (c).abs = tgetstr ("cm", &bufptr);
1117   TTY_CM (c).hor_abs = tgetstr ("ch", &bufptr);
1118   TTY_CM (c).ver_abs = tgetstr ("cv", &bufptr);
1119
1120   /* Verify that the terminal is powerful enough to run Emacs */
1121   if (!TTY_CM (c).abs)
1122     {
1123       if (!TTY_CM (c).up || !TTY_CM (c).down
1124           || !TTY_CM (c).left || !TTY_CM (c).right)
1125         return TTY_TYPE_INSUFFICIENT;
1126     }
1127
1128   /* parameterized local cursor movement */
1129   TTY_CM (c).multi_up = tgetstr ("UP", &bufptr);
1130   TTY_CM (c).multi_down = tgetstr ("DO", &bufptr);
1131   TTY_CM (c).multi_left = tgetstr ("LE", &bufptr);
1132   TTY_CM (c).multi_right = tgetstr ("RI", &bufptr);
1133
1134   /* scrolling */
1135   TTY_CM (c).scroll_forw = tgetstr ("sf", &bufptr);
1136   TTY_CM (c).scroll_back = tgetstr ("sr", &bufptr);
1137   TTY_CM (c).multi_scroll_forw = tgetstr ("SF", &bufptr);
1138   TTY_CM (c).multi_scroll_back = tgetstr ("SR", &bufptr);
1139   TTY_CM (c).set_scroll_region = tgetstr ("cs", &bufptr);
1140
1141
1142   /*
1143    * Initialize screen editing information.
1144    */
1145
1146   /* adding to the screen */
1147   TTY_SE (c).ins_line = tgetstr ("al", &bufptr);
1148   TTY_SE (c).multi_ins_line = tgetstr ("AL", &bufptr);
1149   TTY_SE (c).repeat = tgetstr ("rp", &bufptr);
1150   TTY_SE (c).begin_ins_mode = tgetstr ("im", &bufptr);
1151   TTY_SE (c).end_ins_mode = tgetstr ("ei", &bufptr);
1152   TTY_SE (c).ins_char = tgetstr ("ic", &bufptr);
1153   TTY_SE (c).multi_ins_char = tgetstr ("IC", &bufptr);
1154   TTY_SE (c).insert_pad = tgetstr ("ip", &bufptr);
1155
1156   /* deleting from the screen */
1157   TTY_SE (c).clr_frame = tgetstr ("cl", &bufptr);
1158   TTY_SE (c).clr_from_cursor = tgetstr ("cd", &bufptr);
1159   TTY_SE (c).clr_to_eol = tgetstr ("ce", &bufptr);
1160   TTY_SE (c).del_line = tgetstr ("dl", &bufptr);
1161   TTY_SE (c).multi_del_line = tgetstr ("DL", &bufptr);
1162   TTY_SE (c).del_char = tgetstr ("dc", &bufptr);
1163   TTY_SE (c).multi_del_char = tgetstr ("DC", &bufptr);
1164   TTY_SE (c).begin_del_mode = tgetstr ("dm", &bufptr);
1165   TTY_SE (c).end_del_mode = tgetstr ("ed", &bufptr);
1166   TTY_SE (c).erase_at_cursor = tgetstr ("ec", &bufptr);
1167
1168
1169   /*
1170    * Initialize screen display information.
1171    */
1172   TTY_SD (c).begin_standout = tgetstr ("so", &bufptr);
1173   TTY_SD (c).end_standout = tgetstr ("se", &bufptr);
1174   TTY_SD (c).begin_underline = tgetstr ("us", &bufptr);
1175   TTY_SD (c).end_underline = tgetstr ("ue", &bufptr);
1176   TTY_SD (c).begin_alternate = tgetstr ("as", &bufptr);
1177   TTY_SD (c).end_alternate = tgetstr ("ae", &bufptr);
1178   TTY_SD (c).turn_on_reverse = tgetstr ("mr", &bufptr);
1179   TTY_SD (c).turn_on_blinking = tgetstr ("mb", &bufptr);
1180   TTY_SD (c).turn_on_bold = tgetstr ("md", &bufptr);
1181   TTY_SD (c).turn_on_dim = tgetstr ("mh", &bufptr);
1182   TTY_SD (c).turn_off_attributes = tgetstr ("me", &bufptr);
1183   TTY_SD (c).orig_pair = tgetstr ("op", &bufptr);
1184
1185   TTY_SD (c).visual_bell = tgetstr ("vb", &bufptr);
1186   TTY_SD (c).audio_bell = tgetstr ("bl", &bufptr);
1187   if (!TTY_SD (c).audio_bell)
1188     {
1189       /* If audio_bell doesn't get set, then assume C-g.  This is gross and
1190          ugly but is what Emacs has done from time immortal. */
1191       TTY_SD (c).audio_bell = "\07";
1192     }
1193
1194   TTY_SD (c).cursor_visible = tgetstr ("vs", &bufptr);
1195   TTY_SD (c).cursor_normal = tgetstr ("ve", &bufptr);
1196   TTY_SD (c).init_motion = tgetstr ("ti", &bufptr);
1197   TTY_SD (c).end_motion = tgetstr ("te", &bufptr);
1198   TTY_SD (c).keypad_on = tgetstr ("ks", &bufptr);
1199   TTY_SD (c).keypad_off = tgetstr ("ke", &bufptr);
1200   TTY_SD (c).disable_auto_margins = tgetstr ("RA", &bufptr);
1201   TTY_SD (c).enable_auto_margins = tgetstr ("SA", &bufptr);
1202
1203
1204   /*
1205    * Initialize additional terminal information.
1206    */
1207   TTY_FLAGS (c).must_write_spaces = tgetflag ("in");
1208   TTY_FLAGS (c).insert_mode_motion = tgetflag ("mi");
1209   TTY_FLAGS (c).standout_motion = tgetflag ("ms");
1210   TTY_FLAGS (c).memory_above_frame = tgetflag ("da");
1211   TTY_FLAGS (c).memory_below_frame = tgetflag ("db");
1212   TTY_FLAGS (c).standout_width = tgetnum ("sg");
1213   TTY_FLAGS (c).underline_width = tgetnum ("ug");
1214   TTY_FLAGS (c).auto_margins = tgetflag ("am");
1215
1216   if (TTY_FLAGS (c).standout_width == -1)
1217     TTY_FLAGS (c).standout_width = 0;
1218   if (TTY_FLAGS (c).underline_width == -1)
1219     TTY_FLAGS (c).underline_width = 0;
1220
1221    TTY_FLAGS (c).meta_key =
1222      eight_bit_tty (d) ? tgetflag ("km") || tgetflag ("MT") ? 1 : 2 : 0;
1223
1224
1225   /*
1226    * Setup the costs tables for this tty console.
1227    */
1228   cm_cost_init (c);
1229
1230 #ifdef NOT_YET
1231   /*
1232    * Initialize local flags.
1233    */
1234   insert_mode_on = 0;
1235   standout_mode_on = 0;
1236   underline_mode_on = 0;
1237   alternate_mode_on = 0;
1238   attributes_on = 0;
1239 #endif
1240
1241   /*
1242    * Attempt to initialize the function_key_map to
1243    * some kind of sensible value
1244    */
1245
1246   term_get_fkeys (c->function_key_map, &bufptr);
1247
1248   {
1249     /* check for ANSI set-foreground and set-background strings,
1250        and assume color if so.
1251
1252        #### we should support the other (non-ANSI) ways of specifying
1253        color, too. */
1254     char foobuf[500];
1255     char *fooptr = foobuf;
1256     if ((tgetstr ("AB", &fooptr) && tgetstr ("AF", &fooptr)) ||
1257         (tgetstr ("Sf", &fooptr) && tgetstr ("Sb", &fooptr)) ||
1258         ((tgetnum ("Co") > 0) && (tgetnum ("pa") > 0)))
1259       DEVICE_CLASS (d) = Qcolor;
1260     else
1261       DEVICE_CLASS (d) = Qmono;
1262   }
1263
1264   return TTY_INIT_SUCCESS;
1265 }
1266 \f
1267 struct fkey_table
1268 {
1269   const char *cap;
1270   const char *name;
1271 };
1272
1273   /* Termcap capability names that correspond directly to X keysyms.
1274      Some of these (marked "terminfo") aren't supplied by old-style
1275      (Berkeley) termcap entries.  They're listed in X keysym order;
1276      except we put the keypad keys first, so that if they clash with
1277      other keys (as on the IBM PC keyboard) they get overridden.
1278   */
1279
1280 static struct fkey_table keys[] =
1281 {
1282   {"kh", "home"},       /* termcap */
1283   {"kl", "left"},       /* termcap */
1284   {"ku", "up"},         /* termcap */
1285   {"kr", "right"},      /* termcap */
1286   {"kd", "down"},       /* termcap */
1287   {"%8", "prior"},      /* terminfo */
1288   {"%5", "next"},       /* terminfo */
1289   {"@7", "end"},        /* terminfo */
1290   {"@1", "begin"},      /* terminfo */
1291   {"*6", "select"},     /* terminfo */
1292   {"%9", "print"},      /* terminfo */
1293   {"@4", "execute"},    /* terminfo --- actually the `command' key */
1294   /*
1295    * "insert" --- see below
1296    */
1297   {"&8", "undo"},       /* terminfo */
1298   {"%0", "redo"},       /* terminfo */
1299   {"%7", "menu"},       /* terminfo --- actually the `options' key */
1300   {"@0", "find"},       /* terminfo */
1301   {"@2", "cancel"},     /* terminfo */
1302   {"%1", "help"},       /* terminfo */
1303   /*
1304    * "break" goes here, but can't be reliably intercepted with termcap
1305    */
1306   {"&4", "reset"},      /* terminfo --- actually `restart' */
1307   /*
1308    * "system" and "user" --- no termcaps
1309    */
1310   {"kE", "clearline"},  /* terminfo */
1311   {"kA", "insertline"}, /* terminfo */
1312   {"kL", "deleteline"}, /* terminfo */
1313   {"kI", "insertchar"}, /* terminfo */
1314   {"kD", "delete"},     /* terminfo */
1315   {"kB", "backtab"},    /* terminfo */
1316   /*
1317    * "kp-backtab", "kp-space", "kp-tab" --- no termcaps
1318    */
1319   {"@8", "kp-enter"},   /* terminfo */
1320   /*
1321    * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1322    * "kp-multiply", "kp-add", "kp-separator",
1323    * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1324    * --- no termcaps for any of these.
1325    */
1326   {"K4", "kp-1"},       /* terminfo */
1327   /*
1328    * "kp-2" --- no termcap
1329    */
1330   {"K5", "kp-3"},       /* terminfo */
1331   /*
1332    * "kp-4" --- no termcap
1333    */
1334   {"K2", "kp-5"},       /* terminfo */
1335   /*
1336    * "kp-6" --- no termcap
1337    */
1338   {"K1", "kp-7"},       /* terminfo */
1339   /*
1340    * "kp-8" --- no termcap
1341    */
1342   {"K3", "kp-9"},       /* terminfo */
1343   /*
1344    * "kp-equal" --- no termcap
1345    */
1346   {"k1", "f1"},
1347   {"k2", "f2"},
1348   {"k3", "f3"},
1349   {"k4", "f4"},
1350   {"k5", "f5"},
1351   {"k6", "f6"},
1352   {"k7", "f7"},
1353   {"k8", "f8"},
1354   {"k9", "f9"},
1355 };
1356
1357 static char **term_get_fkeys_arg;
1358
1359 static Lisp_Object term_get_fkeys_1 (Lisp_Object keymap);
1360 static Lisp_Object term_get_fkeys_error (Lisp_Object err, Lisp_Object arg);
1361
1362 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1363    This function scans the termcap function key sequence entries, and
1364    adds entries to Vfunction_key_map for each function key it finds.  */
1365
1366 static void
1367 term_get_fkeys (Lisp_Object keymap, char **address)
1368 {
1369   /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1370      errors during the call.  The only errors should be from Fdefine_key
1371      when given a key sequence containing an invalid prefix key.  If the
1372      termcap defines function keys which use a prefix that is already bound
1373      to a command by the default bindings, we should silently ignore that
1374      function key specification, rather than giving the user an error and
1375      refusing to run at all on such a terminal.  */
1376
1377   term_get_fkeys_arg = address;
1378
1379   condition_case_1 (Qerror,
1380                     term_get_fkeys_1, keymap,
1381                     term_get_fkeys_error, Qnil);
1382 }
1383
1384 static Lisp_Object
1385 term_get_fkeys_error (Lisp_Object err, Lisp_Object arg)
1386 {
1387   return arg;
1388 }
1389
1390 static Lisp_Object
1391 term_get_fkeys_1 (Lisp_Object function_key_map)
1392 {
1393   int i;
1394
1395   char **address = term_get_fkeys_arg;
1396
1397   for (i = 0; i < countof (keys); i++)
1398     {
1399       char *sequence = tgetstr (keys[i].cap, address);
1400       if (sequence)
1401         Fdefine_key (function_key_map,
1402                      build_ext_string (sequence, Qbinary),
1403                      vector1 (intern (keys[i].name)));
1404     }
1405
1406   /* The uses of the "k0" capability are inconsistent; sometimes it
1407      describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1408      We will attempt to politely accommodate both systems by testing for
1409      "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1410   */
1411   {
1412     const char *k_semi  = tgetstr ("k;", address);
1413     const char *k0      = tgetstr ("k0", address);
1414
1415     if (k_semi)
1416       Fdefine_key (function_key_map, build_ext_string (k_semi, Qbinary),
1417                    vector1 (intern ("f10")));
1418
1419     if (k0)
1420       Fdefine_key (function_key_map, build_ext_string (k0, Qbinary),
1421                    vector1 (intern (k_semi ? "f0" : "f10")));
1422   }
1423
1424   /* Set up cookies for numbered function keys above f10. */
1425   {
1426     char fcap[3], fkey[4];
1427
1428     fcap[0] = 'F'; fcap[2] = '\0';
1429     for (i = 11; i < 64; i++)
1430       {
1431         if (i <= 19)
1432           fcap[1] = '1' + i - 11;
1433         else if (i <= 45)
1434           fcap[1] = 'A' + i - 20;
1435         else
1436           fcap[1] = 'a' + i - 46;
1437
1438         {
1439           char *sequence = tgetstr (fcap, address);
1440           if (sequence)
1441             {
1442               sprintf (fkey, "f%d", i);
1443               Fdefine_key (function_key_map,
1444                            build_ext_string (sequence, Qbinary),
1445                            vector1 (intern (fkey)));
1446             }
1447         }
1448       }
1449   }
1450
1451   /*
1452    * Various mappings to try and get a better fit.
1453    */
1454 #define CONDITIONAL_REASSIGN(cap1, cap2, keyname) do {          \
1455     if (!tgetstr (cap1, address))                               \
1456       {                                                         \
1457         char *sequence = tgetstr (cap2, address);               \
1458         if (sequence)                                           \
1459           Fdefine_key (function_key_map,                        \
1460                        build_ext_string (sequence, Qbinary),    \
1461                        vector1 (intern (keyname)));             \
1462       }                                                         \
1463   } while (0)
1464
1465   /* if there's no key_next keycap, map key_npage to `next' keysym */
1466   CONDITIONAL_REASSIGN ("%5", "kN", "next");
1467   /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1468   CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1469   /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1470   CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1471
1472   /* IBM has their own non-standard dialect of terminfo.
1473      If the standard name isn't found, try the IBM name.  */
1474   CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1475   CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1476   CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1477   CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1478   CONDITIONAL_REASSIGN ("@7", "kw", "end");
1479   CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1480   CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1481   CONDITIONAL_REASSIGN ("%1", "kq", "help");
1482   CONDITIONAL_REASSIGN ("*6", "kU", "select");
1483 #undef CONDITIONAL_REASSIGN
1484
1485   return Qnil;
1486 }
1487
1488 \f
1489 /************************************************************************/
1490 /*                            initialization                            */
1491 /************************************************************************/
1492
1493 void
1494 console_type_create_redisplay_tty (void)
1495 {
1496   /* redisplay methods */
1497   CONSOLE_HAS_METHOD (tty, text_width);
1498   CONSOLE_HAS_METHOD (tty, output_display_block);
1499   CONSOLE_HAS_METHOD (tty, output_vertical_divider);
1500   CONSOLE_HAS_METHOD (tty, divider_height);
1501   CONSOLE_HAS_METHOD (tty, eol_cursor_width);
1502   CONSOLE_HAS_METHOD (tty, clear_to_window_end);
1503   CONSOLE_HAS_METHOD (tty, clear_region);
1504   CONSOLE_HAS_METHOD (tty, clear_frame);
1505   CONSOLE_HAS_METHOD (tty, frame_output_begin);
1506   CONSOLE_HAS_METHOD (tty, frame_output_end);
1507   CONSOLE_HAS_METHOD (tty, flash);
1508   CONSOLE_HAS_METHOD (tty, ring_bell);
1509   CONSOLE_HAS_METHOD (tty, set_final_cursor_coords);
1510 }