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