XEmacs 21.2.36 "Notos"
[chise/xemacs-chise.git.1] / src / redisplay-tty.c
1 /* Communication module for TTY terminals.
2    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4    Copyright (C) 1995, 1996 Ben Wing.
5    Copyright (C) 1996 Chuck Thompson.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: Not completely synched with FSF.  Mostly divergent
25    from FSF. */
26
27 /* This file has been Mule-ized. */
28
29 /* Written by Chuck Thompson. */
30 /* Color support added by Ben Wing. */
31
32 #include <config.h>
33 #include "lisp.h"
34
35 #include "buffer.h"
36 #include "console-tty.h"
37 #include "events.h"
38 #include "faces.h"
39 #include "frame.h"
40 #include "glyphs.h"
41 #include "lstream.h"
42 #include "objects-tty.h"
43 #include "redisplay.h"
44 #include "sysdep.h"
45 #include "window.h"
46
47 /* These headers #define all kinds of common words like "columns"...
48    What a bunch of losers.  If we were to include them, we'd have to
49    include them last to prevent them from messing up our own header
50    files (struct slot names, etc.).  But it turns out that there are
51    other conflicts as well on some systems, so screw it: we'll just
52    re-declare the routines we use and assume the code in this file is
53    invoking them correctly. */
54 /* # include <curses.h> */
55 /* # include <term.h> */
56 EXTERN_C int tgetent (const char *, const char *);
57 EXTERN_C int tgetflag (const char *);
58 EXTERN_C int tgetnum (const char *);
59 EXTERN_C char *tgetstr (const char *, char **);
60 EXTERN_C void tputs (const char *, int, void (*)(int));
61
62 #define FORCE_CURSOR_UPDATE(c) send_string_to_tty_console (c, 0, 0)
63 #define OUTPUTN(c, a, n)                        \
64   do {                                          \
65     cmputc_console = c;                         \
66     FORCE_CURSOR_UPDATE (c);                    \
67     tputs (a, n, cmputc);                       \
68   } while (0)
69 #define OUTPUT1(c, a) OUTPUTN (c, a, 1)
70 #define OUTPUTN_IF(c, a, n)                     \
71   do {                                          \
72     cmputc_console = c;                         \
73     FORCE_CURSOR_UPDATE (c);                    \
74     if (a)                                      \
75       tputs (a, n, cmputc);                     \
76   } while (0)
77 #define OUTPUT1_IF(c, a) OUTPUTN_IF (c, a, 1)
78
79 static void tty_output_emchar_dynarr (struct window *w,
80                                       struct display_line *dl,
81                                       Emchar_dynarr *buf, int xpos,
82                                       face_index findex,
83                                       int cursor);
84 static void tty_output_bufbyte_string (struct window *w,
85                                        struct display_line *dl,
86                                        Bufbyte *str, Bytecount len,
87                                        int xpos, face_index findex,
88                                        int cursor);
89 static void tty_turn_on_face (struct window *w, face_index findex);
90 static void tty_turn_off_face (struct window *w, face_index findex);
91 static void tty_turn_on_frame_face (struct frame *f, Lisp_Object face);
92 static void tty_turn_off_frame_face (struct frame *f, Lisp_Object face);
93
94 static void term_get_fkeys (Lisp_Object keymap, char **address);
95
96 /*****************************************************************************
97  tty_text_width
98
99  Non-Mule tty's don't have fonts (that we use at least), so everything
100  is considered to be fixed width -- in other words, we return LEN.
101  Under Mule, however, a character can still cover more than one
102  column, so we use emchar_string_displayed_columns().
103  ****************************************************************************/
104 static int
105 tty_text_width (struct frame *f, struct face_cachel *cachel, const Emchar *str,
106                 Charcount len)
107 {
108   return emchar_string_displayed_columns (str, len);
109 }
110
111 /*****************************************************************************
112  tty_divider_height
113
114  Return the width of the horizontal divider.  This is a function
115  because divider_height is a console method.
116  ****************************************************************************/
117 static int
118 tty_divider_height (void)
119 {
120   return 1;
121 }
122
123 /*****************************************************************************
124  tty_eol_cursor_width
125
126  Return the width of the end-of-line cursor.  This is a function
127  because eol_cursor_width is a console method.
128  ****************************************************************************/
129 static int
130 tty_eol_cursor_width (void)
131 {
132   return 1;
133 }
134
135 /*****************************************************************************
136  tty_frame_output_begin
137
138  Perform any necessary initialization prior to an update.
139  ****************************************************************************/
140 #ifdef DEBUG_XEMACS
141 void tty_frame_output_begin (struct frame *f);
142 void
143 #else
144 static void
145 #endif
146 tty_frame_output_begin (struct frame *f)
147 {
148 #ifndef HAVE_TERMIOS
149   /* Termcap requires `ospeed' to be a global variable so we have to
150      always set it for whatever tty console we are actually currently
151      working with. */
152   ospeed = DEVICE_TTY_DATA (XDEVICE (FRAME_DEVICE (f)))->ospeed;
153 #endif
154 }
155
156 /*****************************************************************************
157  tty_frame_output_end
158
159  Perform any necessary flushing of queues when an update has completed.
160  ****************************************************************************/
161 #ifdef DEBUG_XEMACS
162 void tty_frame_output_end (struct frame *f);
163 void
164 #else
165 static void
166 #endif
167 tty_frame_output_end (struct frame *f)
168 {
169   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
170
171   CONSOLE_TTY_CURSOR_X (c) = CONSOLE_TTY_FINAL_CURSOR_X (c);
172   CONSOLE_TTY_CURSOR_Y (c) = CONSOLE_TTY_FINAL_CURSOR_Y (c);
173   FORCE_CURSOR_UPDATE (c);
174   Lstream_flush (XLSTREAM (CONSOLE_TTY_DATA (c)->outstream));
175 }
176
177 static void
178 tty_set_final_cursor_coords (struct frame *f, int y, int x)
179 {
180   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
181
182   CONSOLE_TTY_FINAL_CURSOR_X (c) = x;
183   CONSOLE_TTY_FINAL_CURSOR_Y (c) = y;
184 }
185
186 /*****************************************************************************
187  tty_output_display_block
188
189  Given a display line, a block number for that start line, output all
190  runes between start and end in the specified display block.
191  ****************************************************************************/
192 static void
193 tty_output_display_block (struct window *w, struct display_line *dl, int block,
194                           int start, int end, int start_pixpos,
195                           int cursor_start, int cursor_width,
196                           int cursor_height)
197 {
198   struct frame *f = XFRAME (w->frame);
199   Emchar_dynarr *buf = Dynarr_new (Emchar);
200
201   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
202   rune_dynarr *rba = db->runes;
203   struct rune *rb;
204
205   int elt = start;
206   face_index findex;
207   int xpos;
208
209   rb = Dynarr_atp (rba, elt);
210
211   if (!rb)
212     {
213       /* Nothing to do so don't do anything. */
214       return;
215     }
216   else
217     {
218       findex = rb->findex;
219       xpos = rb->xpos;
220     }
221
222   if (end < 0)
223     end = Dynarr_length (rba);
224
225   Dynarr_reset (buf);
226
227   while (elt < end && Dynarr_atp (rba, elt)->xpos < start_pixpos)
228     {
229       elt++;
230       findex = Dynarr_atp (rba, elt)->findex;
231       xpos = Dynarr_atp (rba, elt)->xpos;
232     }
233
234   while (elt < end)
235     {
236       rb = Dynarr_atp (rba, elt);
237
238       if (rb->findex == findex && rb->type == RUNE_CHAR
239           && rb->object.chr.ch != '\n'
240           && (rb->cursor_type != CURSOR_ON
241               || NILP (w->text_cursor_visible_p)))
242         {
243           Dynarr_add (buf, rb->object.chr.ch);
244           elt++;
245         }
246       else
247         {
248           if (Dynarr_length (buf))
249             {
250               tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
251               xpos = rb->xpos;
252             }
253           Dynarr_reset (buf);
254
255           if (rb->type == RUNE_CHAR)
256             {
257               findex = rb->findex;
258               xpos = rb->xpos;
259
260               if (rb->object.chr.ch == '\n')
261                 {
262                   /* Clear in case a cursor was formerly here. */
263
264                   Dynarr_add (buf, ' ');
265                   tty_output_emchar_dynarr (w, dl, buf, rb->xpos,
266                                             DEFAULT_INDEX, 0);
267                   Dynarr_reset (buf);
268
269                   cmgoto (f, dl->ypos - 1, rb->xpos);
270
271                   elt++;
272                 }
273               else if (rb->cursor_type == CURSOR_ON)
274                 {
275                   /* There is not a distinct eol cursor on tty's. */
276
277                   Dynarr_add (buf, rb->object.chr.ch);
278                   tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
279                   Dynarr_reset (buf);
280
281                   cmgoto (f, dl->ypos - 1, xpos);
282
283                   xpos += rb->width;
284                   elt++;
285                 }
286             }
287           /* #### RUNE_HLINE is actually a little more complicated than this
288              but at the moment it is only used to draw a turned off
289              modeline and this will suffice for that. */
290           else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
291             {
292               Emchar ch_to_add;
293               int size = rb->width;
294
295               if (rb->type == RUNE_BLANK)
296                 ch_to_add = ' ';
297               else
298                 ch_to_add = '-';
299
300               while (size--)
301                 Dynarr_add (buf, ch_to_add);
302               tty_output_emchar_dynarr (w, dl, buf, rb->xpos, findex, 0);
303
304               if (xpos >= cursor_start
305                   && cursor_start < xpos + Dynarr_length (buf))
306                 {
307                   cmgoto (f, dl->ypos - 1, cursor_start);
308                 }
309
310               Dynarr_reset (buf);
311
312               elt++;
313               if (elt < end)
314                 {
315                   rb = Dynarr_atp (rba, elt);
316
317                   findex = rb->findex;
318                   xpos = rb->xpos;
319                 }
320             }
321           else if (rb->type == RUNE_DGLYPH)
322             {
323               Lisp_Object window;
324               Lisp_Object instance;
325
326               XSETWINDOW (window, w);
327               instance = glyph_image_instance (rb->object.dglyph.glyph,
328                                                window, ERROR_ME_NOT, 1);
329
330               if (IMAGE_INSTANCEP (instance))
331                 {
332                   switch (XIMAGE_INSTANCE_TYPE (instance))
333                     {
334                     case IMAGE_MONO_PIXMAP:
335                     case IMAGE_COLOR_PIXMAP:
336                     case IMAGE_SUBWINDOW:
337                     case IMAGE_WIDGET:
338                       /* just do nothing here */
339                       break;
340
341                     case IMAGE_NOTHING:
342                       /* nothing is as nothing does */
343                       break;
344
345                     case IMAGE_TEXT:
346                     case IMAGE_POINTER:
347                     default:
348                       abort ();
349                     }
350                   IMAGE_INSTANCE_OPTIMIZE_OUTPUT
351                     (XIMAGE_INSTANCE (instance)) = 0;
352                 }
353
354               xpos += rb->width;
355               elt++;
356             }
357           else
358             abort ();
359         }
360     }
361
362   if (Dynarr_length (buf))
363     tty_output_emchar_dynarr (w, dl, buf, xpos, findex, 0);
364   Dynarr_free (buf);
365
366 }
367
368
369
370 /*****************************************************************************
371  tty_output_vertical_divider
372
373  Draw a vertical divider down the right side of the given window.
374  ****************************************************************************/
375 static void
376 tty_output_vertical_divider (struct window *w, int clear)
377 {
378   /* Divider width can either be 0 or 1 on TTYs */
379   if (window_divider_width (w))
380     {
381       struct frame *f = XFRAME (w->frame);
382       struct console *c = XCONSOLE (FRAME_CONSOLE (f));
383       int line;
384       int y_top = WINDOW_TEXT_TOP (w);
385       int y_bot = WINDOW_TEXT_BOTTOM (w);
386       unsigned char divv = '|';
387
388       tty_turn_on_face (w, MODELINE_INDEX);
389       for (line = y_top; line < y_bot; line++)
390         {
391           cmgoto (f, line, WINDOW_TEXT_RIGHT (w));
392           send_string_to_tty_console (c, &divv, 1);
393           TTY_INC_CURSOR_X (c, 1);
394         }
395
396       /* Draw the divider in the modeline. */
397       cmgoto (f, y_bot, WINDOW_TEXT_RIGHT (w));
398       send_string_to_tty_console (c, &divv, 1);
399       TTY_INC_CURSOR_X (c, 1);
400       tty_turn_off_face (w, MODELINE_INDEX);
401     }
402 }
403
404 /****************************************************************************
405  tty_clear_region
406
407  Clear the area in the box defined by the given parameters.
408  ****************************************************************************/
409 static void
410 tty_clear_region (Lisp_Object window, struct device* d, struct frame * f,
411                   face_index findex, int x, int y,
412                   int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
413                   Lisp_Object background_pixmap)
414 {
415   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
416   int line;
417   struct window* w = XWINDOW (window);
418
419   tty_turn_on_face (w, findex);
420   for (line = y; line < y + height; line++)
421     {
422       int col;
423
424       cmgoto (f, line, x);
425
426       if (window_is_leftmost (w)
427           && window_is_rightmost (w)
428           && TTY_SE (c).clr_to_eol)
429         {
430           OUTPUT1 (c, TTY_SE (c).clr_to_eol);
431         }
432       else
433         {
434           unsigned char sp = ' ';
435           /* #### Of course, this is all complete and utter crap. */
436           for (col = x; col < x + width; col++)
437             send_string_to_tty_console (c, &sp, 1);
438           TTY_INC_CURSOR_X (c, width);
439         }
440     }
441   tty_turn_off_face (w, findex);
442   cmgoto (f, y, x);
443 }
444
445 /*****************************************************************************
446  tty_clear_to_window_end
447
448  Clear the area between ypos1 and ypos2.  Each margin area and the
449  text area is handled separately since they may each have their own
450  background color.
451  ****************************************************************************/
452 static void
453 tty_clear_to_window_end (struct window *w, int ypos1, int ypos2)
454 {
455   struct frame *f = XFRAME (w->frame);
456   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
457   int x, width;
458
459   x = WINDOW_TEXT_LEFT (w);
460   width = WINDOW_TEXT_WIDTH (w);
461
462   if (window_is_rightmost (w))
463     {
464       /* #### Optimize to use clr_to_eol function of tty if available, if
465          the window is the entire width of the frame. */
466       /* #### Is this actually an optimization? */
467       int line;
468       tty_turn_on_face (w, DEFAULT_INDEX);
469       for (line = ypos1; line < ypos2; line++)
470         {
471           cmgoto (XFRAME (w->frame), line, x);
472           OUTPUT1 (c, TTY_SE (c).clr_to_eol);
473         }
474       tty_turn_off_face (w, DEFAULT_INDEX);
475     }
476   else
477     {
478       Lisp_Object window;
479
480       XSETWINDOW (window, w);
481       redisplay_clear_region (window, DEFAULT_INDEX, x, ypos1, width, ypos2 - ypos1);
482     }
483 }
484
485 /****************************************************************************
486  tty_clear_frame
487
488  Clear the entire frame.
489  ****************************************************************************/
490 static void
491 tty_clear_frame (struct frame *f)
492 {
493   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
494
495   tty_turn_on_frame_face (f, Vdefault_face);
496   if (TTY_SE (c).clr_frame)
497     {
498       OUTPUT1 (c, TTY_SE (c).clr_frame);
499       CONSOLE_TTY_REAL_CURSOR_X (c) = 0;
500       CONSOLE_TTY_REAL_CURSOR_Y (c) = 0;
501 #ifdef NOT_SURE
502       FRAME_CURSOR_X (f) = 0;
503       FRAME_CURSOR_Y (f) = 0;
504 #endif
505     }
506   else
507     {
508 #ifdef NOT_SURE
509       internal_cursor_to (f, 0, 0);
510       clear_to_end (f);
511 #else
512       /* #### Not implemented. */
513       stderr_out ("Not yet.\n");
514 #endif
515     }
516   tty_turn_off_frame_face (f, Vdefault_face);
517 }
518
519 static void
520 tty_output_bufbyte_string (struct window *w, struct display_line *dl,
521                            Bufbyte *str, Bytecount len, int xpos,
522                            face_index findex, int cursor)
523 {
524   struct frame *f = XFRAME (w->frame);
525   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
526
527   /* First position the cursor. */
528   cmgoto (f, dl->ypos - 1, xpos);
529
530   /* Enable any face properties. */
531   tty_turn_on_face (w, findex);
532
533   send_string_to_tty_console (c, str, len);
534   TTY_INC_CURSOR_X (c, bufbyte_string_displayed_columns (str, len));
535
536   /* Turn the face properties back off. */
537   tty_turn_off_face (w, findex);
538 }
539
540 static Bufbyte_dynarr *tty_output_emchar_dynarr_dynarr;
541
542 /*****************************************************************************
543  tty_output_emchar_dynarr
544
545  Given a string and a starting position, output that string in the
546  given face.  If cursor is true, draw a cursor around the string.
547  ****************************************************************************/
548 static void
549 tty_output_emchar_dynarr (struct window *w, struct display_line *dl,
550                           Emchar_dynarr *buf, int xpos, face_index findex,
551                           int cursor)
552 {
553   if (!tty_output_emchar_dynarr_dynarr)
554     tty_output_emchar_dynarr_dynarr = Dynarr_new (Bufbyte);
555   else
556     Dynarr_reset (tty_output_emchar_dynarr_dynarr);
557
558   convert_emchar_string_into_bufbyte_dynarr (Dynarr_atp (buf, 0),
559                                             Dynarr_length (buf),
560                                             tty_output_emchar_dynarr_dynarr);
561
562   tty_output_bufbyte_string (w, dl,
563                              Dynarr_atp (tty_output_emchar_dynarr_dynarr, 0),
564                              Dynarr_length (tty_output_emchar_dynarr_dynarr),
565                              xpos, findex, cursor);
566 }
567
568 #if 0
569
570 static Bufbyte_dynarr *sidcs_dynarr;
571
572 static void
573 substitute_in_dynamic_color_string (Lisp_Object spec, Lisp_Object string)
574 {
575   int i;
576   Bufbyte *specdata = XSTRING_DATA   (spec);
577   Bytecount speclen = XSTRING_LENGTH (spec);
578
579   if (!sidcs_dynarr)
580     sidcs_dynarr = Dynarr_new (Bufbyte);
581   else
582     Dynarr_reset (sidcs_dynarr);
583
584   for (i = 0; i < speclen; i++)
585     {
586       if (specdata[i] == '%' && specdata[i+1] == '%')
587         {
588           Dynarr_add (sidcs_dynarr, '%');
589           i++;
590         }
591       else if (specdata[i] == '%' && specdata[i+1] == 's')
592         {
593           Dynarr_add_many (sidcs_dynarr,
594                            XSTRING_DATA   (string),
595                            XSTRING_LENGTH (string));
596           i++;
597         }
598       else
599         Dynarr_add (sidcs_dynarr, specdata[i]);
600     }
601 }
602
603 #endif
604
605 static void
606 set_foreground_to (struct console *c, Lisp_Object sym)
607 {
608   Lisp_Object result;
609   Bufbyte *escseq = 0;
610   Bytecount escseqlen = 0;
611
612   result = assq_no_quit (sym, Vtty_color_alist);
613   if (!NILP (result))
614     {
615       Lisp_Object esc_seq = XCAR (XCDR (result));
616       escseq    = XSTRING_DATA   (esc_seq);
617       escseqlen = XSTRING_LENGTH (esc_seq);
618     }
619 #if 0
620   else if (STRINGP (Vtty_dynamic_color_fg))
621     {
622       substitute_in_dynamic_color_string (Vtty_dynamic_color_fg,
623                                           Fsymbol_name (sym));
624       escseq = Dynarr_atp (sidcs_dynarr, 0);
625       escseqlen = Dynarr_length (sidcs_dynarr);
626     }
627 #endif
628
629   if (escseq)
630     {
631       send_string_to_tty_console (c, escseq, escseqlen);
632     }
633 }
634
635 static void
636 set_background_to (struct console *c, Lisp_Object sym)
637 {
638   Lisp_Object result;
639   Bufbyte *escseq = 0;
640   Bytecount escseqlen = 0;
641
642   result = assq_no_quit (sym, Vtty_color_alist);
643   if (!NILP (result))
644     {
645       Lisp_Object esc_seq = XCDR (XCDR (result));
646       escseq    = XSTRING_DATA   (esc_seq);
647       escseqlen = XSTRING_LENGTH (esc_seq);
648     }
649 #if 0
650   else if (STRINGP (Vtty_dynamic_color_bg))
651     {
652       substitute_in_dynamic_color_string (Vtty_dynamic_color_bg,
653                                           Fsymbol_name (sym));
654       escseq = Dynarr_atp (sidcs_dynarr, 0);
655       escseqlen = Dynarr_length (sidcs_dynarr);
656     }
657 #endif
658
659   if (escseq)
660     {
661       send_string_to_tty_console (c, escseq, escseqlen);
662     }
663 }
664
665 static void
666 tty_turn_on_face_1 (struct console *c, int highlight_p,
667                     int blinking_p, int dim_p, int underline_p,
668                     int reverse_p, Lisp_Object cinst_fore,
669                     Lisp_Object cinst_back)
670 {
671   if (highlight_p)
672     {
673       OUTPUT1_IF (c, TTY_SD (c).turn_on_bold);
674     }
675
676   if (blinking_p)
677     {
678       OUTPUT1_IF (c, TTY_SD (c).turn_on_blinking);
679     }
680
681   if (dim_p)
682     {
683       OUTPUT1_IF (c, TTY_SD (c).turn_on_dim);
684     }
685
686   if (underline_p)
687     {
688       /* #### punt for now if underline mode is glitchy */
689       if (!TTY_FLAGS (c).underline_width)
690         {
691           OUTPUT1_IF (c, TTY_SD (c).begin_underline);
692         }
693     }
694
695   if (reverse_p)
696     {
697       /* #### punt for now if standout mode is glitchy */
698       if (!TTY_FLAGS (c).standout_width)
699         {
700           OUTPUT1_IF (c, TTY_SD (c).begin_standout);
701         }
702       else
703         reverse_p = 0;
704     }
705
706   if (reverse_p)
707     {
708       Lisp_Object temp = cinst_fore;
709       cinst_fore = cinst_back;
710       cinst_back = temp;
711     }
712
713   if (COLOR_INSTANCEP (cinst_fore)
714       && !EQ (cinst_fore, Vthe_null_color_instance))
715     set_foreground_to (c, COLOR_INSTANCE_TTY_SYMBOL
716                        (XCOLOR_INSTANCE (cinst_fore)));
717
718   if (COLOR_INSTANCEP (cinst_back)
719       && !EQ (cinst_back, Vthe_null_color_instance))
720     set_background_to (c, COLOR_INSTANCE_TTY_SYMBOL
721                        (XCOLOR_INSTANCE (cinst_back)));
722 }
723
724 /*****************************************************************************
725  tty_turn_on_face
726
727  Turn on all set properties of the given face.
728  ****************************************************************************/
729 static void
730 tty_turn_on_face (struct window *w, face_index findex)
731 {
732   struct frame *f = XFRAME (w->frame);
733   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
734
735   tty_turn_on_face_1 (c,
736                       WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex),
737                       WINDOW_FACE_CACHEL_BLINKING_P (w, findex),
738                       WINDOW_FACE_CACHEL_DIM_P (w, findex),
739                       WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex),
740                       WINDOW_FACE_CACHEL_REVERSE_P (w, findex),
741                       WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
742                       WINDOW_FACE_CACHEL_BACKGROUND (w, findex));
743 }
744
745 /*****************************************************************************
746  tty_turn_off_face
747
748  Turn off all set properties of the given face (revert to default
749  face).  We assume that tty_turn_on_face has been called for the given
750  face so that its properties are actually active.
751  ****************************************************************************/
752 static void
753 tty_turn_off_face (struct window *w, face_index findex)
754 {
755   struct frame *f = XFRAME (w->frame);
756   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
757
758   if (WINDOW_FACE_CACHEL_REVERSE_P (w, findex))
759     {
760       /* #### punt for now if standout mode is glitchy */
761       if (!TTY_FLAGS (c).standout_width)
762         {
763           OUTPUT1_IF (c, TTY_SD (c).end_standout);
764         }
765     }
766
767   if (WINDOW_FACE_CACHEL_UNDERLINE_P (w, findex))
768     {
769       /* #### punt for now if underline mode is glitchy */
770       if (!TTY_FLAGS (c).underline_width)
771         {
772           OUTPUT1_IF (c, TTY_SD (c).end_underline);
773         }
774     }
775
776   if (WINDOW_FACE_CACHEL_HIGHLIGHT_P (w, findex) ||
777       WINDOW_FACE_CACHEL_BLINKING_P (w, findex) ||
778       WINDOW_FACE_CACHEL_DIM_P (w, findex) ||
779       !EQ (WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
780            Vthe_null_color_instance) ||
781       !EQ (WINDOW_FACE_CACHEL_BACKGROUND (w, findex),
782            Vthe_null_color_instance))
783     {
784       OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
785     }
786 }
787
788 /*****************************************************************************
789  tty_turn_on_frame_face
790
791  Turn on all set properties of the given face.
792  ****************************************************************************/
793 static void
794 tty_turn_on_frame_face (struct frame *f, Lisp_Object face)
795 {
796   Lisp_Object frame;
797   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
798
799   XSETFRAME (frame, f);
800   tty_turn_on_face_1 (c,
801                       FACE_HIGHLIGHT_P (face, frame),
802                       FACE_BLINKING_P (face, frame),
803                       FACE_DIM_P (face, frame),
804                       FACE_UNDERLINE_P (face, frame),
805                       FACE_REVERSE_P (face, frame),
806                       FACE_FOREGROUND (face, frame),
807                       FACE_BACKGROUND (face, frame));
808 }
809
810 /*****************************************************************************
811  tty_turn_off_frame_face
812
813  Turn off all set properties of the given face (revert to default
814  face).  We assume that tty_turn_on_face has been called for the given
815  face so that its properties are actually active.
816  ****************************************************************************/
817 static void
818 tty_turn_off_frame_face (struct frame *f, Lisp_Object face)
819 {
820   Lisp_Object frame;
821   struct console *c = XCONSOLE (FRAME_CONSOLE (f));
822
823   XSETFRAME (frame, f);
824
825   if (FACE_REVERSE_P (face, frame))
826     {
827       /* #### punt for now if standout mode is glitchy */
828       if (!TTY_FLAGS (c).standout_width)
829         {
830           OUTPUT1_IF (c, TTY_SD (c).end_standout);
831         }
832     }
833
834   if (FACE_UNDERLINE_P (face, frame))
835     {
836       /* #### punt for now if underline mode is glitchy */
837       if (!TTY_FLAGS (c).underline_width)
838         {
839           OUTPUT1_IF (c, TTY_SD (c).end_underline);
840         }
841     }
842
843   if (FACE_HIGHLIGHT_P (face, frame) ||
844       FACE_BLINKING_P (face, frame) ||
845       FACE_DIM_P (face, frame) ||
846       !EQ (FACE_FOREGROUND (face, frame), Vthe_null_color_instance) ||
847       !EQ (FACE_BACKGROUND (face, frame), Vthe_null_color_instance))
848     {
849       OUTPUT1_IF (c, TTY_SD (c).turn_off_attributes);
850     }
851 }
852
853 /*****************************************************************************
854  set_tty_modes
855
856  Sets up various parameters on tty modes.
857  ****************************************************************************/
858 void
859 set_tty_modes (struct console *c)
860 {
861   if (!CONSOLE_TTY_P (c))
862     return;
863
864   OUTPUT1_IF (c, TTY_SD (c).init_motion);
865   OUTPUT1_IF (c, TTY_SD (c).cursor_visible);
866   OUTPUT1_IF (c, TTY_SD (c).keypad_on);
867 }
868
869 /*****************************************************************************
870  reset_tty_modes
871
872  Restore default state of tty.
873  ****************************************************************************/
874 void
875 reset_tty_modes (struct console *c)
876 {
877   if (!CONSOLE_TTY_P (c))
878     return;
879
880   OUTPUT1_IF (c, TTY_SD (c).orig_pair);
881   OUTPUT1_IF (c, TTY_SD (c).keypad_off);
882   OUTPUT1_IF (c, TTY_SD (c).cursor_normal);
883   OUTPUT1_IF (c, TTY_SD (c).end_motion);
884
885   {
886     Lisp_Object frm = CONSOLE_SELECTED_FRAME (c);
887
888     if (!NILP (frm))
889       tty_frame_output_end (XFRAME (frm));
890   }
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_frame_output_end (f);
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 #ifdef SIGTTOU
1063   /* SIGTT* don't exist under win32 */
1064   EMACS_BLOCK_SIGNAL (SIGTTOU);
1065 #endif
1066   status = tgetent (entry_buffer, terminal_type);
1067 #ifdef SIGTTOU
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, frame_output_begin);
1495   CONSOLE_HAS_METHOD (tty, frame_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 }