Put doc strings in comments.
[bpt/emacs.git] / src / term.c
1 /* Terminal control module for terminals described by TERMCAP
2 Copyright (C) 1985, 86, 87, 93, 94, 95, 98, 2000, 2001
3 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 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., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 /* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>. */
23
24 #include <config.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <string.h>
28 #include "termchar.h"
29 #include "termopts.h"
30 #define DOC_STRINGS_IN_COMMENTS
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
42 /* For now, don't try to include termcap.h. On some systems,
43 configure finds a non-standard termcap.h that the main build
44 won't find. */
45
46 #if defined HAVE_TERMCAP_H && 0
47 #include <termcap.h>
48 #else
49 extern void tputs P_ ((const char *, int, int (*)(int)));
50 extern int tgetent P_ ((char *, const char *));
51 extern int tgetflag P_ ((char *id));
52 extern int tgetnum P_ ((char *id));
53 #endif
54
55 #include "cm.h"
56 #ifdef HAVE_X_WINDOWS
57 #include "xterm.h"
58 #endif
59 #ifdef macintosh
60 #include "macterm.h"
61 #endif
62
63 static void turn_on_face P_ ((struct frame *, int face_id));
64 static void turn_off_face P_ ((struct frame *, int face_id));
65 static void tty_show_cursor P_ ((void));
66 static void tty_hide_cursor P_ ((void));
67
68 #define OUTPUT(a) \
69 tputs (a, (int) (FRAME_HEIGHT (XFRAME (selected_frame)) - curY), cmputc)
70 #define OUTPUT1(a) tputs (a, 1, cmputc)
71 #define OUTPUTL(a, lines) tputs (a, lines, cmputc)
72
73 #define OUTPUT_IF(a) \
74 do { \
75 if (a) \
76 tputs (a, (int) (FRAME_HEIGHT (XFRAME (selected_frame)) \
77 - curY), cmputc); \
78 } while (0)
79
80 #define OUTPUT1_IF(a) do { if (a) tputs (a, 1, cmputc); } while (0)
81
82 /* Function to use to ring the bell. */
83
84 Lisp_Object Vring_bell_function;
85
86 /* Terminal characteristics that higher levels want to look at.
87 These are all extern'd in termchar.h */
88
89 int must_write_spaces; /* Nonzero means spaces in the text
90 must actually be output; can't just skip
91 over some columns to leave them blank. */
92 int min_padding_speed; /* Speed below which no padding necessary */
93
94 int line_ins_del_ok; /* Terminal can insert and delete lines */
95 int char_ins_del_ok; /* Terminal can insert and delete chars */
96 int scroll_region_ok; /* Terminal supports setting the
97 scroll window */
98 int scroll_region_cost; /* Cost of setting a scroll window,
99 measured in characters */
100 int memory_below_frame; /* Terminal remembers lines
101 scrolled off bottom */
102 int fast_clear_end_of_line; /* Terminal has a `ce' string */
103
104 /* Nonzero means no need to redraw the entire frame on resuming
105 a suspended Emacs. This is useful on terminals with multiple pages,
106 where one page is used for Emacs and another for all else. */
107
108 int no_redraw_on_reenter;
109
110 /* Hook functions that you can set to snap out the functions in this file.
111 These are all extern'd in termhooks.h */
112
113 void (*cursor_to_hook) P_ ((int, int));
114 void (*raw_cursor_to_hook) P_ ((int, int));
115 void (*clear_to_end_hook) P_ ((void));
116 void (*clear_frame_hook) P_ ((void));
117 void (*clear_end_of_line_hook) P_ ((int));
118
119 void (*ins_del_lines_hook) P_ ((int, int));
120
121 void (*change_line_highlight_hook) P_ ((int, int, int, int));
122 void (*reassert_line_highlight_hook) P_ ((int, int));
123
124 void (*delete_glyphs_hook) P_ ((int));
125
126 void (*ring_bell_hook) P_ ((void));
127
128 void (*reset_terminal_modes_hook) P_ ((void));
129 void (*set_terminal_modes_hook) P_ ((void));
130 void (*update_begin_hook) P_ ((struct frame *));
131 void (*update_end_hook) P_ ((struct frame *));
132 void (*set_terminal_window_hook) P_ ((int));
133 void (*insert_glyphs_hook) P_ ((struct glyph *, int));
134 void (*write_glyphs_hook) P_ ((struct glyph *, int));
135 void (*delete_glyphs_hook) P_ ((int));
136
137 int (*read_socket_hook) P_ ((int, struct input_event *, int, int));
138
139 void (*frame_up_to_date_hook) P_ ((struct frame *));
140
141 /* Return the current position of the mouse.
142
143 Set *f to the frame the mouse is in, or zero if the mouse is in no
144 Emacs frame. If it is set to zero, all the other arguments are
145 garbage.
146
147 If the motion started in a scroll bar, set *bar_window to the
148 scroll bar's window, *part to the part the mouse is currently over,
149 *x to the position of the mouse along the scroll bar, and *y to the
150 overall length of the scroll bar.
151
152 Otherwise, set *bar_window to Qnil, and *x and *y to the column and
153 row of the character cell the mouse is over.
154
155 Set *time to the time the mouse was at the returned position.
156
157 This should clear mouse_moved until the next motion
158 event arrives. */
159
160 void (*mouse_position_hook) P_ ((FRAME_PTR *f, int insist,
161 Lisp_Object *bar_window,
162 enum scroll_bar_part *part,
163 Lisp_Object *x,
164 Lisp_Object *y,
165 unsigned long *time));
166
167 /* When reading from a minibuffer in a different frame, Emacs wants
168 to shift the highlight from the selected frame to the mini-buffer's
169 frame; under X, this means it lies about where the focus is.
170 This hook tells the window system code to re-decide where to put
171 the highlight. */
172
173 void (*frame_rehighlight_hook) P_ ((FRAME_PTR f));
174
175 /* If we're displaying frames using a window system that can stack
176 frames on top of each other, this hook allows you to bring a frame
177 to the front, or bury it behind all the other windows. If this
178 hook is zero, that means the device we're displaying on doesn't
179 support overlapping frames, so there's no need to raise or lower
180 anything.
181
182 If RAISE is non-zero, F is brought to the front, before all other
183 windows. If RAISE is zero, F is sent to the back, behind all other
184 windows. */
185
186 void (*frame_raise_lower_hook) P_ ((FRAME_PTR f, int raise));
187
188 /* Set the vertical scroll bar for WINDOW to have its upper left corner
189 at (TOP, LEFT), and be LENGTH rows high. Set its handle to
190 indicate that we are displaying PORTION characters out of a total
191 of WHOLE characters, starting at POSITION. If WINDOW doesn't yet
192 have a scroll bar, create one for it. */
193
194 void (*set_vertical_scroll_bar_hook)
195 P_ ((struct window *window,
196 int portion, int whole, int position));
197
198
199 /* The following three hooks are used when we're doing a thorough
200 redisplay of the frame. We don't explicitly know which scroll bars
201 are going to be deleted, because keeping track of when windows go
202 away is a real pain - can you say set-window-configuration?
203 Instead, we just assert at the beginning of redisplay that *all*
204 scroll bars are to be removed, and then save scroll bars from the
205 fiery pit when we actually redisplay their window. */
206
207 /* Arrange for all scroll bars on FRAME to be removed at the next call
208 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
209 `*redeem_scroll_bar_hook' is applied to its window before the judgment.
210
211 This should be applied to each frame each time its window tree is
212 redisplayed, even if it is not displaying scroll bars at the moment;
213 if the HAS_SCROLL_BARS flag has just been turned off, only calling
214 this and the judge_scroll_bars_hook will get rid of them.
215
216 If non-zero, this hook should be safe to apply to any frame,
217 whether or not it can support scroll bars, and whether or not it is
218 currently displaying them. */
219
220 void (*condemn_scroll_bars_hook) P_ ((FRAME_PTR frame));
221
222 /* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
223 Note that it's okay to redeem a scroll bar that is not condemned. */
224
225 void (*redeem_scroll_bar_hook) P_ ((struct window *window));
226
227 /* Remove all scroll bars on FRAME that haven't been saved since the
228 last call to `*condemn_scroll_bars_hook'.
229
230 This should be applied to each frame after each time its window
231 tree is redisplayed, even if it is not displaying scroll bars at the
232 moment; if the HAS_SCROLL_BARS flag has just been turned off, only
233 calling this and condemn_scroll_bars_hook will get rid of them.
234
235 If non-zero, this hook should be safe to apply to any frame,
236 whether or not it can support scroll bars, and whether or not it is
237 currently displaying them. */
238
239 void (*judge_scroll_bars_hook) P_ ((FRAME_PTR FRAME));
240
241 /* Hook to call in estimate_mode_line_height, if any. */
242
243 int (* estimate_mode_line_height_hook) P_ ((struct frame *f, enum face_id));
244
245
246 /* Strings, numbers and flags taken from the termcap entry. */
247
248 char *TS_ins_line; /* "al" */
249 char *TS_ins_multi_lines; /* "AL" (one parameter, # lines to insert) */
250 char *TS_bell; /* "bl" */
251 char *TS_clr_to_bottom; /* "cd" */
252 char *TS_clr_line; /* "ce", clear to end of line */
253 char *TS_clr_frame; /* "cl" */
254 char *TS_set_scroll_region; /* "cs" (2 params, first line and last line) */
255 char *TS_set_scroll_region_1; /* "cS" (4 params: total lines,
256 lines above scroll region, lines below it,
257 total lines again) */
258 char *TS_del_char; /* "dc" */
259 char *TS_del_multi_chars; /* "DC" (one parameter, # chars to delete) */
260 char *TS_del_line; /* "dl" */
261 char *TS_del_multi_lines; /* "DL" (one parameter, # lines to delete) */
262 char *TS_delete_mode; /* "dm", enter character-delete mode */
263 char *TS_end_delete_mode; /* "ed", leave character-delete mode */
264 char *TS_end_insert_mode; /* "ei", leave character-insert mode */
265 char *TS_ins_char; /* "ic" */
266 char *TS_ins_multi_chars; /* "IC" (one parameter, # chars to insert) */
267 char *TS_insert_mode; /* "im", enter character-insert mode */
268 char *TS_pad_inserted_char; /* "ip". Just padding, no commands. */
269 char *TS_end_keypad_mode; /* "ke" */
270 char *TS_keypad_mode; /* "ks" */
271 char *TS_pad_char; /* "pc", char to use as padding */
272 char *TS_repeat; /* "rp" (2 params, # times to repeat
273 and character to be repeated) */
274 char *TS_end_standout_mode; /* "se" */
275 char *TS_fwd_scroll; /* "sf" */
276 char *TS_standout_mode; /* "so" */
277 char *TS_rev_scroll; /* "sr" */
278 char *TS_end_termcap_modes; /* "te" */
279 char *TS_termcap_modes; /* "ti" */
280 char *TS_visible_bell; /* "vb" */
281 char *TS_cursor_normal; /* "ve" */
282 char *TS_cursor_visible; /* "vs" */
283 char *TS_cursor_invisible; /* "vi" */
284 char *TS_set_window; /* "wi" (4 params, start and end of window,
285 each as vpos and hpos) */
286
287 /* Value of the "NC" (no_color_video) capability, or 0 if not
288 present. */
289
290 static int TN_no_color_video;
291
292 /* Meaning of bits in no_color_video. Each bit set means that the
293 corresponding attribute cannot be combined with colors. */
294
295 enum no_color_bit
296 {
297 NC_STANDOUT = 1 << 0,
298 NC_UNDERLINE = 1 << 1,
299 NC_REVERSE = 1 << 2,
300 NC_BLINK = 1 << 3,
301 NC_DIM = 1 << 4,
302 NC_BOLD = 1 << 5,
303 NC_INVIS = 1 << 6,
304 NC_PROTECT = 1 << 7,
305 NC_ALT_CHARSET = 1 << 8
306 };
307
308 /* "md" -- turn on bold (extra bright mode). */
309
310 char *TS_enter_bold_mode;
311
312 /* "mh" -- turn on half-bright mode. */
313
314 char *TS_enter_dim_mode;
315
316 /* "mb" -- enter blinking mode. */
317
318 char *TS_enter_blink_mode;
319
320 /* "mr" -- enter reverse video mode. */
321
322 char *TS_enter_reverse_mode;
323
324 /* "us"/"ue" -- start/end underlining. */
325
326 char *TS_exit_underline_mode, *TS_enter_underline_mode;
327
328 /* "ug" -- number of blanks left by underline. */
329
330 int TN_magic_cookie_glitch_ul;
331
332 /* "as"/"ae" -- start/end alternate character set. Not really
333 supported, yet. */
334
335 char *TS_enter_alt_charset_mode, *TS_exit_alt_charset_mode;
336
337 /* "me" -- switch appearances off. */
338
339 char *TS_exit_attribute_mode;
340
341 /* "Co" -- number of colors. */
342
343 int TN_max_colors;
344
345 /* "pa" -- max. number of color pairs on screen. Not handled yet.
346 Could be a problem if not equal to TN_max_colors * TN_max_colors. */
347
348 int TN_max_pairs;
349
350 /* "op" -- SVr4 set default pair to its original value. */
351
352 char *TS_orig_pair;
353
354 /* "AF"/"AB" or "Sf"/"Sb"-- set ANSI or SVr4 foreground/background color.
355 1 param, the color index. */
356
357 char *TS_set_foreground, *TS_set_background;
358
359 int TF_hazeltine; /* termcap hz flag. */
360 int TF_insmode_motion; /* termcap mi flag: can move while in insert mode. */
361 int TF_standout_motion; /* termcap mi flag: can move while in standout mode. */
362 int TF_underscore; /* termcap ul flag: _ underlines if over-struck on
363 non-blank position. Must clear before writing _. */
364 int TF_teleray; /* termcap xt flag: many weird consequences.
365 For t1061. */
366
367 int TF_xs; /* Nonzero for "xs". If set together with
368 TN_standout_width == 0, it means don't bother
369 to write any end-standout cookies. */
370
371 int TN_standout_width; /* termcap sg number: width occupied by standout
372 markers */
373
374 static int RPov; /* # chars to start a TS_repeat */
375
376 static int delete_in_insert_mode; /* delete mode == insert mode */
377
378 static int se_is_so; /* 1 if same string both enters and leaves
379 standout mode */
380
381 /* internal state */
382
383 /* The largest frame width in any call to calculate_costs. */
384
385 int max_frame_width;
386
387 /* The largest frame height in any call to calculate_costs. */
388
389 int max_frame_height;
390
391 /* Number of chars of space used for standout marker at beginning of line,
392 or'd with 0100. Zero if no standout marker at all.
393 The length of these vectors is max_frame_height.
394
395 Used IFF TN_standout_width >= 0. */
396
397 static char *chars_wasted;
398 static char *copybuf;
399
400 /* nonzero means supposed to write text in standout mode. */
401
402 int standout_requested;
403
404 int insert_mode; /* Nonzero when in insert mode. */
405 int standout_mode; /* Nonzero when in standout mode. */
406
407 /* Size of window specified by higher levels.
408 This is the number of lines, from the top of frame downwards,
409 which can participate in insert-line/delete-line operations.
410
411 Effectively it excludes the bottom frame_height - specified_window_size
412 lines from those operations. */
413
414 int specified_window;
415
416 /* Frame currently being redisplayed; 0 if not currently redisplaying.
417 (Direct output does not count). */
418
419 FRAME_PTR updating_frame;
420
421 /* Provided for lisp packages. */
422
423 static int system_uses_terminfo;
424
425 /* Flag used in tty_show/hide_cursor. */
426
427 static int tty_cursor_hidden;
428
429 char *tparam ();
430
431 extern char *tgetstr ();
432 \f
433
434 #ifdef WINDOWSNT
435 /* We aren't X windows, but we aren't termcap either. This makes me
436 uncertain as to what value to use for frame.output_method. For
437 this file, we'll define FRAME_TERMCAP_P to be zero so that our
438 output hooks get called instead of the termcap functions. Probably
439 the best long-term solution is to define an output_windows_nt... */
440
441 #undef FRAME_TERMCAP_P
442 #define FRAME_TERMCAP_P(_f_) 0
443 #endif /* WINDOWSNT */
444
445 void
446 ring_bell ()
447 {
448 if (!NILP (Vring_bell_function))
449 {
450 Lisp_Object function;
451
452 /* Temporarily set the global variable to nil
453 so that if we get an error, it stays nil
454 and we don't call it over and over.
455
456 We don't specbind it, because that would carefully
457 restore the bad value if there's an error
458 and make the loop of errors happen anyway. */
459
460 function = Vring_bell_function;
461 Vring_bell_function = Qnil;
462
463 call0 (function);
464
465 Vring_bell_function = function;
466 }
467 else if (!FRAME_TERMCAP_P (XFRAME (selected_frame)))
468 (*ring_bell_hook) ();
469 else
470 OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
471 }
472
473 void
474 set_terminal_modes ()
475 {
476 if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
477 {
478 OUTPUT_IF (TS_termcap_modes);
479 OUTPUT_IF (TS_cursor_visible);
480 OUTPUT_IF (TS_keypad_mode);
481 losecursor ();
482 }
483 else
484 (*set_terminal_modes_hook) ();
485 }
486
487 void
488 reset_terminal_modes ()
489 {
490 if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
491 {
492 if (TN_standout_width < 0)
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 /* But on magic-cookie terminals this can erase an end-standout
501 marker and cause the rest of the frame to be in standout, so
502 move down first. */
503 if (TN_standout_width >= 0)
504 cmputc ('\n');
505 cmputc ('\r');
506 }
507 else if (reset_terminal_modes_hook)
508 (*reset_terminal_modes_hook) ();
509 }
510
511 void
512 update_begin (f)
513 struct frame *f;
514 {
515 updating_frame = f;
516 if (!FRAME_TERMCAP_P (f))
517 update_begin_hook (f);
518 }
519
520 void
521 update_end (f)
522 struct frame *f;
523 {
524 if (FRAME_TERMCAP_P (f))
525 {
526 if (!XWINDOW (selected_window)->cursor_off_p)
527 tty_show_cursor ();
528 turn_off_insert ();
529 background_highlight ();
530 standout_requested = 0;
531 }
532 else
533 update_end_hook (f);
534
535 updating_frame = NULL;
536 }
537
538 void
539 set_terminal_window (size)
540 int size;
541 {
542 if (FRAME_TERMCAP_P (updating_frame))
543 {
544 specified_window = size ? size : FRAME_HEIGHT (updating_frame);
545 if (scroll_region_ok)
546 set_scroll_region (0, specified_window);
547 }
548 else
549 set_terminal_window_hook (size);
550 }
551
552 void
553 set_scroll_region (start, stop)
554 int start, stop;
555 {
556 char *buf;
557 struct frame *sf = XFRAME (selected_frame);
558
559 if (TS_set_scroll_region)
560 buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1);
561 else if (TS_set_scroll_region_1)
562 buf = tparam (TS_set_scroll_region_1, 0, 0,
563 FRAME_HEIGHT (sf), start,
564 FRAME_HEIGHT (sf) - stop,
565 FRAME_HEIGHT (sf));
566 else
567 buf = tparam (TS_set_window, 0, 0, start, 0, stop, FRAME_WIDTH (sf));
568
569 OUTPUT (buf);
570 xfree (buf);
571 losecursor ();
572 }
573
574 \f
575 static void
576 turn_on_insert ()
577 {
578 if (!insert_mode)
579 OUTPUT (TS_insert_mode);
580 insert_mode = 1;
581 }
582
583 void
584 turn_off_insert ()
585 {
586 if (insert_mode)
587 OUTPUT (TS_end_insert_mode);
588 insert_mode = 0;
589 }
590 \f
591 /* Handle highlighting when TN_standout_width (termcap sg) is not specified.
592 In these terminals, output is affected by the value of standout
593 mode when the output is written.
594
595 These functions are called on all terminals, but do nothing
596 on terminals whose standout mode does not work that way. */
597
598 void
599 turn_off_highlight ()
600 {
601 if (TN_standout_width < 0)
602 {
603 if (standout_mode)
604 OUTPUT_IF (TS_end_standout_mode);
605 standout_mode = 0;
606 }
607 }
608
609 static void
610 turn_on_highlight ()
611 {
612 if (TN_standout_width < 0)
613 {
614 if (!standout_mode)
615 OUTPUT_IF (TS_standout_mode);
616 standout_mode = 1;
617 }
618 }
619
620 static void
621 toggle_highlight ()
622 {
623 if (standout_mode)
624 turn_off_highlight ();
625 else
626 turn_on_highlight ();
627 }
628
629
630 /* Make cursor invisible. */
631
632 static void
633 tty_hide_cursor ()
634 {
635 if (tty_cursor_hidden == 0)
636 {
637 tty_cursor_hidden = 1;
638 OUTPUT_IF (TS_cursor_invisible);
639 }
640 }
641
642
643 /* Ensure that cursor is visible. */
644
645 static void
646 tty_show_cursor ()
647 {
648 if (tty_cursor_hidden)
649 {
650 tty_cursor_hidden = 0;
651 OUTPUT_IF (TS_cursor_normal);
652 OUTPUT_IF (TS_cursor_visible);
653 }
654 }
655
656
657 /* Set standout mode to the state it should be in for
658 empty space inside windows. What this is,
659 depends on the user option inverse-video. */
660
661 void
662 background_highlight ()
663 {
664 if (TN_standout_width >= 0)
665 return;
666 if (inverse_video)
667 turn_on_highlight ();
668 else
669 turn_off_highlight ();
670 }
671
672 /* Set standout mode to the mode specified for the text to be output. */
673
674 static void
675 highlight_if_desired ()
676 {
677 if (TN_standout_width >= 0)
678 return;
679 if (!inverse_video == !standout_requested)
680 turn_off_highlight ();
681 else
682 turn_on_highlight ();
683 }
684 \f
685 /* Handle standout mode for terminals in which TN_standout_width >= 0.
686 On these terminals, standout is controlled by markers that
687 live inside the terminal's memory. TN_standout_width is the width
688 that the marker occupies in memory. Standout runs from the marker
689 to the end of the line on some terminals, or to the next
690 turn-off-standout marker (TS_end_standout_mode) string
691 on other terminals. */
692
693 /* Write a standout marker or end-standout marker at the front of the line
694 at vertical position vpos. */
695
696 static void
697 write_standout_marker (flag, vpos)
698 int flag, vpos;
699 {
700 if (flag
701 || (TS_end_standout_mode && !TF_teleray && !se_is_so
702 && !(TF_xs && TN_standout_width == 0)))
703 {
704 cmgoto (vpos, 0);
705 cmplus (TN_standout_width);
706 OUTPUT (flag ? TS_standout_mode : TS_end_standout_mode);
707 chars_wasted[curY] = TN_standout_width | 0100;
708 }
709 }
710 \f
711 /* External interface to control of standout mode.
712 Call this when about to modify line at position VPOS
713 and not change whether it is highlighted. */
714
715 void
716 reassert_line_highlight (highlight, vpos)
717 int highlight;
718 int vpos;
719 {
720 struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame);
721 if (! FRAME_TERMCAP_P (f))
722 {
723 (*reassert_line_highlight_hook) (highlight, vpos);
724 return;
725 }
726 if (TN_standout_width < 0)
727 /* Handle terminals where standout takes affect at output time */
728 standout_requested = highlight;
729 else if (chars_wasted && chars_wasted[vpos] == 0)
730 /* For terminals with standout markers, write one on this line
731 if there isn't one already. */
732 write_standout_marker (inverse_video ? !highlight : highlight, vpos);
733 }
734
735 /* Call this when about to modify line at position VPOS
736 and change whether it is highlighted. */
737
738 void
739 change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
740 int new_highlight, vpos, y, first_unused_hpos;
741 {
742 standout_requested = new_highlight;
743 if (! FRAME_TERMCAP_P (updating_frame))
744 {
745 (*change_line_highlight_hook) (new_highlight, vpos, y, first_unused_hpos);
746 return;
747 }
748
749 cursor_to (vpos, 0);
750
751 if (TN_standout_width < 0)
752 background_highlight ();
753 /* If line starts with a marker, delete the marker */
754 else if (TS_clr_line && chars_wasted[curY])
755 {
756 turn_off_insert ();
757 /* On Teleray, make sure to erase the SO marker. */
758 if (TF_teleray)
759 {
760 cmgoto (curY - 1, FRAME_WIDTH (XFRAME (selected_frame)) - 4);
761 OUTPUT ("\033S");
762 curY++; /* ESC S moves to next line where the TS_standout_mode was */
763 curX = 0;
764 }
765 else
766 cmgoto (curY, 0); /* reposition to kill standout marker */
767 }
768 clear_end_of_line_raw (first_unused_hpos);
769 reassert_line_highlight (new_highlight, curY);
770 }
771 \f
772
773 /* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are
774 frame-relative coordinates. */
775
776 void
777 cursor_to (vpos, hpos)
778 int vpos, hpos;
779 {
780 struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame);
781
782 if (! FRAME_TERMCAP_P (f) && cursor_to_hook)
783 {
784 (*cursor_to_hook) (vpos, hpos);
785 return;
786 }
787
788 /* Detect the case where we are called from reset_sys_modes
789 and the costs have never been calculated. Do nothing. */
790 if (chars_wasted == 0)
791 return;
792
793 hpos += chars_wasted[vpos] & 077;
794 if (curY == vpos && curX == hpos)
795 return;
796 if (!TF_standout_motion)
797 background_highlight ();
798 if (!TF_insmode_motion)
799 turn_off_insert ();
800 cmgoto (vpos, hpos);
801 }
802
803 /* Similar but don't take any account of the wasted characters. */
804
805 void
806 raw_cursor_to (row, col)
807 int row, col;
808 {
809 struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame);
810 if (! FRAME_TERMCAP_P (f))
811 {
812 (*raw_cursor_to_hook) (row, col);
813 return;
814 }
815 if (curY == row && curX == col)
816 return;
817 if (!TF_standout_motion)
818 background_highlight ();
819 if (!TF_insmode_motion)
820 turn_off_insert ();
821 cmgoto (row, col);
822 }
823 \f
824 /* Erase operations */
825
826 /* clear from cursor to end of frame */
827 void
828 clear_to_end ()
829 {
830 register int i;
831
832 if (clear_to_end_hook && ! FRAME_TERMCAP_P (updating_frame))
833 {
834 (*clear_to_end_hook) ();
835 return;
836 }
837 if (TS_clr_to_bottom)
838 {
839 background_highlight ();
840 OUTPUT (TS_clr_to_bottom);
841 bzero (chars_wasted + curY,
842 FRAME_HEIGHT (XFRAME (selected_frame)) - curY);
843 }
844 else
845 {
846 for (i = curY; i < FRAME_HEIGHT (XFRAME (selected_frame)); i++)
847 {
848 cursor_to (i, 0);
849 clear_end_of_line_raw (FRAME_WIDTH (XFRAME (selected_frame)));
850 }
851 }
852 }
853
854 /* Clear entire frame */
855
856 void
857 clear_frame ()
858 {
859 struct frame *sf = XFRAME (selected_frame);
860
861 if (clear_frame_hook
862 && ! FRAME_TERMCAP_P ((updating_frame ? updating_frame : sf)))
863 {
864 (*clear_frame_hook) ();
865 return;
866 }
867 if (TS_clr_frame)
868 {
869 background_highlight ();
870 OUTPUT (TS_clr_frame);
871 bzero (chars_wasted, FRAME_HEIGHT (sf));
872 cmat (0, 0);
873 }
874 else
875 {
876 cursor_to (0, 0);
877 clear_to_end ();
878 }
879 }
880
881 /* Clear to end of line, but do not clear any standout marker.
882 Assumes that the cursor is positioned at a character of real text,
883 which implies it cannot be before a standout marker
884 unless the marker has zero width.
885
886 Note that the cursor may be moved. */
887
888 void
889 clear_end_of_line (first_unused_hpos)
890 int first_unused_hpos;
891 {
892 if (FRAME_TERMCAP_P (XFRAME (selected_frame))
893 && chars_wasted != 0
894 && TN_standout_width == 0 && curX == 0 && chars_wasted[curY] != 0)
895 write_glyphs (&space_glyph, 1);
896 clear_end_of_line_raw (first_unused_hpos);
897 }
898
899 /* Clear from cursor to end of line.
900 Assume that the line is already clear starting at column first_unused_hpos.
901 If the cursor is at a standout marker, erase the marker.
902
903 Note that the cursor may be moved, on terminals lacking a `ce' string. */
904
905 void
906 clear_end_of_line_raw (first_unused_hpos)
907 int first_unused_hpos;
908 {
909 register int i;
910
911 if (clear_end_of_line_hook
912 && ! FRAME_TERMCAP_P ((updating_frame
913 ? updating_frame
914 : XFRAME (selected_frame))))
915 {
916 (*clear_end_of_line_hook) (first_unused_hpos);
917 return;
918 }
919
920 /* Detect the case where we are called from reset_sys_modes
921 and the costs have never been calculated. Do nothing. */
922 if (chars_wasted == 0)
923 return;
924
925 first_unused_hpos += chars_wasted[curY] & 077;
926 if (curX >= first_unused_hpos)
927 return;
928 /* Notice if we are erasing a magic cookie */
929 if (curX == 0)
930 chars_wasted[curY] = 0;
931 background_highlight ();
932 if (TS_clr_line)
933 {
934 OUTPUT1 (TS_clr_line);
935 }
936 else
937 { /* have to do it the hard way */
938 struct frame *sf = XFRAME (selected_frame);
939 turn_off_insert ();
940
941 /* Do not write in last row last col with Auto-wrap on. */
942 if (AutoWrap && curY == FRAME_HEIGHT (sf) - 1
943 && first_unused_hpos == FRAME_WIDTH (sf))
944 first_unused_hpos--;
945
946 for (i = curX; i < first_unused_hpos; i++)
947 {
948 if (termscript)
949 fputc (' ', termscript);
950 putchar (' ');
951 }
952 cmplus (first_unused_hpos - curX);
953 }
954 }
955 \f
956 /* Encode SRC_LEN glyphs starting at SRC to terminal output codes and
957 store them at DST. Do not write more than DST_LEN bytes. That may
958 require stopping before all SRC_LEN input glyphs have been
959 converted.
960
961 We store the number of glyphs actually converted in *CONSUMED. The
962 return value is the number of bytes store in DST. */
963
964 int
965 encode_terminal_code (src, dst, src_len, dst_len, consumed)
966 struct glyph *src;
967 int src_len;
968 unsigned char *dst;
969 int dst_len, *consumed;
970 {
971 struct glyph *src_start = src, *src_end = src + src_len;
972 unsigned char *dst_start = dst, *dst_end = dst + dst_len;
973 register GLYPH g;
974 unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *buf;
975 int len;
976 register int tlen = GLYPH_TABLE_LENGTH;
977 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
978 int result;
979 struct coding_system *coding;
980
981 /* If terminal_coding does any conversion, use it, otherwise use
982 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
983 because it always return 1 if the member src_multibyte is 1. */
984 coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
985 ? &terminal_coding
986 : &safe_terminal_coding);
987
988 while (src < src_end)
989 {
990 /* We must skip glyphs to be padded for a wide character. */
991 if (! CHAR_GLYPH_PADDING_P (*src))
992 {
993 g = GLYPH_FROM_CHAR_GLYPH (src[0]);
994
995 if (g < 0 || g >= tlen)
996 {
997 /* This glyph doesn't has an entry in Vglyph_table. */
998 if (! CHAR_VALID_P (src->u.ch, 0))
999 {
1000 len = 1;
1001 buf = " ";
1002 coding->src_multibyte = 0;
1003 }
1004 else
1005 {
1006 len = CHAR_STRING (src->u.ch, workbuf);
1007 buf = workbuf;
1008 coding->src_multibyte = 1;
1009 }
1010 }
1011 else
1012 {
1013 /* This glyph has an entry in Vglyph_table,
1014 so process any alias before testing for simpleness. */
1015 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
1016
1017 if (GLYPH_SIMPLE_P (tbase, tlen, g))
1018 {
1019 /* We set the multi-byte form of a character in G
1020 (that should be an ASCII character) at
1021 WORKBUF. */
1022 workbuf[0] = FAST_GLYPH_CHAR (g);
1023 len = 1;
1024 buf = workbuf;
1025 coding->src_multibyte = 0;
1026 }
1027 else
1028 {
1029 /* We have a string in Vglyph_table. */
1030 len = GLYPH_LENGTH (tbase, g);
1031 buf = GLYPH_STRING (tbase, g);
1032 coding->src_multibyte = STRING_MULTIBYTE (tbase[g]);
1033 }
1034 }
1035
1036 result = encode_coding (coding, buf, dst, len, dst_end - dst);
1037 len -= coding->consumed;
1038 dst += coding->produced;
1039 if (result == CODING_FINISH_INSUFFICIENT_DST
1040 || (result == CODING_FINISH_INSUFFICIENT_SRC
1041 && len > dst_end - dst))
1042 /* The remaining output buffer is too short. We must
1043 break the loop here without increasing SRC so that the
1044 next call of this function starts from the same glyph. */
1045 break;
1046
1047 if (len > 0)
1048 {
1049 /* This is the case that a code of the range 0200..0237
1050 exists in buf. We must just write out such a code. */
1051 buf += coding->consumed;
1052 while (len--)
1053 *dst++ = *buf++;
1054 }
1055 }
1056 src++;
1057 }
1058
1059 *consumed = src - src_start;
1060 return (dst - dst_start);
1061 }
1062
1063
1064 void
1065 write_glyphs (string, len)
1066 register struct glyph *string;
1067 register int len;
1068 {
1069 int produced, consumed;
1070 struct frame *sf = XFRAME (selected_frame);
1071 struct frame *f = updating_frame ? updating_frame : sf;
1072 unsigned char conversion_buffer[1024];
1073 int conversion_buffer_size = sizeof conversion_buffer;
1074
1075 if (write_glyphs_hook
1076 && ! FRAME_TERMCAP_P (f))
1077 {
1078 (*write_glyphs_hook) (string, len);
1079 return;
1080 }
1081
1082 turn_off_insert ();
1083 tty_hide_cursor ();
1084
1085 /* Don't dare write in last column of bottom line, if Auto-Wrap,
1086 since that would scroll the whole frame on some terminals. */
1087
1088 if (AutoWrap
1089 && curY + 1 == FRAME_HEIGHT (sf)
1090 && (curX + len - (chars_wasted[curY] & 077) == FRAME_WIDTH (sf)))
1091 len --;
1092 if (len <= 0)
1093 return;
1094
1095 cmplus (len);
1096
1097 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
1098 the tail. */
1099 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
1100
1101 while (len > 0)
1102 {
1103 /* Identify a run of glyphs with the same face. */
1104 int face_id = string->face_id;
1105 int n;
1106
1107 for (n = 1; n < len; ++n)
1108 if (string[n].face_id != face_id)
1109 break;
1110
1111 /* Turn appearance modes of the face of the run on. */
1112 highlight_if_desired ();
1113 turn_on_face (f, face_id);
1114
1115 while (n > 0)
1116 {
1117 /* We use a fixed size (1024 bytes) of conversion buffer.
1118 Usually it is sufficient, but if not, we just repeat the
1119 loop. */
1120 produced = encode_terminal_code (string, conversion_buffer,
1121 n, conversion_buffer_size,
1122 &consumed);
1123 if (produced > 0)
1124 {
1125 fwrite (conversion_buffer, 1, produced, stdout);
1126 if (ferror (stdout))
1127 clearerr (stdout);
1128 if (termscript)
1129 fwrite (conversion_buffer, 1, produced, termscript);
1130 }
1131 len -= consumed;
1132 n -= consumed;
1133 string += consumed;
1134 }
1135
1136 /* Turn appearance modes off. */
1137 turn_off_face (f, face_id);
1138 turn_off_highlight ();
1139 }
1140
1141 /* We may have to output some codes to terminate the writing. */
1142 if (CODING_REQUIRE_FLUSHING (&terminal_coding))
1143 {
1144 terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
1145 encode_coding (&terminal_coding, "", conversion_buffer,
1146 0, conversion_buffer_size);
1147 if (terminal_coding.produced > 0)
1148 {
1149 fwrite (conversion_buffer, 1, terminal_coding.produced, stdout);
1150 if (ferror (stdout))
1151 clearerr (stdout);
1152 if (termscript)
1153 fwrite (conversion_buffer, 1, terminal_coding.produced,
1154 termscript);
1155 }
1156 }
1157
1158 cmcheckmagic ();
1159 }
1160
1161 /* If start is zero, insert blanks instead of a string at start */
1162
1163 void
1164 insert_glyphs (start, len)
1165 register struct glyph *start;
1166 register int len;
1167 {
1168 char *buf;
1169 struct glyph *glyph = NULL;
1170 struct frame *f, *sf;
1171
1172 if (len <= 0)
1173 return;
1174
1175 if (insert_glyphs_hook)
1176 {
1177 (*insert_glyphs_hook) (start, len);
1178 return;
1179 }
1180
1181 sf = XFRAME (selected_frame);
1182 f = updating_frame ? updating_frame : sf;
1183
1184 if (TS_ins_multi_chars)
1185 {
1186 buf = tparam (TS_ins_multi_chars, 0, 0, len);
1187 OUTPUT1 (buf);
1188 xfree (buf);
1189 if (start)
1190 write_glyphs (start, len);
1191 return;
1192 }
1193
1194 turn_on_insert ();
1195 cmplus (len);
1196 /* The bit CODING_MODE_LAST_BLOCK should be set to 1 only at the tail. */
1197 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
1198 while (len-- > 0)
1199 {
1200 int produced, consumed;
1201 unsigned char conversion_buffer[1024];
1202 int conversion_buffer_size = sizeof conversion_buffer;
1203
1204 OUTPUT1_IF (TS_ins_char);
1205 if (!start)
1206 {
1207 conversion_buffer[0] = SPACEGLYPH;
1208 produced = 1;
1209 }
1210 else
1211 {
1212 highlight_if_desired ();
1213 turn_on_face (f, start->face_id);
1214 glyph = start;
1215 ++start;
1216 /* We must open sufficient space for a character which
1217 occupies more than one column. */
1218 while (len && CHAR_GLYPH_PADDING_P (*start))
1219 {
1220 OUTPUT1_IF (TS_ins_char);
1221 start++, len--;
1222 }
1223
1224 if (len <= 0)
1225 /* This is the last glyph. */
1226 terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
1227
1228 /* The size of conversion buffer (1024 bytes) is surely
1229 sufficient for just one glyph. */
1230 produced = encode_terminal_code (glyph, conversion_buffer, 1,
1231 conversion_buffer_size, &consumed);
1232 }
1233
1234 if (produced > 0)
1235 {
1236 fwrite (conversion_buffer, 1, produced, stdout);
1237 if (ferror (stdout))
1238 clearerr (stdout);
1239 if (termscript)
1240 fwrite (conversion_buffer, 1, produced, termscript);
1241 }
1242
1243 OUTPUT1_IF (TS_pad_inserted_char);
1244 if (start)
1245 {
1246 turn_off_face (f, glyph->face_id);
1247 turn_off_highlight ();
1248 }
1249 }
1250
1251 cmcheckmagic ();
1252 }
1253
1254 void
1255 delete_glyphs (n)
1256 register int n;
1257 {
1258 char *buf;
1259 register int i;
1260
1261 if (delete_glyphs_hook && ! FRAME_TERMCAP_P (updating_frame))
1262 {
1263 (*delete_glyphs_hook) (n);
1264 return;
1265 }
1266
1267 if (delete_in_insert_mode)
1268 {
1269 turn_on_insert ();
1270 }
1271 else
1272 {
1273 turn_off_insert ();
1274 OUTPUT_IF (TS_delete_mode);
1275 }
1276
1277 if (TS_del_multi_chars)
1278 {
1279 buf = tparam (TS_del_multi_chars, 0, 0, n);
1280 OUTPUT1 (buf);
1281 xfree (buf);
1282 }
1283 else
1284 for (i = 0; i < n; i++)
1285 OUTPUT1 (TS_del_char);
1286 if (!delete_in_insert_mode)
1287 OUTPUT_IF (TS_end_delete_mode);
1288 }
1289 \f
1290 /* Insert N lines at vpos VPOS. If N is negative, delete -N lines. */
1291
1292 void
1293 ins_del_lines (vpos, n)
1294 int vpos, n;
1295 {
1296 char *multi = n > 0 ? TS_ins_multi_lines : TS_del_multi_lines;
1297 char *single = n > 0 ? TS_ins_line : TS_del_line;
1298 char *scroll = n > 0 ? TS_rev_scroll : TS_fwd_scroll;
1299 struct frame *sf;
1300
1301 register int i = n > 0 ? n : -n;
1302 register char *buf;
1303
1304 if (ins_del_lines_hook && ! FRAME_TERMCAP_P (updating_frame))
1305 {
1306 (*ins_del_lines_hook) (vpos, n);
1307 return;
1308 }
1309
1310 sf = XFRAME (selected_frame);
1311
1312 /* If the lines below the insertion are being pushed
1313 into the end of the window, this is the same as clearing;
1314 and we know the lines are already clear, since the matching
1315 deletion has already been done. So can ignore this. */
1316 /* If the lines below the deletion are blank lines coming
1317 out of the end of the window, don't bother,
1318 as there will be a matching inslines later that will flush them. */
1319 if (scroll_region_ok && vpos + i >= specified_window)
1320 return;
1321 if (!memory_below_frame && vpos + i >= FRAME_HEIGHT (sf))
1322 return;
1323
1324 if (multi)
1325 {
1326 raw_cursor_to (vpos, 0);
1327 background_highlight ();
1328 buf = tparam (multi, 0, 0, i);
1329 OUTPUT (buf);
1330 xfree (buf);
1331 }
1332 else if (single)
1333 {
1334 raw_cursor_to (vpos, 0);
1335 background_highlight ();
1336 while (--i >= 0)
1337 OUTPUT (single);
1338 if (TF_teleray)
1339 curX = 0;
1340 }
1341 else
1342 {
1343 set_scroll_region (vpos, specified_window);
1344 if (n < 0)
1345 raw_cursor_to (specified_window - 1, 0);
1346 else
1347 raw_cursor_to (vpos, 0);
1348 background_highlight ();
1349 while (--i >= 0)
1350 OUTPUTL (scroll, specified_window - vpos);
1351 set_scroll_region (0, specified_window);
1352 }
1353
1354 if (TN_standout_width >= 0)
1355 {
1356 register int lower_limit
1357 = (scroll_region_ok
1358 ? specified_window
1359 : FRAME_HEIGHT (sf));
1360
1361 if (n < 0)
1362 {
1363 bcopy (&chars_wasted[vpos - n], &chars_wasted[vpos],
1364 lower_limit - vpos + n);
1365 bzero (&chars_wasted[lower_limit + n], - n);
1366 }
1367 else
1368 {
1369 bcopy (&chars_wasted[vpos], &copybuf[vpos], lower_limit - vpos - n);
1370 bcopy (&copybuf[vpos], &chars_wasted[vpos + n],
1371 lower_limit - vpos - n);
1372 bzero (&chars_wasted[vpos], n);
1373 }
1374 }
1375 if (!scroll_region_ok && memory_below_frame && n < 0)
1376 {
1377 cursor_to (FRAME_HEIGHT (sf) + n, 0);
1378 clear_to_end ();
1379 }
1380 }
1381 \f
1382 /* Compute cost of sending "str", in characters,
1383 not counting any line-dependent padding. */
1384
1385 int
1386 string_cost (str)
1387 char *str;
1388 {
1389 cost = 0;
1390 if (str)
1391 tputs (str, 0, evalcost);
1392 return cost;
1393 }
1394
1395 /* Compute cost of sending "str", in characters,
1396 counting any line-dependent padding at one line. */
1397
1398 static int
1399 string_cost_one_line (str)
1400 char *str;
1401 {
1402 cost = 0;
1403 if (str)
1404 tputs (str, 1, evalcost);
1405 return cost;
1406 }
1407
1408 /* Compute per line amount of line-dependent padding,
1409 in tenths of characters. */
1410
1411 int
1412 per_line_cost (str)
1413 register char *str;
1414 {
1415 cost = 0;
1416 if (str)
1417 tputs (str, 0, evalcost);
1418 cost = - cost;
1419 if (str)
1420 tputs (str, 10, evalcost);
1421 return cost;
1422 }
1423
1424 #ifndef old
1425 /* char_ins_del_cost[n] is cost of inserting N characters.
1426 char_ins_del_cost[-n] is cost of deleting N characters.
1427 The length of this vector is based on max_frame_width. */
1428
1429 int *char_ins_del_vector;
1430
1431 #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_WIDTH ((f))])
1432 #endif
1433
1434 /* ARGSUSED */
1435 static void
1436 calculate_ins_del_char_costs (frame)
1437 FRAME_PTR frame;
1438 {
1439 int ins_startup_cost, del_startup_cost;
1440 int ins_cost_per_char, del_cost_per_char;
1441 register int i;
1442 register int *p;
1443
1444 if (TS_ins_multi_chars)
1445 {
1446 ins_cost_per_char = 0;
1447 ins_startup_cost = string_cost_one_line (TS_ins_multi_chars);
1448 }
1449 else if (TS_ins_char || TS_pad_inserted_char
1450 || (TS_insert_mode && TS_end_insert_mode))
1451 {
1452 ins_startup_cost = (30 * (string_cost (TS_insert_mode)
1453 + string_cost (TS_end_insert_mode))) / 100;
1454 ins_cost_per_char = (string_cost_one_line (TS_ins_char)
1455 + string_cost_one_line (TS_pad_inserted_char));
1456 }
1457 else
1458 {
1459 ins_startup_cost = 9999;
1460 ins_cost_per_char = 0;
1461 }
1462
1463 if (TS_del_multi_chars)
1464 {
1465 del_cost_per_char = 0;
1466 del_startup_cost = string_cost_one_line (TS_del_multi_chars);
1467 }
1468 else if (TS_del_char)
1469 {
1470 del_startup_cost = (string_cost (TS_delete_mode)
1471 + string_cost (TS_end_delete_mode));
1472 if (delete_in_insert_mode)
1473 del_startup_cost /= 2;
1474 del_cost_per_char = string_cost_one_line (TS_del_char);
1475 }
1476 else
1477 {
1478 del_startup_cost = 9999;
1479 del_cost_per_char = 0;
1480 }
1481
1482 /* Delete costs are at negative offsets */
1483 p = &char_ins_del_cost (frame)[0];
1484 for (i = FRAME_WIDTH (frame); --i >= 0;)
1485 *--p = (del_startup_cost += del_cost_per_char);
1486
1487 /* Doing nothing is free */
1488 p = &char_ins_del_cost (frame)[0];
1489 *p++ = 0;
1490
1491 /* Insert costs are at positive offsets */
1492 for (i = FRAME_WIDTH (frame); --i >= 0;)
1493 *p++ = (ins_startup_cost += ins_cost_per_char);
1494 }
1495
1496 void
1497 calculate_costs (frame)
1498 FRAME_PTR frame;
1499 {
1500 register char *f = (TS_set_scroll_region
1501 ? TS_set_scroll_region
1502 : TS_set_scroll_region_1);
1503
1504 FRAME_COST_BAUD_RATE (frame) = baud_rate;
1505
1506 scroll_region_cost = string_cost (f);
1507
1508 /* These variables are only used for terminal stuff. They are allocated
1509 once for the terminal frame of X-windows emacs, but not used afterwards.
1510
1511 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1512 X turns off char_ins_del_ok.
1513
1514 chars_wasted and copybuf are only used here in term.c in cases where
1515 the term hook isn't called. */
1516
1517 max_frame_height = max (max_frame_height, FRAME_HEIGHT (frame));
1518 max_frame_width = max (max_frame_width, FRAME_WIDTH (frame));
1519
1520 if (chars_wasted != 0)
1521 chars_wasted = (char *) xrealloc (chars_wasted, max_frame_height);
1522 else
1523 chars_wasted = (char *) xmalloc (max_frame_height);
1524
1525 if (copybuf != 0)
1526 copybuf = (char *) xrealloc (copybuf, max_frame_height);
1527 else
1528 copybuf = (char *) xmalloc (max_frame_height);
1529
1530 if (char_ins_del_vector != 0)
1531 char_ins_del_vector
1532 = (int *) xrealloc (char_ins_del_vector,
1533 (sizeof (int)
1534 + 2 * max_frame_width * sizeof (int)));
1535 else
1536 char_ins_del_vector
1537 = (int *) xmalloc (sizeof (int)
1538 + 2 * max_frame_width * sizeof (int));
1539
1540 bzero (chars_wasted, max_frame_height);
1541 bzero (copybuf, max_frame_height);
1542 bzero (char_ins_del_vector, (sizeof (int)
1543 + 2 * max_frame_width * sizeof (int)));
1544
1545 if (f && (!TS_ins_line && !TS_del_line))
1546 do_line_insertion_deletion_costs (frame,
1547 TS_rev_scroll, TS_ins_multi_lines,
1548 TS_fwd_scroll, TS_del_multi_lines,
1549 f, f, 1);
1550 else
1551 do_line_insertion_deletion_costs (frame,
1552 TS_ins_line, TS_ins_multi_lines,
1553 TS_del_line, TS_del_multi_lines,
1554 0, 0, 1);
1555
1556 calculate_ins_del_char_costs (frame);
1557
1558 /* Don't use TS_repeat if its padding is worse than sending the chars */
1559 if (TS_repeat && per_line_cost (TS_repeat) * baud_rate < 9000)
1560 RPov = string_cost (TS_repeat);
1561 else
1562 RPov = FRAME_WIDTH (frame) * 2;
1563
1564 cmcostinit (); /* set up cursor motion costs */
1565 }
1566 \f
1567 struct fkey_table {
1568 char *cap, *name;
1569 };
1570
1571 /* Termcap capability names that correspond directly to X keysyms.
1572 Some of these (marked "terminfo") aren't supplied by old-style
1573 (Berkeley) termcap entries. They're listed in X keysym order;
1574 except we put the keypad keys first, so that if they clash with
1575 other keys (as on the IBM PC keyboard) they get overridden.
1576 */
1577
1578 static struct fkey_table keys[] =
1579 {
1580 "kh", "home", /* termcap */
1581 "kl", "left", /* termcap */
1582 "ku", "up", /* termcap */
1583 "kr", "right", /* termcap */
1584 "kd", "down", /* termcap */
1585 "%8", "prior", /* terminfo */
1586 "%5", "next", /* terminfo */
1587 "@7", "end", /* terminfo */
1588 "@1", "begin", /* terminfo */
1589 "*6", "select", /* terminfo */
1590 "%9", "print", /* terminfo */
1591 "@4", "execute", /* terminfo --- actually the `command' key */
1592 /*
1593 * "insert" --- see below
1594 */
1595 "&8", "undo", /* terminfo */
1596 "%0", "redo", /* terminfo */
1597 "%7", "menu", /* terminfo --- actually the `options' key */
1598 "@0", "find", /* terminfo */
1599 "@2", "cancel", /* terminfo */
1600 "%1", "help", /* terminfo */
1601 /*
1602 * "break" goes here, but can't be reliably intercepted with termcap
1603 */
1604 "&4", "reset", /* terminfo --- actually `restart' */
1605 /*
1606 * "system" and "user" --- no termcaps
1607 */
1608 "kE", "clearline", /* terminfo */
1609 "kA", "insertline", /* terminfo */
1610 "kL", "deleteline", /* terminfo */
1611 "kI", "insertchar", /* terminfo */
1612 "kD", "deletechar", /* terminfo */
1613 "kB", "backtab", /* terminfo */
1614 /*
1615 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1616 */
1617 "@8", "kp-enter", /* terminfo */
1618 /*
1619 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1620 * "kp-multiply", "kp-add", "kp-separator",
1621 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1622 * --- no termcaps for any of these.
1623 */
1624 "K4", "kp-1", /* terminfo */
1625 /*
1626 * "kp-2" --- no termcap
1627 */
1628 "K5", "kp-3", /* terminfo */
1629 /*
1630 * "kp-4" --- no termcap
1631 */
1632 "K2", "kp-5", /* terminfo */
1633 /*
1634 * "kp-6" --- no termcap
1635 */
1636 "K1", "kp-7", /* terminfo */
1637 /*
1638 * "kp-8" --- no termcap
1639 */
1640 "K3", "kp-9", /* terminfo */
1641 /*
1642 * "kp-equal" --- no termcap
1643 */
1644 "k1", "f1",
1645 "k2", "f2",
1646 "k3", "f3",
1647 "k4", "f4",
1648 "k5", "f5",
1649 "k6", "f6",
1650 "k7", "f7",
1651 "k8", "f8",
1652 "k9", "f9",
1653 };
1654
1655 static char **term_get_fkeys_arg;
1656 static Lisp_Object term_get_fkeys_1 ();
1657
1658 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1659 This function scans the termcap function key sequence entries, and
1660 adds entries to Vfunction_key_map for each function key it finds. */
1661
1662 void
1663 term_get_fkeys (address)
1664 char **address;
1665 {
1666 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1667 errors during the call. The only errors should be from Fdefine_key
1668 when given a key sequence containing an invalid prefix key. If the
1669 termcap defines function keys which use a prefix that is already bound
1670 to a command by the default bindings, we should silently ignore that
1671 function key specification, rather than giving the user an error and
1672 refusing to run at all on such a terminal. */
1673
1674 extern Lisp_Object Fidentity ();
1675 term_get_fkeys_arg = address;
1676 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1677 }
1678
1679 static Lisp_Object
1680 term_get_fkeys_1 ()
1681 {
1682 int i;
1683
1684 char **address = term_get_fkeys_arg;
1685
1686 /* This can happen if CANNOT_DUMP or with strange options. */
1687 if (!initialized)
1688 Vfunction_key_map = Fmake_sparse_keymap (Qnil);
1689
1690 for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
1691 {
1692 char *sequence = tgetstr (keys[i].cap, address);
1693 if (sequence)
1694 Fdefine_key (Vfunction_key_map, build_string (sequence),
1695 Fmake_vector (make_number (1),
1696 intern (keys[i].name)));
1697 }
1698
1699 /* The uses of the "k0" capability are inconsistent; sometimes it
1700 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1701 We will attempt to politely accommodate both systems by testing for
1702 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1703 */
1704 {
1705 char *k_semi = tgetstr ("k;", address);
1706 char *k0 = tgetstr ("k0", address);
1707 char *k0_name = "f10";
1708
1709 if (k_semi)
1710 {
1711 Fdefine_key (Vfunction_key_map, build_string (k_semi),
1712 Fmake_vector (make_number (1), intern ("f10")));
1713 k0_name = "f0";
1714 }
1715
1716 if (k0)
1717 Fdefine_key (Vfunction_key_map, build_string (k0),
1718 Fmake_vector (make_number (1), intern (k0_name)));
1719 }
1720
1721 /* Set up cookies for numbered function keys above f10. */
1722 {
1723 char fcap[3], fkey[4];
1724
1725 fcap[0] = 'F'; fcap[2] = '\0';
1726 for (i = 11; i < 64; i++)
1727 {
1728 if (i <= 19)
1729 fcap[1] = '1' + i - 11;
1730 else if (i <= 45)
1731 fcap[1] = 'A' + i - 20;
1732 else
1733 fcap[1] = 'a' + i - 46;
1734
1735 {
1736 char *sequence = tgetstr (fcap, address);
1737 if (sequence)
1738 {
1739 sprintf (fkey, "f%d", i);
1740 Fdefine_key (Vfunction_key_map, build_string (sequence),
1741 Fmake_vector (make_number (1),
1742 intern (fkey)));
1743 }
1744 }
1745 }
1746 }
1747
1748 /*
1749 * Various mappings to try and get a better fit.
1750 */
1751 {
1752 #define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1753 if (!tgetstr (cap1, address)) \
1754 { \
1755 char *sequence = tgetstr (cap2, address); \
1756 if (sequence) \
1757 Fdefine_key (Vfunction_key_map, build_string (sequence), \
1758 Fmake_vector (make_number (1), \
1759 intern (sym))); \
1760 }
1761
1762 /* if there's no key_next keycap, map key_npage to `next' keysym */
1763 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1764 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1765 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1766 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1767 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1768 /* if there's no key_end keycap, map key_ll to 'end' keysym */
1769 CONDITIONAL_REASSIGN ("@7", "kH", "end");
1770
1771 /* IBM has their own non-standard dialect of terminfo.
1772 If the standard name isn't found, try the IBM name. */
1773 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1774 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1775 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1776 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1777 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1778 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1779 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1780 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1781 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1782 #undef CONDITIONAL_REASSIGN
1783 }
1784
1785 return Qnil;
1786 }
1787
1788 \f
1789 /***********************************************************************
1790 Character Display Information
1791 ***********************************************************************/
1792
1793 static void append_glyph P_ ((struct it *));
1794
1795
1796 /* Append glyphs to IT's glyph_row. Called from produce_glyphs for
1797 terminal frames if IT->glyph_row != NULL. IT->c is the character
1798 for which to produce glyphs; IT->face_id contains the character's
1799 face. Padding glyphs are appended if IT->c has a IT->pixel_width >
1800 1. */
1801
1802 static void
1803 append_glyph (it)
1804 struct it *it;
1805 {
1806 struct glyph *glyph, *end;
1807 int i;
1808
1809 xassert (it->glyph_row);
1810 glyph = (it->glyph_row->glyphs[it->area]
1811 + it->glyph_row->used[it->area]);
1812 end = it->glyph_row->glyphs[1 + it->area];
1813
1814 for (i = 0;
1815 i < it->pixel_width && glyph < end;
1816 ++i)
1817 {
1818 glyph->type = CHAR_GLYPH;
1819 glyph->pixel_width = 1;
1820 glyph->u.ch = it->c;
1821 glyph->face_id = it->face_id;
1822 glyph->padding_p = i > 0;
1823 glyph->charpos = CHARPOS (it->position);
1824 glyph->object = it->object;
1825
1826 ++it->glyph_row->used[it->area];
1827 ++glyph;
1828 }
1829 }
1830
1831
1832 /* Produce glyphs for the display element described by IT. The
1833 function fills output fields of IT with pixel information like the
1834 pixel width and height of a character, and maybe produces glyphs at
1835 the same time if IT->glyph_row is non-null. See the explanation of
1836 struct display_iterator in dispextern.h for an overview. */
1837
1838 void
1839 produce_glyphs (it)
1840 struct it *it;
1841 {
1842 /* If a hook is installed, let it do the work. */
1843 xassert (it->what == IT_CHARACTER
1844 || it->what == IT_COMPOSITION
1845 || it->what == IT_IMAGE
1846 || it->what == IT_STRETCH);
1847
1848 /* Nothing but characters are supported on terminal frames. For a
1849 composition sequence, it->c is the first character of the
1850 sequence. */
1851 xassert (it->what == IT_CHARACTER
1852 || it->what == IT_COMPOSITION);
1853
1854 if (it->c >= 040 && it->c < 0177)
1855 {
1856 it->pixel_width = it->nglyphs = 1;
1857 if (it->glyph_row)
1858 append_glyph (it);
1859 }
1860 else if (it->c == '\n')
1861 it->pixel_width = it->nglyphs = 0;
1862 else if (it->c == '\t')
1863 {
1864 int absolute_x = (it->current_x
1865 + it->continuation_lines_width);
1866 int next_tab_x
1867 = (((1 + absolute_x + it->tab_width - 1)
1868 / it->tab_width)
1869 * it->tab_width);
1870 int nspaces;
1871
1872 /* If part of the TAB has been displayed on the previous line
1873 which is continued now, continuation_lines_width will have
1874 been incremented already by the part that fitted on the
1875 continued line. So, we will get the right number of spaces
1876 here. */
1877 nspaces = next_tab_x - absolute_x;
1878
1879 if (it->glyph_row)
1880 {
1881 int n = nspaces;
1882
1883 it->c = ' ';
1884 it->pixel_width = it->len = 1;
1885
1886 while (n--)
1887 append_glyph (it);
1888
1889 it->c = '\t';
1890 }
1891
1892 it->pixel_width = nspaces;
1893 it->nglyphs = nspaces;
1894 }
1895 else if (SINGLE_BYTE_CHAR_P (it->c))
1896 {
1897 /* Coming here means that it->c is from display table, thus we
1898 must send the code as is to the terminal. Although there's
1899 no way to know how many columns it occupies on a screen, it
1900 is a good assumption that a single byte code has 1-column
1901 width. */
1902 it->pixel_width = it->nglyphs = 1;
1903 if (it->glyph_row)
1904 append_glyph (it);
1905 }
1906 else
1907 {
1908 /* A multi-byte character. The display width is fixed for all
1909 characters of the set. Some of the glyphs may have to be
1910 ignored because they are already displayed in a continued
1911 line. */
1912 int charset = CHAR_CHARSET (it->c);
1913
1914 it->pixel_width = CHARSET_WIDTH (charset);
1915 it->nglyphs = it->pixel_width;
1916
1917 if (it->glyph_row)
1918 append_glyph (it);
1919 }
1920
1921 /* Advance current_x by the pixel width as a convenience for
1922 the caller. */
1923 if (it->area == TEXT_AREA)
1924 it->current_x += it->pixel_width;
1925 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1926 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
1927 }
1928
1929
1930 /* Get information about special display element WHAT in an
1931 environment described by IT. WHAT is one of IT_TRUNCATION or
1932 IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a
1933 non-null glyph_row member. This function ensures that fields like
1934 face_id, c, len of IT are left untouched. */
1935
1936 void
1937 produce_special_glyphs (it, what)
1938 struct it *it;
1939 enum display_element_type what;
1940 {
1941 struct it temp_it;
1942
1943 temp_it = *it;
1944 temp_it.dp = NULL;
1945 temp_it.what = IT_CHARACTER;
1946 temp_it.len = 1;
1947 temp_it.object = make_number (0);
1948 bzero (&temp_it.current, sizeof temp_it.current);
1949
1950 if (what == IT_CONTINUATION)
1951 {
1952 /* Continuation glyph. */
1953 if (it->dp
1954 && INTEGERP (DISP_CONTINUE_GLYPH (it->dp))
1955 && GLYPH_CHAR_VALID_P (XINT (DISP_CONTINUE_GLYPH (it->dp))))
1956 {
1957 temp_it.c = FAST_GLYPH_CHAR (XINT (DISP_CONTINUE_GLYPH (it->dp)));
1958 temp_it.len = CHAR_BYTES (temp_it.c);
1959 }
1960 else
1961 temp_it.c = '\\';
1962
1963 produce_glyphs (&temp_it);
1964 it->pixel_width = temp_it.pixel_width;
1965 it->nglyphs = temp_it.pixel_width;
1966 }
1967 else if (what == IT_TRUNCATION)
1968 {
1969 /* Truncation glyph. */
1970 if (it->dp
1971 && INTEGERP (DISP_TRUNC_GLYPH (it->dp))
1972 && GLYPH_CHAR_VALID_P (XINT (DISP_TRUNC_GLYPH (it->dp))))
1973 {
1974 temp_it.c = FAST_GLYPH_CHAR (XINT (DISP_TRUNC_GLYPH (it->dp)));
1975 temp_it.len = CHAR_BYTES (temp_it.c);
1976 }
1977 else
1978 temp_it.c = '$';
1979
1980 produce_glyphs (&temp_it);
1981 it->pixel_width = temp_it.pixel_width;
1982 it->nglyphs = temp_it.pixel_width;
1983 }
1984 else
1985 abort ();
1986 }
1987
1988
1989 /* Return an estimation of the pixel height of mode or top lines on
1990 frame F. FACE_ID specifies what line's height to estimate. */
1991
1992 int
1993 estimate_mode_line_height (f, face_id)
1994 struct frame *f;
1995 enum face_id face_id;
1996 {
1997 if (estimate_mode_line_height_hook)
1998 return estimate_mode_line_height_hook (f, face_id);
1999 else
2000 return 1;
2001 }
2002
2003
2004 \f
2005 /***********************************************************************
2006 Faces
2007 ***********************************************************************/
2008
2009 /* Value is non-zero if attribute ATTR may be used. ATTR should be
2010 one of the enumerators from enum no_color_bit, or a bit set built
2011 from them. Some display attributes may not be used together with
2012 color; the termcap capability `NC' specifies which ones. */
2013
2014 #define MAY_USE_WITH_COLORS_P(ATTR) \
2015 (TN_max_colors > 0 \
2016 ? (TN_no_color_video & (ATTR)) == 0 \
2017 : 1)
2018
2019 /* Turn appearances of face FACE_ID on tty frame F on. */
2020
2021 static void
2022 turn_on_face (f, face_id)
2023 struct frame *f;
2024 int face_id;
2025 {
2026 struct face *face = FACE_FROM_ID (f, face_id);
2027 long fg = face->foreground;
2028 long bg = face->background;
2029
2030 /* Do this first because TS_end_standout_mode may be the same
2031 as TS_exit_attribute_mode, which turns all appearances off. */
2032 if (MAY_USE_WITH_COLORS_P (NC_REVERSE))
2033 {
2034 if (TN_max_colors > 0)
2035 {
2036 if (fg >= 0 && bg >= 0)
2037 {
2038 /* If the terminal supports colors, we can set them
2039 below without using reverse video. The face's fg
2040 and bg colors are set as they should appear on
2041 the screen, i.e. they take the inverse-video'ness
2042 of the face already into account. */
2043 }
2044 else if (inverse_video)
2045 {
2046 if (fg == FACE_TTY_DEFAULT_FG_COLOR
2047 || bg == FACE_TTY_DEFAULT_BG_COLOR)
2048 toggle_highlight ();
2049 }
2050 else
2051 {
2052 if (fg == FACE_TTY_DEFAULT_BG_COLOR
2053 || bg == FACE_TTY_DEFAULT_FG_COLOR)
2054 toggle_highlight ();
2055 }
2056 }
2057 else
2058 {
2059 /* If we can't display colors, use reverse video
2060 if the face specifies that. */
2061 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 }
2075
2076 if (face->tty_bold_p)
2077 {
2078 if (MAY_USE_WITH_COLORS_P (NC_BOLD))
2079 OUTPUT1_IF (TS_enter_bold_mode);
2080 }
2081 else if (face->tty_dim_p)
2082 if (MAY_USE_WITH_COLORS_P (NC_DIM))
2083 OUTPUT1_IF (TS_enter_dim_mode);
2084
2085 /* Alternate charset and blinking not yet used. */
2086 if (face->tty_alt_charset_p
2087 && MAY_USE_WITH_COLORS_P (NC_ALT_CHARSET))
2088 OUTPUT1_IF (TS_enter_alt_charset_mode);
2089
2090 if (face->tty_blinking_p
2091 && MAY_USE_WITH_COLORS_P (NC_BLINK))
2092 OUTPUT1_IF (TS_enter_blink_mode);
2093
2094 if (face->tty_underline_p
2095 /* Don't underline if that's difficult. */
2096 && TN_magic_cookie_glitch_ul <= 0
2097 && MAY_USE_WITH_COLORS_P (NC_UNDERLINE))
2098 OUTPUT1_IF (TS_enter_underline_mode);
2099
2100 if (TN_max_colors > 0)
2101 {
2102 char *p;
2103
2104 if (fg >= 0 && TS_set_foreground)
2105 {
2106 p = tparam (TS_set_foreground, NULL, 0, (int) fg);
2107 OUTPUT (p);
2108 xfree (p);
2109 }
2110
2111 if (bg >= 0 && TS_set_background)
2112 {
2113 p = tparam (TS_set_background, NULL, 0, (int) bg);
2114 OUTPUT (p);
2115 xfree (p);
2116 }
2117 }
2118 }
2119
2120
2121 /* Turn off appearances of face FACE_ID on tty frame F. */
2122
2123 static void
2124 turn_off_face (f, face_id)
2125 struct frame *f;
2126 int face_id;
2127 {
2128 struct face *face = FACE_FROM_ID (f, face_id);
2129
2130 xassert (face != NULL);
2131
2132 if (TS_exit_attribute_mode)
2133 {
2134 /* Capability "me" will turn off appearance modes double-bright,
2135 half-bright, reverse-video, standout, underline. It may or
2136 may not turn off alt-char-mode. */
2137 if (face->tty_bold_p
2138 || face->tty_dim_p
2139 || face->tty_reverse_p
2140 || face->tty_alt_charset_p
2141 || face->tty_blinking_p
2142 || face->tty_underline_p)
2143 {
2144 OUTPUT1_IF (TS_exit_attribute_mode);
2145 if (strcmp (TS_exit_attribute_mode, TS_end_standout_mode) == 0)
2146 standout_mode = 0;
2147 }
2148
2149 if (face->tty_alt_charset_p)
2150 OUTPUT_IF (TS_exit_alt_charset_mode);
2151 }
2152 else
2153 {
2154 /* If we don't have "me" we can only have those appearances
2155 that have exit sequences defined. */
2156 if (face->tty_alt_charset_p)
2157 OUTPUT_IF (TS_exit_alt_charset_mode);
2158
2159 if (face->tty_underline_p
2160 /* We don't underline if that's difficult. */
2161 && TN_magic_cookie_glitch_ul <= 0)
2162 OUTPUT_IF (TS_exit_underline_mode);
2163 }
2164
2165 /* Switch back to default colors. */
2166 if (TN_max_colors > 0
2167 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
2168 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
2169 || (face->background != FACE_TTY_DEFAULT_COLOR
2170 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
2171 OUTPUT1_IF (TS_orig_pair);
2172 }
2173
2174
2175 /* Return non-zero if the terminal is capable to display colors. */
2176
2177 DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
2178 0, 1, 0,
2179 /* Return non-nil if TTY can display colors on FRAME. */
2180 (frame))
2181 Lisp_Object frame;
2182 {
2183 return TN_max_colors > 0 ? Qt : Qnil;
2184 }
2185
2186
2187
2188 \f
2189 /***********************************************************************
2190 Initialization
2191 ***********************************************************************/
2192
2193 void
2194 term_init (terminal_type)
2195 char *terminal_type;
2196 {
2197 char *area;
2198 char **address = &area;
2199 char buffer[2044];
2200 register char *p;
2201 int status;
2202 struct frame *sf = XFRAME (selected_frame);
2203
2204 #ifdef WINDOWSNT
2205 initialize_w32_display ();
2206
2207 Wcm_clear ();
2208
2209 area = (char *) xmalloc (2044);
2210
2211 if (area == 0)
2212 abort ();
2213
2214 FrameRows = FRAME_HEIGHT (sf);
2215 FrameCols = FRAME_WIDTH (sf);
2216 specified_window = FRAME_HEIGHT (sf);
2217
2218 delete_in_insert_mode = 1;
2219
2220 UseTabs = 0;
2221 scroll_region_ok = 0;
2222
2223 /* Seems to insert lines when it's not supposed to, messing
2224 up the display. In doing a trace, it didn't seem to be
2225 called much, so I don't think we're losing anything by
2226 turning it off. */
2227
2228 line_ins_del_ok = 0;
2229 char_ins_del_ok = 1;
2230
2231 baud_rate = 19200;
2232
2233 FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0;
2234 FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none;
2235 TN_max_colors = 16; /* Required to be non-zero for tty-display-color-p */
2236
2237 return;
2238 #else /* not WINDOWSNT */
2239
2240 Wcm_clear ();
2241
2242 status = tgetent (buffer, terminal_type);
2243 if (status < 0)
2244 {
2245 #ifdef TERMINFO
2246 fatal ("Cannot open terminfo database file");
2247 #else
2248 fatal ("Cannot open termcap database file");
2249 #endif
2250 }
2251 if (status == 0)
2252 {
2253 #ifdef TERMINFO
2254 fatal ("Terminal type %s is not defined.\n\
2255 If that is not the actual type of terminal you have,\n\
2256 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
2257 `setenv TERM ...') to specify the correct type. It may be necessary\n\
2258 to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
2259 terminal_type);
2260 #else
2261 fatal ("Terminal type %s is not defined.\n\
2262 If that is not the actual type of terminal you have,\n\
2263 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
2264 `setenv TERM ...') to specify the correct type. It may be necessary\n\
2265 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
2266 terminal_type);
2267 #endif
2268 }
2269 #ifdef TERMINFO
2270 area = (char *) xmalloc (2044);
2271 #else
2272 area = (char *) xmalloc (strlen (buffer));
2273 #endif /* not TERMINFO */
2274 if (area == 0)
2275 abort ();
2276
2277 TS_ins_line = tgetstr ("al", address);
2278 TS_ins_multi_lines = tgetstr ("AL", address);
2279 TS_bell = tgetstr ("bl", address);
2280 BackTab = tgetstr ("bt", address);
2281 TS_clr_to_bottom = tgetstr ("cd", address);
2282 TS_clr_line = tgetstr ("ce", address);
2283 TS_clr_frame = tgetstr ("cl", address);
2284 ColPosition = NULL; /* tgetstr ("ch", address); */
2285 AbsPosition = tgetstr ("cm", address);
2286 CR = tgetstr ("cr", address);
2287 TS_set_scroll_region = tgetstr ("cs", address);
2288 TS_set_scroll_region_1 = tgetstr ("cS", address);
2289 RowPosition = tgetstr ("cv", address);
2290 TS_del_char = tgetstr ("dc", address);
2291 TS_del_multi_chars = tgetstr ("DC", address);
2292 TS_del_line = tgetstr ("dl", address);
2293 TS_del_multi_lines = tgetstr ("DL", address);
2294 TS_delete_mode = tgetstr ("dm", address);
2295 TS_end_delete_mode = tgetstr ("ed", address);
2296 TS_end_insert_mode = tgetstr ("ei", address);
2297 Home = tgetstr ("ho", address);
2298 TS_ins_char = tgetstr ("ic", address);
2299 TS_ins_multi_chars = tgetstr ("IC", address);
2300 TS_insert_mode = tgetstr ("im", address);
2301 TS_pad_inserted_char = tgetstr ("ip", address);
2302 TS_end_keypad_mode = tgetstr ("ke", address);
2303 TS_keypad_mode = tgetstr ("ks", address);
2304 LastLine = tgetstr ("ll", address);
2305 Right = tgetstr ("nd", address);
2306 Down = tgetstr ("do", address);
2307 if (!Down)
2308 Down = tgetstr ("nl", address); /* Obsolete name for "do" */
2309 #ifdef VMS
2310 /* VMS puts a carriage return before each linefeed,
2311 so it is not safe to use linefeeds. */
2312 if (Down && Down[0] == '\n' && Down[1] == '\0')
2313 Down = 0;
2314 #endif /* VMS */
2315 if (tgetflag ("bs"))
2316 Left = "\b"; /* can't possibly be longer! */
2317 else /* (Actually, "bs" is obsolete...) */
2318 Left = tgetstr ("le", address);
2319 if (!Left)
2320 Left = tgetstr ("bc", address); /* Obsolete name for "le" */
2321 TS_pad_char = tgetstr ("pc", address);
2322 TS_repeat = tgetstr ("rp", address);
2323 TS_end_standout_mode = tgetstr ("se", address);
2324 TS_fwd_scroll = tgetstr ("sf", address);
2325 TS_standout_mode = tgetstr ("so", address);
2326 TS_rev_scroll = tgetstr ("sr", address);
2327 Wcm.cm_tab = tgetstr ("ta", address);
2328 TS_end_termcap_modes = tgetstr ("te", address);
2329 TS_termcap_modes = tgetstr ("ti", address);
2330 Up = tgetstr ("up", address);
2331 TS_visible_bell = tgetstr ("vb", address);
2332 TS_cursor_normal = tgetstr ("ve", address);
2333 TS_cursor_visible = tgetstr ("vs", address);
2334 TS_cursor_invisible = tgetstr ("vi", address);
2335 TS_set_window = tgetstr ("wi", address);
2336
2337 TS_enter_underline_mode = tgetstr ("us", address);
2338 TS_exit_underline_mode = tgetstr ("ue", address);
2339 TN_magic_cookie_glitch_ul = tgetnum ("ug");
2340 TS_enter_bold_mode = tgetstr ("md", address);
2341 TS_enter_dim_mode = tgetstr ("mh", address);
2342 TS_enter_blink_mode = tgetstr ("mb", address);
2343 TS_enter_reverse_mode = tgetstr ("mr", address);
2344 TS_enter_alt_charset_mode = tgetstr ("as", address);
2345 TS_exit_alt_charset_mode = tgetstr ("ae", address);
2346 TS_exit_attribute_mode = tgetstr ("me", address);
2347
2348 MultiUp = tgetstr ("UP", address);
2349 MultiDown = tgetstr ("DO", address);
2350 MultiLeft = tgetstr ("LE", address);
2351 MultiRight = tgetstr ("RI", address);
2352
2353 /* SVr4/ANSI color suppert. If "op" isn't available, don't support
2354 color because we can't switch back to the default foreground and
2355 background. */
2356 TS_orig_pair = tgetstr ("op", address);
2357 if (TS_orig_pair)
2358 {
2359 TS_set_foreground = tgetstr ("AF", address);
2360 TS_set_background = tgetstr ("AB", address);
2361 if (!TS_set_foreground)
2362 {
2363 /* SVr4. */
2364 TS_set_foreground = tgetstr ("Sf", address);
2365 TS_set_background = tgetstr ("Sb", address);
2366 }
2367
2368 TN_max_colors = tgetnum ("Co");
2369 TN_max_pairs = tgetnum ("pa");
2370
2371 TN_no_color_video = tgetnum ("NC");
2372 if (TN_no_color_video == -1)
2373 TN_no_color_video = 0;
2374 }
2375
2376 MagicWrap = tgetflag ("xn");
2377 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
2378 the former flag imply the latter. */
2379 AutoWrap = MagicWrap || tgetflag ("am");
2380 memory_below_frame = tgetflag ("db");
2381 TF_hazeltine = tgetflag ("hz");
2382 must_write_spaces = tgetflag ("in");
2383 meta_key = tgetflag ("km") || tgetflag ("MT");
2384 TF_insmode_motion = tgetflag ("mi");
2385 TF_standout_motion = tgetflag ("ms");
2386 TF_underscore = tgetflag ("ul");
2387 TF_xs = tgetflag ("xs");
2388 TF_teleray = tgetflag ("xt");
2389
2390 term_get_fkeys (address);
2391
2392 /* Get frame size from system, or else from termcap. */
2393 {
2394 int height, width;
2395 get_frame_size (&width, &height);
2396 FRAME_WIDTH (sf) = width;
2397 FRAME_HEIGHT (sf) = height;
2398 }
2399
2400 if (FRAME_WIDTH (sf) <= 0)
2401 SET_FRAME_WIDTH (sf, tgetnum ("co"));
2402 else
2403 /* Keep width and external_width consistent */
2404 SET_FRAME_WIDTH (sf, FRAME_WIDTH (sf));
2405 if (FRAME_HEIGHT (sf) <= 0)
2406 FRAME_HEIGHT (sf) = tgetnum ("li");
2407
2408 if (FRAME_HEIGHT (sf) < 3 || FRAME_WIDTH (sf) < 3)
2409 fatal ("Screen size %dx%d is too small",
2410 FRAME_HEIGHT (sf), FRAME_WIDTH (sf));
2411
2412 min_padding_speed = tgetnum ("pb");
2413 TN_standout_width = tgetnum ("sg");
2414 TabWidth = tgetnum ("tw");
2415
2416 #ifdef VMS
2417 /* These capabilities commonly use ^J.
2418 I don't know why, but sending them on VMS does not work;
2419 it causes following spaces to be lost, sometimes.
2420 For now, the simplest fix is to avoid using these capabilities ever. */
2421 if (Down && Down[0] == '\n')
2422 Down = 0;
2423 #endif /* VMS */
2424
2425 if (!TS_bell)
2426 TS_bell = "\07";
2427
2428 if (!TS_fwd_scroll)
2429 TS_fwd_scroll = Down;
2430
2431 PC = TS_pad_char ? *TS_pad_char : 0;
2432
2433 if (TabWidth < 0)
2434 TabWidth = 8;
2435
2436 /* Turned off since /etc/termcap seems to have :ta= for most terminals
2437 and newer termcap doc does not seem to say there is a default.
2438 if (!Wcm.cm_tab)
2439 Wcm.cm_tab = "\t";
2440 */
2441
2442 if (TS_standout_mode == 0)
2443 {
2444 TN_standout_width = tgetnum ("ug");
2445 TS_end_standout_mode = tgetstr ("ue", address);
2446 TS_standout_mode = tgetstr ("us", address);
2447 }
2448
2449 /* If no `se' string, try using a `me' string instead.
2450 If that fails, we can't use standout mode at all. */
2451 if (TS_end_standout_mode == 0)
2452 {
2453 char *s = tgetstr ("me", address);
2454 if (s != 0)
2455 TS_end_standout_mode = s;
2456 else
2457 TS_standout_mode = 0;
2458 }
2459
2460 if (TF_teleray)
2461 {
2462 Wcm.cm_tab = 0;
2463 /* Teleray: most programs want a space in front of TS_standout_mode,
2464 but Emacs can do without it (and give one extra column). */
2465 TS_standout_mode = "\033RD";
2466 TN_standout_width = 1;
2467 /* But that means we cannot rely on ^M to go to column zero! */
2468 CR = 0;
2469 /* LF can't be trusted either -- can alter hpos */
2470 /* if move at column 0 thru a line with TS_standout_mode */
2471 Down = 0;
2472 }
2473
2474 /* Special handling for certain terminal types known to need it */
2475
2476 if (!strcmp (terminal_type, "supdup"))
2477 {
2478 memory_below_frame = 1;
2479 Wcm.cm_losewrap = 1;
2480 }
2481 if (!strncmp (terminal_type, "c10", 3)
2482 || !strcmp (terminal_type, "perq"))
2483 {
2484 /* Supply a makeshift :wi string.
2485 This string is not valid in general since it works only
2486 for windows starting at the upper left corner;
2487 but that is all Emacs uses.
2488
2489 This string works only if the frame is using
2490 the top of the video memory, because addressing is memory-relative.
2491 So first check the :ti string to see if that is true.
2492
2493 It would be simpler if the :wi string could go in the termcap
2494 entry, but it can't because it is not fully valid.
2495 If it were in the termcap entry, it would confuse other programs. */
2496 if (!TS_set_window)
2497 {
2498 p = TS_termcap_modes;
2499 while (*p && strcmp (p, "\033v "))
2500 p++;
2501 if (*p)
2502 TS_set_window = "\033v%C %C %C %C ";
2503 }
2504 /* Termcap entry often fails to have :in: flag */
2505 must_write_spaces = 1;
2506 /* :ti string typically fails to have \E^G! in it */
2507 /* This limits scope of insert-char to one line. */
2508 strcpy (area, TS_termcap_modes);
2509 strcat (area, "\033\007!");
2510 TS_termcap_modes = area;
2511 area += strlen (area) + 1;
2512 p = AbsPosition;
2513 /* Change all %+ parameters to %C, to handle
2514 values above 96 correctly for the C100. */
2515 while (*p)
2516 {
2517 if (p[0] == '%' && p[1] == '+')
2518 p[1] = 'C';
2519 p++;
2520 }
2521 }
2522
2523 FrameRows = FRAME_HEIGHT (sf);
2524 FrameCols = FRAME_WIDTH (sf);
2525 specified_window = FRAME_HEIGHT (sf);
2526
2527 if (Wcm_init () == -1) /* can't do cursor motion */
2528 #ifdef VMS
2529 fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
2530 It lacks the ability to position the cursor.\n\
2531 If that is not the actual type of terminal you have, use either the\n\
2532 DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
2533 or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.",
2534 terminal_type);
2535 #else /* not VMS */
2536 # ifdef TERMINFO
2537 fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
2538 It lacks the ability to position the cursor.\n\
2539 If that is not the actual type of terminal you have,\n\
2540 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
2541 `setenv TERM ...') to specify the correct type. It may be necessary\n\
2542 to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
2543 terminal_type);
2544 # else /* TERMCAP */
2545 fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
2546 It lacks the ability to position the cursor.\n\
2547 If that is not the actual type of terminal you have,\n\
2548 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
2549 `setenv TERM ...') to specify the correct type. It may be necessary\n\
2550 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
2551 terminal_type);
2552 # endif /* TERMINFO */
2553 #endif /*VMS */
2554 if (FRAME_HEIGHT (sf) <= 0
2555 || FRAME_WIDTH (sf) <= 0)
2556 fatal ("The frame size has not been specified");
2557
2558 delete_in_insert_mode
2559 = TS_delete_mode && TS_insert_mode
2560 && !strcmp (TS_delete_mode, TS_insert_mode);
2561
2562 se_is_so = (TS_standout_mode
2563 && TS_end_standout_mode
2564 && !strcmp (TS_standout_mode, TS_end_standout_mode));
2565
2566 /* Remove width of standout marker from usable width of line */
2567 if (TN_standout_width > 0)
2568 SET_FRAME_WIDTH (sf, FRAME_WIDTH (sf) - TN_standout_width);
2569
2570 UseTabs = tabs_safe_p () && TabWidth == 8;
2571
2572 scroll_region_ok
2573 = (Wcm.cm_abs
2574 && (TS_set_window || TS_set_scroll_region || TS_set_scroll_region_1));
2575
2576 line_ins_del_ok = (((TS_ins_line || TS_ins_multi_lines)
2577 && (TS_del_line || TS_del_multi_lines))
2578 || (scroll_region_ok && TS_fwd_scroll && TS_rev_scroll));
2579
2580 char_ins_del_ok = ((TS_ins_char || TS_insert_mode
2581 || TS_pad_inserted_char || TS_ins_multi_chars)
2582 && (TS_del_char || TS_del_multi_chars));
2583
2584 fast_clear_end_of_line = TS_clr_line != 0;
2585
2586 init_baud_rate ();
2587 if (read_socket_hook) /* Baudrate is somewhat */
2588 /* meaningless in this case */
2589 baud_rate = 9600;
2590
2591 FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0;
2592 FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none;
2593 #endif /* WINDOWSNT */
2594 }
2595
2596 /* VARARGS 1 */
2597 void
2598 fatal (str, arg1, arg2)
2599 char *str, *arg1, *arg2;
2600 {
2601 fprintf (stderr, "emacs: ");
2602 fprintf (stderr, str, arg1, arg2);
2603 fprintf (stderr, "\n");
2604 fflush (stderr);
2605 exit (1);
2606 }
2607
2608 void
2609 syms_of_term ()
2610 {
2611 DEFVAR_BOOL ("system-uses-terminfo", &system_uses_terminfo
2612 /* Non-nil means the system uses terminfo rather than termcap.
2613 This variable can be used by terminal emulator packages. */);
2614 #ifdef TERMINFO
2615 system_uses_terminfo = 1;
2616 #else
2617 system_uses_terminfo = 0;
2618 #endif
2619
2620 DEFVAR_LISP ("ring-bell-function", &Vring_bell_function
2621 /* Non-nil means call this function to ring the bell.
2622 The function should accept no arguments. */);
2623 Vring_bell_function = Qnil;
2624
2625 defsubr (&Stty_display_color_p);
2626 }
2627