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