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