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