Add seq-set-equal-p to test for set equality
[emacs.git] / src / term.c
blob8770aff8a92d6bb97e5c6dd934f3c9f3e111c6f9
1 /* Terminal control module for terminals described by TERMCAP
2 Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2017 Free Software
3 Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 /* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>. */
22 #include <config.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <sys/file.h>
28 #include <sys/time.h>
29 #include <unistd.h>
31 #include "lisp.h"
32 #include "termchar.h"
33 #include "tparam.h"
34 #include "character.h"
35 #include "buffer.h"
36 #include "charset.h"
37 #include "coding.h"
38 #include "composite.h"
39 #include "keyboard.h"
40 #include "frame.h"
41 #include "disptab.h"
42 #include "termhooks.h"
43 #include "dispextern.h"
44 #include "window.h"
45 #include "keymap.h"
46 #include "blockinput.h"
47 #include "syssignal.h"
48 #ifdef MSDOS
49 #include "msdos.h"
50 static int been_here = -1;
51 #endif
53 #ifdef USE_X_TOOLKIT
54 #include "../lwlib/lwlib.h"
55 #endif
57 #include "cm.h"
58 #include "menu.h"
60 /* The name of the default console device. */
61 #ifdef WINDOWSNT
62 #include "w32term.h"
63 #endif
65 static void tty_set_scroll_region (struct frame *f, int start, int stop);
66 static void turn_on_face (struct frame *, int face_id);
67 static void turn_off_face (struct frame *, int face_id);
68 static void tty_turn_off_highlight (struct tty_display_info *);
69 static void tty_show_cursor (struct tty_display_info *);
70 static void tty_hide_cursor (struct tty_display_info *);
71 static void tty_background_highlight (struct tty_display_info *tty);
72 static void clear_tty_hooks (struct terminal *terminal);
73 static void set_tty_hooks (struct terminal *terminal);
74 static void dissociate_if_controlling_tty (int fd);
75 static void delete_tty (struct terminal *);
76 static _Noreturn void maybe_fatal (bool, struct terminal *,
77 const char *, const char *, ...)
78 ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5);
79 static _Noreturn void vfatal (const char *str, va_list ap)
80 ATTRIBUTE_FORMAT_PRINTF (1, 0);
83 #define OUTPUT(tty, a) \
84 emacs_tputs ((tty), a, \
85 FRAME_TOTAL_LINES (XFRAME (selected_frame)) - curY (tty), \
86 cmputc)
88 #define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
89 #define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
91 #define OUTPUT_IF(tty, a) \
92 do { \
93 if (a) \
94 OUTPUT (tty, a); \
95 } while (0)
97 #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
99 /* Display space properties. */
101 /* Chain of all tty device parameters. */
102 struct tty_display_info *tty_list;
104 /* Meaning of bits in no_color_video. Each bit set means that the
105 corresponding attribute cannot be combined with colors. */
107 enum no_color_bit
109 NC_STANDOUT = 1 << 0,
110 NC_UNDERLINE = 1 << 1,
111 NC_REVERSE = 1 << 2,
112 NC_ITALIC = 1 << 3,
113 NC_DIM = 1 << 4,
114 NC_BOLD = 1 << 5,
115 NC_INVIS = 1 << 6,
116 NC_PROTECT = 1 << 7
119 /* internal state */
121 /* The largest frame width in any call to calculate_costs. */
123 static int max_frame_cols;
127 #ifdef HAVE_GPM
128 #include <sys/fcntl.h>
130 /* The device for which we have enabled gpm support (or NULL). */
131 struct tty_display_info *gpm_tty = NULL;
133 /* Last recorded mouse coordinates. */
134 static int last_mouse_x, last_mouse_y;
135 #endif /* HAVE_GPM */
137 /* Ring the bell on a tty. */
139 static void
140 tty_ring_bell (struct frame *f)
142 struct tty_display_info *tty = FRAME_TTY (f);
144 if (tty->output)
146 OUTPUT (tty, (tty->TS_visible_bell && visible_bell
147 ? tty->TS_visible_bell
148 : tty->TS_bell));
149 fflush (tty->output);
153 /* Set up termcap modes for Emacs. */
155 static void
156 tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
158 Lisp_Object lisp_terminal;
159 Lisp_Object extra_codes;
160 struct tty_display_info *tty = terminal->display_info.tty;
162 XSETTERMINAL (lisp_terminal, terminal);
163 for (extra_codes = Fterminal_parameter (lisp_terminal, sym);
164 CONSP (extra_codes);
165 extra_codes = XCDR (extra_codes))
167 Lisp_Object string = XCAR (extra_codes);
168 if (STRINGP (string))
170 fwrite (SDATA (string), 1, SBYTES (string), tty->output);
171 if (tty->termscript)
172 fwrite (SDATA (string), 1, SBYTES (string), tty->termscript);
177 static void
178 tty_set_terminal_modes (struct terminal *terminal)
180 struct tty_display_info *tty = terminal->display_info.tty;
182 if (tty->output)
184 if (tty->TS_termcap_modes)
185 OUTPUT (tty, tty->TS_termcap_modes);
186 else
188 /* Output enough newlines to scroll all the old screen contents
189 off the screen, so it won't be overwritten and lost. */
190 int i;
191 current_tty = tty;
192 for (i = 0; i < FRAME_TOTAL_LINES (XFRAME (selected_frame)); i++)
193 cmputc ('\n');
196 OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
197 OUTPUT_IF (tty, tty->TS_keypad_mode);
198 losecursor (tty);
199 tty_send_additional_strings (terminal, Qtty_mode_set_strings);
200 fflush (tty->output);
204 /* Reset termcap modes before exiting Emacs. */
206 static void
207 tty_reset_terminal_modes (struct terminal *terminal)
209 struct tty_display_info *tty = terminal->display_info.tty;
211 if (tty->output)
213 tty_send_additional_strings (terminal, Qtty_mode_reset_strings);
214 tty_turn_off_highlight (tty);
215 tty_turn_off_insert (tty);
216 OUTPUT_IF (tty, tty->TS_end_keypad_mode);
217 OUTPUT_IF (tty, tty->TS_cursor_normal);
218 OUTPUT_IF (tty, tty->TS_end_termcap_modes);
219 OUTPUT_IF (tty, tty->TS_orig_pair);
220 /* Output raw CR so kernel can track the cursor hpos. */
221 current_tty = tty;
222 cmputc ('\r');
223 fflush (tty->output);
227 /* Flag the end of a display update on a termcap terminal. */
229 static void
230 tty_update_end (struct frame *f)
232 struct tty_display_info *tty = FRAME_TTY (f);
234 if (!XWINDOW (selected_window)->cursor_off_p)
235 tty_show_cursor (tty);
236 tty_turn_off_insert (tty);
237 tty_background_highlight (tty);
238 fflush (tty->output);
241 /* The implementation of set_terminal_window for termcap frames. */
243 static void
244 tty_set_terminal_window (struct frame *f, int size)
246 struct tty_display_info *tty = FRAME_TTY (f);
248 tty->specified_window = size ? size : FRAME_TOTAL_LINES (f);
249 if (FRAME_SCROLL_REGION_OK (f))
250 tty_set_scroll_region (f, 0, tty->specified_window);
253 static void
254 tty_set_scroll_region (struct frame *f, int start, int stop)
256 char *buf;
257 struct tty_display_info *tty = FRAME_TTY (f);
259 if (tty->TS_set_scroll_region)
260 buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1, 0, 0);
261 else if (tty->TS_set_scroll_region_1)
262 buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
263 FRAME_TOTAL_LINES (f), start,
264 FRAME_TOTAL_LINES (f) - stop,
265 FRAME_TOTAL_LINES (f));
266 else
267 buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
269 OUTPUT (tty, buf);
270 xfree (buf);
271 losecursor (tty);
275 static void
276 tty_turn_on_insert (struct tty_display_info *tty)
278 if (!tty->insert_mode)
279 OUTPUT (tty, tty->TS_insert_mode);
280 tty->insert_mode = 1;
283 void
284 tty_turn_off_insert (struct tty_display_info *tty)
286 if (tty->insert_mode)
287 OUTPUT (tty, tty->TS_end_insert_mode);
288 tty->insert_mode = 0;
291 /* Handle highlighting. */
293 static void
294 tty_turn_off_highlight (struct tty_display_info *tty)
296 if (tty->standout_mode)
297 OUTPUT_IF (tty, tty->TS_end_standout_mode);
298 tty->standout_mode = 0;
301 static void
302 tty_turn_on_highlight (struct tty_display_info *tty)
304 if (!tty->standout_mode)
305 OUTPUT_IF (tty, tty->TS_standout_mode);
306 tty->standout_mode = 1;
309 static void
310 tty_toggle_highlight (struct tty_display_info *tty)
312 if (tty->standout_mode)
313 tty_turn_off_highlight (tty);
314 else
315 tty_turn_on_highlight (tty);
319 /* Make cursor invisible. */
321 static void
322 tty_hide_cursor (struct tty_display_info *tty)
324 if (tty->cursor_hidden == 0)
326 tty->cursor_hidden = 1;
327 #ifdef WINDOWSNT
328 w32con_hide_cursor ();
329 #else
330 OUTPUT_IF (tty, tty->TS_cursor_invisible);
331 #endif
336 /* Ensure that cursor is visible. */
338 static void
339 tty_show_cursor (struct tty_display_info *tty)
341 if (tty->cursor_hidden)
343 tty->cursor_hidden = 0;
344 #ifdef WINDOWSNT
345 w32con_show_cursor ();
346 #else
347 OUTPUT_IF (tty, tty->TS_cursor_normal);
348 if (visible_cursor)
349 OUTPUT_IF (tty, tty->TS_cursor_visible);
350 #endif
355 /* Set standout mode to the state it should be in for
356 empty space inside windows. What this is,
357 depends on the user option inverse-video. */
359 static void
360 tty_background_highlight (struct tty_display_info *tty)
362 if (inverse_video)
363 tty_turn_on_highlight (tty);
364 else
365 tty_turn_off_highlight (tty);
368 /* Set standout mode to the mode specified for the text to be output. */
370 static void
371 tty_highlight_if_desired (struct tty_display_info *tty)
373 if (inverse_video)
374 tty_turn_on_highlight (tty);
375 else
376 tty_turn_off_highlight (tty);
380 /* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are
381 frame-relative coordinates. */
383 static void
384 tty_cursor_to (struct frame *f, int vpos, int hpos)
386 struct tty_display_info *tty = FRAME_TTY (f);
388 /* Detect the case where we are called from reset_sys_modes
389 and the costs have never been calculated. Do nothing. */
390 if (! tty->costs_set)
391 return;
393 if (curY (tty) == vpos
394 && curX (tty) == hpos)
395 return;
396 if (!tty->TF_standout_motion)
397 tty_background_highlight (tty);
398 if (!tty->TF_insmode_motion)
399 tty_turn_off_insert (tty);
400 cmgoto (tty, vpos, hpos);
403 /* Similar but don't take any account of the wasted characters. */
405 static void
406 tty_raw_cursor_to (struct frame *f, int row, int col)
408 struct tty_display_info *tty = FRAME_TTY (f);
410 if (curY (tty) == row
411 && curX (tty) == col)
412 return;
413 if (!tty->TF_standout_motion)
414 tty_background_highlight (tty);
415 if (!tty->TF_insmode_motion)
416 tty_turn_off_insert (tty);
417 cmgoto (tty, row, col);
420 /* Erase operations */
422 /* Clear from cursor to end of frame on a termcap device. */
424 static void
425 tty_clear_to_end (struct frame *f)
427 register int i;
428 struct tty_display_info *tty = FRAME_TTY (f);
430 if (tty->TS_clr_to_bottom)
432 tty_background_highlight (tty);
433 OUTPUT (tty, tty->TS_clr_to_bottom);
435 else
437 for (i = curY (tty); i < FRAME_TOTAL_LINES (f); i++)
439 cursor_to (f, i, 0);
440 clear_end_of_line (f, FRAME_COLS (f));
445 /* Clear an entire termcap frame. */
447 static void
448 tty_clear_frame (struct frame *f)
450 struct tty_display_info *tty = FRAME_TTY (f);
452 if (tty->TS_clr_frame)
454 tty_background_highlight (tty);
455 OUTPUT (tty, tty->TS_clr_frame);
456 cmat (tty, 0, 0);
458 else
460 cursor_to (f, 0, 0);
461 clear_to_end (f);
465 /* An implementation of clear_end_of_line for termcap frames.
467 Note that the cursor may be moved, on terminals lacking a `ce' string. */
469 static void
470 tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
472 register int i;
473 struct tty_display_info *tty = FRAME_TTY (f);
475 /* Detect the case where we are called from reset_sys_modes
476 and the costs have never been calculated. Do nothing. */
477 if (! tty->costs_set)
478 return;
480 if (curX (tty) >= first_unused_hpos)
481 return;
482 tty_background_highlight (tty);
483 if (tty->TS_clr_line)
485 OUTPUT1 (tty, tty->TS_clr_line);
487 else
488 { /* have to do it the hard way */
489 tty_turn_off_insert (tty);
491 /* Do not write in last row last col with Auto-wrap on. */
492 if (AutoWrap (tty)
493 && curY (tty) == FrameRows (tty) - 1
494 && first_unused_hpos == FrameCols (tty))
495 first_unused_hpos--;
497 for (i = curX (tty); i < first_unused_hpos; i++)
499 if (tty->termscript)
500 fputc (' ', tty->termscript);
501 fputc (' ', tty->output);
503 cmplus (tty, first_unused_hpos - curX (tty));
507 /* Buffers to store the source and result of code conversion for terminal. */
508 static unsigned char *encode_terminal_src;
509 static unsigned char *encode_terminal_dst;
510 /* Allocated sizes of the above buffers. */
511 static ptrdiff_t encode_terminal_src_size;
512 static ptrdiff_t encode_terminal_dst_size;
514 /* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
515 Set CODING->produced to the byte-length of the resulting byte
516 sequence, and return a pointer to that byte sequence. */
518 unsigned char *
519 encode_terminal_code (struct glyph *src, int src_len,
520 struct coding_system *coding)
522 struct glyph *src_end = src + src_len;
523 unsigned char *buf;
524 ptrdiff_t nchars, nbytes, required;
525 ptrdiff_t tlen = GLYPH_TABLE_LENGTH;
526 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
527 Lisp_Object charset_list;
529 /* Allocate sufficient size of buffer to store all characters in
530 multibyte-form. But, it may be enlarged on demand if
531 Vglyph_table contains a string or a composite glyph is
532 encountered. */
533 if (INT_MULTIPLY_WRAPV (src_len, MAX_MULTIBYTE_LENGTH, &required))
534 memory_full (SIZE_MAX);
535 if (encode_terminal_src_size < required)
536 encode_terminal_src = xpalloc (encode_terminal_src,
537 &encode_terminal_src_size,
538 required - encode_terminal_src_size,
539 -1, sizeof *encode_terminal_src);
541 charset_list = coding_charset_list (coding);
543 buf = encode_terminal_src;
544 nchars = 0;
545 while (src < src_end)
547 if (src->type == COMPOSITE_GLYPH)
549 struct composition *cmp UNINIT;
550 Lisp_Object gstring UNINIT;
551 int i;
553 nbytes = buf - encode_terminal_src;
554 if (src->u.cmp.automatic)
556 gstring = composition_gstring_from_id (src->u.cmp.id);
557 required = src->slice.cmp.to - src->slice.cmp.from + 1;
559 else
561 cmp = composition_table[src->u.cmp.id];
562 required = cmp->glyph_len;
563 required *= MAX_MULTIBYTE_LENGTH;
566 if (encode_terminal_src_size - nbytes < required)
568 encode_terminal_src =
569 xpalloc (encode_terminal_src, &encode_terminal_src_size,
570 required - (encode_terminal_src_size - nbytes),
571 -1, 1);
572 buf = encode_terminal_src + nbytes;
575 if (src->u.cmp.automatic)
576 for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
578 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
579 int c = LGLYPH_CHAR (g);
581 if (! char_charset (c, charset_list, NULL))
582 c = '?';
583 buf += CHAR_STRING (c, buf);
584 nchars++;
586 else
587 for (i = 0; i < cmp->glyph_len; i++)
589 int c = COMPOSITION_GLYPH (cmp, i);
591 /* TAB in a composition means display glyphs with
592 padding space on the left or right. */
593 if (c == '\t')
594 continue;
595 if (char_charset (c, charset_list, NULL))
597 if (CHARACTER_WIDTH (c) == 0
598 && i > 0 && COMPOSITION_GLYPH (cmp, i - 1) == '\t')
599 /* Should be left-padded */
601 buf += CHAR_STRING (' ', buf);
602 nchars++;
605 else
606 c = '?';
607 buf += CHAR_STRING (c, buf);
608 nchars++;
611 /* We must skip glyphs to be padded for a wide character. */
612 else if (! CHAR_GLYPH_PADDING_P (*src))
614 GLYPH g;
615 int c UNINIT;
616 Lisp_Object string;
618 string = Qnil;
619 SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
621 if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
623 /* This glyph doesn't have an entry in Vglyph_table. */
624 c = src->u.ch;
626 else
628 /* This glyph has an entry in Vglyph_table,
629 so process any alias before testing for simpleness. */
630 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
632 if (GLYPH_SIMPLE_P (tbase, tlen, g))
633 /* We set the multi-byte form of a character in G
634 (that should be an ASCII character) at WORKBUF. */
635 c = GLYPH_CHAR (g);
636 else
637 /* We have a string in Vglyph_table. */
638 string = tbase[GLYPH_CHAR (g)];
641 if (NILP (string))
643 nbytes = buf - encode_terminal_src;
644 if (encode_terminal_src_size - nbytes < MAX_MULTIBYTE_LENGTH)
646 encode_terminal_src =
647 xpalloc (encode_terminal_src, &encode_terminal_src_size,
648 MAX_MULTIBYTE_LENGTH, -1, 1);
649 buf = encode_terminal_src + nbytes;
651 if (CHAR_BYTE8_P (c)
652 || char_charset (c, charset_list, NULL))
654 /* Store the multibyte form of C at BUF. */
655 buf += CHAR_STRING (c, buf);
656 nchars++;
658 else
660 /* C is not encodable. */
661 *buf++ = '?';
662 nchars++;
663 while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
665 *buf++ = '?';
666 nchars++;
667 src++;
671 else
673 if (! STRING_MULTIBYTE (string))
674 string = string_to_multibyte (string);
675 nbytes = buf - encode_terminal_src;
676 if (encode_terminal_src_size - nbytes < SBYTES (string))
678 encode_terminal_src =
679 xpalloc (encode_terminal_src, &encode_terminal_src_size,
680 (SBYTES (string)
681 - (encode_terminal_src_size - nbytes)),
682 -1, 1);
683 buf = encode_terminal_src + nbytes;
685 memcpy (buf, SDATA (string), SBYTES (string));
686 buf += SBYTES (string);
687 nchars += SCHARS (string);
690 src++;
693 if (nchars == 0)
695 coding->produced = 0;
696 return NULL;
699 nbytes = buf - encode_terminal_src;
700 coding->source = encode_terminal_src;
701 if (encode_terminal_dst_size == 0)
703 encode_terminal_dst = xrealloc (encode_terminal_dst,
704 encode_terminal_src_size);
705 encode_terminal_dst_size = encode_terminal_src_size;
707 coding->destination = encode_terminal_dst;
708 coding->dst_bytes = encode_terminal_dst_size;
709 encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
710 /* coding->destination may have been reallocated. */
711 encode_terminal_dst = coding->destination;
712 encode_terminal_dst_size = coding->dst_bytes;
714 return (encode_terminal_dst);
719 /* An implementation of write_glyphs for termcap frames. */
721 static void
722 tty_write_glyphs (struct frame *f, struct glyph *string, int len)
724 unsigned char *conversion_buffer;
725 struct coding_system *coding;
726 int n, stringlen;
728 struct tty_display_info *tty = FRAME_TTY (f);
730 tty_turn_off_insert (tty);
731 tty_hide_cursor (tty);
733 /* Don't dare write in last column of bottom line, if Auto-Wrap,
734 since that would scroll the whole frame on some terminals. */
736 if (AutoWrap (tty)
737 && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
738 && (curX (tty) + len) == FRAME_COLS (f))
739 len --;
740 if (len <= 0)
741 return;
743 cmplus (tty, len);
745 /* If terminal_coding does any conversion, use it, otherwise use
746 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
747 because it always return 1 if the member src_multibyte is 1. */
748 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
749 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
750 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
751 the tail. */
752 coding->mode &= ~CODING_MODE_LAST_BLOCK;
754 for (stringlen = len; stringlen != 0; stringlen -= n)
756 /* Identify a run of glyphs with the same face. */
757 int face_id = string->face_id;
759 for (n = 1; n < stringlen; ++n)
760 if (string[n].face_id != face_id)
761 break;
763 /* Turn appearance modes of the face of the run on. */
764 tty_highlight_if_desired (tty);
765 turn_on_face (f, face_id);
767 if (n == stringlen)
768 /* This is the last run. */
769 coding->mode |= CODING_MODE_LAST_BLOCK;
770 conversion_buffer = encode_terminal_code (string, n, coding);
771 if (coding->produced > 0)
773 block_input ();
774 fwrite (conversion_buffer, 1, coding->produced, tty->output);
775 if (ferror (tty->output))
776 clearerr (tty->output);
777 if (tty->termscript)
778 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
779 unblock_input ();
781 string += n;
783 /* Turn appearance modes off. */
784 turn_off_face (f, face_id);
785 tty_turn_off_highlight (tty);
788 cmcheckmagic (tty);
791 #ifdef HAVE_GPM /* Only used by GPM code. */
793 static void
794 tty_write_glyphs_with_face (register struct frame *f, register struct glyph *string,
795 register int len, register int face_id)
797 unsigned char *conversion_buffer;
798 struct coding_system *coding;
800 struct tty_display_info *tty = FRAME_TTY (f);
802 tty_turn_off_insert (tty);
803 tty_hide_cursor (tty);
805 /* Don't dare write in last column of bottom line, if Auto-Wrap,
806 since that would scroll the whole frame on some terminals. */
808 if (AutoWrap (tty)
809 && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
810 && (curX (tty) + len) == FRAME_COLS (f))
811 len --;
812 if (len <= 0)
813 return;
815 cmplus (tty, len);
817 /* If terminal_coding does any conversion, use it, otherwise use
818 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
819 because it always return 1 if the member src_multibyte is 1. */
820 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
821 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
822 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
823 the tail. */
824 coding->mode &= ~CODING_MODE_LAST_BLOCK;
826 /* Turn appearance modes of the face. */
827 tty_highlight_if_desired (tty);
828 turn_on_face (f, face_id);
830 coding->mode |= CODING_MODE_LAST_BLOCK;
831 conversion_buffer = encode_terminal_code (string, len, coding);
832 if (coding->produced > 0)
834 block_input ();
835 fwrite (conversion_buffer, 1, coding->produced, tty->output);
836 if (ferror (tty->output))
837 clearerr (tty->output);
838 if (tty->termscript)
839 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
840 unblock_input ();
843 /* Turn appearance modes off. */
844 turn_off_face (f, face_id);
845 tty_turn_off_highlight (tty);
847 cmcheckmagic (tty);
849 #endif
851 /* An implementation of insert_glyphs for termcap frames. */
853 static void
854 tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
856 char *buf;
857 struct glyph *glyph = NULL;
858 unsigned char *conversion_buffer;
859 unsigned char space[1];
860 struct coding_system *coding;
862 struct tty_display_info *tty = FRAME_TTY (f);
864 if (tty->TS_ins_multi_chars)
866 buf = tparam (tty->TS_ins_multi_chars, 0, 0, len, 0, 0, 0);
867 OUTPUT1 (tty, buf);
868 xfree (buf);
869 if (start)
870 write_glyphs (f, start, len);
871 return;
874 tty_turn_on_insert (tty);
875 cmplus (tty, len);
877 if (! start)
878 space[0] = SPACEGLYPH;
880 /* If terminal_coding does any conversion, use it, otherwise use
881 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
882 because it always return 1 if the member src_multibyte is 1. */
883 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
884 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
885 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
886 the tail. */
887 coding->mode &= ~CODING_MODE_LAST_BLOCK;
889 while (len-- > 0)
891 OUTPUT1_IF (tty, tty->TS_ins_char);
892 if (!start)
894 conversion_buffer = space;
895 coding->produced = 1;
897 else
899 tty_highlight_if_desired (tty);
900 turn_on_face (f, start->face_id);
901 glyph = start;
902 ++start;
903 /* We must open sufficient space for a character which
904 occupies more than one column. */
905 while (len && CHAR_GLYPH_PADDING_P (*start))
907 OUTPUT1_IF (tty, tty->TS_ins_char);
908 start++, len--;
911 if (len <= 0)
912 /* This is the last glyph. */
913 coding->mode |= CODING_MODE_LAST_BLOCK;
915 conversion_buffer = encode_terminal_code (glyph, 1, coding);
918 if (coding->produced > 0)
920 block_input ();
921 fwrite (conversion_buffer, 1, coding->produced, tty->output);
922 if (ferror (tty->output))
923 clearerr (tty->output);
924 if (tty->termscript)
925 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
926 unblock_input ();
929 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
930 if (start)
932 turn_off_face (f, glyph->face_id);
933 tty_turn_off_highlight (tty);
937 cmcheckmagic (tty);
940 /* An implementation of delete_glyphs for termcap frames. */
942 static void
943 tty_delete_glyphs (struct frame *f, int n)
945 char *buf;
946 register int i;
948 struct tty_display_info *tty = FRAME_TTY (f);
950 if (tty->delete_in_insert_mode)
952 tty_turn_on_insert (tty);
954 else
956 tty_turn_off_insert (tty);
957 OUTPUT_IF (tty, tty->TS_delete_mode);
960 if (tty->TS_del_multi_chars)
962 buf = tparam (tty->TS_del_multi_chars, 0, 0, n, 0, 0, 0);
963 OUTPUT1 (tty, buf);
964 xfree (buf);
966 else
967 for (i = 0; i < n; i++)
968 OUTPUT1 (tty, tty->TS_del_char);
969 if (!tty->delete_in_insert_mode)
970 OUTPUT_IF (tty, tty->TS_end_delete_mode);
973 /* An implementation of ins_del_lines for termcap frames. */
975 static void
976 tty_ins_del_lines (struct frame *f, int vpos, int n)
978 struct tty_display_info *tty = FRAME_TTY (f);
979 const char *multi =
980 n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
981 const char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
982 const char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
984 int i = eabs (n);
985 char *buf;
987 /* If the lines below the insertion are being pushed
988 into the end of the window, this is the same as clearing;
989 and we know the lines are already clear, since the matching
990 deletion has already been done. So can ignore this. */
991 /* If the lines below the deletion are blank lines coming
992 out of the end of the window, don't bother,
993 as there will be a matching inslines later that will flush them. */
994 if (FRAME_SCROLL_REGION_OK (f)
995 && vpos + i >= tty->specified_window)
996 return;
997 if (!FRAME_MEMORY_BELOW_FRAME (f)
998 && vpos + i >= FRAME_TOTAL_LINES (f))
999 return;
1001 if (multi)
1003 raw_cursor_to (f, vpos, 0);
1004 tty_background_highlight (tty);
1005 buf = tparam (multi, 0, 0, i, 0, 0, 0);
1006 OUTPUT (tty, buf);
1007 xfree (buf);
1009 else if (single)
1011 raw_cursor_to (f, vpos, 0);
1012 tty_background_highlight (tty);
1013 while (--i >= 0)
1014 OUTPUT (tty, single);
1015 if (tty->TF_teleray)
1016 curX (tty) = 0;
1018 else
1020 tty_set_scroll_region (f, vpos, tty->specified_window);
1021 if (n < 0)
1022 raw_cursor_to (f, tty->specified_window - 1, 0);
1023 else
1024 raw_cursor_to (f, vpos, 0);
1025 tty_background_highlight (tty);
1026 while (--i >= 0)
1027 OUTPUTL (tty, scroll, tty->specified_window - vpos);
1028 tty_set_scroll_region (f, 0, tty->specified_window);
1031 if (!FRAME_SCROLL_REGION_OK (f)
1032 && FRAME_MEMORY_BELOW_FRAME (f)
1033 && n < 0)
1035 cursor_to (f, FRAME_TOTAL_LINES (f) + n, 0);
1036 clear_to_end (f);
1040 /* Compute cost of sending "str", in characters,
1041 not counting any line-dependent padding. */
1044 string_cost (const char *str)
1046 cost = 0;
1047 if (str)
1048 tputs (str, 0, evalcost);
1049 return cost;
1052 /* Compute cost of sending "str", in characters,
1053 counting any line-dependent padding at one line. */
1055 static int
1056 string_cost_one_line (const char *str)
1058 cost = 0;
1059 if (str)
1060 tputs (str, 1, evalcost);
1061 return cost;
1064 /* Compute per line amount of line-dependent padding,
1065 in tenths of characters. */
1068 per_line_cost (const char *str)
1070 cost = 0;
1071 if (str)
1072 tputs (str, 0, evalcost);
1073 cost = - cost;
1074 if (str)
1075 tputs (str, 10, evalcost);
1076 return cost;
1079 /* char_ins_del_cost[n] is cost of inserting N characters.
1080 char_ins_del_cost[-n] is cost of deleting N characters.
1081 The length of this vector is based on max_frame_cols. */
1083 int *char_ins_del_vector;
1085 #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_COLS ((f))])
1087 /* ARGSUSED */
1088 static void
1089 calculate_ins_del_char_costs (struct frame *f)
1091 struct tty_display_info *tty = FRAME_TTY (f);
1092 int ins_startup_cost, del_startup_cost;
1093 int ins_cost_per_char, del_cost_per_char;
1094 register int i;
1095 register int *p;
1097 if (tty->TS_ins_multi_chars)
1099 ins_cost_per_char = 0;
1100 ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars);
1102 else if (tty->TS_ins_char || tty->TS_pad_inserted_char
1103 || (tty->TS_insert_mode && tty->TS_end_insert_mode))
1105 ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode)
1106 + string_cost (tty->TS_end_insert_mode))) / 100;
1107 ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char)
1108 + string_cost_one_line (tty->TS_pad_inserted_char));
1110 else
1112 ins_startup_cost = 9999;
1113 ins_cost_per_char = 0;
1116 if (tty->TS_del_multi_chars)
1118 del_cost_per_char = 0;
1119 del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars);
1121 else if (tty->TS_del_char)
1123 del_startup_cost = (string_cost (tty->TS_delete_mode)
1124 + string_cost (tty->TS_end_delete_mode));
1125 if (tty->delete_in_insert_mode)
1126 del_startup_cost /= 2;
1127 del_cost_per_char = string_cost_one_line (tty->TS_del_char);
1129 else
1131 del_startup_cost = 9999;
1132 del_cost_per_char = 0;
1135 /* Delete costs are at negative offsets */
1136 p = &char_ins_del_cost (f)[0];
1137 for (i = FRAME_COLS (f); --i >= 0;)
1138 *--p = (del_startup_cost += del_cost_per_char);
1140 /* Doing nothing is free */
1141 p = &char_ins_del_cost (f)[0];
1142 *p++ = 0;
1144 /* Insert costs are at positive offsets */
1145 for (i = FRAME_COLS (f); --i >= 0;)
1146 *p++ = (ins_startup_cost += ins_cost_per_char);
1149 void
1150 calculate_costs (struct frame *frame)
1152 FRAME_COST_BAUD_RATE (frame) = baud_rate;
1154 if (FRAME_TERMCAP_P (frame))
1156 struct tty_display_info *tty = FRAME_TTY (frame);
1157 register const char *f = (tty->TS_set_scroll_region
1158 ? tty->TS_set_scroll_region
1159 : tty->TS_set_scroll_region_1);
1161 FRAME_SCROLL_REGION_COST (frame) = string_cost (f);
1163 tty->costs_set = 1;
1165 /* These variables are only used for terminal stuff. They are
1166 allocated once for the terminal frame of X-windows emacs, but not
1167 used afterwards.
1169 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1170 X turns off char_ins_del_ok. */
1172 max_frame_cols = max (max_frame_cols, FRAME_COLS (frame));
1173 if ((min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) - 1) / 2
1174 < max_frame_cols)
1175 memory_full (SIZE_MAX);
1177 char_ins_del_vector =
1178 xrealloc (char_ins_del_vector,
1179 (sizeof (int) + 2 * sizeof (int) * max_frame_cols));
1181 memset (char_ins_del_vector, 0,
1182 (sizeof (int) + 2 * sizeof (int) * max_frame_cols));
1185 if (f && (!tty->TS_ins_line && !tty->TS_del_line))
1186 do_line_insertion_deletion_costs (frame,
1187 tty->TS_rev_scroll, tty->TS_ins_multi_lines,
1188 tty->TS_fwd_scroll, tty->TS_del_multi_lines,
1189 f, f, 1);
1190 else
1191 do_line_insertion_deletion_costs (frame,
1192 tty->TS_ins_line, tty->TS_ins_multi_lines,
1193 tty->TS_del_line, tty->TS_del_multi_lines,
1194 0, 0, 1);
1196 calculate_ins_del_char_costs (frame);
1198 /* Don't use TS_repeat if its padding is worse than sending the chars */
1199 if (tty->TS_repeat && per_line_cost (tty->TS_repeat) * baud_rate < 9000)
1200 tty->RPov = string_cost (tty->TS_repeat);
1201 else
1202 tty->RPov = FRAME_COLS (frame) * 2;
1204 cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */
1208 struct fkey_table {
1209 const char *cap, *name;
1212 /* Termcap capability names that correspond directly to X keysyms.
1213 Some of these (marked "terminfo") aren't supplied by old-style
1214 (Berkeley) termcap entries. They're listed in X keysym order;
1215 except we put the keypad keys first, so that if they clash with
1216 other keys (as on the IBM PC keyboard) they get overridden.
1219 static const struct fkey_table keys[] =
1221 {"kh", "home"}, /* termcap */
1222 {"kl", "left"}, /* termcap */
1223 {"ku", "up"}, /* termcap */
1224 {"kr", "right"}, /* termcap */
1225 {"kd", "down"}, /* termcap */
1226 {"%8", "prior"}, /* terminfo */
1227 {"%5", "next"}, /* terminfo */
1228 {"@7", "end"}, /* terminfo */
1229 {"@1", "begin"}, /* terminfo */
1230 {"*6", "select"}, /* terminfo */
1231 {"%9", "print"}, /* terminfo */
1232 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1234 * "insert" --- see below
1236 {"&8", "undo"}, /* terminfo */
1237 {"%0", "redo"}, /* terminfo */
1238 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1239 {"@0", "find"}, /* terminfo */
1240 {"@2", "cancel"}, /* terminfo */
1241 {"%1", "help"}, /* terminfo */
1243 * "break" goes here, but can't be reliably intercepted with termcap
1245 {"&4", "reset"}, /* terminfo --- actually `restart' */
1247 * "system" and "user" --- no termcaps
1249 {"kE", "clearline"}, /* terminfo */
1250 {"kA", "insertline"}, /* terminfo */
1251 {"kL", "deleteline"}, /* terminfo */
1252 {"kI", "insertchar"}, /* terminfo */
1253 {"kD", "deletechar"}, /* terminfo */
1254 {"kB", "backtab"}, /* terminfo */
1256 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1258 {"@8", "kp-enter"}, /* terminfo */
1260 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1261 * "kp-multiply", "kp-add", "kp-separator",
1262 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1263 * --- no termcaps for any of these.
1265 {"K4", "kp-1"}, /* terminfo */
1267 * "kp-2" --- no termcap
1269 {"K5", "kp-3"}, /* terminfo */
1271 * "kp-4" --- no termcap
1273 {"K2", "kp-5"}, /* terminfo */
1275 * "kp-6" --- no termcap
1277 {"K1", "kp-7"}, /* terminfo */
1279 * "kp-8" --- no termcap
1281 {"K3", "kp-9"}, /* terminfo */
1283 * "kp-equal" --- no termcap
1285 {"k1", "f1"},
1286 {"k2", "f2"},
1287 {"k3", "f3"},
1288 {"k4", "f4"},
1289 {"k5", "f5"},
1290 {"k6", "f6"},
1291 {"k7", "f7"},
1292 {"k8", "f8"},
1293 {"k9", "f9"},
1295 {"&0", "S-cancel"}, /*shifted cancel key*/
1296 {"&9", "S-begin"}, /*shifted begin key*/
1297 {"*0", "S-find"}, /*shifted find key*/
1298 {"*1", "S-execute"}, /*shifted execute? actually shifted command key*/
1299 {"*4", "S-delete"}, /*shifted delete-character key*/
1300 {"*7", "S-end"}, /*shifted end key*/
1301 {"*8", "S-clearline"}, /*shifted clear-to end-of-line key*/
1302 {"#1", "S-help"}, /*shifted help key*/
1303 {"#2", "S-home"}, /*shifted home key*/
1304 {"#3", "S-insert"}, /*shifted insert-character key*/
1305 {"#4", "S-left"}, /*shifted left-arrow key*/
1306 {"%d", "S-menu"}, /*shifted menu? actually shifted options key*/
1307 {"%c", "S-next"}, /*shifted next key*/
1308 {"%e", "S-prior"}, /*shifted previous key*/
1309 {"%f", "S-print"}, /*shifted print key*/
1310 {"%g", "S-redo"}, /*shifted redo key*/
1311 {"%i", "S-right"}, /*shifted right-arrow key*/
1312 {"!3", "S-undo"} /*shifted undo key*/
1315 #ifndef DOS_NT
1316 static char **term_get_fkeys_address;
1317 static KBOARD *term_get_fkeys_kboard;
1318 static Lisp_Object term_get_fkeys_1 (void);
1320 /* Find the escape codes sent by the function keys for Vinput_decode_map.
1321 This function scans the termcap function key sequence entries, and
1322 adds entries to Vinput_decode_map for each function key it finds. */
1324 static void
1325 term_get_fkeys (char **address, KBOARD *kboard)
1327 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1328 errors during the call. The only errors should be from Fdefine_key
1329 when given a key sequence containing an invalid prefix key. If the
1330 termcap defines function keys which use a prefix that is already bound
1331 to a command by the default bindings, we should silently ignore that
1332 function key specification, rather than giving the user an error and
1333 refusing to run at all on such a terminal. */
1335 term_get_fkeys_address = address;
1336 term_get_fkeys_kboard = kboard;
1337 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1340 static Lisp_Object
1341 term_get_fkeys_1 (void)
1343 int i;
1345 char **address = term_get_fkeys_address;
1346 KBOARD *kboard = term_get_fkeys_kboard;
1348 /* This can happen if CANNOT_DUMP or with strange options. */
1349 if (!KEYMAPP (KVAR (kboard, Vinput_decode_map)))
1350 kset_input_decode_map (kboard, Fmake_sparse_keymap (Qnil));
1352 for (i = 0; i < ARRAYELTS (keys); i++)
1354 char *sequence = tgetstr (keys[i].cap, address);
1355 if (sequence)
1356 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
1357 Fmake_vector (make_number (1),
1358 intern (keys[i].name)));
1361 /* The uses of the "k0" capability are inconsistent; sometimes it
1362 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1363 We will attempt to politely accommodate both systems by testing for
1364 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1367 const char *k_semi = tgetstr ("k;", address);
1368 const char *k0 = tgetstr ("k0", address);
1369 const char *k0_name = "f10";
1371 if (k_semi)
1373 if (k0)
1374 /* Define f0 first, so that f10 takes precedence in case the
1375 key sequences happens to be the same. */
1376 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
1377 Fmake_vector (make_number (1), intern ("f0")));
1378 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k_semi),
1379 Fmake_vector (make_number (1), intern ("f10")));
1381 else if (k0)
1382 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
1383 Fmake_vector (make_number (1), intern (k0_name)));
1386 /* Set up cookies for numbered function keys above f10. */
1388 char fcap[3], fkey[4];
1390 fcap[0] = 'F'; fcap[2] = '\0';
1391 for (i = 11; i < 64; i++)
1393 if (i <= 19)
1394 fcap[1] = '1' + i - 11;
1395 else if (i <= 45)
1396 fcap[1] = 'A' + i - 20;
1397 else
1398 fcap[1] = 'a' + i - 46;
1401 char *sequence = tgetstr (fcap, address);
1402 if (sequence)
1404 sprintf (fkey, "f%d", i);
1405 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
1406 Fmake_vector (make_number (1),
1407 intern (fkey)));
1414 * Various mappings to try and get a better fit.
1417 #define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1418 if (!tgetstr (cap1, address)) \
1420 char *sequence = tgetstr (cap2, address); \
1421 if (sequence) \
1422 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence), \
1423 Fmake_vector (make_number (1), \
1424 intern (sym))); \
1427 /* if there's no key_next keycap, map key_npage to `next' keysym */
1428 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1429 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1430 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1431 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1432 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1433 /* if there's no key_end keycap, map key_ll to 'end' keysym */
1434 CONDITIONAL_REASSIGN ("@7", "kH", "end");
1435 #undef CONDITIONAL_REASSIGN
1438 return Qnil;
1440 #endif /* not DOS_NT */
1443 /***********************************************************************
1444 Character Display Information
1445 ***********************************************************************/
1446 static void append_glyph (struct it *);
1447 static void append_composite_glyph (struct it *);
1448 static void produce_composite_glyph (struct it *);
1449 static void append_glyphless_glyph (struct it *, int, const char *);
1450 static void produce_glyphless_glyph (struct it *, Lisp_Object);
1452 /* Append glyphs to IT's glyph_row. Called from produce_glyphs for
1453 terminal frames if IT->glyph_row != NULL. IT->char_to_display is
1454 the character for which to produce glyphs; IT->face_id contains the
1455 character's face. Padding glyphs are appended if IT->c has a
1456 IT->pixel_width > 1. */
1458 static void
1459 append_glyph (struct it *it)
1461 struct glyph *glyph, *end;
1462 int i;
1464 eassert (it->glyph_row);
1465 glyph = (it->glyph_row->glyphs[it->area]
1466 + it->glyph_row->used[it->area]);
1467 end = it->glyph_row->glyphs[1 + it->area];
1469 /* If the glyph row is reversed, we need to prepend the glyph rather
1470 than append it. */
1471 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1473 struct glyph *g;
1474 int move_by = it->pixel_width;
1476 /* Make room for the new glyphs. */
1477 if (move_by > end - glyph) /* don't overstep end of this area */
1478 move_by = end - glyph;
1479 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1480 g[move_by] = *g;
1481 glyph = it->glyph_row->glyphs[it->area];
1482 end = glyph + move_by;
1485 /* BIDI Note: we put the glyphs of a "multi-pixel" character left to
1486 right, even in the REVERSED_P case, since (a) all of its u.ch are
1487 identical, and (b) the PADDING_P flag needs to be set for the
1488 leftmost one, because we write to the terminal left-to-right. */
1489 for (i = 0;
1490 i < it->pixel_width && glyph < end;
1491 ++i)
1493 glyph->type = CHAR_GLYPH;
1494 glyph->pixel_width = 1;
1495 glyph->u.ch = it->char_to_display;
1496 glyph->face_id = it->face_id;
1497 glyph->avoid_cursor_p = it->avoid_cursor_p;
1498 glyph->multibyte_p = it->multibyte_p;
1499 glyph->padding_p = i > 0;
1500 glyph->charpos = CHARPOS (it->position);
1501 glyph->object = it->object;
1502 if (it->bidi_p)
1504 glyph->resolved_level = it->bidi_it.resolved_level;
1505 eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
1506 glyph->bidi_type = it->bidi_it.type;
1508 else
1510 glyph->resolved_level = 0;
1511 glyph->bidi_type = UNKNOWN_BT;
1514 ++it->glyph_row->used[it->area];
1515 ++glyph;
1519 /* For external use. */
1520 void
1521 tty_append_glyph (struct it *it)
1523 append_glyph (it);
1527 /* Produce glyphs for the display element described by IT. *IT
1528 specifies what we want to produce a glyph for (character, image, ...),
1529 and where in the glyph matrix we currently are (glyph row and hpos).
1530 produce_glyphs fills in output fields of *IT with information such as the
1531 pixel width and height of a character, and maybe output actual glyphs at
1532 the same time if IT->glyph_row is non-null. For an overview, see
1533 the explanation in dispextern.h, before the definition of the
1534 display_element_type enumeration.
1536 produce_glyphs also stores the result of glyph width, ascent
1537 etc. computations in *IT.
1539 IT->glyph_row may be null, in which case produce_glyphs does not
1540 actually fill in the glyphs. This is used in the move_* functions
1541 in xdisp.c for text width and height computations.
1543 Callers usually don't call produce_glyphs directly;
1544 instead they use the macro PRODUCE_GLYPHS. */
1546 void
1547 produce_glyphs (struct it *it)
1549 /* If a hook is installed, let it do the work. */
1551 /* Nothing but characters are supported on terminal frames. */
1552 eassert (it->what == IT_CHARACTER
1553 || it->what == IT_COMPOSITION
1554 || it->what == IT_STRETCH
1555 || it->what == IT_GLYPHLESS);
1557 if (it->what == IT_STRETCH)
1559 produce_stretch_glyph (it);
1560 goto done;
1563 if (it->what == IT_COMPOSITION)
1565 produce_composite_glyph (it);
1566 goto done;
1569 if (it->what == IT_GLYPHLESS)
1571 produce_glyphless_glyph (it, Qnil);
1572 goto done;
1575 if (it->char_to_display >= 040 && it->char_to_display < 0177)
1577 it->pixel_width = it->nglyphs = 1;
1578 if (it->glyph_row)
1579 append_glyph (it);
1581 else if (it->char_to_display == '\n')
1582 it->pixel_width = it->nglyphs = 0;
1583 else if (it->char_to_display == '\t')
1585 int absolute_x = (it->current_x
1586 + it->continuation_lines_width);
1587 int next_tab_x
1588 = (((1 + absolute_x + it->tab_width - 1)
1589 / it->tab_width)
1590 * it->tab_width);
1591 int nspaces;
1593 /* If part of the TAB has been displayed on the previous line
1594 which is continued now, continuation_lines_width will have
1595 been incremented already by the part that fitted on the
1596 continued line. So, we will get the right number of spaces
1597 here. */
1598 nspaces = next_tab_x - absolute_x;
1600 if (it->glyph_row)
1602 int n = nspaces;
1604 it->char_to_display = ' ';
1605 it->pixel_width = it->len = 1;
1607 while (n--)
1608 append_glyph (it);
1611 it->pixel_width = nspaces;
1612 it->nglyphs = nspaces;
1614 else if (CHAR_BYTE8_P (it->char_to_display))
1616 /* Coming here means that we must send the raw 8-bit byte as is
1617 to the terminal. Although there's no way to know how many
1618 columns it occupies on a screen, it is a good assumption that
1619 a single byte code has 1-column width. */
1620 it->pixel_width = it->nglyphs = 1;
1621 if (it->glyph_row)
1622 append_glyph (it);
1624 else
1626 Lisp_Object charset_list = FRAME_TERMINAL (it->f)->charset_list;
1628 if (char_charset (it->char_to_display, charset_list, NULL))
1630 it->pixel_width = CHARACTER_WIDTH (it->char_to_display);
1631 it->nglyphs = it->pixel_width;
1632 if (it->glyph_row)
1633 append_glyph (it);
1635 else
1637 Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
1639 eassert (it->what == IT_GLYPHLESS);
1640 produce_glyphless_glyph (it, acronym);
1644 done:
1645 /* Advance current_x by the pixel width as a convenience for
1646 the caller. */
1647 if (it->area == TEXT_AREA)
1648 it->current_x += it->pixel_width;
1649 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1650 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
1653 /* Append glyphs to IT's glyph_row for the composition IT->cmp_id.
1654 Called from produce_composite_glyph for terminal frames if
1655 IT->glyph_row != NULL. IT->face_id contains the character's
1656 face. */
1658 static void
1659 append_composite_glyph (struct it *it)
1661 struct glyph *glyph;
1663 eassert (it->glyph_row);
1664 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1665 if (glyph < it->glyph_row->glyphs[1 + it->area])
1667 /* If the glyph row is reversed, we need to prepend the glyph
1668 rather than append it. */
1669 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1671 struct glyph *g;
1673 /* Make room for the new glyph. */
1674 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1675 g[1] = *g;
1676 glyph = it->glyph_row->glyphs[it->area];
1678 glyph->type = COMPOSITE_GLYPH;
1679 eassert (it->pixel_width <= SHRT_MAX);
1680 glyph->pixel_width = it->pixel_width;
1681 glyph->u.cmp.id = it->cmp_it.id;
1682 if (it->cmp_it.ch < 0)
1684 glyph->u.cmp.automatic = 0;
1685 glyph->u.cmp.id = it->cmp_it.id;
1687 else
1689 glyph->u.cmp.automatic = 1;
1690 glyph->u.cmp.id = it->cmp_it.id;
1691 glyph->slice.cmp.from = it->cmp_it.from;
1692 glyph->slice.cmp.to = it->cmp_it.to - 1;
1695 glyph->avoid_cursor_p = it->avoid_cursor_p;
1696 glyph->multibyte_p = it->multibyte_p;
1697 glyph->face_id = it->face_id;
1698 glyph->padding_p = false;
1699 glyph->charpos = CHARPOS (it->position);
1700 glyph->object = it->object;
1701 if (it->bidi_p)
1703 glyph->resolved_level = it->bidi_it.resolved_level;
1704 eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
1705 glyph->bidi_type = it->bidi_it.type;
1707 else
1709 glyph->resolved_level = 0;
1710 glyph->bidi_type = UNKNOWN_BT;
1713 ++it->glyph_row->used[it->area];
1714 ++glyph;
1719 /* Produce a composite glyph for iterator IT. IT->cmp_id is the ID of
1720 the composition. We simply produces components of the composition
1721 assuming that the terminal has a capability to layout/render it
1722 correctly. */
1724 static void
1725 produce_composite_glyph (struct it *it)
1727 if (it->cmp_it.ch < 0)
1729 struct composition *cmp = composition_table[it->cmp_it.id];
1731 it->pixel_width = cmp->width;
1733 else
1735 Lisp_Object gstring = composition_gstring_from_id (it->cmp_it.id);
1737 it->pixel_width = composition_gstring_width (gstring, it->cmp_it.from,
1738 it->cmp_it.to, NULL);
1740 it->nglyphs = 1;
1741 if (it->glyph_row)
1742 append_composite_glyph (it);
1746 /* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID
1747 is a face ID to be used for the glyph. What is actually appended
1748 are glyphs of type CHAR_GLYPH whose characters are in STR (which
1749 comes from it->nglyphs bytes). */
1751 static void
1752 append_glyphless_glyph (struct it *it, int face_id, const char *str)
1754 struct glyph *glyph, *end;
1755 int i;
1757 eassert (it->glyph_row);
1758 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1759 end = it->glyph_row->glyphs[1 + it->area];
1761 /* If the glyph row is reversed, we need to prepend the glyph rather
1762 than append it. */
1763 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1765 struct glyph *g;
1766 int move_by = it->pixel_width;
1768 /* Make room for the new glyphs. */
1769 if (move_by > end - glyph) /* don't overstep end of this area */
1770 move_by = end - glyph;
1771 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1772 g[move_by] = *g;
1773 glyph = it->glyph_row->glyphs[it->area];
1774 end = glyph + move_by;
1777 if (glyph >= end)
1778 return;
1779 glyph->type = CHAR_GLYPH;
1780 glyph->pixel_width = 1;
1781 glyph->avoid_cursor_p = it->avoid_cursor_p;
1782 glyph->multibyte_p = it->multibyte_p;
1783 glyph->face_id = face_id;
1784 glyph->padding_p = false;
1785 glyph->charpos = CHARPOS (it->position);
1786 glyph->object = it->object;
1787 if (it->bidi_p)
1789 glyph->resolved_level = it->bidi_it.resolved_level;
1790 eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
1791 glyph->bidi_type = it->bidi_it.type;
1793 else
1795 glyph->resolved_level = 0;
1796 glyph->bidi_type = UNKNOWN_BT;
1799 /* BIDI Note: we put the glyphs of characters left to right, even in
1800 the REVERSED_P case because we write to the terminal
1801 left-to-right. */
1802 for (i = 0; i < it->nglyphs && glyph < end; ++i)
1804 if (i > 0)
1805 glyph[0] = glyph[-1];
1806 glyph->u.ch = str[i];
1807 ++it->glyph_row->used[it->area];
1808 ++glyph;
1812 /* Produce glyphs for a glyphless character for iterator IT.
1813 IT->glyphless_method specifies which method to use for displaying
1814 the character. See the description of enum
1815 glyphless_display_method in dispextern.h for the details.
1817 ACRONYM, if non-nil, is an acronym string for the character.
1819 The glyphs actually produced are of type CHAR_GLYPH. */
1821 static void
1822 produce_glyphless_glyph (struct it *it, Lisp_Object acronym)
1824 int len, face_id = merge_glyphless_glyph_face (it);
1825 char buf[sizeof "\\x" + max (6, (INT_WIDTH + 3) / 4)];
1826 char const *str = " ";
1828 if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
1830 /* As there's no way to produce a thin space, we produce a space
1831 of canonical width. */
1832 len = 1;
1834 else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
1836 len = CHARACTER_WIDTH (it->c);
1837 if (len == 0)
1838 len = 1;
1839 else if (len > 4)
1840 len = 4;
1841 len = sprintf (buf, "[%.*s]", len, str);
1842 str = buf;
1844 else
1846 if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
1848 if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
1849 acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
1850 if (CONSP (acronym))
1851 acronym = XCDR (acronym);
1852 buf[0] = '[';
1853 str = STRINGP (acronym) ? SSDATA (acronym) : "";
1854 for (len = 0; len < 6 && str[len] && ASCII_CHAR_P (str[len]); len++)
1855 buf[1 + len] = str[len];
1856 buf[1 + len] = ']';
1857 len += 2;
1859 else
1861 eassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEX_CODE);
1862 len = sprintf (buf,
1863 (it->c < 0x10000 ? "\\u%04X"
1864 : it->c <= MAX_UNICODE_CHAR ? "\\U%06X"
1865 : "\\x%06X"),
1866 it->c + 0u);
1868 str = buf;
1871 it->pixel_width = len;
1872 it->nglyphs = len;
1873 if (it->glyph_row)
1874 append_glyphless_glyph (it, face_id, str);
1878 /***********************************************************************
1879 Faces
1880 ***********************************************************************/
1882 /* Value is non-zero if attribute ATTR may be used. ATTR should be
1883 one of the enumerators from enum no_color_bit, or a bit set built
1884 from them. Some display attributes may not be used together with
1885 color; the termcap capability `NC' specifies which ones. */
1887 #define MAY_USE_WITH_COLORS_P(tty, ATTR) \
1888 (tty->TN_max_colors > 0 \
1889 ? (tty->TN_no_color_video & (ATTR)) == 0 \
1890 : 1)
1892 /* Turn appearances of face FACE_ID on tty frame F on.
1893 FACE_ID is a realized face ID number, in the face cache. */
1895 static void
1896 turn_on_face (struct frame *f, int face_id)
1898 struct face *face = FACE_FROM_ID (f, face_id);
1899 unsigned long fg = face->foreground;
1900 unsigned long bg = face->background;
1901 struct tty_display_info *tty = FRAME_TTY (f);
1903 /* Use reverse video if the face specifies that.
1904 Do this first because TS_end_standout_mode may be the same
1905 as TS_exit_attribute_mode, which turns all appearances off. */
1906 if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE)
1907 && (inverse_video
1908 ? fg == FACE_TTY_DEFAULT_FG_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR
1909 : fg == FACE_TTY_DEFAULT_BG_COLOR || bg == FACE_TTY_DEFAULT_FG_COLOR))
1910 tty_toggle_highlight (tty);
1912 if (face->tty_bold_p && MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
1913 OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
1915 if (face->tty_italic_p && MAY_USE_WITH_COLORS_P (tty, NC_ITALIC))
1917 if (tty->TS_enter_italic_mode)
1918 OUTPUT1 (tty, tty->TS_enter_italic_mode);
1919 else
1920 /* Italics mode is unavailable on many terminals. In that
1921 case, map slant to dimmed text; we want italic text to
1922 appear different and dimming is not otherwise used. */
1923 OUTPUT1 (tty, tty->TS_enter_dim_mode);
1926 if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
1927 OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
1929 if (tty->TN_max_colors > 0)
1931 const char *ts;
1932 char *p;
1934 ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
1935 if (face_tty_specified_color (fg) && ts)
1937 p = tparam (ts, NULL, 0, fg, 0, 0, 0);
1938 OUTPUT (tty, p);
1939 xfree (p);
1942 ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
1943 if (face_tty_specified_color (bg) && ts)
1945 p = tparam (ts, NULL, 0, bg, 0, 0, 0);
1946 OUTPUT (tty, p);
1947 xfree (p);
1953 /* Turn off appearances of face FACE_ID on tty frame F. */
1955 static void
1956 turn_off_face (struct frame *f, int face_id)
1958 struct face *face = FACE_FROM_ID (f, face_id);
1959 struct tty_display_info *tty = FRAME_TTY (f);
1961 if (tty->TS_exit_attribute_mode)
1963 /* Capability "me" will turn off appearance modes double-bright,
1964 half-bright, reverse-video, standout, underline. It may or
1965 may not turn off alt-char-mode. */
1966 if (face->tty_bold_p
1967 || face->tty_italic_p
1968 || face->tty_reverse_p
1969 || face->tty_underline_p)
1971 OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
1972 if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0)
1973 tty->standout_mode = 0;
1976 else
1978 /* If we don't have "me" we can only have those appearances
1979 that have exit sequences defined. */
1980 if (face->tty_underline_p)
1981 OUTPUT_IF (tty, tty->TS_exit_underline_mode);
1984 /* Switch back to default colors. */
1985 if (tty->TN_max_colors > 0
1986 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
1987 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
1988 || (face->background != FACE_TTY_DEFAULT_COLOR
1989 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
1990 OUTPUT1_IF (tty, tty->TS_orig_pair);
1994 /* Return true if the terminal on frame F supports all of the
1995 capabilities in CAPS simultaneously. */
1997 bool
1998 tty_capable_p (struct tty_display_info *tty, unsigned int caps)
2000 #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
2001 if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
2002 return 0;
2004 TTY_CAPABLE_P_TRY (tty, TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE);
2005 TTY_CAPABLE_P_TRY (tty, TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode, NC_UNDERLINE);
2006 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
2007 TTY_CAPABLE_P_TRY (tty, TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM);
2008 TTY_CAPABLE_P_TRY (tty, TTY_CAP_ITALIC, tty->TS_enter_italic_mode, NC_ITALIC);
2010 /* We can do it! */
2011 return 1;
2014 /* Return non-zero if the terminal is capable to display colors. */
2016 DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
2017 0, 1, 0,
2018 doc: /* Return non-nil if the tty device TERMINAL can display colors.
2020 TERMINAL can be a terminal object, a frame, or nil (meaning the
2021 selected frame's terminal). This function always returns nil if
2022 TERMINAL does not refer to a text terminal. */)
2023 (Lisp_Object terminal)
2025 struct terminal *t = decode_tty_terminal (terminal);
2027 return (t && t->display_info.tty->TN_max_colors > 0) ? Qt : Qnil;
2030 /* Return the number of supported colors. */
2031 DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
2032 Stty_display_color_cells, 0, 1, 0,
2033 doc: /* Return the number of colors supported by the tty device TERMINAL.
2035 TERMINAL can be a terminal object, a frame, or nil (meaning the
2036 selected frame's terminal). This function always returns 0 if
2037 TERMINAL does not refer to a text terminal. */)
2038 (Lisp_Object terminal)
2040 struct terminal *t = decode_tty_terminal (terminal);
2042 return make_number (t ? t->display_info.tty->TN_max_colors : 0);
2045 #ifndef DOS_NT
2047 /* Declare here rather than in the function, as in the rest of Emacs,
2048 to work around an HPUX compiler bug (?). See
2049 http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00410.html */
2050 static int default_max_colors;
2051 static int default_no_color_video;
2052 static char *default_orig_pair;
2053 static char *default_set_foreground;
2054 static char *default_set_background;
2056 /* Save or restore the default color-related capabilities of this
2057 terminal. */
2058 static void
2059 tty_default_color_capabilities (struct tty_display_info *tty, bool save)
2062 if (save)
2064 dupstring (&default_orig_pair, tty->TS_orig_pair);
2065 dupstring (&default_set_foreground, tty->TS_set_foreground);
2066 dupstring (&default_set_background, tty->TS_set_background);
2067 default_max_colors = tty->TN_max_colors;
2068 default_no_color_video = tty->TN_no_color_video;
2070 else
2072 tty->TS_orig_pair = default_orig_pair;
2073 tty->TS_set_foreground = default_set_foreground;
2074 tty->TS_set_background = default_set_background;
2075 tty->TN_max_colors = default_max_colors;
2076 tty->TN_no_color_video = default_no_color_video;
2080 /* Setup one of the standard tty color schemes according to MODE.
2081 MODE's value is generally the number of colors which we want to
2082 support; zero means set up for the default capabilities, the ones
2083 we saw at init_tty time; -1 means turn off color support. */
2084 static void
2085 tty_setup_colors (struct tty_display_info *tty, int mode)
2087 /* Canonicalize all negative values of MODE. */
2088 if (mode < -1)
2089 mode = -1;
2091 switch (mode)
2093 case -1: /* no colors at all */
2094 tty->TN_max_colors = 0;
2095 tty->TN_no_color_video = 0;
2096 tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL;
2097 break;
2098 case 0: /* default colors, if any */
2099 default:
2100 tty_default_color_capabilities (tty, 0);
2101 break;
2102 case 8: /* 8 standard ANSI colors */
2103 tty->TS_orig_pair = "\033[0m";
2104 #ifdef TERMINFO
2105 tty->TS_set_foreground = "\033[3%p1%dm";
2106 tty->TS_set_background = "\033[4%p1%dm";
2107 #else
2108 tty->TS_set_foreground = "\033[3%dm";
2109 tty->TS_set_background = "\033[4%dm";
2110 #endif
2111 tty->TN_max_colors = 8;
2112 tty->TN_no_color_video = 0;
2113 break;
2117 void
2118 set_tty_color_mode (struct tty_display_info *tty, struct frame *f)
2120 Lisp_Object tem, val;
2121 Lisp_Object color_mode;
2122 int mode;
2123 Lisp_Object tty_color_mode_alist
2124 = Fintern_soft (build_string ("tty-color-mode-alist"), Qnil);
2126 tem = assq_no_quit (Qtty_color_mode, f->param_alist);
2127 val = CONSP (tem) ? XCDR (tem) : Qnil;
2129 if (INTEGERP (val))
2130 color_mode = val;
2131 else if (SYMBOLP (tty_color_mode_alist))
2133 tem = Fassq (val, Fsymbol_value (tty_color_mode_alist));
2134 color_mode = CONSP (tem) ? XCDR (tem) : Qnil;
2136 else
2137 color_mode = Qnil;
2139 mode = TYPE_RANGED_INTEGERP (int, color_mode) ? XINT (color_mode) : 0;
2141 if (mode != tty->previous_color_mode)
2143 tty->previous_color_mode = mode;
2144 tty_setup_colors (tty , mode);
2145 /* This recomputes all the faces given the new color definitions. */
2146 safe_call (1, intern ("tty-set-up-initial-frame-faces"));
2150 #endif /* !DOS_NT */
2152 DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
2153 doc: /* Return the type of the tty device that TERMINAL uses.
2154 Returns nil if TERMINAL is not on a tty device.
2156 TERMINAL can be a terminal object, a frame, or nil (meaning the
2157 selected frame's terminal). */)
2158 (Lisp_Object terminal)
2160 struct terminal *t = decode_tty_terminal (terminal);
2162 return (t && t->display_info.tty->type
2163 ? build_string (t->display_info.tty->type) : Qnil);
2166 DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
2167 doc: /* Return non-nil if TERMINAL is the controlling tty of the Emacs process.
2169 TERMINAL can be a terminal object, a frame, or nil (meaning the
2170 selected frame's terminal). This function always returns nil if
2171 TERMINAL is not on a tty device. */)
2172 (Lisp_Object terminal)
2174 struct terminal *t = decode_tty_terminal (terminal);
2176 return (t && !strcmp (t->display_info.tty->name, DEV_TTY) ? Qt : Qnil);
2179 DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
2180 doc: /* Declare that the tty used by TERMINAL does not handle underlining.
2181 This is used to override the terminfo data, for certain terminals that
2182 do not really do underlining, but say that they do. This function has
2183 no effect if used on a non-tty terminal.
2185 TERMINAL can be a terminal object, a frame or nil (meaning the
2186 selected frame's terminal). This function always returns nil if
2187 TERMINAL does not refer to a text terminal. */)
2188 (Lisp_Object terminal)
2190 struct terminal *t = decode_live_terminal (terminal);
2192 if (t->type == output_termcap)
2193 t->display_info.tty->TS_enter_underline_mode = 0;
2194 return Qnil;
2197 DEFUN ("tty-top-frame", Ftty_top_frame, Stty_top_frame, 0, 1, 0,
2198 doc: /* Return the topmost terminal frame on TERMINAL.
2199 TERMINAL can be a terminal object, a frame or nil (meaning the
2200 selected frame's terminal). This function returns nil if TERMINAL
2201 does not refer to a text terminal. Otherwise, it returns the
2202 top-most frame on the text terminal. */)
2203 (Lisp_Object terminal)
2205 struct terminal *t = decode_live_terminal (terminal);
2207 if (t->type == output_termcap)
2208 return t->display_info.tty->top_frame;
2209 return Qnil;
2214 DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
2215 doc: /* Suspend the terminal device TTY.
2217 The device is restored to its default state, and Emacs ceases all
2218 access to the tty device. Frames that use the device are not deleted,
2219 but input is not read from them and if they change, their display is
2220 not updated.
2222 TTY may be a terminal object, a frame, or nil for the terminal device
2223 of the currently selected frame.
2225 This function runs `suspend-tty-functions' after suspending the
2226 device. The functions are run with one arg, the id of the suspended
2227 terminal device.
2229 `suspend-tty' does nothing if it is called on a device that is already
2230 suspended.
2232 A suspended tty may be resumed by calling `resume-tty' on it. */)
2233 (Lisp_Object tty)
2235 struct terminal *t = decode_tty_terminal (tty);
2236 FILE *f;
2238 if (!t)
2239 error ("Attempt to suspend a non-text terminal device");
2241 f = t->display_info.tty->input;
2243 if (f)
2245 /* First run `suspend-tty-functions' and then clean up the tty
2246 state because `suspend-tty-functions' might need to change
2247 the tty state. */
2248 Lisp_Object term;
2249 XSETTERMINAL (term, t);
2250 CALLN (Frun_hook_with_args, intern ("suspend-tty-functions"), term);
2252 reset_sys_modes (t->display_info.tty);
2253 delete_keyboard_wait_descriptor (fileno (f));
2255 #ifndef MSDOS
2256 fclose (f);
2257 if (f != t->display_info.tty->output)
2258 fclose (t->display_info.tty->output);
2259 #endif
2261 t->display_info.tty->input = 0;
2262 t->display_info.tty->output = 0;
2264 if (FRAMEP (t->display_info.tty->top_frame))
2265 SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
2269 /* Clear display hooks to prevent further output. */
2270 clear_tty_hooks (t);
2272 return Qnil;
2275 DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
2276 doc: /* Resume the previously suspended terminal device TTY.
2277 The terminal is opened and reinitialized. Frames that are on the
2278 suspended terminal are revived.
2280 It is an error to resume a terminal while another terminal is active
2281 on the same device.
2283 This function runs `resume-tty-functions' after resuming the terminal.
2284 The functions are run with one arg, the id of the resumed terminal
2285 device.
2287 `resume-tty' does nothing if it is called on a device that is not
2288 suspended.
2290 TTY may be a terminal object, a frame, or nil (meaning the selected
2291 frame's terminal). */)
2292 (Lisp_Object tty)
2294 struct terminal *t = decode_tty_terminal (tty);
2295 int fd;
2297 if (!t)
2298 error ("Attempt to resume a non-text terminal device");
2300 if (!t->display_info.tty->input)
2302 if (get_named_terminal (t->display_info.tty->name))
2303 error ("Cannot resume display while another display is active on the same device");
2305 #ifdef MSDOS
2306 t->display_info.tty->output = stdout;
2307 t->display_info.tty->input = stdin;
2308 #else /* !MSDOS */
2309 fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
2310 t->display_info.tty->input = t->display_info.tty->output
2311 = fd < 0 ? 0 : fdopen (fd, "w+");
2313 if (! t->display_info.tty->input)
2315 int open_errno = errno;
2316 emacs_close (fd);
2317 report_file_errno ("Cannot reopen tty device",
2318 build_string (t->display_info.tty->name),
2319 open_errno);
2322 if (!O_IGNORE_CTTY && strcmp (t->display_info.tty->name, DEV_TTY) != 0)
2323 dissociate_if_controlling_tty (fd);
2324 #endif
2326 add_keyboard_wait_descriptor (fd);
2328 if (FRAMEP (t->display_info.tty->top_frame))
2330 struct frame *f = XFRAME (t->display_info.tty->top_frame);
2331 int width, height;
2332 int old_height = FRAME_COLS (f);
2333 int old_width = FRAME_TOTAL_LINES (f);
2335 /* Check if terminal/window size has changed while the frame
2336 was suspended. */
2337 get_tty_size (fileno (t->display_info.tty->input), &width, &height);
2338 if (width != old_width || height != old_height)
2339 change_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f),
2340 0, 0, 0, 0);
2341 SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
2344 set_tty_hooks (t);
2345 init_sys_modes (t->display_info.tty);
2347 /* Run `resume-tty-functions'. */
2348 Lisp_Object term;
2349 XSETTERMINAL (term, t);
2350 CALLN (Frun_hook_with_args, intern ("resume-tty-functions"), term);
2353 set_tty_hooks (t);
2355 return Qnil;
2359 /***********************************************************************
2360 Mouse
2361 ***********************************************************************/
2363 #ifdef HAVE_GPM
2365 #ifndef HAVE_WINDOW_SYSTEM
2366 void
2367 term_mouse_moveto (int x, int y)
2369 /* TODO: how to set mouse position?
2370 const char *name;
2371 int fd;
2372 name = (const char *) ttyname (0);
2373 fd = emacs_open (name, O_WRONLY, 0);
2374 SOME_FUNCTION (x, y, fd);
2375 emacs_close (fd);
2376 last_mouse_x = x;
2377 last_mouse_y = y; */
2379 #endif /* HAVE_WINDOW_SYSTEM */
2381 /* Implementation of draw_row_with_mouse_face for TTY/GPM. */
2382 void
2383 tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
2384 int start_hpos, int end_hpos,
2385 enum draw_glyphs_face draw)
2387 int nglyphs = end_hpos - start_hpos;
2388 struct frame *f = XFRAME (WINDOW_FRAME (w));
2389 struct tty_display_info *tty = FRAME_TTY (f);
2390 int face_id = tty->mouse_highlight.mouse_face_face_id;
2391 int save_x, save_y, pos_x, pos_y;
2393 if (end_hpos >= row->used[TEXT_AREA])
2394 nglyphs = row->used[TEXT_AREA] - start_hpos;
2396 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
2397 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w);
2399 /* Save current cursor co-ordinates. */
2400 save_y = curY (tty);
2401 save_x = curX (tty);
2402 cursor_to (f, pos_y, pos_x);
2404 if (draw == DRAW_MOUSE_FACE)
2405 tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
2406 nglyphs, face_id);
2407 else if (draw == DRAW_NORMAL_TEXT)
2408 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
2410 cursor_to (f, save_y, save_x);
2413 static bool
2414 term_mouse_movement (struct frame *frame, Gpm_Event *event)
2416 /* Has the mouse moved off the glyph it was on at the last sighting? */
2417 if (event->x != last_mouse_x || event->y != last_mouse_y)
2419 frame->mouse_moved = 1;
2420 note_mouse_highlight (frame, event->x, event->y);
2421 /* Remember which glyph we're now on. */
2422 last_mouse_x = event->x;
2423 last_mouse_y = event->y;
2424 return 1;
2426 return 0;
2429 /* Return the Time that corresponds to T. Wrap around on overflow. */
2430 static Time
2431 timeval_to_Time (struct timeval const *t)
2433 Time s_1000, ms;
2435 s_1000 = t->tv_sec;
2436 s_1000 *= 1000;
2437 ms = t->tv_usec / 1000;
2438 return s_1000 + ms;
2441 /* Return the current position of the mouse.
2443 Set *f to the frame the mouse is in, or zero if the mouse is in no
2444 Emacs frame. If it is set to zero, all the other arguments are
2445 garbage.
2447 Set *bar_window to Qnil, and *x and *y to the column and
2448 row of the character cell the mouse is over.
2450 Set *timeptr to the time the mouse was at the returned position.
2452 This clears mouse_moved until the next motion
2453 event arrives. */
2454 static void
2455 term_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2456 enum scroll_bar_part *part, Lisp_Object *x,
2457 Lisp_Object *y, Time *timeptr)
2459 struct timeval now;
2461 *fp = SELECTED_FRAME ();
2462 (*fp)->mouse_moved = 0;
2464 *bar_window = Qnil;
2465 *part = scroll_bar_above_handle;
2467 XSETINT (*x, last_mouse_x);
2468 XSETINT (*y, last_mouse_y);
2469 gettimeofday(&now, 0);
2470 *timeptr = timeval_to_Time (&now);
2473 /* Prepare a mouse-event in *RESULT for placement in the input queue.
2475 If the event is a button press, then note that we have grabbed
2476 the mouse. */
2478 static Lisp_Object
2479 term_mouse_click (struct input_event *result, Gpm_Event *event,
2480 struct frame *f)
2482 struct timeval now;
2483 int i, j;
2485 result->kind = GPM_CLICK_EVENT;
2486 for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
2488 if (event->buttons & j) {
2489 result->code = i; /* button number */
2490 break;
2493 gettimeofday(&now, 0);
2494 result->timestamp = timeval_to_Time (&now);
2496 if (event->type & GPM_UP)
2497 result->modifiers = up_modifier;
2498 else if (event->type & GPM_DOWN)
2499 result->modifiers = down_modifier;
2500 else
2501 result->modifiers = 0;
2503 if (event->type & GPM_SINGLE)
2504 result->modifiers |= click_modifier;
2506 if (event->type & GPM_DOUBLE)
2507 result->modifiers |= double_modifier;
2509 if (event->type & GPM_TRIPLE)
2510 result->modifiers |= triple_modifier;
2512 if (event->type & GPM_DRAG)
2513 result->modifiers |= drag_modifier;
2515 if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
2517 /* 1 << KG_SHIFT */
2518 if (event->modifiers & (1 << 0))
2519 result->modifiers |= shift_modifier;
2521 /* 1 << KG_CTRL */
2522 if (event->modifiers & (1 << 2))
2523 result->modifiers |= ctrl_modifier;
2525 /* 1 << KG_ALT || KG_ALTGR */
2526 if (event->modifiers & (1 << 3)
2527 || event->modifiers & (1 << 1))
2528 result->modifiers |= meta_modifier;
2531 XSETINT (result->x, event->x);
2532 XSETINT (result->y, event->y);
2533 XSETFRAME (result->frame_or_window, f);
2534 result->arg = Qnil;
2535 return Qnil;
2539 handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event,
2540 struct input_event *hold_quit)
2542 struct frame *f = XFRAME (tty->top_frame);
2543 struct input_event ie;
2544 bool do_help = 0;
2545 int count = 0;
2547 EVENT_INIT (ie);
2548 ie.kind = NO_EVENT;
2549 ie.arg = Qnil;
2551 if (event->type & (GPM_MOVE | GPM_DRAG)) {
2552 previous_help_echo_string = help_echo_string;
2553 help_echo_string = Qnil;
2555 Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
2557 if (!term_mouse_movement (f, event))
2558 help_echo_string = previous_help_echo_string;
2560 /* If the contents of the global variable help_echo_string
2561 has changed, generate a HELP_EVENT. */
2562 if (!NILP (help_echo_string)
2563 || !NILP (previous_help_echo_string))
2564 do_help = 1;
2566 goto done;
2568 else {
2569 f->mouse_moved = 0;
2570 term_mouse_click (&ie, event, f);
2573 done:
2574 if (ie.kind != NO_EVENT)
2576 kbd_buffer_store_event_hold (&ie, hold_quit);
2577 count++;
2580 if (do_help
2581 && !(hold_quit && hold_quit->kind != NO_EVENT))
2583 Lisp_Object frame;
2585 if (f)
2586 XSETFRAME (frame, f);
2587 else
2588 frame = Qnil;
2590 gen_help_event (help_echo_string, frame, help_echo_window,
2591 help_echo_object, help_echo_pos);
2592 count++;
2595 return count;
2598 DEFUN ("gpm-mouse-start", Fgpm_mouse_start, Sgpm_mouse_start,
2599 0, 0, 0,
2600 doc: /* Open a connection to Gpm.
2601 Gpm-mouse can only be activated for one tty at a time. */)
2602 (void)
2604 struct frame *f = SELECTED_FRAME ();
2605 struct tty_display_info *tty
2606 = ((f)->output_method == output_termcap
2607 ? (f)->terminal->display_info.tty : NULL);
2608 Gpm_Connect connection;
2610 if (!tty)
2611 error ("Gpm-mouse only works in the GNU/Linux console");
2612 if (gpm_tty == tty)
2613 return Qnil; /* Already activated, nothing to do. */
2614 if (gpm_tty)
2615 error ("Gpm-mouse can only be activated for one tty at a time");
2617 connection.eventMask = ~0;
2618 connection.defaultMask = ~GPM_HARD;
2619 connection.maxMod = ~0;
2620 connection.minMod = 0;
2621 gpm_zerobased = 1;
2623 if (Gpm_Open (&connection, 0) < 0)
2624 error ("Gpm-mouse failed to connect to the gpm daemon");
2625 else
2627 gpm_tty = tty;
2628 /* `init_sys_modes' arranges for mouse movements sent through gpm_fd
2629 to generate SIGIOs. Apparently we need to call reset_sys_modes
2630 before calling init_sys_modes. */
2631 reset_sys_modes (tty);
2632 init_sys_modes (tty);
2633 add_gpm_wait_descriptor (gpm_fd);
2634 return Qnil;
2638 void
2639 close_gpm (int fd)
2641 if (fd >= 0)
2642 delete_gpm_wait_descriptor (fd);
2643 while (Gpm_Close()); /* close all the stack */
2644 gpm_tty = NULL;
2647 DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
2648 0, 0, 0,
2649 doc: /* Close a connection to Gpm. */)
2650 (void)
2652 struct frame *f = SELECTED_FRAME ();
2653 struct tty_display_info *tty
2654 = ((f)->output_method == output_termcap
2655 ? (f)->terminal->display_info.tty : NULL);
2657 if (!tty || gpm_tty != tty)
2658 return Qnil; /* Not activated on this terminal, nothing to do. */
2660 close_gpm (gpm_fd);
2661 return Qnil;
2663 #endif /* HAVE_GPM */
2666 /***********************************************************************
2667 Menus
2668 ***********************************************************************/
2670 #if !defined (MSDOS)
2672 /* TTY menu implementation and main ideas are borrowed from msdos.c.
2674 However, unlike on MSDOS, where the menu text is drawn directly to
2675 the display video memory, on a TTY we use display_string (see
2676 display_tty_menu_item in xdisp.c) to put the glyphs produced from
2677 the menu items into the frame's 'desired_matrix' glyph matrix, and
2678 then call update_frame_with_menu to deliver the results to the
2679 glass. The previous contents of the screen, in the form of the
2680 current_matrix, is stashed away, and used to restore screen
2681 contents when the menu selection changes or when the final
2682 selection is made and the menu should be popped down.
2684 The idea of this implementation was suggested by Gerd Moellmann. */
2686 #define TTYM_FAILURE -1
2687 #define TTYM_SUCCESS 1
2688 #define TTYM_NO_SELECT 2
2689 #define TTYM_IA_SELECT 3
2690 #define TTYM_NEXT 4
2691 #define TTYM_PREV 5
2693 /* These hold text of the current and the previous menu help messages. */
2694 static const char *menu_help_message, *prev_menu_help_message;
2695 /* Pane number and item number of the menu item which generated the
2696 last menu help message. */
2697 static int menu_help_paneno, menu_help_itemno;
2699 typedef struct tty_menu_struct
2701 int count;
2702 char **text;
2703 struct tty_menu_struct **submenu;
2704 int *panenumber; /* Also used as enabled flag. */
2705 ptrdiff_t allocated;
2706 int panecount;
2707 int width;
2708 const char **help_text;
2709 } tty_menu;
2711 /* Create a brand new menu structure. */
2713 static tty_menu *
2714 tty_menu_create (void)
2716 return xzalloc (sizeof *tty_menu_create ());
2719 /* Allocate some (more) memory for MENU ensuring that there is room for one
2720 more item. */
2722 static void
2723 tty_menu_make_room (tty_menu *menu)
2725 if (menu->allocated == menu->count)
2727 ptrdiff_t allocated = menu->allocated;
2728 menu->text = xpalloc (menu->text, &allocated, 1, -1, sizeof *menu->text);
2729 menu->text = xrealloc (menu->text, allocated * sizeof *menu->text);
2730 menu->submenu = xrealloc (menu->submenu,
2731 allocated * sizeof *menu->submenu);
2732 menu->panenumber = xrealloc (menu->panenumber,
2733 allocated * sizeof *menu->panenumber);
2734 menu->help_text = xrealloc (menu->help_text,
2735 allocated * sizeof *menu->help_text);
2736 menu->allocated = allocated;
2740 /* Search the given menu structure for a given pane number. */
2742 static tty_menu *
2743 tty_menu_search_pane (tty_menu *menu, int pane)
2745 int i;
2746 tty_menu *try;
2748 for (i = 0; i < menu->count; i++)
2749 if (menu->submenu[i])
2751 if (pane == menu->panenumber[i])
2752 return menu->submenu[i];
2753 try = tty_menu_search_pane (menu->submenu[i], pane);
2754 if (try)
2755 return try;
2757 return (tty_menu *) 0;
2760 /* Determine how much screen space a given menu needs. */
2762 static void
2763 tty_menu_calc_size (tty_menu *menu, int *width, int *height)
2765 int i, h2, w2, maxsubwidth, maxheight;
2767 maxsubwidth = menu->width;
2768 maxheight = menu->count;
2769 for (i = 0; i < menu->count; i++)
2771 if (menu->submenu[i])
2773 tty_menu_calc_size (menu->submenu[i], &w2, &h2);
2774 if (w2 > maxsubwidth) maxsubwidth = w2;
2775 if (i + h2 > maxheight) maxheight = i + h2;
2778 *width = maxsubwidth;
2779 *height = maxheight;
2782 static void
2783 mouse_get_xy (int *x, int *y)
2785 struct frame *sf = SELECTED_FRAME ();
2786 Lisp_Object lmx = Qnil, lmy = Qnil, lisp_dummy;
2787 enum scroll_bar_part part_dummy;
2788 Time time_dummy;
2790 if (FRAME_TERMINAL (sf)->mouse_position_hook)
2791 (*FRAME_TERMINAL (sf)->mouse_position_hook) (&sf, -1,
2792 &lisp_dummy, &part_dummy,
2793 &lmx, &lmy,
2794 &time_dummy);
2795 if (!NILP (lmx))
2797 *x = XINT (lmx);
2798 *y = XINT (lmy);
2802 /* Display MENU at (X,Y) using FACES, starting with FIRST_ITEM
2803 (zero-based). */
2805 static void
2806 tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
2807 int mx, int my, int first_item, bool disp_help)
2809 int i, face, width, enabled, mousehere, row, col;
2810 struct frame *sf = SELECTED_FRAME ();
2811 struct tty_display_info *tty = FRAME_TTY (sf);
2812 /* Don't try to display more menu items than the console can display
2813 using the available screen lines. Exclude the echo area line, as
2814 it will be overwritten by the help-echo anyway. */
2815 int max_items = min (menu->count - first_item, FRAME_TOTAL_LINES (sf) - 1 - y);
2817 menu_help_message = NULL;
2819 width = menu->width;
2820 col = cursorX (tty);
2821 row = cursorY (tty);
2822 for (i = 0; i < max_items; i++)
2824 int max_width = width + 2; /* +2 for padding blanks on each side */
2825 int j = i + first_item;
2827 if (menu->submenu[j])
2828 max_width += 2; /* for displaying " >" after the item */
2829 enabled
2830 = (!menu->submenu[j] && menu->panenumber[j]) || (menu->submenu[j]);
2831 mousehere = (y + i == my && x <= mx && mx < x + max_width);
2832 face = faces[enabled + mousehere * 2];
2833 /* Display the menu help string for the i-th menu item even if
2834 the menu item is currently disabled. That's what the GUI
2835 code does. */
2836 if (disp_help && enabled + mousehere * 2 >= 2)
2838 menu_help_message = menu->help_text[j];
2839 menu_help_paneno = pn - 1;
2840 menu_help_itemno = j;
2842 /* Take note of the coordinates of the active menu item, to
2843 display the cursor there. */
2844 if (mousehere)
2846 row = y + i;
2847 col = x;
2849 display_tty_menu_item (menu->text[j], max_width, face, x, y + i,
2850 menu->submenu[j] != NULL);
2852 update_frame_with_menu (sf, row, col);
2855 /* --------------------------- X Menu emulation ---------------------- */
2857 /* Create a new pane and place it on the outer-most level. */
2859 static int
2860 tty_menu_add_pane (tty_menu *menu, const char *txt)
2862 int len;
2864 tty_menu_make_room (menu);
2865 menu->submenu[menu->count] = tty_menu_create ();
2866 menu->text[menu->count] = (char *)txt;
2867 menu->panenumber[menu->count] = ++menu->panecount;
2868 menu->help_text[menu->count] = NULL;
2869 menu->count++;
2871 /* Update the menu width, if necessary. */
2872 len = menu_item_width ((const unsigned char *) txt);
2873 if (len > menu->width)
2874 menu->width = len;
2876 return menu->panecount;
2879 /* Create a new item in a menu pane. */
2881 static bool
2882 tty_menu_add_selection (tty_menu *menu, int pane,
2883 char *txt, bool enable, char const *help_text)
2885 int len;
2887 if (pane)
2889 menu = tty_menu_search_pane (menu, pane);
2890 if (! menu)
2891 return 0;
2893 tty_menu_make_room (menu);
2894 menu->submenu[menu->count] = (tty_menu *) 0;
2895 menu->text[menu->count] = txt;
2896 menu->panenumber[menu->count] = enable;
2897 menu->help_text[menu->count] = help_text;
2898 menu->count++;
2900 /* Update the menu width, if necessary. */
2901 len = menu_item_width ((const unsigned char *) txt);
2902 if (len > menu->width)
2903 menu->width = len;
2905 return 1;
2908 /* Decide where the menu would be placed if requested at (X,Y). */
2910 static void
2911 tty_menu_locate (tty_menu *menu, int x, int y,
2912 int *ulx, int *uly, int *width, int *height)
2914 tty_menu_calc_size (menu, width, height);
2915 *ulx = x + 1;
2916 *uly = y;
2917 *width += 2;
2920 struct tty_menu_state
2922 struct glyph_matrix *screen_behind;
2923 tty_menu *menu;
2924 int pane;
2925 int x, y;
2928 /* Save away the contents of frame F's current frame matrix, and
2929 enable all its rows. Value is a glyph matrix holding the contents
2930 of F's current frame matrix with all its glyph rows enabled. */
2932 static struct glyph_matrix *
2933 save_and_enable_current_matrix (struct frame *f)
2935 int i;
2936 struct glyph_matrix *saved = xzalloc (sizeof *saved);
2937 saved->nrows = f->current_matrix->nrows;
2938 saved->rows = xzalloc (saved->nrows * sizeof *saved->rows);
2940 for (i = 0; i < saved->nrows; ++i)
2942 struct glyph_row *from = f->current_matrix->rows + i;
2943 struct glyph_row *to = saved->rows + i;
2944 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
2946 to->glyphs[TEXT_AREA] = xmalloc (nbytes);
2947 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
2948 to->used[TEXT_AREA] = from->used[TEXT_AREA];
2949 /* Make sure every row is enabled, or else update_frame will not
2950 redraw them. (Rows that are identical to what is already on
2951 screen will not be redrawn anyway.) */
2952 to->enabled_p = true;
2953 to->hash = from->hash;
2956 return saved;
2959 /* Restore the contents of frame F's desired frame matrix from SAVED,
2960 and free memory associated with SAVED. */
2962 static void
2963 restore_desired_matrix (struct frame *f, struct glyph_matrix *saved)
2965 int i;
2967 for (i = 0; i < saved->nrows; ++i)
2969 struct glyph_row *from = saved->rows + i;
2970 struct glyph_row *to = f->desired_matrix->rows + i;
2971 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
2973 eassert (to->glyphs[TEXT_AREA] != from->glyphs[TEXT_AREA]);
2974 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
2975 to->used[TEXT_AREA] = from->used[TEXT_AREA];
2976 to->enabled_p = from->enabled_p;
2977 to->hash = from->hash;
2981 static void
2982 free_saved_screen (struct glyph_matrix *saved)
2984 int i;
2986 if (!saved)
2987 return; /* Already freed! */
2989 for (i = 0; i < saved->nrows; ++i)
2991 struct glyph_row *from = saved->rows + i;
2993 xfree (from->glyphs[TEXT_AREA]);
2996 xfree (saved->rows);
2997 xfree (saved);
3000 /* Update the display of frame F from its saved contents. */
3001 static void
3002 screen_update (struct frame *f, struct glyph_matrix *mtx)
3004 restore_desired_matrix (f, mtx);
3005 update_frame_with_menu (f, -1, -1);
3008 typedef enum {
3009 MI_QUIT_MENU = -1,
3010 MI_CONTINUE = 0,
3011 MI_ITEM_SELECTED = 1,
3012 MI_NEXT_ITEM = 2,
3013 MI_PREV_ITEM = 3,
3014 MI_SCROLL_FORWARD = 4,
3015 MI_SCROLL_BACK = 5
3016 } mi_result;
3018 /* Read user input and return X and Y coordinates where that input
3019 puts us. We only consider mouse movement and click events, and
3020 keyboard movement commands; the rest are ignored. */
3021 static mi_result
3022 read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
3023 bool *first_time)
3025 if (*first_time)
3027 *first_time = false;
3028 sf->mouse_moved = 1;
3030 else
3032 Lisp_Object cmd;
3033 bool usable_input = 1;
3034 mi_result st = MI_CONTINUE;
3035 struct tty_display_info *tty = FRAME_TTY (sf);
3036 Lisp_Object saved_mouse_tracking = do_mouse_tracking;
3038 /* Signal the keyboard reading routines we are displaying a menu
3039 on this terminal. */
3040 tty->showing_menu = 1;
3041 /* We want mouse movements be reported by read_menu_command. */
3042 do_mouse_tracking = Qt;
3043 do {
3044 cmd = read_menu_command ();
3045 } while (NILP (cmd));
3046 tty->showing_menu = 0;
3047 do_mouse_tracking = saved_mouse_tracking;
3049 if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit)
3050 /* If some input switched frames under our feet, exit the
3051 menu, since the menu faces are no longer valid, and the
3052 menu is no longer relevant anyway. */
3053 || sf != SELECTED_FRAME ())
3054 return MI_QUIT_MENU;
3055 if (EQ (cmd, Qtty_menu_mouse_movement))
3056 mouse_get_xy (x, y);
3057 else if (EQ (cmd, Qtty_menu_next_menu))
3059 usable_input = 0;
3060 st = MI_NEXT_ITEM;
3062 else if (EQ (cmd, Qtty_menu_prev_menu))
3064 usable_input = 0;
3065 st = MI_PREV_ITEM;
3067 else if (EQ (cmd, Qtty_menu_next_item))
3069 if (*y < max_y)
3070 *y += 1;
3071 else
3072 st = MI_SCROLL_FORWARD;
3074 else if (EQ (cmd, Qtty_menu_prev_item))
3076 if (*y > min_y)
3077 *y -= 1;
3078 else
3079 st = MI_SCROLL_BACK;
3081 else if (EQ (cmd, Qtty_menu_select))
3082 st = MI_ITEM_SELECTED;
3083 else if (!EQ (cmd, Qtty_menu_ignore))
3084 usable_input = 0;
3085 if (usable_input)
3086 sf->mouse_moved = 1;
3087 return st;
3089 return MI_CONTINUE;
3092 /* Display menu, wait for user's response, and return that response. */
3093 static int
3094 tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
3095 int x0, int y0, char **txt,
3096 void (*help_callback)(char const *, int, int),
3097 bool kbd_navigation)
3099 struct tty_menu_state *state;
3100 int statecount, x, y, i;
3101 bool leave, onepane;
3102 int result UNINIT;
3103 int title_faces[4]; /* Face to display the menu title. */
3104 int faces[4], buffers_num_deleted = 0;
3105 struct frame *sf = SELECTED_FRAME ();
3106 struct tty_display_info *tty = FRAME_TTY (sf);
3107 bool first_time;
3108 Lisp_Object selectface;
3109 int first_item = 0;
3110 int col, row;
3111 Lisp_Object prev_inhibit_redisplay = Vinhibit_redisplay;
3112 USE_SAFE_ALLOCA;
3114 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3115 around the display. */
3116 if (x0 <= 0)
3117 x0 = 1;
3118 if (y0 <= 0)
3119 y0 = 1;
3121 SAFE_NALLOCA (state, 1, menu->panecount);
3122 memset (state, 0, sizeof (*state));
3123 faces[0]
3124 = lookup_derived_face (sf, intern ("tty-menu-disabled-face"),
3125 DEFAULT_FACE_ID, 1);
3126 faces[1]
3127 = lookup_derived_face (sf, intern ("tty-menu-enabled-face"),
3128 DEFAULT_FACE_ID, 1);
3129 selectface = intern ("tty-menu-selected-face");
3130 faces[2] = lookup_derived_face (sf, selectface,
3131 faces[0], 1);
3132 faces[3] = lookup_derived_face (sf, selectface,
3133 faces[1], 1);
3135 /* Make sure the menu title is always displayed with
3136 `tty-menu-selected-face', no matter where the mouse pointer is. */
3137 for (i = 0; i < 4; i++)
3138 title_faces[i] = faces[3];
3140 statecount = 1;
3142 /* Don't let the title for the "Buffers" popup menu include a
3143 digit (which is ugly).
3145 This is a terrible kludge, but I think the "Buffers" case is
3146 the only one where the title includes a number, so it doesn't
3147 seem to be necessary to make this more general. */
3148 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3150 menu->text[0][7] = '\0';
3151 buffers_num_deleted = 1;
3154 /* Inhibit redisplay for as long as the menu is active, to avoid
3155 messing the screen if some timer calls sit-for or a similar
3156 function. */
3157 Vinhibit_redisplay = Qt;
3159 /* Force update of the current frame, so that the desired and the
3160 current matrices are identical. */
3161 update_frame_with_menu (sf, -1, -1);
3162 state[0].menu = menu;
3163 state[0].screen_behind = save_and_enable_current_matrix (sf);
3165 /* Display the menu title. We subtract 1 from x0 and y0 because we
3166 want to interpret them as zero-based column and row coordinates,
3167 and also because we want the first item of the menu, not its
3168 title, to appear at x0,y0. */
3169 tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0, 0);
3171 /* Turn off the cursor. Otherwise it shows through the menu
3172 panes, which is ugly. */
3173 col = cursorX (tty);
3174 row = cursorY (tty);
3175 tty_hide_cursor (tty);
3177 if (buffers_num_deleted)
3178 menu->text[0][7] = ' ';
3179 onepane = menu->count == 1 && menu->submenu[0];
3180 if (onepane)
3182 menu->width = menu->submenu[0]->width;
3183 state[0].menu = menu->submenu[0];
3185 else
3187 state[0].menu = menu;
3189 state[0].x = x0 - 1;
3190 state[0].y = y0;
3191 state[0].pane = onepane;
3193 x = state[0].x;
3194 y = state[0].y;
3195 first_time = true;
3197 leave = 0;
3198 while (!leave)
3200 mi_result input_status;
3201 int min_y = state[0].y;
3202 int max_y = min (min_y + state[0].menu->count, FRAME_TOTAL_LINES (sf) - 1) - 1;
3204 input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
3205 if (input_status)
3207 leave = 1;
3208 switch (input_status)
3210 case MI_QUIT_MENU:
3211 /* Remove the last help-echo, so that it doesn't
3212 re-appear after "Quit". */
3213 show_help_echo (Qnil, Qnil, Qnil, Qnil);
3214 result = TTYM_NO_SELECT;
3215 break;
3216 case MI_NEXT_ITEM:
3217 if (kbd_navigation)
3218 result = TTYM_NEXT;
3219 else
3220 leave = 0;
3221 break;
3222 case MI_PREV_ITEM:
3223 if (kbd_navigation)
3224 result = TTYM_PREV;
3225 else
3226 leave = 0;
3227 break;
3228 case MI_SCROLL_FORWARD:
3229 if (y - min_y == state[0].menu->count - 1 - first_item)
3231 y = min_y;
3232 first_item = 0;
3234 else
3235 first_item++;
3236 leave = 0;
3237 break;
3238 case MI_SCROLL_BACK:
3239 if (first_item == 0)
3241 y = max_y;
3242 first_item = state[0].menu->count - 1 - (y - min_y);
3244 else
3245 first_item--;
3246 leave = 0;
3247 break;
3248 default:
3249 /* MI_ITEM_SELECTED is handled below, so nothing to do. */
3250 break;
3253 if (sf->mouse_moved && input_status != MI_QUIT_MENU)
3255 sf->mouse_moved = 0;
3256 result = TTYM_IA_SELECT;
3257 for (i = 0; i < statecount; i++)
3258 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3260 int dy = y - state[i].y + first_item;
3261 if (0 <= dy && dy < state[i].menu->count)
3263 if (!state[i].menu->submenu[dy])
3265 if (state[i].menu->panenumber[dy])
3266 result = TTYM_SUCCESS;
3267 else
3268 result = TTYM_IA_SELECT;
3270 *pane = state[i].pane - 1;
3271 *selidx = dy;
3272 /* We hit some part of a menu, so drop extra menus that
3273 have been opened. That does not include an open and
3274 active submenu. */
3275 if (i != statecount - 2
3276 || state[i].menu->submenu[dy] != state[i + 1].menu)
3277 while (i != statecount - 1)
3279 statecount--;
3280 screen_update (sf, state[statecount].screen_behind);
3281 state[statecount].screen_behind = NULL;
3283 if (i == statecount - 1 && state[i].menu->submenu[dy])
3285 tty_menu_display (state[i].menu,
3286 state[i].x,
3287 state[i].y,
3288 state[i].pane,
3289 faces, x, y, first_item, 1);
3290 state[statecount].menu = state[i].menu->submenu[dy];
3291 state[statecount].pane = state[i].menu->panenumber[dy];
3292 state[statecount].screen_behind
3293 = save_and_enable_current_matrix (sf);
3294 state[statecount].x
3295 = state[i].x + state[i].menu->width + 2;
3296 state[statecount].y = y;
3297 statecount++;
3301 tty_menu_display (state[statecount - 1].menu,
3302 state[statecount - 1].x,
3303 state[statecount - 1].y,
3304 state[statecount - 1].pane,
3305 faces, x, y, first_item, 1);
3306 /* The call to display help-echo below will move the cursor,
3307 so remember its current position as computed by
3308 tty_menu_display. */
3309 col = cursorX (tty);
3310 row = cursorY (tty);
3313 /* Display the help-echo message for the currently-selected menu
3314 item. */
3315 if ((menu_help_message || prev_menu_help_message)
3316 && menu_help_message != prev_menu_help_message)
3318 help_callback (menu_help_message,
3319 menu_help_paneno, menu_help_itemno);
3320 /* Move the cursor to the beginning of the current menu
3321 item, so that screen readers and other accessibility aids
3322 know where the active region is. */
3323 cursor_to (sf, row, col);
3324 prev_menu_help_message = menu_help_message;
3326 /* Both tty_menu_display and help_callback invoke update_end,
3327 which calls tty_show_cursor. Re-hide it, so it doesn't show
3328 through the menus. */
3329 tty_hide_cursor (tty);
3330 fflush (tty->output);
3333 sf->mouse_moved = 0;
3334 screen_update (sf, state[0].screen_behind);
3335 while (statecount--)
3336 free_saved_screen (state[statecount].screen_behind);
3337 tty_show_cursor (tty); /* Turn cursor back on. */
3338 fflush (tty->output);
3340 /* Clean up any mouse events that are waiting inside Emacs event queue.
3341 These events are likely to be generated before the menu was even
3342 displayed, probably because the user pressed and released the button
3343 (which invoked the menu) too quickly. If we don't remove these events,
3344 Emacs will process them after we return and surprise the user. */
3345 discard_mouse_events ();
3346 if (!kbd_buffer_events_waiting ())
3347 clear_input_pending ();
3348 SAFE_FREE ();
3349 Vinhibit_redisplay = prev_inhibit_redisplay;
3350 return result;
3353 /* Dispose of a menu. */
3355 static void
3356 tty_menu_destroy (tty_menu *menu)
3358 int i;
3359 if (menu->allocated)
3361 for (i = 0; i < menu->count; i++)
3362 if (menu->submenu[i])
3363 tty_menu_destroy (menu->submenu[i]);
3364 xfree (menu->text);
3365 xfree (menu->submenu);
3366 xfree (menu->panenumber);
3367 xfree (menu->help_text);
3369 xfree (menu);
3370 menu_help_message = prev_menu_help_message = NULL;
3373 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
3375 PANE is the pane number, and ITEM is the menu item number in
3376 the menu (currently not used). */
3378 static void
3379 tty_menu_help_callback (char const *help_string, int pane, int item)
3381 Lisp_Object *first_item;
3382 Lisp_Object pane_name;
3383 Lisp_Object menu_object;
3385 first_item = XVECTOR (menu_items)->contents;
3386 if (EQ (first_item[0], Qt))
3387 pane_name = first_item[MENU_ITEMS_PANE_NAME];
3388 else if (EQ (first_item[0], Qquote))
3389 /* This shouldn't happen, see xmenu_show. */
3390 pane_name = empty_unibyte_string;
3391 else
3392 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
3394 /* (menu-item MENU-NAME PANE-NUMBER) */
3395 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
3396 show_help_echo (help_string ? build_string (help_string) : Qnil,
3397 Qnil, menu_object, make_number (item));
3400 static void
3401 tty_pop_down_menu (Lisp_Object arg)
3403 tty_menu *menu = XSAVE_POINTER (arg, 0);
3404 struct buffer *orig_buffer = XSAVE_POINTER (arg, 1);
3406 block_input ();
3407 tty_menu_destroy (menu);
3408 set_buffer_internal (orig_buffer);
3409 unblock_input ();
3412 /* Return the zero-based index of the last menu-bar item on frame F. */
3413 static int
3414 tty_menu_last_menubar_item (struct frame *f)
3416 int i = 0;
3418 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3419 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3421 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3423 while (i < ASIZE (items))
3425 Lisp_Object str;
3427 str = AREF (items, i + 1);
3428 if (NILP (str))
3429 break;
3430 i += 4;
3432 i -= 4; /* Went one too far! */
3434 return i;
3437 /* Find in frame F's menu bar the menu item that is next or previous
3438 to the item at X/Y, and return that item's position in X/Y. WHICH
3439 says which one--next or previous--item to look for. X and Y are
3440 measured in character cells. This should only be called on TTY
3441 frames. */
3442 static void
3443 tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
3445 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3446 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3448 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3449 int last_i = tty_menu_last_menubar_item (f);
3450 int i, prev_x;
3452 /* This loop assumes a single menu-bar line, and will fail to
3453 find an item if it is not in the first line. Note that
3454 make_lispy_event in keyboard.c makes the same assumption. */
3455 for (i = 0, prev_x = -1; i < ASIZE (items); i += 4)
3457 Lisp_Object pos, str;
3458 int ix;
3460 str = AREF (items, i + 1);
3461 pos = AREF (items, i + 3);
3462 if (NILP (str))
3463 return;
3464 ix = XINT (pos);
3465 if (ix <= *x
3466 /* We use <= so the blank between 2 items on a TTY is
3467 considered part of the previous item. */
3468 && *x <= ix + menu_item_width (SDATA (str)))
3470 /* Found current item. Now compute the X coordinate of
3471 the previous or next item. */
3472 if (which == TTYM_NEXT)
3474 if (i < last_i)
3475 *x = XINT (AREF (items, i + 4 + 3));
3476 else
3477 *x = 0; /* Wrap around to the first item. */
3479 else if (prev_x < 0)
3481 /* Wrap around to the last item. */
3482 *x = XINT (AREF (items, last_i + 3));
3484 else
3485 *x = prev_x;
3486 return;
3488 prev_x = ix;
3493 /* WINDOWSNT uses this as menu_show_hook, see w32console.c. */
3494 Lisp_Object
3495 tty_menu_show (struct frame *f, int x, int y, int menuflags,
3496 Lisp_Object title, const char **error_name)
3498 tty_menu *menu;
3499 int pane, selidx, lpane, status;
3500 Lisp_Object entry, pane_prefix;
3501 char *datap;
3502 int ulx, uly, width, height;
3503 int item_x, item_y;
3504 int dispwidth, dispheight;
3505 int i, j, lines, maxlines;
3506 int maxwidth;
3507 ptrdiff_t specpdl_count;
3509 eassert (FRAME_TERMCAP_P (f));
3511 *error_name = 0;
3512 if (menu_items_n_panes == 0)
3513 return Qnil;
3515 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
3517 *error_name = "Empty menu";
3518 return Qnil;
3521 /* Make the menu on that window. */
3522 menu = tty_menu_create ();
3524 /* Don't GC while we prepare and show the menu, because we give the
3525 menu functions pointers to the contents of strings. */
3526 specpdl_count = inhibit_garbage_collection ();
3528 /* Avoid crashes if, e.g., another client will connect while we
3529 are in a menu. */
3530 temporarily_switch_to_single_kboard (f);
3532 /* Adjust coordinates to be root-window-relative. */
3533 item_x = x += f->left_pos;
3534 item_y = y += f->top_pos;
3536 /* Create all the necessary panes and their items. */
3537 USE_SAFE_ALLOCA;
3538 maxwidth = maxlines = lines = i = 0;
3539 lpane = TTYM_FAILURE;
3540 while (i < menu_items_used)
3542 if (EQ (AREF (menu_items, i), Qt))
3544 /* Create a new pane. */
3545 Lisp_Object pane_name, prefix;
3546 const char *pane_string;
3548 maxlines = max (maxlines, lines);
3549 lines = 0;
3550 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
3551 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
3552 pane_string = (NILP (pane_name)
3553 ? "" : SSDATA (pane_name));
3554 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
3555 pane_string++;
3557 lpane = tty_menu_add_pane (menu, pane_string);
3558 if (lpane == TTYM_FAILURE)
3560 tty_menu_destroy (menu);
3561 *error_name = "Can't create pane";
3562 entry = Qnil;
3563 goto tty_menu_end;
3565 i += MENU_ITEMS_PANE_LENGTH;
3567 /* Find the width of the widest item in this pane. */
3568 j = i;
3569 while (j < menu_items_used)
3571 Lisp_Object item;
3572 item = AREF (menu_items, j);
3573 if (EQ (item, Qt))
3574 break;
3575 if (NILP (item))
3577 j++;
3578 continue;
3580 width = SBYTES (item);
3581 if (width > maxwidth)
3582 maxwidth = width;
3584 j += MENU_ITEMS_ITEM_LENGTH;
3587 /* Ignore a nil in the item list.
3588 It's meaningful only for dialog boxes. */
3589 else if (EQ (AREF (menu_items, i), Qquote))
3590 i += 1;
3591 else
3593 /* Create a new item within current pane. */
3594 Lisp_Object item_name, enable, descrip, help;
3595 char *item_data;
3596 char const *help_string;
3598 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
3599 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
3600 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
3601 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
3602 help_string = STRINGP (help) ? SSDATA (help) : NULL;
3604 if (!NILP (descrip))
3606 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
3607 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
3608 for (j = SCHARS (item_name); j < maxwidth; j++)
3609 item_data[j] = ' ';
3610 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
3611 item_data[j + SBYTES (descrip)] = 0;
3613 else
3614 item_data = SSDATA (item_name);
3616 if (lpane == TTYM_FAILURE
3617 || (! tty_menu_add_selection (menu, lpane, item_data,
3618 !NILP (enable), help_string)))
3620 tty_menu_destroy (menu);
3621 *error_name = "Can't add selection to menu";
3622 entry = Qnil;
3623 goto tty_menu_end;
3625 i += MENU_ITEMS_ITEM_LENGTH;
3626 lines++;
3630 maxlines = max (maxlines, lines);
3632 /* All set and ready to fly. */
3633 dispwidth = f->text_cols;
3634 dispheight = f->text_lines;
3635 x = min (x, dispwidth);
3636 y = min (y, dispheight);
3637 x = max (x, 1);
3638 y = max (y, 1);
3639 tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
3640 if (ulx + width > dispwidth)
3642 x -= (ulx + width) - dispwidth;
3643 ulx = dispwidth - width;
3645 if (uly + height > dispheight)
3647 y -= (uly + height) - dispheight;
3648 uly = dispheight - height;
3651 if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 2)
3653 /* Move the menu away of the echo area, to avoid overwriting the
3654 menu with help echo messages or vice versa. */
3655 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
3657 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
3658 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
3660 else
3662 y -= 2;
3663 uly -= 2;
3667 if (ulx < 0) x -= ulx;
3668 if (uly < 0) y -= uly;
3670 #if 0
3671 /* This code doesn't make sense on a TTY, since it can easily annul
3672 the adjustments above that carefully avoid truncation of the menu
3673 items. I think it was written to fix some problem that only
3674 happens on X11. */
3675 if (! for_click)
3677 /* If position was not given by a mouse click, adjust so upper left
3678 corner of the menu as a whole ends up at given coordinates. This
3679 is what x-popup-menu says in its documentation. */
3680 x += width / 2;
3681 y += 1.5 * height / (maxlines + 2);
3683 #endif
3685 pane = selidx = 0;
3687 /* We save and restore the current buffer because tty_menu_activate
3688 triggers redisplay, which switches buffers at will. */
3689 record_unwind_protect (tty_pop_down_menu,
3690 make_save_ptr_ptr (menu, current_buffer));
3692 specbind (Qoverriding_terminal_local_map,
3693 Fsymbol_value (Qtty_menu_navigation_map));
3694 status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
3695 tty_menu_help_callback,
3696 menuflags & MENU_KBD_NAVIGATION);
3697 entry = pane_prefix = Qnil;
3699 switch (status)
3701 case TTYM_SUCCESS:
3702 /* Find the item number SELIDX in pane number PANE. */
3703 i = 0;
3704 while (i < menu_items_used)
3706 if (EQ (AREF (menu_items, i), Qt))
3708 if (pane == 0)
3709 pane_prefix
3710 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
3711 pane--;
3712 i += MENU_ITEMS_PANE_LENGTH;
3714 else
3716 if (pane == -1)
3718 if (selidx == 0)
3720 entry
3721 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
3722 if (menuflags & MENU_KEYMAPS)
3724 entry = Fcons (entry, Qnil);
3725 if (!NILP (pane_prefix))
3726 entry = Fcons (pane_prefix, entry);
3728 break;
3730 selidx--;
3732 i += MENU_ITEMS_ITEM_LENGTH;
3735 break;
3737 case TTYM_NEXT:
3738 case TTYM_PREV:
3739 tty_menu_new_item_coords (f, status, &item_x, &item_y);
3740 entry = Fcons (make_number (item_x), make_number (item_y));
3741 break;
3743 case TTYM_FAILURE:
3744 *error_name = "Can't activate menu";
3745 case TTYM_IA_SELECT:
3746 break;
3747 case TTYM_NO_SELECT:
3748 /* If the selected frame was changed while we displayed a menu,
3749 throw to top level in order to undo any temporary settings
3750 made by TTY menu code. */
3751 if (f != SELECTED_FRAME ())
3752 Ftop_level ();
3753 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
3754 the menu was invoked with a mouse event as POSITION). */
3755 if (!(menuflags & MENU_FOR_CLICK))
3756 quit ();
3757 break;
3760 tty_menu_end:
3762 SAFE_FREE ();
3763 unbind_to (specpdl_count, Qnil);
3764 return entry;
3767 #endif /* !MSDOS */
3770 #ifndef MSDOS
3771 /***********************************************************************
3772 Initialization
3773 ***********************************************************************/
3775 /* Initialize the tty-dependent part of frame F. The frame must
3776 already have its device initialized. */
3778 void
3779 create_tty_output (struct frame *f)
3781 struct tty_output *t = xzalloc (sizeof *t);
3783 eassert (FRAME_TERMCAP_P (f));
3785 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
3787 f->output_data.tty = t;
3790 /* Delete frame F's face cache, and its tty-dependent part. */
3792 static void
3793 tty_free_frame_resources (struct frame *f)
3795 eassert (FRAME_TERMCAP_P (f));
3796 free_frame_faces (f);
3797 xfree (f->output_data.tty);
3800 #else /* MSDOS */
3802 /* Delete frame F's face cache. */
3804 static void
3805 tty_free_frame_resources (struct frame *f)
3807 eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
3808 free_frame_faces (f);
3810 #endif /* MSDOS */
3812 /* Reset the hooks in TERMINAL. */
3814 static void
3815 clear_tty_hooks (struct terminal *terminal)
3817 terminal->rif = 0;
3818 terminal->cursor_to_hook = 0;
3819 terminal->raw_cursor_to_hook = 0;
3820 terminal->clear_to_end_hook = 0;
3821 terminal->clear_frame_hook = 0;
3822 terminal->clear_end_of_line_hook = 0;
3823 terminal->ins_del_lines_hook = 0;
3824 terminal->insert_glyphs_hook = 0;
3825 terminal->write_glyphs_hook = 0;
3826 terminal->delete_glyphs_hook = 0;
3827 terminal->ring_bell_hook = 0;
3828 terminal->reset_terminal_modes_hook = 0;
3829 terminal->set_terminal_modes_hook = 0;
3830 terminal->update_begin_hook = 0;
3831 terminal->update_end_hook = 0;
3832 terminal->set_terminal_window_hook = 0;
3833 terminal->mouse_position_hook = 0;
3834 terminal->frame_rehighlight_hook = 0;
3835 terminal->frame_raise_lower_hook = 0;
3836 terminal->fullscreen_hook = 0;
3837 terminal->menu_show_hook = 0;
3838 terminal->set_vertical_scroll_bar_hook = 0;
3839 terminal->set_horizontal_scroll_bar_hook = 0;
3840 terminal->condemn_scroll_bars_hook = 0;
3841 terminal->redeem_scroll_bar_hook = 0;
3842 terminal->judge_scroll_bars_hook = 0;
3843 terminal->read_socket_hook = 0;
3844 terminal->frame_up_to_date_hook = 0;
3846 /* Leave these two set, or suspended frames are not deleted
3847 correctly. */
3848 terminal->delete_frame_hook = &tty_free_frame_resources;
3849 terminal->delete_terminal_hook = &delete_tty;
3852 /* Initialize hooks in TERMINAL with the values needed for a tty. */
3854 static void
3855 set_tty_hooks (struct terminal *terminal)
3857 terminal->cursor_to_hook = &tty_cursor_to;
3858 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
3859 terminal->clear_to_end_hook = &tty_clear_to_end;
3860 terminal->clear_frame_hook = &tty_clear_frame;
3861 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
3862 terminal->ins_del_lines_hook = &tty_ins_del_lines;
3863 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3864 terminal->write_glyphs_hook = &tty_write_glyphs;
3865 terminal->delete_glyphs_hook = &tty_delete_glyphs;
3866 terminal->ring_bell_hook = &tty_ring_bell;
3867 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3868 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
3869 terminal->update_end_hook = &tty_update_end;
3870 #ifdef MSDOS
3871 terminal->menu_show_hook = &x_menu_show;
3872 #else
3873 terminal->menu_show_hook = &tty_menu_show;
3874 #endif
3875 terminal->set_terminal_window_hook = &tty_set_terminal_window;
3876 terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
3877 terminal->delete_frame_hook = &tty_free_frame_resources;
3878 terminal->delete_terminal_hook = &delete_tty;
3879 /* Other hooks are NULL by default. */
3882 /* If FD is the controlling terminal, drop it. */
3883 static void
3884 dissociate_if_controlling_tty (int fd)
3886 /* If tcgetpgrp succeeds, fd is the controlling terminal,
3887 so dissociate it by invoking setsid. */
3888 if (tcgetpgrp (fd) >= 0 && setsid () < 0)
3890 #ifdef TIOCNOTTY
3891 /* setsid failed, presumably because Emacs is already a process
3892 group leader. Fall back on the obsolescent way to dissociate
3893 a controlling tty. */
3894 sigset_t oldset;
3895 block_tty_out_signal (&oldset);
3896 ioctl (fd, TIOCNOTTY, 0);
3897 unblock_tty_out_signal (&oldset);
3898 #endif
3902 /* Create a termcap display on the tty device with the given name and
3903 type.
3905 If NAME is NULL, then use the controlling tty, i.e., DEV_TTY.
3906 Otherwise NAME should be a path to the tty device file,
3907 e.g. "/dev/pts/7".
3909 TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
3911 If MUST_SUCCEED is true, then all errors are fatal. */
3913 struct terminal *
3914 init_tty (const char *name, const char *terminal_type, bool must_succeed)
3916 struct tty_display_info *tty = NULL;
3917 struct terminal *terminal = NULL;
3918 #ifndef DOS_NT
3919 char *area;
3920 char **address = &area;
3921 int status;
3922 sigset_t oldset;
3923 bool ctty = false; /* True if asked to open controlling tty. */
3924 #endif
3926 if (!terminal_type)
3927 maybe_fatal (must_succeed, 0,
3928 "Unknown terminal type",
3929 "Unknown terminal type");
3931 if (name == NULL)
3932 name = DEV_TTY;
3933 #ifndef DOS_NT
3934 if (!strcmp (name, DEV_TTY))
3935 ctty = 1;
3936 #endif
3938 /* If we already have a terminal on the given device, use that. If
3939 all such terminals are suspended, create a new one instead. */
3940 /* XXX Perhaps this should be made explicit by having init_tty
3941 always create a new terminal and separating terminal and frame
3942 creation on Lisp level. */
3943 terminal = get_named_terminal (name);
3944 if (terminal)
3945 return terminal;
3947 terminal = create_terminal (output_termcap, NULL);
3948 #ifdef MSDOS
3949 if (been_here > 0)
3950 maybe_fatal (0, 0, "Attempt to create another terminal %s", "",
3951 name, "");
3952 been_here = 1;
3953 tty = &the_only_display_info;
3954 #else
3955 tty = xzalloc (sizeof *tty);
3956 #endif
3957 tty->top_frame = Qnil;
3958 tty->next = tty_list;
3959 tty_list = tty;
3961 terminal->display_info.tty = tty;
3962 tty->terminal = terminal;
3964 tty->Wcm = xmalloc (sizeof *tty->Wcm);
3965 Wcm_clear (tty);
3967 encode_terminal_src_size = 0;
3968 encode_terminal_dst_size = 0;
3971 #ifndef DOS_NT
3972 set_tty_hooks (terminal);
3975 /* Open the terminal device. */
3977 /* If !ctty, don't recognize it as our controlling terminal, and
3978 don't make it the controlling tty if we don't have one now.
3980 Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
3981 defined on Hurd. On other systems, we need to explicitly
3982 dissociate ourselves from the controlling tty when we want to
3983 open a frame on the same terminal. */
3984 int flags = O_RDWR | O_NOCTTY | (ctty ? 0 : O_IGNORE_CTTY);
3985 int fd = emacs_open (name, flags, 0);
3986 tty->input = tty->output
3987 = ((fd < 0 || ! isatty (fd))
3988 ? NULL
3989 : fdopen (fd, "w+"));
3991 if (! tty->input)
3993 char const *diagnostic
3994 = (fd < 0) ? "Could not open file: %s" : "Not a tty device: %s";
3995 emacs_close (fd);
3996 maybe_fatal (must_succeed, terminal, diagnostic, diagnostic, name);
3999 tty->name = xstrdup (name);
4000 terminal->name = xstrdup (name);
4002 if (!O_IGNORE_CTTY && !ctty)
4003 dissociate_if_controlling_tty (fd);
4006 tty->type = xstrdup (terminal_type);
4008 add_keyboard_wait_descriptor (fileno (tty->input));
4010 Wcm_clear (tty);
4012 /* On some systems, tgetent tries to access the controlling
4013 terminal. */
4014 block_tty_out_signal (&oldset);
4015 status = tgetent (tty->termcap_term_buffer, terminal_type);
4016 if (tty->termcap_term_buffer[TERMCAP_BUFFER_SIZE - 1])
4017 emacs_abort ();
4018 unblock_tty_out_signal (&oldset);
4020 if (status < 0)
4022 #ifdef TERMINFO
4023 maybe_fatal (must_succeed, terminal,
4024 "Cannot open terminfo database file",
4025 "Cannot open terminfo database file");
4026 #else
4027 maybe_fatal (must_succeed, terminal,
4028 "Cannot open termcap database file",
4029 "Cannot open termcap database file");
4030 #endif
4032 if (status == 0)
4034 maybe_fatal (must_succeed, terminal,
4035 "Terminal type %s is not defined",
4036 "Terminal type %s is not defined.\n\
4037 If that is not the actual type of terminal you have,\n\
4038 use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\
4039 'setenv TERM ...') to specify the correct type. It may be necessary\n"
4040 #ifdef TERMINFO
4041 "to do 'unset TERMINFO' (C-shell: 'unsetenv TERMINFO') as well.",
4042 #else
4043 "to do 'unset TERMCAP' (C-shell: 'unsetenv TERMCAP') as well.",
4044 #endif
4045 terminal_type);
4048 area = tty->termcap_strings_buffer;
4049 tty->TS_ins_line = tgetstr ("al", address);
4050 tty->TS_ins_multi_lines = tgetstr ("AL", address);
4051 tty->TS_bell = tgetstr ("bl", address);
4052 BackTab (tty) = tgetstr ("bt", address);
4053 tty->TS_clr_to_bottom = tgetstr ("cd", address);
4054 tty->TS_clr_line = tgetstr ("ce", address);
4055 tty->TS_clr_frame = tgetstr ("cl", address);
4056 ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
4057 AbsPosition (tty) = tgetstr ("cm", address);
4058 CR (tty) = tgetstr ("cr", address);
4059 tty->TS_set_scroll_region = tgetstr ("cs", address);
4060 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
4061 RowPosition (tty) = tgetstr ("cv", address);
4062 tty->TS_del_char = tgetstr ("dc", address);
4063 tty->TS_del_multi_chars = tgetstr ("DC", address);
4064 tty->TS_del_line = tgetstr ("dl", address);
4065 tty->TS_del_multi_lines = tgetstr ("DL", address);
4066 tty->TS_delete_mode = tgetstr ("dm", address);
4067 tty->TS_end_delete_mode = tgetstr ("ed", address);
4068 tty->TS_end_insert_mode = tgetstr ("ei", address);
4069 Home (tty) = tgetstr ("ho", address);
4070 tty->TS_ins_char = tgetstr ("ic", address);
4071 tty->TS_ins_multi_chars = tgetstr ("IC", address);
4072 tty->TS_insert_mode = tgetstr ("im", address);
4073 tty->TS_pad_inserted_char = tgetstr ("ip", address);
4074 tty->TS_end_keypad_mode = tgetstr ("ke", address);
4075 tty->TS_keypad_mode = tgetstr ("ks", address);
4076 LastLine (tty) = tgetstr ("ll", address);
4077 Right (tty) = tgetstr ("nd", address);
4078 Down (tty) = tgetstr ("do", address);
4079 if (!Down (tty))
4080 Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do". */
4081 if (tgetflag ("bs"))
4082 Left (tty) = "\b"; /* Can't possibly be longer! */
4083 else /* (Actually, "bs" is obsolete...) */
4084 Left (tty) = tgetstr ("le", address);
4085 if (!Left (tty))
4086 Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le". */
4087 tty->TS_pad_char = tgetstr ("pc", address);
4088 tty->TS_repeat = tgetstr ("rp", address);
4089 tty->TS_end_standout_mode = tgetstr ("se", address);
4090 tty->TS_fwd_scroll = tgetstr ("sf", address);
4091 tty->TS_standout_mode = tgetstr ("so", address);
4092 tty->TS_rev_scroll = tgetstr ("sr", address);
4093 tty->Wcm->cm_tab = tgetstr ("ta", address);
4094 tty->TS_end_termcap_modes = tgetstr ("te", address);
4095 tty->TS_termcap_modes = tgetstr ("ti", address);
4096 Up (tty) = tgetstr ("up", address);
4097 tty->TS_visible_bell = tgetstr ("vb", address);
4098 tty->TS_cursor_normal = tgetstr ("ve", address);
4099 tty->TS_cursor_visible = tgetstr ("vs", address);
4100 tty->TS_cursor_invisible = tgetstr ("vi", address);
4101 tty->TS_set_window = tgetstr ("wi", address);
4103 tty->TS_enter_underline_mode = tgetstr ("us", address);
4104 tty->TS_exit_underline_mode = tgetstr ("ue", address);
4105 tty->TS_enter_bold_mode = tgetstr ("md", address);
4106 tty->TS_enter_italic_mode = tgetstr ("ZH", address);
4107 tty->TS_enter_dim_mode = tgetstr ("mh", address);
4108 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
4109 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
4110 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
4111 tty->TS_exit_attribute_mode = tgetstr ("me", address);
4113 MultiUp (tty) = tgetstr ("UP", address);
4114 MultiDown (tty) = tgetstr ("DO", address);
4115 MultiLeft (tty) = tgetstr ("LE", address);
4116 MultiRight (tty) = tgetstr ("RI", address);
4118 /* SVr4/ANSI color support. If "op" isn't available, don't support
4119 color because we can't switch back to the default foreground and
4120 background. */
4121 tty->TS_orig_pair = tgetstr ("op", address);
4122 if (tty->TS_orig_pair)
4124 tty->TS_set_foreground = tgetstr ("AF", address);
4125 tty->TS_set_background = tgetstr ("AB", address);
4126 if (!tty->TS_set_foreground)
4128 /* SVr4. */
4129 tty->TS_set_foreground = tgetstr ("Sf", address);
4130 tty->TS_set_background = tgetstr ("Sb", address);
4133 tty->TN_max_colors = tgetnum ("Co");
4135 #ifdef TERMINFO
4136 /* Non-standard support for 24-bit colors. */
4138 const char *fg = tigetstr ("setf24");
4139 const char *bg = tigetstr ("setb24");
4140 if (fg && bg
4141 && fg != (char *) (intptr_t) -1
4142 && bg != (char *) (intptr_t) -1)
4144 tty->TS_set_foreground = fg;
4145 tty->TS_set_background = bg;
4146 tty->TN_max_colors = 16777216;
4149 #endif
4151 tty->TN_no_color_video = tgetnum ("NC");
4152 if (tty->TN_no_color_video == -1)
4153 tty->TN_no_color_video = 0;
4156 tty_default_color_capabilities (tty, 1);
4158 MagicWrap (tty) = tgetflag ("xn");
4159 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
4160 the former flag imply the latter. */
4161 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
4162 tty->memory_below_frame = tgetflag ("db");
4163 tty->TF_hazeltine = tgetflag ("hz");
4164 tty->must_write_spaces = tgetflag ("in");
4165 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
4166 tty->TF_insmode_motion = tgetflag ("mi");
4167 tty->TF_standout_motion = tgetflag ("ms");
4168 tty->TF_underscore = tgetflag ("ul");
4169 tty->TF_teleray = tgetflag ("xt");
4171 #else /* DOS_NT */
4172 #ifdef WINDOWSNT
4174 struct frame *f = XFRAME (selected_frame);
4175 int height, width;
4177 initialize_w32_display (terminal, &width, &height);
4179 FrameRows (tty) = height;
4180 FrameCols (tty) = width;
4181 tty->specified_window = height;
4183 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
4184 FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) = 0;
4185 tty->char_ins_del_ok = 1;
4186 baud_rate = 19200;
4188 #else /* MSDOS */
4190 int height, width;
4191 if (strcmp (terminal_type, "internal") == 0)
4192 terminal->type = output_msdos_raw;
4193 initialize_msdos_display (terminal);
4195 get_tty_size (fileno (tty->input), &width, &height);
4196 FrameCols (tty) = width;
4197 FrameRows (tty) = height;
4198 tty->char_ins_del_ok = 0;
4199 init_baud_rate (fileno (tty->input));
4201 #endif /* MSDOS */
4202 tty->output = stdout;
4203 tty->input = stdin;
4204 /* The following two are inaccessible from w32console.c. */
4205 terminal->delete_frame_hook = &tty_free_frame_resources;
4206 terminal->delete_terminal_hook = &delete_tty;
4208 tty->name = xstrdup (name);
4209 terminal->name = xstrdup (name);
4210 tty->type = xstrdup (terminal_type);
4212 add_keyboard_wait_descriptor (0);
4214 tty->delete_in_insert_mode = 1;
4216 UseTabs (tty) = 0;
4217 tty->scroll_region_ok = 0;
4219 /* Seems to insert lines when it's not supposed to, messing up the
4220 display. In doing a trace, it didn't seem to be called much, so I
4221 don't think we're losing anything by turning it off. */
4222 tty->line_ins_del_ok = 0;
4224 tty->TN_max_colors = 16; /* Must be non-zero for tty-display-color-p. */
4225 #endif /* DOS_NT */
4227 #ifdef HAVE_GPM
4228 terminal->mouse_position_hook = term_mouse_position;
4229 tty->mouse_highlight.mouse_face_window = Qnil;
4230 #endif
4232 terminal->kboard = allocate_kboard (Qnil);
4233 terminal->kboard->reference_count++;
4234 /* Don't let the initial kboard remain current longer than necessary.
4235 That would cause problems if a file loaded on startup tries to
4236 prompt in the mini-buffer. */
4237 if (current_kboard == initial_kboard)
4238 current_kboard = terminal->kboard;
4239 #ifndef DOS_NT
4240 term_get_fkeys (address, terminal->kboard);
4242 /* Get frame size from system, or else from termcap. */
4244 int height, width;
4245 get_tty_size (fileno (tty->input), &width, &height);
4246 FrameCols (tty) = width;
4247 FrameRows (tty) = height;
4250 if (FrameCols (tty) <= 0)
4251 FrameCols (tty) = tgetnum ("co");
4252 if (FrameRows (tty) <= 0)
4253 FrameRows (tty) = tgetnum ("li");
4255 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
4256 maybe_fatal (must_succeed, terminal,
4257 "Screen size %dx%d is too small",
4258 "Screen size %dx%d is too small",
4259 FrameCols (tty), FrameRows (tty));
4261 TabWidth (tty) = tgetnum ("tw");
4263 if (!tty->TS_bell)
4264 tty->TS_bell = "\07";
4266 if (!tty->TS_fwd_scroll)
4267 tty->TS_fwd_scroll = Down (tty);
4269 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
4271 if (TabWidth (tty) < 0)
4272 TabWidth (tty) = 8;
4274 /* Turned off since /etc/termcap seems to have :ta= for most terminals
4275 and newer termcap doc does not seem to say there is a default.
4276 if (!tty->Wcm->cm_tab)
4277 tty->Wcm->cm_tab = "\t";
4280 /* We don't support standout modes that use `magic cookies', so
4281 turn off any that do. */
4282 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
4284 tty->TS_standout_mode = 0;
4285 tty->TS_end_standout_mode = 0;
4287 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
4289 tty->TS_enter_underline_mode = 0;
4290 tty->TS_exit_underline_mode = 0;
4293 /* If there's no standout mode, try to use underlining instead. */
4294 if (tty->TS_standout_mode == 0)
4296 tty->TS_standout_mode = tty->TS_enter_underline_mode;
4297 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
4300 /* If no `se' string, try using a `me' string instead.
4301 If that fails, we can't use standout mode at all. */
4302 if (tty->TS_end_standout_mode == 0)
4304 char *s = tgetstr ("me", address);
4305 if (s != 0)
4306 tty->TS_end_standout_mode = s;
4307 else
4308 tty->TS_standout_mode = 0;
4311 if (tty->TF_teleray)
4313 tty->Wcm->cm_tab = 0;
4314 /* We can't support standout mode, because it uses magic cookies. */
4315 tty->TS_standout_mode = 0;
4316 /* But that means we cannot rely on ^M to go to column zero! */
4317 CR (tty) = 0;
4318 /* LF can't be trusted either -- can alter hpos. */
4319 /* If move at column 0 thru a line with TS_standout_mode. */
4320 Down (tty) = 0;
4323 tty->specified_window = FrameRows (tty);
4325 if (Wcm_init (tty) == -1) /* Can't do cursor motion. */
4327 maybe_fatal (must_succeed, terminal,
4328 "Terminal type \"%s\" is not powerful enough to run Emacs",
4329 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
4330 It lacks the ability to position the cursor.\n\
4331 If that is not the actual type of terminal you have,\n\
4332 use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\
4333 'setenv TERM ...') to specify the correct type. It may be necessary\n"
4334 # ifdef TERMINFO
4335 "to do 'unset TERMINFO' (C-shell: 'unsetenv TERMINFO') as well.",
4336 # else /* TERMCAP */
4337 "to do 'unset TERMCAP' (C-shell: 'unsetenv TERMCAP') as well.",
4338 # endif /* TERMINFO */
4339 terminal_type);
4342 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
4343 maybe_fatal (must_succeed, terminal,
4344 "Could not determine the frame size",
4345 "Could not determine the frame size");
4347 tty->delete_in_insert_mode
4348 = tty->TS_delete_mode && tty->TS_insert_mode
4349 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
4351 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
4353 tty->scroll_region_ok
4354 = (tty->Wcm->cm_abs
4355 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
4357 tty->line_ins_del_ok
4358 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
4359 && (tty->TS_del_line || tty->TS_del_multi_lines))
4360 || (tty->scroll_region_ok
4361 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
4363 tty->char_ins_del_ok
4364 = ((tty->TS_ins_char || tty->TS_insert_mode
4365 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
4366 && (tty->TS_del_char || tty->TS_del_multi_chars));
4368 init_baud_rate (fileno (tty->input));
4370 #endif /* not DOS_NT */
4372 /* Init system terminal modes (RAW or CBREAK, etc.). */
4373 init_sys_modes (tty);
4375 return terminal;
4379 static void
4380 vfatal (const char *str, va_list ap)
4382 fprintf (stderr, "emacs: ");
4383 vfprintf (stderr, str, ap);
4384 if (!(strlen (str) > 0 && str[strlen (str) - 1] == '\n'))
4385 fprintf (stderr, "\n");
4386 fflush (stderr);
4387 exit (1);
4391 /* Auxiliary error-handling function for init_tty.
4392 Delete TERMINAL, then call error or fatal with str1 or str2,
4393 respectively, according to whether MUST_SUCCEED is true. */
4395 static void
4396 maybe_fatal (bool must_succeed, struct terminal *terminal,
4397 const char *str1, const char *str2, ...)
4399 va_list ap;
4400 va_start (ap, str2);
4401 if (terminal)
4402 delete_tty (terminal);
4404 if (must_succeed)
4405 vfatal (str2, ap);
4406 else
4407 verror (str1, ap);
4410 void
4411 fatal (const char *str, ...)
4413 va_list ap;
4414 va_start (ap, str);
4415 vfatal (str, ap);
4420 /* Delete the given tty terminal, closing all frames on it. */
4422 static void
4423 delete_tty (struct terminal *terminal)
4425 struct tty_display_info *tty;
4427 /* Protect against recursive calls. delete_frame in
4428 delete_terminal calls us back when it deletes our last frame. */
4429 if (!terminal->name)
4430 return;
4432 eassert (terminal->type == output_termcap);
4434 tty = terminal->display_info.tty;
4436 if (tty == tty_list)
4437 tty_list = tty->next;
4438 else
4440 struct tty_display_info *p;
4441 for (p = tty_list; p && p->next != tty; p = p->next)
4444 if (! p)
4445 /* This should not happen. */
4446 emacs_abort ();
4448 p->next = tty->next;
4449 tty->next = 0;
4452 /* reset_sys_modes needs a valid device, so this call needs to be
4453 before delete_terminal. */
4454 reset_sys_modes (tty);
4456 delete_terminal (terminal);
4458 xfree (tty->name);
4459 xfree (tty->type);
4461 if (tty->input)
4463 delete_keyboard_wait_descriptor (fileno (tty->input));
4464 if (tty->input != stdin)
4465 fclose (tty->input);
4467 if (tty->output && tty->output != stdout && tty->output != tty->input)
4468 fclose (tty->output);
4469 if (tty->termscript)
4470 fclose (tty->termscript);
4472 xfree (tty->old_tty);
4473 xfree (tty->Wcm);
4474 xfree (tty);
4477 void
4478 syms_of_term (void)
4480 DEFVAR_BOOL ("system-uses-terminfo", system_uses_terminfo,
4481 doc: /* Non-nil means the system uses terminfo rather than termcap.
4482 This variable can be used by terminal emulator packages. */);
4483 #ifdef TERMINFO
4484 system_uses_terminfo = 1;
4485 #else
4486 system_uses_terminfo = 0;
4487 #endif
4489 DEFVAR_LISP ("suspend-tty-functions", Vsuspend_tty_functions,
4490 doc: /* Functions run after suspending a tty.
4491 The functions are run with one argument, the terminal object to be suspended.
4492 See `suspend-tty'. */);
4493 Vsuspend_tty_functions = Qnil;
4496 DEFVAR_LISP ("resume-tty-functions", Vresume_tty_functions,
4497 doc: /* Functions run after resuming a tty.
4498 The functions are run with one argument, the terminal object that was revived.
4499 See `resume-tty'. */);
4500 Vresume_tty_functions = Qnil;
4502 DEFVAR_BOOL ("visible-cursor", visible_cursor,
4503 doc: /* Non-nil means to make the cursor very visible.
4504 This only has an effect when running in a text terminal.
4505 What means \"very visible\" is up to your terminal. It may make the cursor
4506 bigger, or it may make it blink, or it may do nothing at all. */);
4507 visible_cursor = 1;
4509 defsubr (&Stty_display_color_p);
4510 defsubr (&Stty_display_color_cells);
4511 defsubr (&Stty_no_underline);
4512 defsubr (&Stty_type);
4513 defsubr (&Scontrolling_tty_p);
4514 defsubr (&Stty_top_frame);
4515 defsubr (&Ssuspend_tty);
4516 defsubr (&Sresume_tty);
4517 #ifdef HAVE_GPM
4518 defsubr (&Sgpm_mouse_start);
4519 defsubr (&Sgpm_mouse_stop);
4520 #endif /* HAVE_GPM */
4522 #ifndef DOS_NT
4523 default_orig_pair = NULL;
4524 default_set_foreground = NULL;
4525 default_set_background = NULL;
4526 #endif /* !DOS_NT */
4528 encode_terminal_src = NULL;
4529 encode_terminal_dst = NULL;
4531 DEFSYM (Qtty_mode_set_strings, "tty-mode-set-strings");
4532 DEFSYM (Qtty_mode_reset_strings, "tty-mode-reset-strings");
4534 #ifndef MSDOS
4535 DEFSYM (Qtty_menu_next_item, "tty-menu-next-item");
4536 DEFSYM (Qtty_menu_prev_item, "tty-menu-prev-item");
4537 DEFSYM (Qtty_menu_next_menu, "tty-menu-next-menu");
4538 DEFSYM (Qtty_menu_prev_menu, "tty-menu-prev-menu");
4539 DEFSYM (Qtty_menu_select, "tty-menu-select");
4540 DEFSYM (Qtty_menu_ignore, "tty-menu-ignore");
4541 DEFSYM (Qtty_menu_exit, "tty-menu-exit");
4542 DEFSYM (Qtty_menu_mouse_movement, "tty-menu-mouse-movement");
4543 DEFSYM (Qtty_menu_navigation_map, "tty-menu-navigation-map");
4544 #endif