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