]> code.delx.au - gnu-emacs/blob - src/term.c
* dispnew.c: Rename locals to avoid shadowing.
[gnu-emacs] / src / term.c
1 /* Terminal control module for terminals described by TERMCAP
2 Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2011
3 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
20 /* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>. */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <sys/file.h>
27 #include <unistd.h>
28 #include <signal.h>
29 #include <stdarg.h>
30 #include <setjmp.h>
31
32 #include "lisp.h"
33 #include "termchar.h"
34 #include "termopts.h"
35 #include "buffer.h"
36 #include "character.h"
37 #include "charset.h"
38 #include "coding.h"
39 #include "composite.h"
40 #include "keyboard.h"
41 #include "frame.h"
42 #include "disptab.h"
43 #include "termhooks.h"
44 #include "dispextern.h"
45 #include "window.h"
46 #include "keymap.h"
47 #include "blockinput.h"
48 #include "syssignal.h"
49 #include "systty.h"
50 #include "intervals.h"
51 #ifdef MSDOS
52 #include "msdos.h"
53 static int been_here = -1;
54 #endif
55
56 /* For now, don't try to include termcap.h. On some systems,
57 configure finds a non-standard termcap.h that the main build
58 won't find. */
59 extern void tputs (const char *, int, int (*)(int));
60 extern int tgetent (char *, const char *);
61 extern int tgetflag (char *id);
62 extern int tgetnum (char *id);
63
64 char *tparam (char *, char *, int, int, ...);
65
66 extern char *tgetstr (char *, char **);
67
68 #include "cm.h"
69 #ifdef HAVE_X_WINDOWS
70 #include "xterm.h"
71 #endif
72
73 #ifndef O_RDWR
74 #define O_RDWR 2
75 #endif
76
77 #ifndef O_NOCTTY
78 #define O_NOCTTY 0
79 #endif
80
81 /* The name of the default console device. */
82 #ifdef WINDOWSNT
83 #define DEV_TTY "CONOUT$"
84 #else
85 #define DEV_TTY "/dev/tty"
86 #endif
87
88 static void tty_set_scroll_region (struct frame *f, int start, int stop);
89 static void turn_on_face (struct frame *, int face_id);
90 static void turn_off_face (struct frame *, int face_id);
91 static void tty_show_cursor (struct tty_display_info *);
92 static void tty_hide_cursor (struct tty_display_info *);
93 static void tty_background_highlight (struct tty_display_info *tty);
94 static void clear_tty_hooks (struct terminal *terminal);
95 static void set_tty_hooks (struct terminal *terminal);
96 static void dissociate_if_controlling_tty (int fd);
97 static void delete_tty (struct terminal *);
98 static void maybe_fatal (int must_succeed, struct terminal *terminal,
99 const char *str1, const char *str2, ...) NO_RETURN;
100 static void vfatal (const char *str, va_list ap) NO_RETURN;
101
102
103 #define OUTPUT(tty, a) \
104 emacs_tputs ((tty), a, \
105 (int) (FRAME_LINES (XFRAME (selected_frame)) \
106 - curY (tty)), \
107 cmputc)
108
109 #define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
110 #define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
111
112 #define OUTPUT_IF(tty, a) \
113 do { \
114 if (a) \
115 OUTPUT (tty, a); \
116 } while (0)
117
118 #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
119
120 /* Display space properties */
121
122 /* Chain of all tty device parameters. */
123 struct tty_display_info *tty_list;
124
125 /* Meaning of bits in no_color_video. Each bit set means that the
126 corresponding attribute cannot be combined with colors. */
127
128 enum no_color_bit
129 {
130 NC_STANDOUT = 1 << 0,
131 NC_UNDERLINE = 1 << 1,
132 NC_REVERSE = 1 << 2,
133 NC_BLINK = 1 << 3,
134 NC_DIM = 1 << 4,
135 NC_BOLD = 1 << 5,
136 NC_INVIS = 1 << 6,
137 NC_PROTECT = 1 << 7,
138 NC_ALT_CHARSET = 1 << 8
139 };
140
141 /* internal state */
142
143 /* The largest frame width in any call to calculate_costs. */
144
145 int max_frame_cols;
146
147 /* The largest frame height in any call to calculate_costs. */
148
149 int max_frame_lines;
150
151 /* Non-zero if we have dropped our controlling tty and therefore
152 should not open a frame on stdout. */
153 static int no_controlling_tty;
154
155 \f
156
157 #ifdef HAVE_GPM
158 #include <sys/fcntl.h>
159
160 /* The device for which we have enabled gpm support (or NULL). */
161 struct tty_display_info *gpm_tty = NULL;
162
163 /* Last recorded mouse coordinates. */
164 static int last_mouse_x, last_mouse_y;
165 #endif /* HAVE_GPM */
166
167 /* Ring the bell on a tty. */
168
169 static void
170 tty_ring_bell (struct frame *f)
171 {
172 struct tty_display_info *tty = FRAME_TTY (f);
173
174 if (tty->output)
175 {
176 OUTPUT (tty, (tty->TS_visible_bell && visible_bell
177 ? tty->TS_visible_bell
178 : tty->TS_bell));
179 fflush (tty->output);
180 }
181 }
182
183 /* Set up termcap modes for Emacs. */
184
185 void
186 tty_set_terminal_modes (struct terminal *terminal)
187 {
188 struct tty_display_info *tty = terminal->display_info.tty;
189
190 if (tty->output)
191 {
192 if (tty->TS_termcap_modes)
193 OUTPUT (tty, tty->TS_termcap_modes);
194 else
195 {
196 /* Output enough newlines to scroll all the old screen contents
197 off the screen, so it won't be overwritten and lost. */
198 int i;
199 current_tty = tty;
200 for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
201 cmputc ('\n');
202 }
203
204 OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
205 OUTPUT_IF (tty, tty->TS_keypad_mode);
206 losecursor (tty);
207 fflush (tty->output);
208 }
209 }
210
211 /* Reset termcap modes before exiting Emacs. */
212
213 void
214 tty_reset_terminal_modes (struct terminal *terminal)
215 {
216 struct tty_display_info *tty = terminal->display_info.tty;
217
218 if (tty->output)
219 {
220 tty_turn_off_highlight (tty);
221 tty_turn_off_insert (tty);
222 OUTPUT_IF (tty, tty->TS_end_keypad_mode);
223 OUTPUT_IF (tty, tty->TS_cursor_normal);
224 OUTPUT_IF (tty, tty->TS_end_termcap_modes);
225 OUTPUT_IF (tty, tty->TS_orig_pair);
226 /* Output raw CR so kernel can track the cursor hpos. */
227 current_tty = tty;
228 cmputc ('\r');
229 fflush (tty->output);
230 }
231 }
232
233 /* Flag the end of a display update on a termcap terminal. */
234
235 static void
236 tty_update_end (struct frame *f)
237 {
238 struct tty_display_info *tty = FRAME_TTY (f);
239
240 if (!XWINDOW (selected_window)->cursor_off_p)
241 tty_show_cursor (tty);
242 tty_turn_off_insert (tty);
243 tty_background_highlight (tty);
244 }
245
246 /* The implementation of set_terminal_window for termcap frames. */
247
248 static void
249 tty_set_terminal_window (struct frame *f, int size)
250 {
251 struct tty_display_info *tty = FRAME_TTY (f);
252
253 tty->specified_window = size ? size : FRAME_LINES (f);
254 if (FRAME_SCROLL_REGION_OK (f))
255 tty_set_scroll_region (f, 0, tty->specified_window);
256 }
257
258 static void
259 tty_set_scroll_region (struct frame *f, int start, int stop)
260 {
261 char *buf;
262 struct tty_display_info *tty = FRAME_TTY (f);
263
264 if (tty->TS_set_scroll_region)
265 buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1);
266 else if (tty->TS_set_scroll_region_1)
267 buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
268 FRAME_LINES (f), start,
269 FRAME_LINES (f) - stop,
270 FRAME_LINES (f));
271 else
272 buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
273
274 OUTPUT (tty, buf);
275 xfree (buf);
276 losecursor (tty);
277 }
278
279 \f
280 static void
281 tty_turn_on_insert (struct tty_display_info *tty)
282 {
283 if (!tty->insert_mode)
284 OUTPUT (tty, tty->TS_insert_mode);
285 tty->insert_mode = 1;
286 }
287
288 void
289 tty_turn_off_insert (struct tty_display_info *tty)
290 {
291 if (tty->insert_mode)
292 OUTPUT (tty, tty->TS_end_insert_mode);
293 tty->insert_mode = 0;
294 }
295 \f
296 /* Handle highlighting. */
297
298 void
299 tty_turn_off_highlight (struct tty_display_info *tty)
300 {
301 if (tty->standout_mode)
302 OUTPUT_IF (tty, tty->TS_end_standout_mode);
303 tty->standout_mode = 0;
304 }
305
306 static void
307 tty_turn_on_highlight (struct tty_display_info *tty)
308 {
309 if (!tty->standout_mode)
310 OUTPUT_IF (tty, tty->TS_standout_mode);
311 tty->standout_mode = 1;
312 }
313
314 static void
315 tty_toggle_highlight (struct tty_display_info *tty)
316 {
317 if (tty->standout_mode)
318 tty_turn_off_highlight (tty);
319 else
320 tty_turn_on_highlight (tty);
321 }
322
323
324 /* Make cursor invisible. */
325
326 static void
327 tty_hide_cursor (struct tty_display_info *tty)
328 {
329 if (tty->cursor_hidden == 0)
330 {
331 tty->cursor_hidden = 1;
332 OUTPUT_IF (tty, tty->TS_cursor_invisible);
333 }
334 }
335
336
337 /* Ensure that cursor is visible. */
338
339 static void
340 tty_show_cursor (struct tty_display_info *tty)
341 {
342 if (tty->cursor_hidden)
343 {
344 tty->cursor_hidden = 0;
345 OUTPUT_IF (tty, tty->TS_cursor_normal);
346 if (visible_cursor)
347 OUTPUT_IF (tty, tty->TS_cursor_visible);
348 }
349 }
350
351
352 /* Set standout mode to the state it should be in for
353 empty space inside windows. What this is,
354 depends on the user option inverse-video. */
355
356 static void
357 tty_background_highlight (struct tty_display_info *tty)
358 {
359 if (inverse_video)
360 tty_turn_on_highlight (tty);
361 else
362 tty_turn_off_highlight (tty);
363 }
364
365 /* Set standout mode to the mode specified for the text to be output. */
366
367 static void
368 tty_highlight_if_desired (struct tty_display_info *tty)
369 {
370 if (inverse_video)
371 tty_turn_on_highlight (tty);
372 else
373 tty_turn_off_highlight (tty);
374 }
375 \f
376
377 /* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are
378 frame-relative coordinates. */
379
380 static void
381 tty_cursor_to (struct frame *f, int vpos, int hpos)
382 {
383 struct tty_display_info *tty = FRAME_TTY (f);
384
385 /* Detect the case where we are called from reset_sys_modes
386 and the costs have never been calculated. Do nothing. */
387 if (! tty->costs_set)
388 return;
389
390 if (curY (tty) == vpos
391 && curX (tty) == hpos)
392 return;
393 if (!tty->TF_standout_motion)
394 tty_background_highlight (tty);
395 if (!tty->TF_insmode_motion)
396 tty_turn_off_insert (tty);
397 cmgoto (tty, vpos, hpos);
398 }
399
400 /* Similar but don't take any account of the wasted characters. */
401
402 static void
403 tty_raw_cursor_to (struct frame *f, int row, int col)
404 {
405 struct tty_display_info *tty = FRAME_TTY (f);
406
407 if (curY (tty) == row
408 && curX (tty) == col)
409 return;
410 if (!tty->TF_standout_motion)
411 tty_background_highlight (tty);
412 if (!tty->TF_insmode_motion)
413 tty_turn_off_insert (tty);
414 cmgoto (tty, row, col);
415 }
416 \f
417 /* Erase operations */
418
419 /* Clear from cursor to end of frame on a termcap device. */
420
421 static void
422 tty_clear_to_end (struct frame *f)
423 {
424 register int i;
425 struct tty_display_info *tty = FRAME_TTY (f);
426
427 if (tty->TS_clr_to_bottom)
428 {
429 tty_background_highlight (tty);
430 OUTPUT (tty, tty->TS_clr_to_bottom);
431 }
432 else
433 {
434 for (i = curY (tty); i < FRAME_LINES (f); i++)
435 {
436 cursor_to (f, i, 0);
437 clear_end_of_line (f, FRAME_COLS (f));
438 }
439 }
440 }
441
442 /* Clear an entire termcap frame. */
443
444 static void
445 tty_clear_frame (struct frame *f)
446 {
447 struct tty_display_info *tty = FRAME_TTY (f);
448
449 if (tty->TS_clr_frame)
450 {
451 tty_background_highlight (tty);
452 OUTPUT (tty, tty->TS_clr_frame);
453 cmat (tty, 0, 0);
454 }
455 else
456 {
457 cursor_to (f, 0, 0);
458 clear_to_end (f);
459 }
460 }
461
462 /* An implementation of clear_end_of_line for termcap frames.
463
464 Note that the cursor may be moved, on terminals lacking a `ce' string. */
465
466 static void
467 tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
468 {
469 register int i;
470 struct tty_display_info *tty = FRAME_TTY (f);
471
472 /* Detect the case where we are called from reset_sys_modes
473 and the costs have never been calculated. Do nothing. */
474 if (! tty->costs_set)
475 return;
476
477 if (curX (tty) >= first_unused_hpos)
478 return;
479 tty_background_highlight (tty);
480 if (tty->TS_clr_line)
481 {
482 OUTPUT1 (tty, tty->TS_clr_line);
483 }
484 else
485 { /* have to do it the hard way */
486 tty_turn_off_insert (tty);
487
488 /* Do not write in last row last col with Auto-wrap on. */
489 if (AutoWrap (tty)
490 && curY (tty) == FrameRows (tty) - 1
491 && first_unused_hpos == FrameCols (tty))
492 first_unused_hpos--;
493
494 for (i = curX (tty); i < first_unused_hpos; i++)
495 {
496 if (tty->termscript)
497 fputc (' ', tty->termscript);
498 fputc (' ', tty->output);
499 }
500 cmplus (tty, first_unused_hpos - curX (tty));
501 }
502 }
503 \f
504 /* Buffers to store the source and result of code conversion for terminal. */
505 static unsigned char *encode_terminal_src;
506 static unsigned char *encode_terminal_dst;
507 /* Allocated sizes of the above buffers. */
508 static int encode_terminal_src_size;
509 static int encode_terminal_dst_size;
510
511 /* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
512 Set CODING->produced to the byte-length of the resulting byte
513 sequence, and return a pointer to that byte sequence. */
514
515 unsigned char *
516 encode_terminal_code (struct glyph *src, int src_len, struct coding_system *coding)
517 {
518 struct glyph *src_end = src + src_len;
519 unsigned char *buf;
520 int nchars, nbytes, required;
521 register int tlen = GLYPH_TABLE_LENGTH;
522 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
523 Lisp_Object charset_list;
524
525 /* Allocate sufficient size of buffer to store all characters in
526 multibyte-form. But, it may be enlarged on demand if
527 Vglyph_table contains a string or a composite glyph is
528 encountered. */
529 required = MAX_MULTIBYTE_LENGTH * src_len;
530 if (encode_terminal_src_size < required)
531 {
532 if (encode_terminal_src)
533 encode_terminal_src = xrealloc (encode_terminal_src, required);
534 else
535 encode_terminal_src = xmalloc (required);
536 encode_terminal_src_size = required;
537 }
538
539 charset_list = coding_charset_list (coding);
540
541 buf = encode_terminal_src;
542 nchars = 0;
543 while (src < src_end)
544 {
545 if (src->type == COMPOSITE_GLYPH)
546 {
547 struct composition *cmp;
548 Lisp_Object gstring;
549 int i;
550
551 nbytes = buf - encode_terminal_src;
552 if (src->u.cmp.automatic)
553 {
554 gstring = composition_gstring_from_id (src->u.cmp.id);
555 required = src->slice.cmp.to + 1 - src->slice.cmp.from;
556 }
557 else
558 {
559 cmp = composition_table[src->u.cmp.id];
560 required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len;
561 }
562
563 if (encode_terminal_src_size < nbytes + required)
564 {
565 encode_terminal_src_size = nbytes + required;
566 encode_terminal_src = xrealloc (encode_terminal_src,
567 encode_terminal_src_size);
568 buf = encode_terminal_src + nbytes;
569 }
570
571 if (src->u.cmp.automatic)
572 for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
573 {
574 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
575 int c = LGLYPH_CHAR (g);
576
577 if (! char_charset (c, charset_list, NULL))
578 c = '?';
579 buf += CHAR_STRING (c, buf);
580 nchars++;
581 }
582 else
583 for (i = 0; i < cmp->glyph_len; i++)
584 {
585 int c = COMPOSITION_GLYPH (cmp, i);
586
587 if (c == '\t')
588 continue;
589 if (char_charset (c, charset_list, NULL))
590 {
591 if (CHAR_WIDTH (c) == 0
592 && i > 0 && COMPOSITION_GLYPH (cmp, i - 1) == '\t')
593 /* Should be left-padded */
594 {
595 buf += CHAR_STRING (' ', buf);
596 nchars++;
597 }
598 }
599 else
600 c = '?';
601 buf += CHAR_STRING (c, buf);
602 nchars++;
603 }
604 }
605 /* We must skip glyphs to be padded for a wide character. */
606 else if (! CHAR_GLYPH_PADDING_P (*src))
607 {
608 GLYPH g;
609 int c;
610 Lisp_Object string;
611
612 string = Qnil;
613 SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
614
615 if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
616 {
617 /* This glyph doesn't have an entry in Vglyph_table. */
618 c = src->u.ch;
619 }
620 else
621 {
622 /* This glyph has an entry in Vglyph_table,
623 so process any alias before testing for simpleness. */
624 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
625
626 if (GLYPH_SIMPLE_P (tbase, tlen, g))
627 /* We set the multi-byte form of a character in G
628 (that should be an ASCII character) at WORKBUF. */
629 c = GLYPH_CHAR (g);
630 else
631 /* We have a string in Vglyph_table. */
632 string = tbase[GLYPH_CHAR (g)];
633 }
634
635 if (NILP (string))
636 {
637 nbytes = buf - encode_terminal_src;
638 if (encode_terminal_src_size < nbytes + MAX_MULTIBYTE_LENGTH)
639 {
640 encode_terminal_src_size = nbytes + MAX_MULTIBYTE_LENGTH;
641 encode_terminal_src = xrealloc (encode_terminal_src,
642 encode_terminal_src_size);
643 buf = encode_terminal_src + nbytes;
644 }
645 if (CHAR_BYTE8_P (c)
646 || char_charset (c, charset_list, NULL))
647 {
648 /* Store the multibyte form of C at BUF. */
649 buf += CHAR_STRING (c, buf);
650 nchars++;
651 }
652 else
653 {
654 /* C is not encodable. */
655 *buf++ = '?';
656 nchars++;
657 while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
658 {
659 *buf++ = '?';
660 nchars++;
661 src++;
662 }
663 }
664 }
665 else
666 {
667 unsigned char *p = SDATA (string);
668
669 if (! STRING_MULTIBYTE (string))
670 string = string_to_multibyte (string);
671 nbytes = buf - encode_terminal_src;
672 if (encode_terminal_src_size < nbytes + SBYTES (string))
673 {
674 encode_terminal_src_size = nbytes + SBYTES (string);
675 encode_terminal_src = xrealloc (encode_terminal_src,
676 encode_terminal_src_size);
677 buf = encode_terminal_src + nbytes;
678 }
679 memcpy (buf, SDATA (string), SBYTES (string));
680 buf += SBYTES (string);
681 nchars += SCHARS (string);
682 }
683 }
684 src++;
685 }
686
687 if (nchars == 0)
688 {
689 coding->produced = 0;
690 return NULL;
691 }
692
693 nbytes = buf - encode_terminal_src;
694 coding->source = encode_terminal_src;
695 if (encode_terminal_dst_size == 0)
696 {
697 encode_terminal_dst_size = encode_terminal_src_size;
698 if (encode_terminal_dst)
699 encode_terminal_dst = xrealloc (encode_terminal_dst,
700 encode_terminal_dst_size);
701 else
702 encode_terminal_dst = xmalloc (encode_terminal_dst_size);
703 }
704 coding->destination = encode_terminal_dst;
705 coding->dst_bytes = encode_terminal_dst_size;
706 encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
707 /* coding->destination may have been reallocated. */
708 encode_terminal_dst = coding->destination;
709 encode_terminal_dst_size = coding->dst_bytes;
710
711 return (encode_terminal_dst);
712 }
713
714
715
716 /* An implementation of write_glyphs for termcap frames. */
717
718 static void
719 tty_write_glyphs (struct frame *f, struct glyph *string, int len)
720 {
721 unsigned char *conversion_buffer;
722 struct coding_system *coding;
723
724 struct tty_display_info *tty = FRAME_TTY (f);
725
726 tty_turn_off_insert (tty);
727 tty_hide_cursor (tty);
728
729 /* Don't dare write in last column of bottom line, if Auto-Wrap,
730 since that would scroll the whole frame on some terminals. */
731
732 if (AutoWrap (tty)
733 && curY (tty) + 1 == FRAME_LINES (f)
734 && (curX (tty) + len) == FRAME_COLS (f))
735 len --;
736 if (len <= 0)
737 return;
738
739 cmplus (tty, len);
740
741 /* If terminal_coding does any conversion, use it, otherwise use
742 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
743 because it always return 1 if the member src_multibyte is 1. */
744 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
745 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
746 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
747 the tail. */
748 coding->mode &= ~CODING_MODE_LAST_BLOCK;
749
750 while (len > 0)
751 {
752 /* Identify a run of glyphs with the same face. */
753 int face_id = string->face_id;
754 int n;
755
756 for (n = 1; n < len; ++n)
757 if (string[n].face_id != face_id)
758 break;
759
760 /* Turn appearance modes of the face of the run on. */
761 tty_highlight_if_desired (tty);
762 turn_on_face (f, face_id);
763
764 if (n == len)
765 /* This is the last run. */
766 coding->mode |= CODING_MODE_LAST_BLOCK;
767 conversion_buffer = encode_terminal_code (string, n, coding);
768 if (coding->produced > 0)
769 {
770 BLOCK_INPUT;
771 fwrite (conversion_buffer, 1, coding->produced, tty->output);
772 if (ferror (tty->output))
773 clearerr (tty->output);
774 if (tty->termscript)
775 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
776 UNBLOCK_INPUT;
777 }
778 len -= n;
779 string += n;
780
781 /* Turn appearance modes off. */
782 turn_off_face (f, face_id);
783 tty_turn_off_highlight (tty);
784 }
785
786 cmcheckmagic (tty);
787 }
788
789 #ifdef HAVE_GPM /* Only used by GPM code. */
790
791 static void
792 tty_write_glyphs_with_face (register struct frame *f, register struct glyph *string,
793 register int len, register int face_id)
794 {
795 unsigned char *conversion_buffer;
796 struct coding_system *coding;
797
798 struct tty_display_info *tty = FRAME_TTY (f);
799
800 tty_turn_off_insert (tty);
801 tty_hide_cursor (tty);
802
803 /* Don't dare write in last column of bottom line, if Auto-Wrap,
804 since that would scroll the whole frame on some terminals. */
805
806 if (AutoWrap (tty)
807 && curY (tty) + 1 == FRAME_LINES (f)
808 && (curX (tty) + len) == FRAME_COLS (f))
809 len --;
810 if (len <= 0)
811 return;
812
813 cmplus (tty, len);
814
815 /* If terminal_coding does any conversion, use it, otherwise use
816 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
817 because it always return 1 if the member src_multibyte is 1. */
818 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
819 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
820 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
821 the tail. */
822 coding->mode &= ~CODING_MODE_LAST_BLOCK;
823
824 /* Turn appearance modes of the face. */
825 tty_highlight_if_desired (tty);
826 turn_on_face (f, face_id);
827
828 coding->mode |= CODING_MODE_LAST_BLOCK;
829 conversion_buffer = encode_terminal_code (string, len, coding);
830 if (coding->produced > 0)
831 {
832 BLOCK_INPUT;
833 fwrite (conversion_buffer, 1, coding->produced, tty->output);
834 if (ferror (tty->output))
835 clearerr (tty->output);
836 if (tty->termscript)
837 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
838 UNBLOCK_INPUT;
839 }
840
841 /* Turn appearance modes off. */
842 turn_off_face (f, face_id);
843 tty_turn_off_highlight (tty);
844
845 cmcheckmagic (tty);
846 }
847 #endif
848
849 /* An implementation of insert_glyphs for termcap frames. */
850
851 static void
852 tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
853 {
854 char *buf;
855 struct glyph *glyph = NULL;
856 unsigned char *conversion_buffer;
857 unsigned char space[1];
858 struct coding_system *coding;
859
860 struct tty_display_info *tty = FRAME_TTY (f);
861
862 if (tty->TS_ins_multi_chars)
863 {
864 buf = tparam (tty->TS_ins_multi_chars, 0, 0, len);
865 OUTPUT1 (tty, buf);
866 xfree (buf);
867 if (start)
868 write_glyphs (f, start, len);
869 return;
870 }
871
872 tty_turn_on_insert (tty);
873 cmplus (tty, len);
874
875 if (! start)
876 space[0] = SPACEGLYPH;
877
878 /* If terminal_coding does any conversion, use it, otherwise use
879 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
880 because it always return 1 if the member src_multibyte is 1. */
881 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
882 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
883 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
884 the tail. */
885 coding->mode &= ~CODING_MODE_LAST_BLOCK;
886
887 while (len-- > 0)
888 {
889 OUTPUT1_IF (tty, tty->TS_ins_char);
890 if (!start)
891 {
892 conversion_buffer = space;
893 coding->produced = 1;
894 }
895 else
896 {
897 tty_highlight_if_desired (tty);
898 turn_on_face (f, start->face_id);
899 glyph = start;
900 ++start;
901 /* We must open sufficient space for a character which
902 occupies more than one column. */
903 while (len && CHAR_GLYPH_PADDING_P (*start))
904 {
905 OUTPUT1_IF (tty, tty->TS_ins_char);
906 start++, len--;
907 }
908
909 if (len <= 0)
910 /* This is the last glyph. */
911 coding->mode |= CODING_MODE_LAST_BLOCK;
912
913 conversion_buffer = encode_terminal_code (glyph, 1, coding);
914 }
915
916 if (coding->produced > 0)
917 {
918 BLOCK_INPUT;
919 fwrite (conversion_buffer, 1, coding->produced, tty->output);
920 if (ferror (tty->output))
921 clearerr (tty->output);
922 if (tty->termscript)
923 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
924 UNBLOCK_INPUT;
925 }
926
927 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
928 if (start)
929 {
930 turn_off_face (f, glyph->face_id);
931 tty_turn_off_highlight (tty);
932 }
933 }
934
935 cmcheckmagic (tty);
936 }
937
938 /* An implementation of delete_glyphs for termcap frames. */
939
940 static void
941 tty_delete_glyphs (struct frame *f, int n)
942 {
943 char *buf;
944 register int i;
945
946 struct tty_display_info *tty = FRAME_TTY (f);
947
948 if (tty->delete_in_insert_mode)
949 {
950 tty_turn_on_insert (tty);
951 }
952 else
953 {
954 tty_turn_off_insert (tty);
955 OUTPUT_IF (tty, tty->TS_delete_mode);
956 }
957
958 if (tty->TS_del_multi_chars)
959 {
960 buf = tparam (tty->TS_del_multi_chars, 0, 0, n);
961 OUTPUT1 (tty, buf);
962 xfree (buf);
963 }
964 else
965 for (i = 0; i < n; i++)
966 OUTPUT1 (tty, tty->TS_del_char);
967 if (!tty->delete_in_insert_mode)
968 OUTPUT_IF (tty, tty->TS_end_delete_mode);
969 }
970 \f
971 /* An implementation of ins_del_lines for termcap frames. */
972
973 static void
974 tty_ins_del_lines (struct frame *f, int vpos, int n)
975 {
976 struct tty_display_info *tty = FRAME_TTY (f);
977 char *multi = n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
978 char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
979 char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
980
981 register int i = n > 0 ? n : -n;
982 register char *buf;
983
984 /* If the lines below the insertion are being pushed
985 into the end of the window, this is the same as clearing;
986 and we know the lines are already clear, since the matching
987 deletion has already been done. So can ignore this. */
988 /* If the lines below the deletion are blank lines coming
989 out of the end of the window, don't bother,
990 as there will be a matching inslines later that will flush them. */
991 if (FRAME_SCROLL_REGION_OK (f)
992 && vpos + i >= tty->specified_window)
993 return;
994 if (!FRAME_MEMORY_BELOW_FRAME (f)
995 && vpos + i >= FRAME_LINES (f))
996 return;
997
998 if (multi)
999 {
1000 raw_cursor_to (f, vpos, 0);
1001 tty_background_highlight (tty);
1002 buf = tparam (multi, 0, 0, i);
1003 OUTPUT (tty, buf);
1004 xfree (buf);
1005 }
1006 else if (single)
1007 {
1008 raw_cursor_to (f, vpos, 0);
1009 tty_background_highlight (tty);
1010 while (--i >= 0)
1011 OUTPUT (tty, single);
1012 if (tty->TF_teleray)
1013 curX (tty) = 0;
1014 }
1015 else
1016 {
1017 tty_set_scroll_region (f, vpos, tty->specified_window);
1018 if (n < 0)
1019 raw_cursor_to (f, tty->specified_window - 1, 0);
1020 else
1021 raw_cursor_to (f, vpos, 0);
1022 tty_background_highlight (tty);
1023 while (--i >= 0)
1024 OUTPUTL (tty, scroll, tty->specified_window - vpos);
1025 tty_set_scroll_region (f, 0, tty->specified_window);
1026 }
1027
1028 if (!FRAME_SCROLL_REGION_OK (f)
1029 && FRAME_MEMORY_BELOW_FRAME (f)
1030 && n < 0)
1031 {
1032 cursor_to (f, FRAME_LINES (f) + n, 0);
1033 clear_to_end (f);
1034 }
1035 }
1036 \f
1037 /* Compute cost of sending "str", in characters,
1038 not counting any line-dependent padding. */
1039
1040 int
1041 string_cost (const char *str)
1042 {
1043 cost = 0;
1044 if (str)
1045 tputs (str, 0, evalcost);
1046 return cost;
1047 }
1048
1049 /* Compute cost of sending "str", in characters,
1050 counting any line-dependent padding at one line. */
1051
1052 static int
1053 string_cost_one_line (const char *str)
1054 {
1055 cost = 0;
1056 if (str)
1057 tputs (str, 1, evalcost);
1058 return cost;
1059 }
1060
1061 /* Compute per line amount of line-dependent padding,
1062 in tenths of characters. */
1063
1064 int
1065 per_line_cost (const char *str)
1066 {
1067 cost = 0;
1068 if (str)
1069 tputs (str, 0, evalcost);
1070 cost = - cost;
1071 if (str)
1072 tputs (str, 10, evalcost);
1073 return cost;
1074 }
1075
1076 /* char_ins_del_cost[n] is cost of inserting N characters.
1077 char_ins_del_cost[-n] is cost of deleting N characters.
1078 The length of this vector is based on max_frame_cols. */
1079
1080 int *char_ins_del_vector;
1081
1082 #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_COLS ((f))])
1083
1084 /* ARGSUSED */
1085 static void
1086 calculate_ins_del_char_costs (struct frame *f)
1087 {
1088 struct tty_display_info *tty = FRAME_TTY (f);
1089 int ins_startup_cost, del_startup_cost;
1090 int ins_cost_per_char, del_cost_per_char;
1091 register int i;
1092 register int *p;
1093
1094 if (tty->TS_ins_multi_chars)
1095 {
1096 ins_cost_per_char = 0;
1097 ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars);
1098 }
1099 else if (tty->TS_ins_char || tty->TS_pad_inserted_char
1100 || (tty->TS_insert_mode && tty->TS_end_insert_mode))
1101 {
1102 ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode)
1103 + string_cost (tty->TS_end_insert_mode))) / 100;
1104 ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char)
1105 + string_cost_one_line (tty->TS_pad_inserted_char));
1106 }
1107 else
1108 {
1109 ins_startup_cost = 9999;
1110 ins_cost_per_char = 0;
1111 }
1112
1113 if (tty->TS_del_multi_chars)
1114 {
1115 del_cost_per_char = 0;
1116 del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars);
1117 }
1118 else if (tty->TS_del_char)
1119 {
1120 del_startup_cost = (string_cost (tty->TS_delete_mode)
1121 + string_cost (tty->TS_end_delete_mode));
1122 if (tty->delete_in_insert_mode)
1123 del_startup_cost /= 2;
1124 del_cost_per_char = string_cost_one_line (tty->TS_del_char);
1125 }
1126 else
1127 {
1128 del_startup_cost = 9999;
1129 del_cost_per_char = 0;
1130 }
1131
1132 /* Delete costs are at negative offsets */
1133 p = &char_ins_del_cost (f)[0];
1134 for (i = FRAME_COLS (f); --i >= 0;)
1135 *--p = (del_startup_cost += del_cost_per_char);
1136
1137 /* Doing nothing is free */
1138 p = &char_ins_del_cost (f)[0];
1139 *p++ = 0;
1140
1141 /* Insert costs are at positive offsets */
1142 for (i = FRAME_COLS (f); --i >= 0;)
1143 *p++ = (ins_startup_cost += ins_cost_per_char);
1144 }
1145
1146 void
1147 calculate_costs (struct frame *frame)
1148 {
1149 FRAME_COST_BAUD_RATE (frame) = baud_rate;
1150
1151 if (FRAME_TERMCAP_P (frame))
1152 {
1153 struct tty_display_info *tty = FRAME_TTY (frame);
1154 register char *f = (tty->TS_set_scroll_region
1155 ? tty->TS_set_scroll_region
1156 : tty->TS_set_scroll_region_1);
1157
1158 FRAME_SCROLL_REGION_COST (frame) = string_cost (f);
1159
1160 tty->costs_set = 1;
1161
1162 /* These variables are only used for terminal stuff. They are
1163 allocated once for the terminal frame of X-windows emacs, but not
1164 used afterwards.
1165
1166 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1167 X turns off char_ins_del_ok. */
1168
1169 max_frame_lines = max (max_frame_lines, FRAME_LINES (frame));
1170 max_frame_cols = max (max_frame_cols, FRAME_COLS (frame));
1171
1172 if (char_ins_del_vector != 0)
1173 char_ins_del_vector
1174 = (int *) xrealloc (char_ins_del_vector,
1175 (sizeof (int)
1176 + 2 * max_frame_cols * sizeof (int)));
1177 else
1178 char_ins_del_vector
1179 = (int *) xmalloc (sizeof (int)
1180 + 2 * max_frame_cols * sizeof (int));
1181
1182 memset (char_ins_del_vector, 0,
1183 (sizeof (int) + 2 * max_frame_cols * sizeof (int)));
1184
1185
1186 if (f && (!tty->TS_ins_line && !tty->TS_del_line))
1187 do_line_insertion_deletion_costs (frame,
1188 tty->TS_rev_scroll, tty->TS_ins_multi_lines,
1189 tty->TS_fwd_scroll, tty->TS_del_multi_lines,
1190 f, f, 1);
1191 else
1192 do_line_insertion_deletion_costs (frame,
1193 tty->TS_ins_line, tty->TS_ins_multi_lines,
1194 tty->TS_del_line, tty->TS_del_multi_lines,
1195 0, 0, 1);
1196
1197 calculate_ins_del_char_costs (frame);
1198
1199 /* Don't use TS_repeat if its padding is worse than sending the chars */
1200 if (tty->TS_repeat && per_line_cost (tty->TS_repeat) * baud_rate < 9000)
1201 tty->RPov = string_cost (tty->TS_repeat);
1202 else
1203 tty->RPov = FRAME_COLS (frame) * 2;
1204
1205 cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */
1206 }
1207 }
1208 \f
1209 struct fkey_table {
1210 char *cap, *name;
1211 };
1212
1213 /* Termcap capability names that correspond directly to X keysyms.
1214 Some of these (marked "terminfo") aren't supplied by old-style
1215 (Berkeley) termcap entries. They're listed in X keysym order;
1216 except we put the keypad keys first, so that if they clash with
1217 other keys (as on the IBM PC keyboard) they get overridden.
1218 */
1219
1220 static const struct fkey_table keys[] =
1221 {
1222 {"kh", "home"}, /* termcap */
1223 {"kl", "left"}, /* termcap */
1224 {"ku", "up"}, /* termcap */
1225 {"kr", "right"}, /* termcap */
1226 {"kd", "down"}, /* termcap */
1227 {"%8", "prior"}, /* terminfo */
1228 {"%5", "next"}, /* terminfo */
1229 {"@7", "end"}, /* terminfo */
1230 {"@1", "begin"}, /* terminfo */
1231 {"*6", "select"}, /* terminfo */
1232 {"%9", "print"}, /* terminfo */
1233 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1234 /*
1235 * "insert" --- see below
1236 */
1237 {"&8", "undo"}, /* terminfo */
1238 {"%0", "redo"}, /* terminfo */
1239 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1240 {"@0", "find"}, /* terminfo */
1241 {"@2", "cancel"}, /* terminfo */
1242 {"%1", "help"}, /* terminfo */
1243 /*
1244 * "break" goes here, but can't be reliably intercepted with termcap
1245 */
1246 {"&4", "reset"}, /* terminfo --- actually `restart' */
1247 /*
1248 * "system" and "user" --- no termcaps
1249 */
1250 {"kE", "clearline"}, /* terminfo */
1251 {"kA", "insertline"}, /* terminfo */
1252 {"kL", "deleteline"}, /* terminfo */
1253 {"kI", "insertchar"}, /* terminfo */
1254 {"kD", "deletechar"}, /* terminfo */
1255 {"kB", "backtab"}, /* terminfo */
1256 /*
1257 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1258 */
1259 {"@8", "kp-enter"}, /* terminfo */
1260 /*
1261 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1262 * "kp-multiply", "kp-add", "kp-separator",
1263 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1264 * --- no termcaps for any of these.
1265 */
1266 {"K4", "kp-1"}, /* terminfo */
1267 /*
1268 * "kp-2" --- no termcap
1269 */
1270 {"K5", "kp-3"}, /* terminfo */
1271 /*
1272 * "kp-4" --- no termcap
1273 */
1274 {"K2", "kp-5"}, /* terminfo */
1275 /*
1276 * "kp-6" --- no termcap
1277 */
1278 {"K1", "kp-7"}, /* terminfo */
1279 /*
1280 * "kp-8" --- no termcap
1281 */
1282 {"K3", "kp-9"}, /* terminfo */
1283 /*
1284 * "kp-equal" --- no termcap
1285 */
1286 {"k1", "f1"},
1287 {"k2", "f2"},
1288 {"k3", "f3"},
1289 {"k4", "f4"},
1290 {"k5", "f5"},
1291 {"k6", "f6"},
1292 {"k7", "f7"},
1293 {"k8", "f8"},
1294 {"k9", "f9"},
1295
1296 {"&0", "S-cancel"}, /*shifted cancel key*/
1297 {"&9", "S-begin"}, /*shifted begin key*/
1298 {"*0", "S-find"}, /*shifted find key*/
1299 {"*1", "S-execute"}, /*shifted execute? actually shifted command key*/
1300 {"*4", "S-delete"}, /*shifted delete-character key*/
1301 {"*7", "S-end"}, /*shifted end key*/
1302 {"*8", "S-clearline"}, /*shifted clear-to end-of-line key*/
1303 {"#1", "S-help"}, /*shifted help key*/
1304 {"#2", "S-home"}, /*shifted home key*/
1305 {"#3", "S-insert"}, /*shifted insert-character key*/
1306 {"#4", "S-left"}, /*shifted left-arrow key*/
1307 {"%d", "S-menu"}, /*shifted menu? actually shifted options key*/
1308 {"%c", "S-next"}, /*shifted next key*/
1309 {"%e", "S-prior"}, /*shifted previous key*/
1310 {"%f", "S-print"}, /*shifted print key*/
1311 {"%g", "S-redo"}, /*shifted redo key*/
1312 {"%i", "S-right"}, /*shifted right-arrow key*/
1313 {"!3", "S-undo"} /*shifted undo key*/
1314 };
1315
1316 #ifndef DOS_NT
1317 static char **term_get_fkeys_address;
1318 static KBOARD *term_get_fkeys_kboard;
1319 static Lisp_Object term_get_fkeys_1 (void);
1320
1321 /* Find the escape codes sent by the function keys for Vinput_decode_map.
1322 This function scans the termcap function key sequence entries, and
1323 adds entries to Vinput_decode_map for each function key it finds. */
1324
1325 static void
1326 term_get_fkeys (char **address, KBOARD *kboard)
1327 {
1328 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1329 errors during the call. The only errors should be from Fdefine_key
1330 when given a key sequence containing an invalid prefix key. If the
1331 termcap defines function keys which use a prefix that is already bound
1332 to a command by the default bindings, we should silently ignore that
1333 function key specification, rather than giving the user an error and
1334 refusing to run at all on such a terminal. */
1335
1336 term_get_fkeys_address = address;
1337 term_get_fkeys_kboard = kboard;
1338 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1339 }
1340
1341 static Lisp_Object
1342 term_get_fkeys_1 (void)
1343 {
1344 int i;
1345
1346 char **address = term_get_fkeys_address;
1347 KBOARD *kboard = term_get_fkeys_kboard;
1348
1349 /* This can happen if CANNOT_DUMP or with strange options. */
1350 if (!KEYMAPP (KVAR (kboard, Vinput_decode_map)))
1351 KVAR (kboard, Vinput_decode_map) = Fmake_sparse_keymap (Qnil);
1352
1353 for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
1354 {
1355 char *sequence = tgetstr (keys[i].cap, address);
1356 if (sequence)
1357 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
1358 Fmake_vector (make_number (1),
1359 intern (keys[i].name)));
1360 }
1361
1362 /* The uses of the "k0" capability are inconsistent; sometimes it
1363 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1364 We will attempt to politely accommodate both systems by testing for
1365 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1366 */
1367 {
1368 char *k_semi = tgetstr ("k;", address);
1369 char *k0 = tgetstr ("k0", address);
1370 char *k0_name = "f10";
1371
1372 if (k_semi)
1373 {
1374 if (k0)
1375 /* Define f0 first, so that f10 takes precedence in case the
1376 key sequences happens to be the same. */
1377 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
1378 Fmake_vector (make_number (1), intern ("f0")));
1379 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k_semi),
1380 Fmake_vector (make_number (1), intern ("f10")));
1381 }
1382 else if (k0)
1383 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
1384 Fmake_vector (make_number (1), intern (k0_name)));
1385 }
1386
1387 /* Set up cookies for numbered function keys above f10. */
1388 {
1389 char fcap[3], fkey[4];
1390
1391 fcap[0] = 'F'; fcap[2] = '\0';
1392 for (i = 11; i < 64; i++)
1393 {
1394 if (i <= 19)
1395 fcap[1] = '1' + i - 11;
1396 else if (i <= 45)
1397 fcap[1] = 'A' + i - 20;
1398 else
1399 fcap[1] = 'a' + i - 46;
1400
1401 {
1402 char *sequence = tgetstr (fcap, address);
1403 if (sequence)
1404 {
1405 sprintf (fkey, "f%d", i);
1406 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
1407 Fmake_vector (make_number (1),
1408 intern (fkey)));
1409 }
1410 }
1411 }
1412 }
1413
1414 /*
1415 * Various mappings to try and get a better fit.
1416 */
1417 {
1418 #define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1419 if (!tgetstr (cap1, address)) \
1420 { \
1421 char *sequence = tgetstr (cap2, address); \
1422 if (sequence) \
1423 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence), \
1424 Fmake_vector (make_number (1), \
1425 intern (sym))); \
1426 }
1427
1428 /* if there's no key_next keycap, map key_npage to `next' keysym */
1429 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1430 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1431 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1432 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1433 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1434 /* if there's no key_end keycap, map key_ll to 'end' keysym */
1435 CONDITIONAL_REASSIGN ("@7", "kH", "end");
1436
1437 /* IBM has their own non-standard dialect of terminfo.
1438 If the standard name isn't found, try the IBM name. */
1439 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1440 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1441 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1442 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1443 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1444 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1445 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1446 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1447 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1448 #undef CONDITIONAL_REASSIGN
1449 }
1450
1451 return Qnil;
1452 }
1453 #endif /* not DOS_NT */
1454
1455 \f
1456 /***********************************************************************
1457 Character Display Information
1458 ***********************************************************************/
1459 static void append_glyph (struct it *);
1460 static void produce_stretch_glyph (struct it *);
1461 static void append_composite_glyph (struct it *);
1462 static void produce_composite_glyph (struct it *);
1463 static void append_glyphless_glyph (struct it *, int, char *);
1464 static void produce_glyphless_glyph (struct it *, int, Lisp_Object);
1465
1466 /* Append glyphs to IT's glyph_row. Called from produce_glyphs for
1467 terminal frames if IT->glyph_row != NULL. IT->char_to_display is
1468 the character for which to produce glyphs; IT->face_id contains the
1469 character's face. Padding glyphs are appended if IT->c has a
1470 IT->pixel_width > 1. */
1471
1472 static void
1473 append_glyph (struct it *it)
1474 {
1475 struct glyph *glyph, *end;
1476 int i;
1477
1478 xassert (it->glyph_row);
1479 glyph = (it->glyph_row->glyphs[it->area]
1480 + it->glyph_row->used[it->area]);
1481 end = it->glyph_row->glyphs[1 + it->area];
1482
1483 /* If the glyph row is reversed, we need to prepend the glyph rather
1484 than append it. */
1485 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1486 {
1487 struct glyph *g;
1488 int move_by = it->pixel_width;
1489
1490 /* Make room for the new glyphs. */
1491 if (move_by > end - glyph) /* don't overstep end of this area */
1492 move_by = end - glyph;
1493 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1494 g[move_by] = *g;
1495 glyph = it->glyph_row->glyphs[it->area];
1496 end = glyph + move_by;
1497 }
1498
1499 /* BIDI Note: we put the glyphs of a "multi-pixel" character left to
1500 right, even in the REVERSED_P case, since (a) all of its u.ch are
1501 identical, and (b) the PADDING_P flag needs to be set for the
1502 leftmost one, because we write to the terminal left-to-right. */
1503 for (i = 0;
1504 i < it->pixel_width && glyph < end;
1505 ++i)
1506 {
1507 glyph->type = CHAR_GLYPH;
1508 glyph->pixel_width = 1;
1509 glyph->u.ch = it->char_to_display;
1510 glyph->face_id = it->face_id;
1511 glyph->padding_p = i > 0;
1512 glyph->charpos = CHARPOS (it->position);
1513 glyph->object = it->object;
1514 if (it->bidi_p)
1515 {
1516 glyph->resolved_level = it->bidi_it.resolved_level;
1517 if ((it->bidi_it.type & 7) != it->bidi_it.type)
1518 abort ();
1519 glyph->bidi_type = it->bidi_it.type;
1520 }
1521 else
1522 {
1523 glyph->resolved_level = 0;
1524 glyph->bidi_type = UNKNOWN_BT;
1525 }
1526
1527 ++it->glyph_row->used[it->area];
1528 ++glyph;
1529 }
1530 }
1531
1532 /* Produce glyphs for the display element described by IT. *IT
1533 specifies what we want to produce a glyph for (character, image, ...),
1534 and where in the glyph matrix we currently are (glyph row and hpos).
1535 produce_glyphs fills in output fields of *IT with information such as the
1536 pixel width and height of a character, and maybe output actual glyphs at
1537 the same time if IT->glyph_row is non-null. For an overview, see
1538 the explanation in dispextern.h, before the definition of the
1539 display_element_type enumeration.
1540
1541 produce_glyphs also stores the result of glyph width, ascent
1542 etc. computations in *IT.
1543
1544 IT->glyph_row may be null, in which case produce_glyphs does not
1545 actually fill in the glyphs. This is used in the move_* functions
1546 in xdisp.c for text width and height computations.
1547
1548 Callers usually don't call produce_glyphs directly;
1549 instead they use the macro PRODUCE_GLYPHS. */
1550
1551 void
1552 produce_glyphs (struct it *it)
1553 {
1554 /* If a hook is installed, let it do the work. */
1555
1556 /* Nothing but characters are supported on terminal frames. */
1557 xassert (it->what == IT_CHARACTER
1558 || it->what == IT_COMPOSITION
1559 || it->what == IT_STRETCH);
1560
1561 if (it->what == IT_STRETCH)
1562 {
1563 produce_stretch_glyph (it);
1564 goto done;
1565 }
1566
1567 if (it->what == IT_COMPOSITION)
1568 {
1569 produce_composite_glyph (it);
1570 goto done;
1571 }
1572
1573 if (it->what == IT_GLYPHLESS)
1574 {
1575 produce_glyphless_glyph (it, 0, Qnil);
1576 goto done;
1577 }
1578
1579 if (it->char_to_display >= 040 && it->char_to_display < 0177)
1580 {
1581 it->pixel_width = it->nglyphs = 1;
1582 if (it->glyph_row)
1583 append_glyph (it);
1584 }
1585 else if (it->char_to_display == '\n')
1586 it->pixel_width = it->nglyphs = 0;
1587 else if (it->char_to_display == '\t')
1588 {
1589 int absolute_x = (it->current_x
1590 + it->continuation_lines_width);
1591 int next_tab_x
1592 = (((1 + absolute_x + it->tab_width - 1)
1593 / it->tab_width)
1594 * it->tab_width);
1595 int nspaces;
1596
1597 /* If part of the TAB has been displayed on the previous line
1598 which is continued now, continuation_lines_width will have
1599 been incremented already by the part that fitted on the
1600 continued line. So, we will get the right number of spaces
1601 here. */
1602 nspaces = next_tab_x - absolute_x;
1603
1604 if (it->glyph_row)
1605 {
1606 int n = nspaces;
1607
1608 it->char_to_display = ' ';
1609 it->pixel_width = it->len = 1;
1610
1611 while (n--)
1612 append_glyph (it);
1613 }
1614
1615 it->pixel_width = nspaces;
1616 it->nglyphs = nspaces;
1617 }
1618 else if (CHAR_BYTE8_P (it->char_to_display))
1619 {
1620 /* Coming here means that we must send the raw 8-bit byte as is
1621 to the terminal. Although there's no way to know how many
1622 columns it occupies on a screen, it is a good assumption that
1623 a single byte code has 1-column width. */
1624 it->pixel_width = it->nglyphs = 1;
1625 if (it->glyph_row)
1626 append_glyph (it);
1627 }
1628 else
1629 {
1630 Lisp_Object charset_list = FRAME_TERMINAL (it->f)->charset_list;
1631
1632 if (char_charset (it->char_to_display, charset_list, NULL))
1633 {
1634 it->pixel_width = CHAR_WIDTH (it->char_to_display);
1635 it->nglyphs = it->pixel_width;
1636 if (it->glyph_row)
1637 append_glyph (it);
1638 }
1639 else
1640 {
1641 Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
1642
1643 xassert (it->what == IT_GLYPHLESS);
1644 produce_glyphless_glyph (it, 1, acronym);
1645 }
1646 }
1647
1648 done:
1649 /* Advance current_x by the pixel width as a convenience for
1650 the caller. */
1651 if (it->area == TEXT_AREA)
1652 it->current_x += it->pixel_width;
1653 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1654 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
1655 }
1656
1657
1658 /* Produce a stretch glyph for iterator IT. IT->object is the value
1659 of the glyph property displayed. The value must be a list
1660 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1661 being recognized:
1662
1663 1. `:width WIDTH' specifies that the space should be WIDTH *
1664 canonical char width wide. WIDTH may be an integer or floating
1665 point number.
1666
1667 2. `:align-to HPOS' specifies that the space should be wide enough
1668 to reach HPOS, a value in canonical character units. */
1669
1670 static void
1671 produce_stretch_glyph (struct it *it)
1672 {
1673 /* (space :width WIDTH ...) */
1674 Lisp_Object prop, plist;
1675 int width = 0, align_to = -1;
1676 int zero_width_ok_p = 0;
1677 double tem;
1678
1679 /* List should start with `space'. */
1680 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1681 plist = XCDR (it->object);
1682
1683 /* Compute the width of the stretch. */
1684 if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
1685 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, 0))
1686 {
1687 /* Absolute width `:width WIDTH' specified and valid. */
1688 zero_width_ok_p = 1;
1689 width = (int)(tem + 0.5);
1690 }
1691 else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
1692 && calc_pixel_width_or_height (&tem, it, prop, 0, 1, &align_to))
1693 {
1694 if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
1695 align_to = (align_to < 0
1696 ? 0
1697 : align_to - window_box_left_offset (it->w, TEXT_AREA));
1698 else if (align_to < 0)
1699 align_to = window_box_left_offset (it->w, TEXT_AREA);
1700 width = max (0, (int)(tem + 0.5) + align_to - it->current_x);
1701 zero_width_ok_p = 1;
1702 }
1703 else
1704 /* Nothing specified -> width defaults to canonical char width. */
1705 width = FRAME_COLUMN_WIDTH (it->f);
1706
1707 if (width <= 0 && (width < 0 || !zero_width_ok_p))
1708 width = 1;
1709
1710 if (width > 0 && it->line_wrap != TRUNCATE
1711 && it->current_x + width > it->last_visible_x)
1712 width = it->last_visible_x - it->current_x - 1;
1713
1714 if (width > 0 && it->glyph_row)
1715 {
1716 Lisp_Object o_object = it->object;
1717 Lisp_Object object = it->stack[it->sp - 1].string;
1718 int n = width;
1719
1720 if (!STRINGP (object))
1721 object = it->w->buffer;
1722 it->object = object;
1723 it->char_to_display = ' ';
1724 it->pixel_width = it->len = 1;
1725 while (n--)
1726 append_glyph (it);
1727 it->object = o_object;
1728 }
1729 it->pixel_width = width;
1730 it->nglyphs = width;
1731 }
1732
1733
1734 /* Append glyphs to IT's glyph_row for the composition IT->cmp_id.
1735 Called from produce_composite_glyph for terminal frames if
1736 IT->glyph_row != NULL. IT->face_id contains the character's
1737 face. */
1738
1739 static void
1740 append_composite_glyph (struct it *it)
1741 {
1742 struct glyph *glyph;
1743
1744 xassert (it->glyph_row);
1745 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1746 if (glyph < it->glyph_row->glyphs[1 + it->area])
1747 {
1748 /* If the glyph row is reversed, we need to prepend the glyph
1749 rather than append it. */
1750 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1751 {
1752 struct glyph *g;
1753
1754 /* Make room for the new glyph. */
1755 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1756 g[1] = *g;
1757 glyph = it->glyph_row->glyphs[it->area];
1758 }
1759 glyph->type = COMPOSITE_GLYPH;
1760 glyph->pixel_width = it->pixel_width;
1761 glyph->u.cmp.id = it->cmp_it.id;
1762 if (it->cmp_it.ch < 0)
1763 {
1764 glyph->u.cmp.automatic = 0;
1765 glyph->u.cmp.id = it->cmp_it.id;
1766 }
1767 else
1768 {
1769 glyph->u.cmp.automatic = 1;
1770 glyph->u.cmp.id = it->cmp_it.id;
1771 glyph->slice.cmp.from = it->cmp_it.from;
1772 glyph->slice.cmp.to = it->cmp_it.to - 1;
1773 }
1774
1775 glyph->face_id = it->face_id;
1776 glyph->padding_p = 0;
1777 glyph->charpos = CHARPOS (it->position);
1778 glyph->object = it->object;
1779 if (it->bidi_p)
1780 {
1781 glyph->resolved_level = it->bidi_it.resolved_level;
1782 if ((it->bidi_it.type & 7) != it->bidi_it.type)
1783 abort ();
1784 glyph->bidi_type = it->bidi_it.type;
1785 }
1786 else
1787 {
1788 glyph->resolved_level = 0;
1789 glyph->bidi_type = UNKNOWN_BT;
1790 }
1791
1792 ++it->glyph_row->used[it->area];
1793 ++glyph;
1794 }
1795 }
1796
1797
1798 /* Produce a composite glyph for iterator IT. IT->cmp_id is the ID of
1799 the composition. We simply produces components of the composition
1800 assuming that the terminal has a capability to layout/render it
1801 correctly. */
1802
1803 static void
1804 produce_composite_glyph (struct it *it)
1805 {
1806 if (it->cmp_it.ch < 0)
1807 {
1808 struct composition *cmp = composition_table[it->cmp_it.id];
1809
1810 it->pixel_width = cmp->width;
1811 }
1812 else
1813 {
1814 Lisp_Object gstring = composition_gstring_from_id (it->cmp_it.id);
1815
1816 it->pixel_width = composition_gstring_width (gstring, it->cmp_it.from,
1817 it->cmp_it.to, NULL);
1818 }
1819 it->nglyphs = 1;
1820 if (it->glyph_row)
1821 append_composite_glyph (it);
1822 }
1823
1824
1825 /* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID
1826 is a face ID to be used for the glyph. What is actually appended
1827 are glyphs of type CHAR_GLYPH whose characters are in STR (which
1828 comes from it->nglyphs bytes). */
1829
1830 static void
1831 append_glyphless_glyph (struct it *it, int face_id, char *str)
1832 {
1833 struct glyph *glyph, *end;
1834 int i;
1835
1836 xassert (it->glyph_row);
1837 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1838 end = it->glyph_row->glyphs[1 + it->area];
1839
1840 /* If the glyph row is reversed, we need to prepend the glyph rather
1841 than append it. */
1842 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1843 {
1844 struct glyph *g;
1845 int move_by = it->pixel_width;
1846
1847 /* Make room for the new glyphs. */
1848 if (move_by > end - glyph) /* don't overstep end of this area */
1849 move_by = end - glyph;
1850 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1851 g[move_by] = *g;
1852 glyph = it->glyph_row->glyphs[it->area];
1853 end = glyph + move_by;
1854 }
1855
1856 if (glyph >= end)
1857 return;
1858 glyph->type = CHAR_GLYPH;
1859 glyph->pixel_width = 1;
1860 glyph->face_id = face_id;
1861 glyph->padding_p = 0;
1862 glyph->charpos = CHARPOS (it->position);
1863 glyph->object = it->object;
1864 if (it->bidi_p)
1865 {
1866 glyph->resolved_level = it->bidi_it.resolved_level;
1867 if ((it->bidi_it.type & 7) != it->bidi_it.type)
1868 abort ();
1869 glyph->bidi_type = it->bidi_it.type;
1870 }
1871 else
1872 {
1873 glyph->resolved_level = 0;
1874 glyph->bidi_type = UNKNOWN_BT;
1875 }
1876
1877 /* BIDI Note: we put the glyphs of characters left to right, even in
1878 the REVERSED_P case because we write to the terminal
1879 left-to-right. */
1880 for (i = 0; i < it->nglyphs && glyph < end; ++i)
1881 {
1882 if (i > 0)
1883 glyph[0] = glyph[-1];
1884 glyph->u.ch = str[i];
1885 ++it->glyph_row->used[it->area];
1886 ++glyph;
1887 }
1888 }
1889
1890 /* Produce glyphs for a glyphless character for iterator IT.
1891 IT->glyphless_method specifies which method to use for displaying
1892 the character. See the description of enum
1893 glyphless_display_method in dispextern.h for the details.
1894
1895 FOR_NO_FONT is nonzero if and only if this is for a character that
1896 is not supproted by the coding system of the terminal. ACRONYM, if
1897 non-nil, is an acronym string for the character.
1898
1899 The glyphs actually produced are of type CHAR_GLYPH. */
1900
1901 static void
1902 produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
1903 {
1904 int face_id;
1905 int len;
1906 char buf[9], *str = " ";
1907
1908 /* Get a face ID for the glyph by utilizing a cache (the same way as
1909 done for `escape-glyph' in get_next_display_element). */
1910 if (it->f == last_glyphless_glyph_frame
1911 && it->face_id == last_glyphless_glyph_face_id)
1912 {
1913 face_id = last_glyphless_glyph_merged_face_id;
1914 }
1915 else
1916 {
1917 /* Merge the `glyphless-char' face into the current face. */
1918 face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id);
1919 last_glyphless_glyph_frame = it->f;
1920 last_glyphless_glyph_face_id = it->face_id;
1921 last_glyphless_glyph_merged_face_id = face_id;
1922 }
1923
1924 if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
1925 {
1926 /* As there's no way to produce a thin space, we produce a space
1927 of canonical width. */
1928 len = 1;
1929 }
1930 else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
1931 {
1932 len = CHAR_WIDTH (it->c);
1933 if (len == 0)
1934 len = 1;
1935 else if (len > 4)
1936 len = 4;
1937 sprintf (buf, "[%.*s]", len, str);
1938 len += 2;
1939 str = buf;
1940 }
1941 else
1942 {
1943 if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
1944 {
1945 if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
1946 acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
1947 buf[0] = '[';
1948 str = STRINGP (acronym) ? SSDATA (acronym) : "";
1949 for (len = 0; len < 6 && str[len] && ASCII_BYTE_P (str[len]); len++)
1950 buf[1 + len] = str[len];
1951 buf[1 + len] = ']';
1952 len += 2;
1953 }
1954 else
1955 {
1956 xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEX_CODE);
1957 len = (it->c < 0x10000 ? sprintf (buf, "\\u%04X", it->c)
1958 : it->c <= MAX_UNICODE_CHAR ? sprintf (buf, "\\U%06X", it->c)
1959 : sprintf (buf, "\\x%06X", it->c));
1960 }
1961 str = buf;
1962 }
1963
1964 it->pixel_width = len;
1965 it->nglyphs = len;
1966 if (len > 0 && it->glyph_row)
1967 append_glyphless_glyph (it, face_id, str);
1968 }
1969
1970
1971 /* Get information about special display element WHAT in an
1972 environment described by IT. WHAT is one of IT_TRUNCATION or
1973 IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a
1974 non-null glyph_row member. This function ensures that fields like
1975 face_id, c, len of IT are left untouched. */
1976
1977 void
1978 produce_special_glyphs (struct it *it, enum display_element_type what)
1979 {
1980 struct it temp_it;
1981 Lisp_Object gc;
1982 GLYPH glyph;
1983
1984 temp_it = *it;
1985 temp_it.dp = NULL;
1986 temp_it.what = IT_CHARACTER;
1987 temp_it.len = 1;
1988 temp_it.object = make_number (0);
1989 memset (&temp_it.current, 0, sizeof temp_it.current);
1990
1991 if (what == IT_CONTINUATION)
1992 {
1993 /* Continuation glyph. For R2L lines, we mirror it by hand. */
1994 if (it->bidi_it.paragraph_dir == R2L)
1995 SET_GLYPH_FROM_CHAR (glyph, '/');
1996 else
1997 SET_GLYPH_FROM_CHAR (glyph, '\\');
1998 if (it->dp
1999 && (gc = DISP_CONTINUE_GLYPH (it->dp), GLYPH_CODE_P (gc))
2000 && GLYPH_CODE_CHAR_VALID_P (gc))
2001 {
2002 /* FIXME: Should we mirror GC for R2L lines? */
2003 SET_GLYPH_FROM_GLYPH_CODE (glyph, gc);
2004 spec_glyph_lookup_face (XWINDOW (it->window), &glyph);
2005 }
2006 }
2007 else if (what == IT_TRUNCATION)
2008 {
2009 /* Truncation glyph. */
2010 SET_GLYPH_FROM_CHAR (glyph, '$');
2011 if (it->dp
2012 && (gc = DISP_TRUNC_GLYPH (it->dp), GLYPH_CODE_P (gc))
2013 && GLYPH_CODE_CHAR_VALID_P (gc))
2014 {
2015 /* FIXME: Should we mirror GC for R2L lines? */
2016 SET_GLYPH_FROM_GLYPH_CODE (glyph, gc);
2017 spec_glyph_lookup_face (XWINDOW (it->window), &glyph);
2018 }
2019 }
2020 else
2021 abort ();
2022
2023 temp_it.c = temp_it.char_to_display = GLYPH_CHAR (glyph);
2024 temp_it.face_id = GLYPH_FACE (glyph);
2025 temp_it.len = CHAR_BYTES (temp_it.c);
2026
2027 produce_glyphs (&temp_it);
2028 it->pixel_width = temp_it.pixel_width;
2029 it->nglyphs = temp_it.pixel_width;
2030 }
2031
2032
2033 \f
2034 /***********************************************************************
2035 Faces
2036 ***********************************************************************/
2037
2038 /* Value is non-zero if attribute ATTR may be used. ATTR should be
2039 one of the enumerators from enum no_color_bit, or a bit set built
2040 from them. Some display attributes may not be used together with
2041 color; the termcap capability `NC' specifies which ones. */
2042
2043 #define MAY_USE_WITH_COLORS_P(tty, ATTR) \
2044 (tty->TN_max_colors > 0 \
2045 ? (tty->TN_no_color_video & (ATTR)) == 0 \
2046 : 1)
2047
2048 /* Turn appearances of face FACE_ID on tty frame F on.
2049 FACE_ID is a realized face ID number, in the face cache. */
2050
2051 static void
2052 turn_on_face (struct frame *f, int face_id)
2053 {
2054 struct face *face = FACE_FROM_ID (f, face_id);
2055 long fg = face->foreground;
2056 long bg = face->background;
2057 struct tty_display_info *tty = FRAME_TTY (f);
2058
2059 /* Do this first because TS_end_standout_mode may be the same
2060 as TS_exit_attribute_mode, which turns all appearances off. */
2061 if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE))
2062 {
2063 if (tty->TN_max_colors > 0)
2064 {
2065 if (fg >= 0 && bg >= 0)
2066 {
2067 /* If the terminal supports colors, we can set them
2068 below without using reverse video. The face's fg
2069 and bg colors are set as they should appear on
2070 the screen, i.e. they take the inverse-video'ness
2071 of the face already into account. */
2072 }
2073 else if (inverse_video)
2074 {
2075 if (fg == FACE_TTY_DEFAULT_FG_COLOR
2076 || bg == FACE_TTY_DEFAULT_BG_COLOR)
2077 tty_toggle_highlight (tty);
2078 }
2079 else
2080 {
2081 if (fg == FACE_TTY_DEFAULT_BG_COLOR
2082 || bg == FACE_TTY_DEFAULT_FG_COLOR)
2083 tty_toggle_highlight (tty);
2084 }
2085 }
2086 else
2087 {
2088 /* If we can't display colors, use reverse video
2089 if the face specifies that. */
2090 if (inverse_video)
2091 {
2092 if (fg == FACE_TTY_DEFAULT_FG_COLOR
2093 || bg == FACE_TTY_DEFAULT_BG_COLOR)
2094 tty_toggle_highlight (tty);
2095 }
2096 else
2097 {
2098 if (fg == FACE_TTY_DEFAULT_BG_COLOR
2099 || bg == FACE_TTY_DEFAULT_FG_COLOR)
2100 tty_toggle_highlight (tty);
2101 }
2102 }
2103 }
2104
2105 if (face->tty_bold_p && MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
2106 OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
2107
2108 if (face->tty_dim_p && MAY_USE_WITH_COLORS_P (tty, NC_DIM))
2109 OUTPUT1_IF (tty, tty->TS_enter_dim_mode);
2110
2111 /* Alternate charset and blinking not yet used. */
2112 if (face->tty_alt_charset_p
2113 && MAY_USE_WITH_COLORS_P (tty, NC_ALT_CHARSET))
2114 OUTPUT1_IF (tty, tty->TS_enter_alt_charset_mode);
2115
2116 if (face->tty_blinking_p
2117 && MAY_USE_WITH_COLORS_P (tty, NC_BLINK))
2118 OUTPUT1_IF (tty, tty->TS_enter_blink_mode);
2119
2120 if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
2121 OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
2122
2123 if (tty->TN_max_colors > 0)
2124 {
2125 char *ts, *p;
2126
2127 ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
2128 if (fg >= 0 && ts)
2129 {
2130 p = tparam (ts, NULL, 0, (int) fg);
2131 OUTPUT (tty, p);
2132 xfree (p);
2133 }
2134
2135 ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
2136 if (bg >= 0 && ts)
2137 {
2138 p = tparam (ts, NULL, 0, (int) bg);
2139 OUTPUT (tty, p);
2140 xfree (p);
2141 }
2142 }
2143 }
2144
2145
2146 /* Turn off appearances of face FACE_ID on tty frame F. */
2147
2148 static void
2149 turn_off_face (struct frame *f, int face_id)
2150 {
2151 struct face *face = FACE_FROM_ID (f, face_id);
2152 struct tty_display_info *tty = FRAME_TTY (f);
2153
2154 xassert (face != NULL);
2155
2156 if (tty->TS_exit_attribute_mode)
2157 {
2158 /* Capability "me" will turn off appearance modes double-bright,
2159 half-bright, reverse-video, standout, underline. It may or
2160 may not turn off alt-char-mode. */
2161 if (face->tty_bold_p
2162 || face->tty_dim_p
2163 || face->tty_reverse_p
2164 || face->tty_alt_charset_p
2165 || face->tty_blinking_p
2166 || face->tty_underline_p)
2167 {
2168 OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
2169 if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0)
2170 tty->standout_mode = 0;
2171 }
2172
2173 if (face->tty_alt_charset_p)
2174 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
2175 }
2176 else
2177 {
2178 /* If we don't have "me" we can only have those appearances
2179 that have exit sequences defined. */
2180 if (face->tty_alt_charset_p)
2181 OUTPUT_IF (tty, tty->TS_exit_alt_charset_mode);
2182
2183 if (face->tty_underline_p)
2184 OUTPUT_IF (tty, tty->TS_exit_underline_mode);
2185 }
2186
2187 /* Switch back to default colors. */
2188 if (tty->TN_max_colors > 0
2189 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
2190 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
2191 || (face->background != FACE_TTY_DEFAULT_COLOR
2192 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
2193 OUTPUT1_IF (tty, tty->TS_orig_pair);
2194 }
2195
2196
2197 /* Return non-zero if the terminal on frame F supports all of the
2198 capabilities in CAPS simultaneously, with foreground and background
2199 colors FG and BG. */
2200
2201 int
2202 tty_capable_p (struct tty_display_info *tty, unsigned int caps,
2203 unsigned long fg, unsigned long bg)
2204 {
2205 #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
2206 if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
2207 return 0;
2208
2209 TTY_CAPABLE_P_TRY (tty, TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE);
2210 TTY_CAPABLE_P_TRY (tty, TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode, NC_UNDERLINE);
2211 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
2212 TTY_CAPABLE_P_TRY (tty, TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM);
2213 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BLINK, tty->TS_enter_blink_mode, NC_BLINK);
2214 TTY_CAPABLE_P_TRY (tty, TTY_CAP_ALT_CHARSET, tty->TS_enter_alt_charset_mode, NC_ALT_CHARSET);
2215
2216 /* We can do it! */
2217 return 1;
2218 }
2219
2220 /* Return non-zero if the terminal is capable to display colors. */
2221
2222 DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
2223 0, 1, 0,
2224 doc: /* Return non-nil if the tty device TERMINAL can display colors.
2225
2226 TERMINAL can be a terminal object, a frame, or nil (meaning the
2227 selected frame's terminal). This function always returns nil if
2228 TERMINAL does not refer to a text-only terminal. */)
2229 (Lisp_Object terminal)
2230 {
2231 struct terminal *t = get_tty_terminal (terminal, 0);
2232 if (!t)
2233 return Qnil;
2234 else
2235 return t->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
2236 }
2237
2238 /* Return the number of supported colors. */
2239 DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
2240 Stty_display_color_cells, 0, 1, 0,
2241 doc: /* Return the number of colors supported by the tty device TERMINAL.
2242
2243 TERMINAL can be a terminal object, a frame, or nil (meaning the
2244 selected frame's terminal). This function always returns 0 if
2245 TERMINAL does not refer to a text-only terminal. */)
2246 (Lisp_Object terminal)
2247 {
2248 struct terminal *t = get_tty_terminal (terminal, 0);
2249 if (!t)
2250 return make_number (0);
2251 else
2252 return make_number (t->display_info.tty->TN_max_colors);
2253 }
2254
2255 #ifndef DOS_NT
2256
2257 /* Declare here rather than in the function, as in the rest of Emacs,
2258 to work around an HPUX compiler bug (?). See
2259 http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00410.html */
2260 static int default_max_colors;
2261 static int default_max_pairs;
2262 static int default_no_color_video;
2263 static char *default_orig_pair;
2264 static char *default_set_foreground;
2265 static char *default_set_background;
2266
2267 /* Save or restore the default color-related capabilities of this
2268 terminal. */
2269 static void
2270 tty_default_color_capabilities (struct tty_display_info *tty, int save)
2271 {
2272
2273 if (save)
2274 {
2275 xfree (default_orig_pair);
2276 default_orig_pair = tty->TS_orig_pair ? xstrdup (tty->TS_orig_pair) : NULL;
2277
2278 xfree (default_set_foreground);
2279 default_set_foreground = tty->TS_set_foreground ? xstrdup (tty->TS_set_foreground)
2280 : NULL;
2281
2282 xfree (default_set_background);
2283 default_set_background = tty->TS_set_background ? xstrdup (tty->TS_set_background)
2284 : NULL;
2285
2286 default_max_colors = tty->TN_max_colors;
2287 default_max_pairs = tty->TN_max_pairs;
2288 default_no_color_video = tty->TN_no_color_video;
2289 }
2290 else
2291 {
2292 tty->TS_orig_pair = default_orig_pair;
2293 tty->TS_set_foreground = default_set_foreground;
2294 tty->TS_set_background = default_set_background;
2295 tty->TN_max_colors = default_max_colors;
2296 tty->TN_max_pairs = default_max_pairs;
2297 tty->TN_no_color_video = default_no_color_video;
2298 }
2299 }
2300
2301 /* Setup one of the standard tty color schemes according to MODE.
2302 MODE's value is generally the number of colors which we want to
2303 support; zero means set up for the default capabilities, the ones
2304 we saw at init_tty time; -1 means turn off color support. */
2305 static void
2306 tty_setup_colors (struct tty_display_info *tty, int mode)
2307 {
2308 /* Canonicalize all negative values of MODE. */
2309 if (mode < -1)
2310 mode = -1;
2311
2312 switch (mode)
2313 {
2314 case -1: /* no colors at all */
2315 tty->TN_max_colors = 0;
2316 tty->TN_max_pairs = 0;
2317 tty->TN_no_color_video = 0;
2318 tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL;
2319 break;
2320 case 0: /* default colors, if any */
2321 default:
2322 tty_default_color_capabilities (tty, 0);
2323 break;
2324 case 8: /* 8 standard ANSI colors */
2325 tty->TS_orig_pair = "\033[0m";
2326 #ifdef TERMINFO
2327 tty->TS_set_foreground = "\033[3%p1%dm";
2328 tty->TS_set_background = "\033[4%p1%dm";
2329 #else
2330 tty->TS_set_foreground = "\033[3%dm";
2331 tty->TS_set_background = "\033[4%dm";
2332 #endif
2333 tty->TN_max_colors = 8;
2334 tty->TN_max_pairs = 64;
2335 tty->TN_no_color_video = 0;
2336 break;
2337 }
2338 }
2339
2340 void
2341 set_tty_color_mode (struct tty_display_info *tty, struct frame *f)
2342 {
2343 Lisp_Object tem, val;
2344 Lisp_Object color_mode;
2345 int mode;
2346 Lisp_Object tty_color_mode_alist
2347 = Fintern_soft (build_string ("tty-color-mode-alist"), Qnil);
2348
2349 tem = assq_no_quit (Qtty_color_mode, f->param_alist);
2350 val = CONSP (tem) ? XCDR (tem) : Qnil;
2351
2352 if (INTEGERP (val))
2353 color_mode = val;
2354 else if (SYMBOLP (tty_color_mode_alist))
2355 {
2356 tem = Fassq (val, Fsymbol_value (tty_color_mode_alist));
2357 color_mode = CONSP (tem) ? XCDR (tem) : Qnil;
2358 }
2359 else
2360 color_mode = Qnil;
2361
2362 mode = INTEGERP (color_mode) ? XINT (color_mode) : 0;
2363
2364 if (mode != tty->previous_color_mode)
2365 {
2366 Lisp_Object funsym = intern ("tty-set-up-initial-frame-faces");
2367 tty->previous_color_mode = mode;
2368 tty_setup_colors (tty , mode);
2369 /* This recomputes all the faces given the new color definitions. */
2370 safe_call (1, &funsym);
2371 }
2372 }
2373
2374 #endif /* !DOS_NT */
2375
2376 \f
2377
2378 /* Return the tty display object specified by TERMINAL. */
2379
2380 struct terminal *
2381 get_tty_terminal (Lisp_Object terminal, int throw)
2382 {
2383 struct terminal *t = get_terminal (terminal, throw);
2384
2385 if (t && t->type != output_termcap && t->type != output_msdos_raw)
2386 {
2387 if (throw)
2388 error ("Device %d is not a termcap terminal device", t->id);
2389 else
2390 return NULL;
2391 }
2392
2393 return t;
2394 }
2395
2396 /* Return an active termcap device that uses the tty device with the
2397 given name.
2398
2399 This function ignores suspended devices.
2400
2401 Returns NULL if the named terminal device is not opened. */
2402
2403 struct terminal *
2404 get_named_tty (const char *name)
2405 {
2406 struct terminal *t;
2407
2408 if (!name)
2409 abort ();
2410
2411 for (t = terminal_list; t; t = t->next_terminal)
2412 {
2413 if ((t->type == output_termcap || t->type == output_msdos_raw)
2414 && !strcmp (t->display_info.tty->name, name)
2415 && TERMINAL_ACTIVE_P (t))
2416 return t;
2417 }
2418
2419 return 0;
2420 }
2421
2422 \f
2423 DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
2424 doc: /* Return the type of the tty device that TERMINAL uses.
2425 Returns nil if TERMINAL is not on a tty device.
2426
2427 TERMINAL can be a terminal object, a frame, or nil (meaning the
2428 selected frame's terminal). */)
2429 (Lisp_Object terminal)
2430 {
2431 struct terminal *t = get_terminal (terminal, 1);
2432
2433 if (t->type != output_termcap && t->type != output_msdos_raw)
2434 return Qnil;
2435
2436 if (t->display_info.tty->type)
2437 return build_string (t->display_info.tty->type);
2438 else
2439 return Qnil;
2440 }
2441
2442 DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
2443 doc: /* Return non-nil if TERMINAL is the controlling tty of the Emacs process.
2444
2445 TERMINAL can be a terminal object, a frame, or nil (meaning the
2446 selected frame's terminal). This function always returns nil if
2447 TERMINAL is not on a tty device. */)
2448 (Lisp_Object terminal)
2449 {
2450 struct terminal *t = get_terminal (terminal, 1);
2451
2452 if ((t->type != output_termcap && t->type != output_msdos_raw)
2453 || strcmp (t->display_info.tty->name, DEV_TTY) != 0)
2454 return Qnil;
2455 else
2456 return Qt;
2457 }
2458
2459 DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
2460 doc: /* Declare that the tty used by TERMINAL does not handle underlining.
2461 This is used to override the terminfo data, for certain terminals that
2462 do not really do underlining, but say that they do. This function has
2463 no effect if used on a non-tty terminal.
2464
2465 TERMINAL can be a terminal object, a frame or nil (meaning the
2466 selected frame's terminal). This function always returns nil if
2467 TERMINAL does not refer to a text-only terminal. */)
2468 (Lisp_Object terminal)
2469 {
2470 struct terminal *t = get_terminal (terminal, 1);
2471
2472 if (t->type == output_termcap)
2473 t->display_info.tty->TS_enter_underline_mode = 0;
2474 return Qnil;
2475 }
2476
2477 \f
2478
2479 DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
2480 doc: /* Suspend the terminal device TTY.
2481
2482 The device is restored to its default state, and Emacs ceases all
2483 access to the tty device. Frames that use the device are not deleted,
2484 but input is not read from them and if they change, their display is
2485 not updated.
2486
2487 TTY may be a terminal object, a frame, or nil for the terminal device
2488 of the currently selected frame.
2489
2490 This function runs `suspend-tty-functions' after suspending the
2491 device. The functions are run with one arg, the id of the suspended
2492 terminal device.
2493
2494 `suspend-tty' does nothing if it is called on a device that is already
2495 suspended.
2496
2497 A suspended tty may be resumed by calling `resume-tty' on it. */)
2498 (Lisp_Object tty)
2499 {
2500 struct terminal *t = get_tty_terminal (tty, 1);
2501 FILE *f;
2502
2503 if (!t)
2504 error ("Unknown tty device");
2505
2506 f = t->display_info.tty->input;
2507
2508 if (f)
2509 {
2510 /* First run `suspend-tty-functions' and then clean up the tty
2511 state because `suspend-tty-functions' might need to change
2512 the tty state. */
2513 if (!NILP (Vrun_hooks))
2514 {
2515 Lisp_Object args[2];
2516 args[0] = intern ("suspend-tty-functions");
2517 XSETTERMINAL (args[1], t);
2518 Frun_hook_with_args (2, args);
2519 }
2520
2521 reset_sys_modes (t->display_info.tty);
2522 delete_keyboard_wait_descriptor (fileno (f));
2523
2524 #ifndef MSDOS
2525 fclose (f);
2526 if (f != t->display_info.tty->output)
2527 fclose (t->display_info.tty->output);
2528 #endif
2529
2530 t->display_info.tty->input = 0;
2531 t->display_info.tty->output = 0;
2532
2533 if (FRAMEP (t->display_info.tty->top_frame))
2534 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
2535
2536 }
2537
2538 /* Clear display hooks to prevent further output. */
2539 clear_tty_hooks (t);
2540
2541 return Qnil;
2542 }
2543
2544 DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
2545 doc: /* Resume the previously suspended terminal device TTY.
2546 The terminal is opened and reinitialized. Frames that are on the
2547 suspended terminal are revived.
2548
2549 It is an error to resume a terminal while another terminal is active
2550 on the same device.
2551
2552 This function runs `resume-tty-functions' after resuming the terminal.
2553 The functions are run with one arg, the id of the resumed terminal
2554 device.
2555
2556 `resume-tty' does nothing if it is called on a device that is not
2557 suspended.
2558
2559 TTY may be a terminal object, a frame, or nil (meaning the selected
2560 frame's terminal). */)
2561 (Lisp_Object tty)
2562 {
2563 struct terminal *t = get_tty_terminal (tty, 1);
2564 int fd;
2565
2566 if (!t)
2567 error ("Unknown tty device");
2568
2569 if (!t->display_info.tty->input)
2570 {
2571 if (get_named_tty (t->display_info.tty->name))
2572 error ("Cannot resume display while another display is active on the same device");
2573
2574 #ifdef MSDOS
2575 t->display_info.tty->output = stdout;
2576 t->display_info.tty->input = stdin;
2577 #else /* !MSDOS */
2578 fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
2579
2580 if (fd == -1)
2581 error ("Can not reopen tty device %s: %s", t->display_info.tty->name, strerror (errno));
2582
2583 if (strcmp (t->display_info.tty->name, DEV_TTY))
2584 dissociate_if_controlling_tty (fd);
2585
2586 t->display_info.tty->output = fdopen (fd, "w+");
2587 t->display_info.tty->input = t->display_info.tty->output;
2588 #endif
2589
2590 add_keyboard_wait_descriptor (fd);
2591
2592 if (FRAMEP (t->display_info.tty->top_frame))
2593 {
2594 struct frame *f = XFRAME (t->display_info.tty->top_frame);
2595 int width, height;
2596 int old_height = FRAME_COLS (f);
2597 int old_width = FRAME_LINES (f);
2598
2599 /* Check if terminal/window size has changed while the frame
2600 was suspended. */
2601 get_tty_size (fileno (t->display_info.tty->input), &width, &height);
2602 if (width != old_width || height != old_height)
2603 change_frame_size (f, height, width, 0, 0, 0);
2604 FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
2605 }
2606
2607 init_sys_modes (t->display_info.tty);
2608
2609 /* Run `resume-tty-functions'. */
2610 if (!NILP (Vrun_hooks))
2611 {
2612 Lisp_Object args[2];
2613 args[0] = intern ("resume-tty-functions");
2614 XSETTERMINAL (args[1], t);
2615 Frun_hook_with_args (2, args);
2616 }
2617 }
2618
2619 set_tty_hooks (t);
2620
2621 return Qnil;
2622 }
2623
2624 \f
2625 /***********************************************************************
2626 Mouse
2627 ***********************************************************************/
2628
2629 #ifdef HAVE_GPM
2630 void
2631 term_mouse_moveto (int x, int y)
2632 {
2633 /* TODO: how to set mouse position?
2634 const char *name;
2635 int fd;
2636 name = (const char *) ttyname (0);
2637 fd = open (name, O_WRONLY);
2638 SOME_FUNCTION (x, y, fd);
2639 close (fd);
2640 last_mouse_x = x;
2641 last_mouse_y = y; */
2642 }
2643
2644 /* Implementation of draw_row_with_mouse_face for TTY/GPM. */
2645 void
2646 tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
2647 int start_hpos, int end_hpos,
2648 enum draw_glyphs_face draw)
2649 {
2650 int nglyphs = end_hpos - start_hpos;
2651 struct frame *f = XFRAME (WINDOW_FRAME (w));
2652 struct tty_display_info *tty = FRAME_TTY (f);
2653 int face_id = tty->mouse_highlight.mouse_face_face_id;
2654 int save_x, save_y, pos_x, pos_y;
2655
2656 if (end_hpos >= row->used[TEXT_AREA])
2657 nglyphs = row->used[TEXT_AREA] - start_hpos;
2658
2659 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
2660 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w);
2661
2662 /* Save current cursor co-ordinates. */
2663 save_y = curY (tty);
2664 save_x = curX (tty);
2665 cursor_to (f, pos_y, pos_x);
2666
2667 if (draw == DRAW_MOUSE_FACE)
2668 tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
2669 nglyphs, face_id);
2670 else if (draw == DRAW_NORMAL_TEXT)
2671 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
2672
2673 cursor_to (f, save_y, save_x);
2674 }
2675
2676 static int
2677 term_mouse_movement (FRAME_PTR frame, Gpm_Event *event)
2678 {
2679 /* Has the mouse moved off the glyph it was on at the last sighting? */
2680 if (event->x != last_mouse_x || event->y != last_mouse_y)
2681 {
2682 frame->mouse_moved = 1;
2683 note_mouse_highlight (frame, event->x, event->y);
2684 /* Remember which glyph we're now on. */
2685 last_mouse_x = event->x;
2686 last_mouse_y = event->y;
2687 return 1;
2688 }
2689 return 0;
2690 }
2691
2692 /* Return the current position of the mouse.
2693
2694 Set *f to the frame the mouse is in, or zero if the mouse is in no
2695 Emacs frame. If it is set to zero, all the other arguments are
2696 garbage.
2697
2698 Set *bar_window to Qnil, and *x and *y to the column and
2699 row of the character cell the mouse is over.
2700
2701 Set *time to the time the mouse was at the returned position.
2702
2703 This clears mouse_moved until the next motion
2704 event arrives. */
2705 static void
2706 term_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window,
2707 enum scroll_bar_part *part, Lisp_Object *x,
2708 Lisp_Object *y, unsigned long *time)
2709 {
2710 struct timeval now;
2711
2712 *fp = SELECTED_FRAME ();
2713 (*fp)->mouse_moved = 0;
2714
2715 *bar_window = Qnil;
2716 *part = 0;
2717
2718 XSETINT (*x, last_mouse_x);
2719 XSETINT (*y, last_mouse_y);
2720 gettimeofday(&now, 0);
2721 *time = (now.tv_sec * 1000) + (now.tv_usec / 1000);
2722 }
2723
2724 /* Prepare a mouse-event in *RESULT for placement in the input queue.
2725
2726 If the event is a button press, then note that we have grabbed
2727 the mouse. */
2728
2729 static Lisp_Object
2730 term_mouse_click (struct input_event *result, Gpm_Event *event,
2731 struct frame *f)
2732 {
2733 struct timeval now;
2734 int i, j;
2735
2736 result->kind = GPM_CLICK_EVENT;
2737 for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
2738 {
2739 if (event->buttons & j) {
2740 result->code = i; /* button number */
2741 break;
2742 }
2743 }
2744 gettimeofday(&now, 0);
2745 result->timestamp = (now.tv_sec * 1000) + (now.tv_usec / 1000);
2746
2747 if (event->type & GPM_UP)
2748 result->modifiers = up_modifier;
2749 else if (event->type & GPM_DOWN)
2750 result->modifiers = down_modifier;
2751 else
2752 result->modifiers = 0;
2753
2754 if (event->type & GPM_SINGLE)
2755 result->modifiers |= click_modifier;
2756
2757 if (event->type & GPM_DOUBLE)
2758 result->modifiers |= double_modifier;
2759
2760 if (event->type & GPM_TRIPLE)
2761 result->modifiers |= triple_modifier;
2762
2763 if (event->type & GPM_DRAG)
2764 result->modifiers |= drag_modifier;
2765
2766 if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
2767
2768 /* 1 << KG_SHIFT */
2769 if (event->modifiers & (1 << 0))
2770 result->modifiers |= shift_modifier;
2771
2772 /* 1 << KG_CTRL */
2773 if (event->modifiers & (1 << 2))
2774 result->modifiers |= ctrl_modifier;
2775
2776 /* 1 << KG_ALT || KG_ALTGR */
2777 if (event->modifiers & (1 << 3)
2778 || event->modifiers & (1 << 1))
2779 result->modifiers |= meta_modifier;
2780 }
2781
2782 XSETINT (result->x, event->x);
2783 XSETINT (result->y, event->y);
2784 XSETFRAME (result->frame_or_window, f);
2785 result->arg = Qnil;
2786 return Qnil;
2787 }
2788
2789 int
2790 handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event, struct input_event* hold_quit)
2791 {
2792 struct frame *f = XFRAME (tty->top_frame);
2793 struct input_event ie;
2794 int do_help = 0;
2795 int count = 0;
2796
2797 EVENT_INIT (ie);
2798 ie.kind = NO_EVENT;
2799 ie.arg = Qnil;
2800
2801 if (event->type & (GPM_MOVE | GPM_DRAG)) {
2802 previous_help_echo_string = help_echo_string;
2803 help_echo_string = Qnil;
2804
2805 Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
2806
2807 if (!term_mouse_movement (f, event))
2808 help_echo_string = previous_help_echo_string;
2809
2810 /* If the contents of the global variable help_echo_string
2811 has changed, generate a HELP_EVENT. */
2812 if (!NILP (help_echo_string)
2813 || !NILP (previous_help_echo_string))
2814 do_help = 1;
2815
2816 goto done;
2817 }
2818 else {
2819 f->mouse_moved = 0;
2820 term_mouse_click (&ie, event, f);
2821 }
2822
2823 done:
2824 if (ie.kind != NO_EVENT)
2825 {
2826 kbd_buffer_store_event_hold (&ie, hold_quit);
2827 count++;
2828 }
2829
2830 if (do_help
2831 && !(hold_quit && hold_quit->kind != NO_EVENT))
2832 {
2833 Lisp_Object frame;
2834
2835 if (f)
2836 XSETFRAME (frame, f);
2837 else
2838 frame = Qnil;
2839
2840 gen_help_event (help_echo_string, frame, help_echo_window,
2841 help_echo_object, help_echo_pos);
2842 count++;
2843 }
2844
2845 return count;
2846 }
2847
2848 DEFUN ("gpm-mouse-start", Fgpm_mouse_start, Sgpm_mouse_start,
2849 0, 0, 0,
2850 doc: /* Open a connection to Gpm.
2851 Gpm-mouse can only be activated for one tty at a time. */)
2852 (void)
2853 {
2854 struct frame *f = SELECTED_FRAME ();
2855 struct tty_display_info *tty
2856 = ((f)->output_method == output_termcap
2857 ? (f)->terminal->display_info.tty : NULL);
2858 Gpm_Connect connection;
2859
2860 if (!tty)
2861 error ("Gpm-mouse only works in the GNU/Linux console");
2862 if (gpm_tty == tty)
2863 return Qnil; /* Already activated, nothing to do. */
2864 if (gpm_tty)
2865 error ("Gpm-mouse can only be activated for one tty at a time");
2866
2867 connection.eventMask = ~0;
2868 connection.defaultMask = ~GPM_HARD;
2869 connection.maxMod = ~0;
2870 connection.minMod = 0;
2871 gpm_zerobased = 1;
2872
2873 if (Gpm_Open (&connection, 0) < 0)
2874 error ("Gpm-mouse failed to connect to the gpm daemon");
2875 else
2876 {
2877 gpm_tty = tty;
2878 /* `init_sys_modes' arranges for mouse movements sent through gpm_fd
2879 to generate SIGIOs. Apparently we need to call reset_sys_modes
2880 before calling init_sys_modes. */
2881 reset_sys_modes (tty);
2882 init_sys_modes (tty);
2883 add_gpm_wait_descriptor (gpm_fd);
2884 return Qnil;
2885 }
2886 }
2887
2888 void
2889 close_gpm (int fd)
2890 {
2891 if (fd >= 0)
2892 delete_gpm_wait_descriptor (fd);
2893 while (Gpm_Close()); /* close all the stack */
2894 gpm_tty = NULL;
2895 }
2896
2897 DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
2898 0, 0, 0,
2899 doc: /* Close a connection to Gpm. */)
2900 (void)
2901 {
2902 struct frame *f = SELECTED_FRAME ();
2903 struct tty_display_info *tty
2904 = ((f)->output_method == output_termcap
2905 ? (f)->terminal->display_info.tty : NULL);
2906
2907 if (!tty || gpm_tty != tty)
2908 return Qnil; /* Not activated on this terminal, nothing to do. */
2909
2910 close_gpm (gpm_fd);
2911 return Qnil;
2912 }
2913 #endif /* HAVE_GPM */
2914
2915 \f
2916 #ifndef MSDOS
2917 /***********************************************************************
2918 Initialization
2919 ***********************************************************************/
2920
2921 /* Initialize the tty-dependent part of frame F. The frame must
2922 already have its device initialized. */
2923
2924 void
2925 create_tty_output (struct frame *f)
2926 {
2927 struct tty_output *t;
2928
2929 if (! FRAME_TERMCAP_P (f))
2930 abort ();
2931
2932 t = xmalloc (sizeof (struct tty_output));
2933 memset (t, 0, sizeof (struct tty_output));
2934
2935 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
2936
2937 f->output_data.tty = t;
2938 }
2939
2940 /* Delete frame F's face cache, and its tty-dependent part. */
2941
2942 static void
2943 tty_free_frame_resources (struct frame *f)
2944 {
2945 if (! FRAME_TERMCAP_P (f))
2946 abort ();
2947
2948 if (FRAME_FACE_CACHE (f))
2949 free_frame_faces (f);
2950
2951 xfree (f->output_data.tty);
2952 }
2953
2954 #else /* MSDOS */
2955
2956 /* Delete frame F's face cache. */
2957
2958 static void
2959 tty_free_frame_resources (struct frame *f)
2960 {
2961 if (! FRAME_TERMCAP_P (f) && ! FRAME_MSDOS_P (f))
2962 abort ();
2963
2964 if (FRAME_FACE_CACHE (f))
2965 free_frame_faces (f);
2966 }
2967 #endif /* MSDOS */
2968 \f
2969 /* Reset the hooks in TERMINAL. */
2970
2971 static void
2972 clear_tty_hooks (struct terminal *terminal)
2973 {
2974 terminal->rif = 0;
2975 terminal->cursor_to_hook = 0;
2976 terminal->raw_cursor_to_hook = 0;
2977 terminal->clear_to_end_hook = 0;
2978 terminal->clear_frame_hook = 0;
2979 terminal->clear_end_of_line_hook = 0;
2980 terminal->ins_del_lines_hook = 0;
2981 terminal->insert_glyphs_hook = 0;
2982 terminal->write_glyphs_hook = 0;
2983 terminal->delete_glyphs_hook = 0;
2984 terminal->ring_bell_hook = 0;
2985 terminal->reset_terminal_modes_hook = 0;
2986 terminal->set_terminal_modes_hook = 0;
2987 terminal->update_begin_hook = 0;
2988 terminal->update_end_hook = 0;
2989 terminal->set_terminal_window_hook = 0;
2990 terminal->mouse_position_hook = 0;
2991 terminal->frame_rehighlight_hook = 0;
2992 terminal->frame_raise_lower_hook = 0;
2993 terminal->fullscreen_hook = 0;
2994 terminal->set_vertical_scroll_bar_hook = 0;
2995 terminal->condemn_scroll_bars_hook = 0;
2996 terminal->redeem_scroll_bar_hook = 0;
2997 terminal->judge_scroll_bars_hook = 0;
2998 terminal->read_socket_hook = 0;
2999 terminal->frame_up_to_date_hook = 0;
3000
3001 /* Leave these two set, or suspended frames are not deleted
3002 correctly. */
3003 terminal->delete_frame_hook = &tty_free_frame_resources;
3004 terminal->delete_terminal_hook = &delete_tty;
3005 }
3006
3007 /* Initialize hooks in TERMINAL with the values needed for a tty. */
3008
3009 static void
3010 set_tty_hooks (struct terminal *terminal)
3011 {
3012 terminal->rif = 0; /* ttys don't support window-based redisplay. */
3013
3014 terminal->cursor_to_hook = &tty_cursor_to;
3015 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
3016
3017 terminal->clear_to_end_hook = &tty_clear_to_end;
3018 terminal->clear_frame_hook = &tty_clear_frame;
3019 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
3020
3021 terminal->ins_del_lines_hook = &tty_ins_del_lines;
3022
3023 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3024 terminal->write_glyphs_hook = &tty_write_glyphs;
3025 terminal->delete_glyphs_hook = &tty_delete_glyphs;
3026
3027 terminal->ring_bell_hook = &tty_ring_bell;
3028
3029 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3030 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
3031 terminal->update_begin_hook = 0; /* Not needed. */
3032 terminal->update_end_hook = &tty_update_end;
3033 terminal->set_terminal_window_hook = &tty_set_terminal_window;
3034
3035 terminal->mouse_position_hook = 0; /* Not needed. */
3036 terminal->frame_rehighlight_hook = 0; /* Not needed. */
3037 terminal->frame_raise_lower_hook = 0; /* Not needed. */
3038
3039 terminal->set_vertical_scroll_bar_hook = 0; /* Not needed. */
3040 terminal->condemn_scroll_bars_hook = 0; /* Not needed. */
3041 terminal->redeem_scroll_bar_hook = 0; /* Not needed. */
3042 terminal->judge_scroll_bars_hook = 0; /* Not needed. */
3043
3044 terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
3045 terminal->frame_up_to_date_hook = 0; /* Not needed. */
3046
3047 terminal->delete_frame_hook = &tty_free_frame_resources;
3048 terminal->delete_terminal_hook = &delete_tty;
3049 }
3050
3051 /* Drop the controlling terminal if fd is the same device. */
3052 static void
3053 dissociate_if_controlling_tty (int fd)
3054 {
3055 #ifndef DOS_NT
3056 int pgid = tcgetpgrp (fd); /* If tcgetpgrp succeeds, fd is the ctty. */
3057 if (pgid != -1)
3058 {
3059 #if defined (USG5)
3060 setpgrp ();
3061 no_controlling_tty = 1;
3062 #elif defined (CYGWIN)
3063 setsid ();
3064 no_controlling_tty = 1;
3065 #else
3066 #ifdef TIOCNOTTY /* Try BSD ioctls. */
3067 sigblock (sigmask (SIGTTOU));
3068 fd = emacs_open (DEV_TTY, O_RDWR, 0);
3069 if (fd != -1 && ioctl (fd, TIOCNOTTY, 0) != -1)
3070 {
3071 no_controlling_tty = 1;
3072 }
3073 if (fd != -1)
3074 emacs_close (fd);
3075 sigunblock (sigmask (SIGTTOU));
3076 #else
3077 /* Unknown system. */
3078 croak ();
3079 #endif /* ! TIOCNOTTY */
3080 #endif /* ! USG */
3081 }
3082 #endif /* !DOS_NT */
3083 }
3084
3085 /* Create a termcap display on the tty device with the given name and
3086 type.
3087
3088 If NAME is NULL, then use the controlling tty, i.e., "/dev/tty".
3089 Otherwise NAME should be a path to the tty device file,
3090 e.g. "/dev/pts/7".
3091
3092 TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
3093
3094 If MUST_SUCCEED is true, then all errors are fatal. */
3095
3096 struct terminal *
3097 init_tty (const char *name, const char *terminal_type, int must_succeed)
3098 {
3099 char *area = NULL;
3100 char **address = &area;
3101 int buffer_size = 4096;
3102 register char *p = NULL;
3103 int status;
3104 struct tty_display_info *tty = NULL;
3105 struct terminal *terminal = NULL;
3106 int ctty = 0; /* 1 if asked to open controlling tty. */
3107
3108 if (!terminal_type)
3109 maybe_fatal (must_succeed, 0,
3110 "Unknown terminal type",
3111 "Unknown terminal type");
3112
3113 if (name == NULL)
3114 name = DEV_TTY;
3115 if (!strcmp (name, DEV_TTY))
3116 ctty = 1;
3117
3118 /* If we already have a terminal on the given device, use that. If
3119 all such terminals are suspended, create a new one instead. */
3120 /* XXX Perhaps this should be made explicit by having init_tty
3121 always create a new terminal and separating terminal and frame
3122 creation on Lisp level. */
3123 terminal = get_named_tty (name);
3124 if (terminal)
3125 return terminal;
3126
3127 terminal = create_terminal ();
3128 #ifdef MSDOS
3129 if (been_here > 0)
3130 maybe_fatal (1, 0, "Attempt to create another terminal %s", "",
3131 name, "");
3132 been_here = 1;
3133 tty = &the_only_display_info;
3134 #else
3135 tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info));
3136 #endif
3137 memset (tty, 0, sizeof (struct tty_display_info));
3138 tty->next = tty_list;
3139 tty_list = tty;
3140
3141 terminal->type = output_termcap;
3142 terminal->display_info.tty = tty;
3143 tty->terminal = terminal;
3144
3145 tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
3146 Wcm_clear (tty);
3147
3148 encode_terminal_src_size = 0;
3149 encode_terminal_dst_size = 0;
3150
3151 #ifdef HAVE_GPM
3152 terminal->mouse_position_hook = term_mouse_position;
3153 tty->mouse_highlight.mouse_face_window = Qnil;
3154 #endif
3155
3156
3157 #ifndef DOS_NT
3158 set_tty_hooks (terminal);
3159
3160 {
3161 int fd;
3162 FILE *file;
3163
3164 #ifdef O_IGNORE_CTTY
3165 if (!ctty)
3166 /* Open the terminal device. Don't recognize it as our
3167 controlling terminal, and don't make it the controlling tty
3168 if we don't have one at the moment. */
3169 fd = emacs_open (name, O_RDWR | O_IGNORE_CTTY | O_NOCTTY, 0);
3170 else
3171 #else
3172 /* Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
3173 defined on Hurd. On other systems, we need to explicitly
3174 dissociate ourselves from the controlling tty when we want to
3175 open a frame on the same terminal. */
3176 fd = emacs_open (name, O_RDWR | O_NOCTTY, 0);
3177 #endif /* O_IGNORE_CTTY */
3178
3179 tty->name = xstrdup (name);
3180 terminal->name = xstrdup (name);
3181
3182 if (fd < 0)
3183 maybe_fatal (must_succeed, terminal,
3184 "Could not open file: %s",
3185 "Could not open file: %s",
3186 name);
3187 if (!isatty (fd))
3188 {
3189 close (fd);
3190 maybe_fatal (must_succeed, terminal,
3191 "Not a tty device: %s",
3192 "Not a tty device: %s",
3193 name);
3194 }
3195
3196 #ifndef O_IGNORE_CTTY
3197 if (!ctty)
3198 dissociate_if_controlling_tty (fd);
3199 #endif
3200
3201 file = fdopen (fd, "w+");
3202 tty->input = file;
3203 tty->output = file;
3204 }
3205
3206 tty->type = xstrdup (terminal_type);
3207
3208 add_keyboard_wait_descriptor (fileno (tty->input));
3209
3210 Wcm_clear (tty);
3211
3212 tty->termcap_term_buffer = (char *) xmalloc (buffer_size);
3213
3214 /* On some systems, tgetent tries to access the controlling
3215 terminal. */
3216 sigblock (sigmask (SIGTTOU));
3217 status = tgetent (tty->termcap_term_buffer, terminal_type);
3218 sigunblock (sigmask (SIGTTOU));
3219
3220 if (status < 0)
3221 {
3222 #ifdef TERMINFO
3223 maybe_fatal (must_succeed, terminal,
3224 "Cannot open terminfo database file",
3225 "Cannot open terminfo database file");
3226 #else
3227 maybe_fatal (must_succeed, terminal,
3228 "Cannot open termcap database file",
3229 "Cannot open termcap database file");
3230 #endif
3231 }
3232 if (status == 0)
3233 {
3234 maybe_fatal (must_succeed, terminal,
3235 "Terminal type %s is not defined",
3236 "Terminal type %s is not defined.\n\
3237 If that is not the actual type of terminal you have,\n\
3238 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3239 `setenv TERM ...') to specify the correct type. It may be necessary\n"
3240 #ifdef TERMINFO
3241 "to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
3242 #else
3243 "to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
3244 #endif
3245 terminal_type);
3246 }
3247
3248 #ifndef TERMINFO
3249 if (strlen (tty->termcap_term_buffer) >= buffer_size)
3250 abort ();
3251 buffer_size = strlen (tty->termcap_term_buffer);
3252 #endif
3253 tty->termcap_strings_buffer = area = (char *) xmalloc (buffer_size);
3254 tty->TS_ins_line = tgetstr ("al", address);
3255 tty->TS_ins_multi_lines = tgetstr ("AL", address);
3256 tty->TS_bell = tgetstr ("bl", address);
3257 BackTab (tty) = tgetstr ("bt", address);
3258 tty->TS_clr_to_bottom = tgetstr ("cd", address);
3259 tty->TS_clr_line = tgetstr ("ce", address);
3260 tty->TS_clr_frame = tgetstr ("cl", address);
3261 ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
3262 AbsPosition (tty) = tgetstr ("cm", address);
3263 CR (tty) = tgetstr ("cr", address);
3264 tty->TS_set_scroll_region = tgetstr ("cs", address);
3265 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
3266 RowPosition (tty) = tgetstr ("cv", address);
3267 tty->TS_del_char = tgetstr ("dc", address);
3268 tty->TS_del_multi_chars = tgetstr ("DC", address);
3269 tty->TS_del_line = tgetstr ("dl", address);
3270 tty->TS_del_multi_lines = tgetstr ("DL", address);
3271 tty->TS_delete_mode = tgetstr ("dm", address);
3272 tty->TS_end_delete_mode = tgetstr ("ed", address);
3273 tty->TS_end_insert_mode = tgetstr ("ei", address);
3274 Home (tty) = tgetstr ("ho", address);
3275 tty->TS_ins_char = tgetstr ("ic", address);
3276 tty->TS_ins_multi_chars = tgetstr ("IC", address);
3277 tty->TS_insert_mode = tgetstr ("im", address);
3278 tty->TS_pad_inserted_char = tgetstr ("ip", address);
3279 tty->TS_end_keypad_mode = tgetstr ("ke", address);
3280 tty->TS_keypad_mode = tgetstr ("ks", address);
3281 LastLine (tty) = tgetstr ("ll", address);
3282 Right (tty) = tgetstr ("nd", address);
3283 Down (tty) = tgetstr ("do", address);
3284 if (!Down (tty))
3285 Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */
3286 if (tgetflag ("bs"))
3287 Left (tty) = "\b"; /* can't possibly be longer! */
3288 else /* (Actually, "bs" is obsolete...) */
3289 Left (tty) = tgetstr ("le", address);
3290 if (!Left (tty))
3291 Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */
3292 tty->TS_pad_char = tgetstr ("pc", address);
3293 tty->TS_repeat = tgetstr ("rp", address);
3294 tty->TS_end_standout_mode = tgetstr ("se", address);
3295 tty->TS_fwd_scroll = tgetstr ("sf", address);
3296 tty->TS_standout_mode = tgetstr ("so", address);
3297 tty->TS_rev_scroll = tgetstr ("sr", address);
3298 tty->Wcm->cm_tab = tgetstr ("ta", address);
3299 tty->TS_end_termcap_modes = tgetstr ("te", address);
3300 tty->TS_termcap_modes = tgetstr ("ti", address);
3301 Up (tty) = tgetstr ("up", address);
3302 tty->TS_visible_bell = tgetstr ("vb", address);
3303 tty->TS_cursor_normal = tgetstr ("ve", address);
3304 tty->TS_cursor_visible = tgetstr ("vs", address);
3305 tty->TS_cursor_invisible = tgetstr ("vi", address);
3306 tty->TS_set_window = tgetstr ("wi", address);
3307
3308 tty->TS_enter_underline_mode = tgetstr ("us", address);
3309 tty->TS_exit_underline_mode = tgetstr ("ue", address);
3310 tty->TS_enter_bold_mode = tgetstr ("md", address);
3311 tty->TS_enter_dim_mode = tgetstr ("mh", address);
3312 tty->TS_enter_blink_mode = tgetstr ("mb", address);
3313 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
3314 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
3315 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
3316 tty->TS_exit_attribute_mode = tgetstr ("me", address);
3317
3318 MultiUp (tty) = tgetstr ("UP", address);
3319 MultiDown (tty) = tgetstr ("DO", address);
3320 MultiLeft (tty) = tgetstr ("LE", address);
3321 MultiRight (tty) = tgetstr ("RI", address);
3322
3323 /* SVr4/ANSI color suppert. If "op" isn't available, don't support
3324 color because we can't switch back to the default foreground and
3325 background. */
3326 tty->TS_orig_pair = tgetstr ("op", address);
3327 if (tty->TS_orig_pair)
3328 {
3329 tty->TS_set_foreground = tgetstr ("AF", address);
3330 tty->TS_set_background = tgetstr ("AB", address);
3331 if (!tty->TS_set_foreground)
3332 {
3333 /* SVr4. */
3334 tty->TS_set_foreground = tgetstr ("Sf", address);
3335 tty->TS_set_background = tgetstr ("Sb", address);
3336 }
3337
3338 tty->TN_max_colors = tgetnum ("Co");
3339 tty->TN_max_pairs = tgetnum ("pa");
3340
3341 tty->TN_no_color_video = tgetnum ("NC");
3342 if (tty->TN_no_color_video == -1)
3343 tty->TN_no_color_video = 0;
3344 }
3345
3346 tty_default_color_capabilities (tty, 1);
3347
3348 MagicWrap (tty) = tgetflag ("xn");
3349 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
3350 the former flag imply the latter. */
3351 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
3352 terminal->memory_below_frame = tgetflag ("db");
3353 tty->TF_hazeltine = tgetflag ("hz");
3354 terminal->must_write_spaces = tgetflag ("in");
3355 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
3356 tty->TF_insmode_motion = tgetflag ("mi");
3357 tty->TF_standout_motion = tgetflag ("ms");
3358 tty->TF_underscore = tgetflag ("ul");
3359 tty->TF_teleray = tgetflag ("xt");
3360
3361 #else /* DOS_NT */
3362 #ifdef WINDOWSNT
3363 {
3364 struct frame *f = XFRAME (selected_frame);
3365
3366 initialize_w32_display (terminal);
3367
3368 FrameRows (tty) = FRAME_LINES (f);
3369 FrameCols (tty) = FRAME_COLS (f);
3370 tty->specified_window = FRAME_LINES (f);
3371
3372 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
3373 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
3374 terminal->char_ins_del_ok = 1;
3375 baud_rate = 19200;
3376 }
3377 #else /* MSDOS */
3378 {
3379 int height, width;
3380 if (strcmp (terminal_type, "internal") == 0)
3381 terminal->type = output_msdos_raw;
3382 initialize_msdos_display (terminal);
3383
3384 get_tty_size (fileno (tty->input), &width, &height);
3385 FrameCols (tty) = width;
3386 FrameRows (tty) = height;
3387 terminal->char_ins_del_ok = 0;
3388 init_baud_rate (fileno (tty->input));
3389 }
3390 #endif /* MSDOS */
3391 tty->output = stdout;
3392 tty->input = stdin;
3393 /* The following two are inaccessible from w32console.c. */
3394 terminal->delete_frame_hook = &tty_free_frame_resources;
3395 terminal->delete_terminal_hook = &delete_tty;
3396
3397 tty->name = xstrdup (name);
3398 terminal->name = xstrdup (name);
3399 tty->type = xstrdup (terminal_type);
3400
3401 add_keyboard_wait_descriptor (0);
3402
3403 tty->delete_in_insert_mode = 1;
3404
3405 UseTabs (tty) = 0;
3406 terminal->scroll_region_ok = 0;
3407
3408 /* Seems to insert lines when it's not supposed to, messing up the
3409 display. In doing a trace, it didn't seem to be called much, so I
3410 don't think we're losing anything by turning it off. */
3411 terminal->line_ins_del_ok = 0;
3412
3413 tty->TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */
3414 #endif /* DOS_NT */
3415
3416 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3417 init_kboard (terminal->kboard);
3418 KVAR (terminal->kboard, Vwindow_system) = Qnil;
3419 terminal->kboard->next_kboard = all_kboards;
3420 all_kboards = terminal->kboard;
3421 terminal->kboard->reference_count++;
3422 /* Don't let the initial kboard remain current longer than necessary.
3423 That would cause problems if a file loaded on startup tries to
3424 prompt in the mini-buffer. */
3425 if (current_kboard == initial_kboard)
3426 current_kboard = terminal->kboard;
3427 #ifndef DOS_NT
3428 term_get_fkeys (address, terminal->kboard);
3429
3430 /* Get frame size from system, or else from termcap. */
3431 {
3432 int height, width;
3433 get_tty_size (fileno (tty->input), &width, &height);
3434 FrameCols (tty) = width;
3435 FrameRows (tty) = height;
3436 }
3437
3438 if (FrameCols (tty) <= 0)
3439 FrameCols (tty) = tgetnum ("co");
3440 if (FrameRows (tty) <= 0)
3441 FrameRows (tty) = tgetnum ("li");
3442
3443 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
3444 maybe_fatal (must_succeed, terminal,
3445 "Screen size %dx%d is too small",
3446 "Screen size %dx%d is too small",
3447 FrameCols (tty), FrameRows (tty));
3448
3449 TabWidth (tty) = tgetnum ("tw");
3450
3451 if (!tty->TS_bell)
3452 tty->TS_bell = "\07";
3453
3454 if (!tty->TS_fwd_scroll)
3455 tty->TS_fwd_scroll = Down (tty);
3456
3457 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
3458
3459 if (TabWidth (tty) < 0)
3460 TabWidth (tty) = 8;
3461
3462 /* Turned off since /etc/termcap seems to have :ta= for most terminals
3463 and newer termcap doc does not seem to say there is a default.
3464 if (!tty->Wcm->cm_tab)
3465 tty->Wcm->cm_tab = "\t";
3466 */
3467
3468 /* We don't support standout modes that use `magic cookies', so
3469 turn off any that do. */
3470 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
3471 {
3472 tty->TS_standout_mode = 0;
3473 tty->TS_end_standout_mode = 0;
3474 }
3475 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
3476 {
3477 tty->TS_enter_underline_mode = 0;
3478 tty->TS_exit_underline_mode = 0;
3479 }
3480
3481 /* If there's no standout mode, try to use underlining instead. */
3482 if (tty->TS_standout_mode == 0)
3483 {
3484 tty->TS_standout_mode = tty->TS_enter_underline_mode;
3485 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
3486 }
3487
3488 /* If no `se' string, try using a `me' string instead.
3489 If that fails, we can't use standout mode at all. */
3490 if (tty->TS_end_standout_mode == 0)
3491 {
3492 char *s = tgetstr ("me", address);
3493 if (s != 0)
3494 tty->TS_end_standout_mode = s;
3495 else
3496 tty->TS_standout_mode = 0;
3497 }
3498
3499 if (tty->TF_teleray)
3500 {
3501 tty->Wcm->cm_tab = 0;
3502 /* We can't support standout mode, because it uses magic cookies. */
3503 tty->TS_standout_mode = 0;
3504 /* But that means we cannot rely on ^M to go to column zero! */
3505 CR (tty) = 0;
3506 /* LF can't be trusted either -- can alter hpos */
3507 /* if move at column 0 thru a line with TS_standout_mode */
3508 Down (tty) = 0;
3509 }
3510
3511 /* Special handling for certain terminal types known to need it */
3512
3513 if (!strcmp (terminal_type, "supdup"))
3514 {
3515 terminal->memory_below_frame = 1;
3516 tty->Wcm->cm_losewrap = 1;
3517 }
3518 if (!strncmp (terminal_type, "c10", 3)
3519 || !strcmp (terminal_type, "perq"))
3520 {
3521 /* Supply a makeshift :wi string.
3522 This string is not valid in general since it works only
3523 for windows starting at the upper left corner;
3524 but that is all Emacs uses.
3525
3526 This string works only if the frame is using
3527 the top of the video memory, because addressing is memory-relative.
3528 So first check the :ti string to see if that is true.
3529
3530 It would be simpler if the :wi string could go in the termcap
3531 entry, but it can't because it is not fully valid.
3532 If it were in the termcap entry, it would confuse other programs. */
3533 if (!tty->TS_set_window)
3534 {
3535 p = tty->TS_termcap_modes;
3536 while (*p && strcmp (p, "\033v "))
3537 p++;
3538 if (*p)
3539 tty->TS_set_window = "\033v%C %C %C %C ";
3540 }
3541 /* Termcap entry often fails to have :in: flag */
3542 terminal->must_write_spaces = 1;
3543 /* :ti string typically fails to have \E^G! in it */
3544 /* This limits scope of insert-char to one line. */
3545 strcpy (area, tty->TS_termcap_modes);
3546 strcat (area, "\033\007!");
3547 tty->TS_termcap_modes = area;
3548 area += strlen (area) + 1;
3549 p = AbsPosition (tty);
3550 /* Change all %+ parameters to %C, to handle
3551 values above 96 correctly for the C100. */
3552 while (*p)
3553 {
3554 if (p[0] == '%' && p[1] == '+')
3555 p[1] = 'C';
3556 p++;
3557 }
3558 }
3559
3560 tty->specified_window = FrameRows (tty);
3561
3562 if (Wcm_init (tty) == -1) /* can't do cursor motion */
3563 {
3564 maybe_fatal (must_succeed, terminal,
3565 "Terminal type \"%s\" is not powerful enough to run Emacs",
3566 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
3567 It lacks the ability to position the cursor.\n\
3568 If that is not the actual type of terminal you have,\n\
3569 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
3570 `setenv TERM ...') to specify the correct type. It may be necessary\n"
3571 # ifdef TERMINFO
3572 "to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
3573 # else /* TERMCAP */
3574 "to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
3575 # endif /* TERMINFO */
3576 terminal_type);
3577 }
3578
3579 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
3580 maybe_fatal (must_succeed, terminal,
3581 "Could not determine the frame size",
3582 "Could not determine the frame size");
3583
3584 tty->delete_in_insert_mode
3585 = tty->TS_delete_mode && tty->TS_insert_mode
3586 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
3587
3588 tty->se_is_so = (tty->TS_standout_mode
3589 && tty->TS_end_standout_mode
3590 && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode));
3591
3592 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
3593
3594 terminal->scroll_region_ok
3595 = (tty->Wcm->cm_abs
3596 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
3597
3598 terminal->line_ins_del_ok
3599 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
3600 && (tty->TS_del_line || tty->TS_del_multi_lines))
3601 || (terminal->scroll_region_ok
3602 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
3603
3604 terminal->char_ins_del_ok
3605 = ((tty->TS_ins_char || tty->TS_insert_mode
3606 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
3607 && (tty->TS_del_char || tty->TS_del_multi_chars));
3608
3609 terminal->fast_clear_end_of_line = tty->TS_clr_line != 0;
3610
3611 init_baud_rate (fileno (tty->input));
3612
3613 #endif /* not DOS_NT */
3614
3615 /* Init system terminal modes (RAW or CBREAK, etc.). */
3616 init_sys_modes (tty);
3617
3618 return terminal;
3619 }
3620
3621
3622 static void
3623 vfatal (const char *str, va_list ap)
3624 {
3625 fprintf (stderr, "emacs: ");
3626 vfprintf (stderr, str, ap);
3627 if (!(strlen (str) > 0 && str[strlen (str) - 1] == '\n'))
3628 fprintf (stderr, "\n");
3629 va_end (ap);
3630 fflush (stderr);
3631 exit (1);
3632 }
3633
3634
3635 /* Auxiliary error-handling function for init_tty.
3636 Delete TERMINAL, then call error or fatal with str1 or str2,
3637 respectively, according to MUST_SUCCEED. */
3638
3639 static void
3640 maybe_fatal (int must_succeed, struct terminal *terminal,
3641 const char *str1, const char *str2, ...)
3642 {
3643 va_list ap;
3644 va_start (ap, str2);
3645 if (terminal)
3646 delete_tty (terminal);
3647
3648 if (must_succeed)
3649 vfatal (str2, ap);
3650 else
3651 verror (str1, ap);
3652
3653 va_end (ap);
3654 abort ();
3655 }
3656
3657 void
3658 fatal (const char *str, ...)
3659 {
3660 va_list ap;
3661 va_start (ap, str);
3662 vfatal (str, ap);
3663 va_end (ap);
3664 }
3665
3666 \f
3667
3668 /* Delete the given tty terminal, closing all frames on it. */
3669
3670 static void
3671 delete_tty (struct terminal *terminal)
3672 {
3673 struct tty_display_info *tty;
3674
3675 /* Protect against recursive calls. delete_frame in
3676 delete_terminal calls us back when it deletes our last frame. */
3677 if (!terminal->name)
3678 return;
3679
3680 if (terminal->type != output_termcap)
3681 abort ();
3682
3683 tty = terminal->display_info.tty;
3684
3685 if (tty == tty_list)
3686 tty_list = tty->next;
3687 else
3688 {
3689 struct tty_display_info *p;
3690 for (p = tty_list; p && p->next != tty; p = p->next)
3691 ;
3692
3693 if (! p)
3694 /* This should not happen. */
3695 abort ();
3696
3697 p->next = tty->next;
3698 tty->next = 0;
3699 }
3700
3701 /* reset_sys_modes needs a valid device, so this call needs to be
3702 before delete_terminal. */
3703 reset_sys_modes (tty);
3704
3705 delete_terminal (terminal);
3706
3707 xfree (tty->name);
3708 xfree (tty->type);
3709
3710 if (tty->input)
3711 {
3712 delete_keyboard_wait_descriptor (fileno (tty->input));
3713 if (tty->input != stdin)
3714 fclose (tty->input);
3715 }
3716 if (tty->output && tty->output != stdout && tty->output != tty->input)
3717 fclose (tty->output);
3718 if (tty->termscript)
3719 fclose (tty->termscript);
3720
3721 xfree (tty->old_tty);
3722 xfree (tty->Wcm);
3723 xfree (tty->termcap_strings_buffer);
3724 xfree (tty->termcap_term_buffer);
3725
3726 memset (tty, 0, sizeof (struct tty_display_info));
3727 xfree (tty);
3728 }
3729
3730 \f
3731
3732 /* Mark the pointers in the tty_display_info objects.
3733 Called by the Fgarbage_collector. */
3734
3735 void
3736 mark_ttys (void)
3737 {
3738 struct tty_display_info *tty;
3739
3740 for (tty = tty_list; tty; tty = tty->next)
3741 mark_object (tty->top_frame);
3742 }
3743
3744 \f
3745
3746 void
3747 syms_of_term (void)
3748 {
3749 DEFVAR_BOOL ("system-uses-terminfo", system_uses_terminfo,
3750 doc: /* Non-nil means the system uses terminfo rather than termcap.
3751 This variable can be used by terminal emulator packages. */);
3752 #ifdef TERMINFO
3753 system_uses_terminfo = 1;
3754 #else
3755 system_uses_terminfo = 0;
3756 #endif
3757
3758 DEFVAR_LISP ("suspend-tty-functions", Vsuspend_tty_functions,
3759 doc: /* Functions to be run after suspending a tty.
3760 The functions are run with one argument, the terminal object to be suspended.
3761 See `suspend-tty'. */);
3762 Vsuspend_tty_functions = Qnil;
3763
3764
3765 DEFVAR_LISP ("resume-tty-functions", Vresume_tty_functions,
3766 doc: /* Functions to be run after resuming a tty.
3767 The functions are run with one argument, the terminal object that was revived.
3768 See `resume-tty'. */);
3769 Vresume_tty_functions = Qnil;
3770
3771 DEFVAR_BOOL ("visible-cursor", visible_cursor,
3772 doc: /* Non-nil means to make the cursor very visible.
3773 This only has an effect when running in a text terminal.
3774 What means \"very visible\" is up to your terminal. It may make the cursor
3775 bigger, or it may make it blink, or it may do nothing at all. */);
3776 visible_cursor = 1;
3777
3778 defsubr (&Stty_display_color_p);
3779 defsubr (&Stty_display_color_cells);
3780 defsubr (&Stty_no_underline);
3781 defsubr (&Stty_type);
3782 defsubr (&Scontrolling_tty_p);
3783 defsubr (&Ssuspend_tty);
3784 defsubr (&Sresume_tty);
3785 #ifdef HAVE_GPM
3786 defsubr (&Sgpm_mouse_start);
3787 defsubr (&Sgpm_mouse_stop);
3788 #endif /* HAVE_GPM */
3789
3790 #ifndef DOS_NT
3791 default_orig_pair = NULL;
3792 default_set_foreground = NULL;
3793 default_set_background = NULL;
3794 #endif /* !DOS_NT */
3795
3796 encode_terminal_src = NULL;
3797 encode_terminal_dst = NULL;
3798 }