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