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