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