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