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