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