Fix etc/tutorials/TUTORIAL.he, again.
[emacs.git] / src / term.c
blobc8ff6f315757263dae9e9b66729ccd5121a800f2
1 /* Terminal control module for terminals described by TERMCAP
2 Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2014 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
10 (at 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 <sys/file.h>
27 #include <sys/time.h>
28 #include <unistd.h>
30 #include "lisp.h"
31 #include "termchar.h"
32 #include "tparam.h"
33 #include "character.h"
34 #include "buffer.h"
35 #include "charset.h"
36 #include "coding.h"
37 #include "composite.h"
38 #include "keyboard.h"
39 #include "frame.h"
40 #include "disptab.h"
41 #include "termhooks.h"
42 #include "dispextern.h"
43 #include "window.h"
44 #include "keymap.h"
45 #include "blockinput.h"
46 #include "syssignal.h"
47 #include "systty.h"
48 #include "intervals.h"
49 #ifdef MSDOS
50 #include "msdos.h"
51 static int been_here = -1;
52 #endif
54 #ifdef USE_X_TOOLKIT
55 #include "../lwlib/lwlib.h"
56 #endif
58 #include "cm.h"
59 #ifdef HAVE_X_WINDOWS
60 #include "xterm.h"
61 #endif
63 #include "menu.h"
65 /* The name of the default console device. */
66 #ifdef WINDOWSNT
67 #define DEV_TTY "CONOUT$"
68 #include "w32term.h"
69 #else
70 #define DEV_TTY "/dev/tty"
71 #endif
73 static void tty_set_scroll_region (struct frame *f, int start, int stop);
74 static void turn_on_face (struct frame *, int face_id);
75 static void turn_off_face (struct frame *, int face_id);
76 static void tty_turn_off_highlight (struct tty_display_info *);
77 static void tty_show_cursor (struct tty_display_info *);
78 static void tty_hide_cursor (struct tty_display_info *);
79 static void tty_background_highlight (struct tty_display_info *tty);
80 static struct terminal *get_tty_terminal (Lisp_Object, bool);
81 static void clear_tty_hooks (struct terminal *terminal);
82 static void set_tty_hooks (struct terminal *terminal);
83 static void dissociate_if_controlling_tty (int fd);
84 static void delete_tty (struct terminal *);
85 static _Noreturn void maybe_fatal (bool, struct terminal *,
86 const char *, const char *, ...)
87 ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5);
88 static _Noreturn void vfatal (const char *str, va_list ap)
89 ATTRIBUTE_FORMAT_PRINTF (1, 0);
92 #define OUTPUT(tty, a) \
93 emacs_tputs ((tty), a, \
94 FRAME_TOTAL_LINES (XFRAME (selected_frame)) - curY (tty), \
95 cmputc)
97 #define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
98 #define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
100 #define OUTPUT_IF(tty, a) \
101 do { \
102 if (a) \
103 OUTPUT (tty, a); \
104 } while (0)
106 #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
108 /* Display space properties. */
110 /* Chain of all tty device parameters. */
111 struct tty_display_info *tty_list;
113 /* Meaning of bits in no_color_video. Each bit set means that the
114 corresponding attribute cannot be combined with colors. */
116 enum no_color_bit
118 NC_STANDOUT = 1 << 0,
119 NC_UNDERLINE = 1 << 1,
120 NC_REVERSE = 1 << 2,
121 NC_ITALIC = 1 << 3,
122 NC_DIM = 1 << 4,
123 NC_BOLD = 1 << 5,
124 NC_INVIS = 1 << 6,
125 NC_PROTECT = 1 << 7
128 /* internal state */
130 /* The largest frame width in any call to calculate_costs. */
132 static int max_frame_cols;
134 static Lisp_Object Qtty_mode_set_strings;
135 static Lisp_Object Qtty_mode_reset_strings;
139 #ifdef HAVE_GPM
140 #include <sys/fcntl.h>
142 /* The device for which we have enabled gpm support (or NULL). */
143 struct tty_display_info *gpm_tty = NULL;
145 /* Last recorded mouse coordinates. */
146 static int last_mouse_x, last_mouse_y;
147 #endif /* HAVE_GPM */
149 /* Ring the bell on a tty. */
151 static void
152 tty_ring_bell (struct frame *f)
154 struct tty_display_info *tty = FRAME_TTY (f);
156 if (tty->output)
158 OUTPUT (tty, (tty->TS_visible_bell && visible_bell
159 ? tty->TS_visible_bell
160 : tty->TS_bell));
161 fflush (tty->output);
165 /* Set up termcap modes for Emacs. */
167 static void
168 tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
170 Lisp_Object lisp_terminal;
171 Lisp_Object extra_codes;
172 struct tty_display_info *tty = terminal->display_info.tty;
174 XSETTERMINAL (lisp_terminal, terminal);
175 for (extra_codes = Fterminal_parameter (lisp_terminal, sym);
176 CONSP (extra_codes);
177 extra_codes = XCDR (extra_codes))
179 Lisp_Object string = XCAR (extra_codes);
180 if (STRINGP (string))
182 fwrite (SDATA (string), 1, SBYTES (string), tty->output);
183 if (tty->termscript)
184 fwrite (SDATA (string), 1, SBYTES (string), tty->termscript);
189 static void
190 tty_set_terminal_modes (struct terminal *terminal)
192 struct tty_display_info *tty = terminal->display_info.tty;
194 if (tty->output)
196 if (tty->TS_termcap_modes)
197 OUTPUT (tty, tty->TS_termcap_modes);
198 else
200 /* Output enough newlines to scroll all the old screen contents
201 off the screen, so it won't be overwritten and lost. */
202 int i;
203 current_tty = tty;
204 for (i = 0; i < FRAME_TOTAL_LINES (XFRAME (selected_frame)); i++)
205 cmputc ('\n');
208 OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
209 OUTPUT_IF (tty, tty->TS_keypad_mode);
210 losecursor (tty);
211 tty_send_additional_strings (terminal, Qtty_mode_set_strings);
212 fflush (tty->output);
216 /* Reset termcap modes before exiting Emacs. */
218 static void
219 tty_reset_terminal_modes (struct terminal *terminal)
221 struct tty_display_info *tty = terminal->display_info.tty;
223 if (tty->output)
225 tty_send_additional_strings (terminal, Qtty_mode_reset_strings);
226 tty_turn_off_highlight (tty);
227 tty_turn_off_insert (tty);
228 OUTPUT_IF (tty, tty->TS_end_keypad_mode);
229 OUTPUT_IF (tty, tty->TS_cursor_normal);
230 OUTPUT_IF (tty, tty->TS_end_termcap_modes);
231 OUTPUT_IF (tty, tty->TS_orig_pair);
232 /* Output raw CR so kernel can track the cursor hpos. */
233 current_tty = tty;
234 cmputc ('\r');
235 fflush (tty->output);
239 /* Flag the end of a display update on a termcap terminal. */
241 static void
242 tty_update_end (struct frame *f)
244 struct tty_display_info *tty = FRAME_TTY (f);
246 if (!XWINDOW (selected_window)->cursor_off_p)
247 tty_show_cursor (tty);
248 tty_turn_off_insert (tty);
249 tty_background_highlight (tty);
250 fflush (tty->output);
253 /* The implementation of set_terminal_window for termcap frames. */
255 static void
256 tty_set_terminal_window (struct frame *f, int size)
258 struct tty_display_info *tty = FRAME_TTY (f);
260 tty->specified_window = size ? size : FRAME_TOTAL_LINES (f);
261 if (FRAME_SCROLL_REGION_OK (f))
262 tty_set_scroll_region (f, 0, tty->specified_window);
265 static void
266 tty_set_scroll_region (struct frame *f, int start, int stop)
268 char *buf;
269 struct tty_display_info *tty = FRAME_TTY (f);
271 if (tty->TS_set_scroll_region)
272 buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1, 0, 0);
273 else if (tty->TS_set_scroll_region_1)
274 buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
275 FRAME_TOTAL_LINES (f), start,
276 FRAME_TOTAL_LINES (f) - stop,
277 FRAME_TOTAL_LINES (f));
278 else
279 buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
281 OUTPUT (tty, buf);
282 xfree (buf);
283 losecursor (tty);
287 static void
288 tty_turn_on_insert (struct tty_display_info *tty)
290 if (!tty->insert_mode)
291 OUTPUT (tty, tty->TS_insert_mode);
292 tty->insert_mode = 1;
295 void
296 tty_turn_off_insert (struct tty_display_info *tty)
298 if (tty->insert_mode)
299 OUTPUT (tty, tty->TS_end_insert_mode);
300 tty->insert_mode = 0;
303 /* Handle highlighting. */
305 static void
306 tty_turn_off_highlight (struct tty_display_info *tty)
308 if (tty->standout_mode)
309 OUTPUT_IF (tty, tty->TS_end_standout_mode);
310 tty->standout_mode = 0;
313 static void
314 tty_turn_on_highlight (struct tty_display_info *tty)
316 if (!tty->standout_mode)
317 OUTPUT_IF (tty, tty->TS_standout_mode);
318 tty->standout_mode = 1;
321 static void
322 tty_toggle_highlight (struct tty_display_info *tty)
324 if (tty->standout_mode)
325 tty_turn_off_highlight (tty);
326 else
327 tty_turn_on_highlight (tty);
331 /* Make cursor invisible. */
333 static void
334 tty_hide_cursor (struct tty_display_info *tty)
336 if (tty->cursor_hidden == 0)
338 tty->cursor_hidden = 1;
339 #ifdef WINDOWSNT
340 w32con_hide_cursor ();
341 #else
342 OUTPUT_IF (tty, tty->TS_cursor_invisible);
343 #endif
348 /* Ensure that cursor is visible. */
350 static void
351 tty_show_cursor (struct tty_display_info *tty)
353 if (tty->cursor_hidden)
355 tty->cursor_hidden = 0;
356 #ifdef WINDOWSNT
357 w32con_show_cursor ();
358 #else
359 OUTPUT_IF (tty, tty->TS_cursor_normal);
360 if (visible_cursor)
361 OUTPUT_IF (tty, tty->TS_cursor_visible);
362 #endif
367 /* Set standout mode to the state it should be in for
368 empty space inside windows. What this is,
369 depends on the user option inverse-video. */
371 static void
372 tty_background_highlight (struct tty_display_info *tty)
374 if (inverse_video)
375 tty_turn_on_highlight (tty);
376 else
377 tty_turn_off_highlight (tty);
380 /* Set standout mode to the mode specified for the text to be output. */
382 static void
383 tty_highlight_if_desired (struct tty_display_info *tty)
385 if (inverse_video)
386 tty_turn_on_highlight (tty);
387 else
388 tty_turn_off_highlight (tty);
392 /* Move cursor to row/column position VPOS/HPOS. HPOS/VPOS are
393 frame-relative coordinates. */
395 static void
396 tty_cursor_to (struct frame *f, int vpos, int hpos)
398 struct tty_display_info *tty = FRAME_TTY (f);
400 /* Detect the case where we are called from reset_sys_modes
401 and the costs have never been calculated. Do nothing. */
402 if (! tty->costs_set)
403 return;
405 if (curY (tty) == vpos
406 && curX (tty) == hpos)
407 return;
408 if (!tty->TF_standout_motion)
409 tty_background_highlight (tty);
410 if (!tty->TF_insmode_motion)
411 tty_turn_off_insert (tty);
412 cmgoto (tty, vpos, hpos);
415 /* Similar but don't take any account of the wasted characters. */
417 static void
418 tty_raw_cursor_to (struct frame *f, int row, int col)
420 struct tty_display_info *tty = FRAME_TTY (f);
422 if (curY (tty) == row
423 && curX (tty) == col)
424 return;
425 if (!tty->TF_standout_motion)
426 tty_background_highlight (tty);
427 if (!tty->TF_insmode_motion)
428 tty_turn_off_insert (tty);
429 cmgoto (tty, row, col);
432 /* Erase operations */
434 /* Clear from cursor to end of frame on a termcap device. */
436 static void
437 tty_clear_to_end (struct frame *f)
439 register int i;
440 struct tty_display_info *tty = FRAME_TTY (f);
442 if (tty->TS_clr_to_bottom)
444 tty_background_highlight (tty);
445 OUTPUT (tty, tty->TS_clr_to_bottom);
447 else
449 for (i = curY (tty); i < FRAME_TOTAL_LINES (f); i++)
451 cursor_to (f, i, 0);
452 clear_end_of_line (f, FRAME_COLS (f));
457 /* Clear an entire termcap frame. */
459 static void
460 tty_clear_frame (struct frame *f)
462 struct tty_display_info *tty = FRAME_TTY (f);
464 if (tty->TS_clr_frame)
466 tty_background_highlight (tty);
467 OUTPUT (tty, tty->TS_clr_frame);
468 cmat (tty, 0, 0);
470 else
472 cursor_to (f, 0, 0);
473 clear_to_end (f);
477 /* An implementation of clear_end_of_line for termcap frames.
479 Note that the cursor may be moved, on terminals lacking a `ce' string. */
481 static void
482 tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
484 register int i;
485 struct tty_display_info *tty = FRAME_TTY (f);
487 /* Detect the case where we are called from reset_sys_modes
488 and the costs have never been calculated. Do nothing. */
489 if (! tty->costs_set)
490 return;
492 if (curX (tty) >= first_unused_hpos)
493 return;
494 tty_background_highlight (tty);
495 if (tty->TS_clr_line)
497 OUTPUT1 (tty, tty->TS_clr_line);
499 else
500 { /* have to do it the hard way */
501 tty_turn_off_insert (tty);
503 /* Do not write in last row last col with Auto-wrap on. */
504 if (AutoWrap (tty)
505 && curY (tty) == FrameRows (tty) - 1
506 && first_unused_hpos == FrameCols (tty))
507 first_unused_hpos--;
509 for (i = curX (tty); i < first_unused_hpos; i++)
511 if (tty->termscript)
512 fputc (' ', tty->termscript);
513 fputc (' ', tty->output);
515 cmplus (tty, first_unused_hpos - curX (tty));
519 /* Buffers to store the source and result of code conversion for terminal. */
520 static unsigned char *encode_terminal_src;
521 static unsigned char *encode_terminal_dst;
522 /* Allocated sizes of the above buffers. */
523 static ptrdiff_t encode_terminal_src_size;
524 static ptrdiff_t encode_terminal_dst_size;
526 /* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
527 Set CODING->produced to the byte-length of the resulting byte
528 sequence, and return a pointer to that byte sequence. */
530 unsigned char *
531 encode_terminal_code (struct glyph *src, int src_len,
532 struct coding_system *coding)
534 struct glyph *src_end = src + src_len;
535 unsigned char *buf;
536 ptrdiff_t nchars, nbytes, required;
537 ptrdiff_t tlen = GLYPH_TABLE_LENGTH;
538 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
539 Lisp_Object charset_list;
541 /* Allocate sufficient size of buffer to store all characters in
542 multibyte-form. But, it may be enlarged on demand if
543 Vglyph_table contains a string or a composite glyph is
544 encountered. */
545 if (min (PTRDIFF_MAX, SIZE_MAX) / MAX_MULTIBYTE_LENGTH < src_len)
546 memory_full (SIZE_MAX);
547 required = src_len;
548 required *= MAX_MULTIBYTE_LENGTH;
549 if (encode_terminal_src_size < required)
551 encode_terminal_src = xrealloc (encode_terminal_src, required);
552 encode_terminal_src_size = required;
555 charset_list = coding_charset_list (coding);
557 buf = encode_terminal_src;
558 nchars = 0;
559 while (src < src_end)
561 if (src->type == COMPOSITE_GLYPH)
563 struct composition *cmp IF_LINT (= NULL);
564 Lisp_Object gstring IF_LINT (= Qnil);
565 int i;
567 nbytes = buf - encode_terminal_src;
568 if (src->u.cmp.automatic)
570 gstring = composition_gstring_from_id (src->u.cmp.id);
571 required = src->slice.cmp.to - src->slice.cmp.from + 1;
573 else
575 cmp = composition_table[src->u.cmp.id];
576 required = cmp->glyph_len;
577 required *= MAX_MULTIBYTE_LENGTH;
580 if (encode_terminal_src_size - nbytes < required)
582 encode_terminal_src =
583 xpalloc (encode_terminal_src, &encode_terminal_src_size,
584 required - (encode_terminal_src_size - nbytes),
585 -1, 1);
586 buf = encode_terminal_src + nbytes;
589 if (src->u.cmp.automatic)
590 for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
592 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
593 int c = LGLYPH_CHAR (g);
595 if (! char_charset (c, charset_list, NULL))
596 c = '?';
597 buf += CHAR_STRING (c, buf);
598 nchars++;
600 else
601 for (i = 0; i < cmp->glyph_len; i++)
603 int c = COMPOSITION_GLYPH (cmp, i);
605 /* TAB in a composition means display glyphs with
606 padding space on the left or right. */
607 if (c == '\t')
608 continue;
609 if (char_charset (c, charset_list, NULL))
611 if (CHAR_WIDTH (c) == 0
612 && i > 0 && COMPOSITION_GLYPH (cmp, i - 1) == '\t')
613 /* Should be left-padded */
615 buf += CHAR_STRING (' ', buf);
616 nchars++;
619 else
620 c = '?';
621 buf += CHAR_STRING (c, buf);
622 nchars++;
625 /* We must skip glyphs to be padded for a wide character. */
626 else if (! CHAR_GLYPH_PADDING_P (*src))
628 GLYPH g;
629 int c IF_LINT (= 0);
630 Lisp_Object string;
632 string = Qnil;
633 SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
635 if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
637 /* This glyph doesn't have an entry in Vglyph_table. */
638 c = src->u.ch;
640 else
642 /* This glyph has an entry in Vglyph_table,
643 so process any alias before testing for simpleness. */
644 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
646 if (GLYPH_SIMPLE_P (tbase, tlen, g))
647 /* We set the multi-byte form of a character in G
648 (that should be an ASCII character) at WORKBUF. */
649 c = GLYPH_CHAR (g);
650 else
651 /* We have a string in Vglyph_table. */
652 string = tbase[GLYPH_CHAR (g)];
655 if (NILP (string))
657 nbytes = buf - encode_terminal_src;
658 if (encode_terminal_src_size - nbytes < MAX_MULTIBYTE_LENGTH)
660 encode_terminal_src =
661 xpalloc (encode_terminal_src, &encode_terminal_src_size,
662 MAX_MULTIBYTE_LENGTH, -1, 1);
663 buf = encode_terminal_src + nbytes;
665 if (CHAR_BYTE8_P (c)
666 || char_charset (c, charset_list, NULL))
668 /* Store the multibyte form of C at BUF. */
669 buf += CHAR_STRING (c, buf);
670 nchars++;
672 else
674 /* C is not encodable. */
675 *buf++ = '?';
676 nchars++;
677 while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
679 *buf++ = '?';
680 nchars++;
681 src++;
685 else
687 if (! STRING_MULTIBYTE (string))
688 string = string_to_multibyte (string);
689 nbytes = buf - encode_terminal_src;
690 if (encode_terminal_src_size - nbytes < SBYTES (string))
692 encode_terminal_src =
693 xpalloc (encode_terminal_src, &encode_terminal_src_size,
694 (SBYTES (string)
695 - (encode_terminal_src_size - nbytes)),
696 -1, 1);
697 buf = encode_terminal_src + nbytes;
699 memcpy (buf, SDATA (string), SBYTES (string));
700 buf += SBYTES (string);
701 nchars += SCHARS (string);
704 src++;
707 if (nchars == 0)
709 coding->produced = 0;
710 return NULL;
713 nbytes = buf - encode_terminal_src;
714 coding->source = encode_terminal_src;
715 if (encode_terminal_dst_size == 0)
717 encode_terminal_dst = xrealloc (encode_terminal_dst,
718 encode_terminal_src_size);
719 encode_terminal_dst_size = encode_terminal_src_size;
721 coding->destination = encode_terminal_dst;
722 coding->dst_bytes = encode_terminal_dst_size;
723 encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
724 /* coding->destination may have been reallocated. */
725 encode_terminal_dst = coding->destination;
726 encode_terminal_dst_size = coding->dst_bytes;
728 return (encode_terminal_dst);
733 /* An implementation of write_glyphs for termcap frames. */
735 static void
736 tty_write_glyphs (struct frame *f, struct glyph *string, int len)
738 unsigned char *conversion_buffer;
739 struct coding_system *coding;
740 int n, stringlen;
742 struct tty_display_info *tty = FRAME_TTY (f);
744 tty_turn_off_insert (tty);
745 tty_hide_cursor (tty);
747 /* Don't dare write in last column of bottom line, if Auto-Wrap,
748 since that would scroll the whole frame on some terminals. */
750 if (AutoWrap (tty)
751 && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
752 && (curX (tty) + len) == FRAME_COLS (f))
753 len --;
754 if (len <= 0)
755 return;
757 cmplus (tty, len);
759 /* If terminal_coding does any conversion, use it, otherwise use
760 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
761 because it always return 1 if the member src_multibyte is 1. */
762 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
763 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
764 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
765 the tail. */
766 coding->mode &= ~CODING_MODE_LAST_BLOCK;
768 for (stringlen = len; stringlen != 0; stringlen -= n)
770 /* Identify a run of glyphs with the same face. */
771 int face_id = string->face_id;
773 for (n = 1; n < stringlen; ++n)
774 if (string[n].face_id != face_id)
775 break;
777 /* Turn appearance modes of the face of the run on. */
778 tty_highlight_if_desired (tty);
779 turn_on_face (f, face_id);
781 if (n == stringlen)
782 /* This is the last run. */
783 coding->mode |= CODING_MODE_LAST_BLOCK;
784 conversion_buffer = encode_terminal_code (string, n, coding);
785 if (coding->produced > 0)
787 block_input ();
788 fwrite (conversion_buffer, 1, coding->produced, tty->output);
789 if (ferror (tty->output))
790 clearerr (tty->output);
791 if (tty->termscript)
792 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
793 unblock_input ();
795 string += n;
797 /* Turn appearance modes off. */
798 turn_off_face (f, face_id);
799 tty_turn_off_highlight (tty);
802 cmcheckmagic (tty);
805 #ifdef HAVE_GPM /* Only used by GPM code. */
807 static void
808 tty_write_glyphs_with_face (register struct frame *f, register struct glyph *string,
809 register int len, register int face_id)
811 unsigned char *conversion_buffer;
812 struct coding_system *coding;
814 struct tty_display_info *tty = FRAME_TTY (f);
816 tty_turn_off_insert (tty);
817 tty_hide_cursor (tty);
819 /* Don't dare write in last column of bottom line, if Auto-Wrap,
820 since that would scroll the whole frame on some terminals. */
822 if (AutoWrap (tty)
823 && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
824 && (curX (tty) + len) == FRAME_COLS (f))
825 len --;
826 if (len <= 0)
827 return;
829 cmplus (tty, len);
831 /* If terminal_coding does any conversion, use it, otherwise use
832 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
833 because it always return 1 if the member src_multibyte is 1. */
834 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
835 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
836 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
837 the tail. */
838 coding->mode &= ~CODING_MODE_LAST_BLOCK;
840 /* Turn appearance modes of the face. */
841 tty_highlight_if_desired (tty);
842 turn_on_face (f, face_id);
844 coding->mode |= CODING_MODE_LAST_BLOCK;
845 conversion_buffer = encode_terminal_code (string, len, coding);
846 if (coding->produced > 0)
848 block_input ();
849 fwrite (conversion_buffer, 1, coding->produced, tty->output);
850 if (ferror (tty->output))
851 clearerr (tty->output);
852 if (tty->termscript)
853 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
854 unblock_input ();
857 /* Turn appearance modes off. */
858 turn_off_face (f, face_id);
859 tty_turn_off_highlight (tty);
861 cmcheckmagic (tty);
863 #endif
865 /* An implementation of insert_glyphs for termcap frames. */
867 static void
868 tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
870 char *buf;
871 struct glyph *glyph = NULL;
872 unsigned char *conversion_buffer;
873 unsigned char space[1];
874 struct coding_system *coding;
876 struct tty_display_info *tty = FRAME_TTY (f);
878 if (tty->TS_ins_multi_chars)
880 buf = tparam (tty->TS_ins_multi_chars, 0, 0, len, 0, 0, 0);
881 OUTPUT1 (tty, buf);
882 xfree (buf);
883 if (start)
884 write_glyphs (f, start, len);
885 return;
888 tty_turn_on_insert (tty);
889 cmplus (tty, len);
891 if (! start)
892 space[0] = SPACEGLYPH;
894 /* If terminal_coding does any conversion, use it, otherwise use
895 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
896 because it always return 1 if the member src_multibyte is 1. */
897 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
898 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
899 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
900 the tail. */
901 coding->mode &= ~CODING_MODE_LAST_BLOCK;
903 while (len-- > 0)
905 OUTPUT1_IF (tty, tty->TS_ins_char);
906 if (!start)
908 conversion_buffer = space;
909 coding->produced = 1;
911 else
913 tty_highlight_if_desired (tty);
914 turn_on_face (f, start->face_id);
915 glyph = start;
916 ++start;
917 /* We must open sufficient space for a character which
918 occupies more than one column. */
919 while (len && CHAR_GLYPH_PADDING_P (*start))
921 OUTPUT1_IF (tty, tty->TS_ins_char);
922 start++, len--;
925 if (len <= 0)
926 /* This is the last glyph. */
927 coding->mode |= CODING_MODE_LAST_BLOCK;
929 conversion_buffer = encode_terminal_code (glyph, 1, coding);
932 if (coding->produced > 0)
934 block_input ();
935 fwrite (conversion_buffer, 1, coding->produced, tty->output);
936 if (ferror (tty->output))
937 clearerr (tty->output);
938 if (tty->termscript)
939 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
940 unblock_input ();
943 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
944 if (start)
946 turn_off_face (f, glyph->face_id);
947 tty_turn_off_highlight (tty);
951 cmcheckmagic (tty);
954 /* An implementation of delete_glyphs for termcap frames. */
956 static void
957 tty_delete_glyphs (struct frame *f, int n)
959 char *buf;
960 register int i;
962 struct tty_display_info *tty = FRAME_TTY (f);
964 if (tty->delete_in_insert_mode)
966 tty_turn_on_insert (tty);
968 else
970 tty_turn_off_insert (tty);
971 OUTPUT_IF (tty, tty->TS_delete_mode);
974 if (tty->TS_del_multi_chars)
976 buf = tparam (tty->TS_del_multi_chars, 0, 0, n, 0, 0, 0);
977 OUTPUT1 (tty, buf);
978 xfree (buf);
980 else
981 for (i = 0; i < n; i++)
982 OUTPUT1 (tty, tty->TS_del_char);
983 if (!tty->delete_in_insert_mode)
984 OUTPUT_IF (tty, tty->TS_end_delete_mode);
987 /* An implementation of ins_del_lines for termcap frames. */
989 static void
990 tty_ins_del_lines (struct frame *f, int vpos, int n)
992 struct tty_display_info *tty = FRAME_TTY (f);
993 const char *multi =
994 n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
995 const char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
996 const char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
998 int i = eabs (n);
999 char *buf;
1001 /* If the lines below the insertion are being pushed
1002 into the end of the window, this is the same as clearing;
1003 and we know the lines are already clear, since the matching
1004 deletion has already been done. So can ignore this. */
1005 /* If the lines below the deletion are blank lines coming
1006 out of the end of the window, don't bother,
1007 as there will be a matching inslines later that will flush them. */
1008 if (FRAME_SCROLL_REGION_OK (f)
1009 && vpos + i >= tty->specified_window)
1010 return;
1011 if (!FRAME_MEMORY_BELOW_FRAME (f)
1012 && vpos + i >= FRAME_TOTAL_LINES (f))
1013 return;
1015 if (multi)
1017 raw_cursor_to (f, vpos, 0);
1018 tty_background_highlight (tty);
1019 buf = tparam (multi, 0, 0, i, 0, 0, 0);
1020 OUTPUT (tty, buf);
1021 xfree (buf);
1023 else if (single)
1025 raw_cursor_to (f, vpos, 0);
1026 tty_background_highlight (tty);
1027 while (--i >= 0)
1028 OUTPUT (tty, single);
1029 if (tty->TF_teleray)
1030 curX (tty) = 0;
1032 else
1034 tty_set_scroll_region (f, vpos, tty->specified_window);
1035 if (n < 0)
1036 raw_cursor_to (f, tty->specified_window - 1, 0);
1037 else
1038 raw_cursor_to (f, vpos, 0);
1039 tty_background_highlight (tty);
1040 while (--i >= 0)
1041 OUTPUTL (tty, scroll, tty->specified_window - vpos);
1042 tty_set_scroll_region (f, 0, tty->specified_window);
1045 if (!FRAME_SCROLL_REGION_OK (f)
1046 && FRAME_MEMORY_BELOW_FRAME (f)
1047 && n < 0)
1049 cursor_to (f, FRAME_TOTAL_LINES (f) + n, 0);
1050 clear_to_end (f);
1054 /* Compute cost of sending "str", in characters,
1055 not counting any line-dependent padding. */
1058 string_cost (const char *str)
1060 cost = 0;
1061 if (str)
1062 tputs (str, 0, evalcost);
1063 return cost;
1066 /* Compute cost of sending "str", in characters,
1067 counting any line-dependent padding at one line. */
1069 static int
1070 string_cost_one_line (const char *str)
1072 cost = 0;
1073 if (str)
1074 tputs (str, 1, evalcost);
1075 return cost;
1078 /* Compute per line amount of line-dependent padding,
1079 in tenths of characters. */
1082 per_line_cost (const char *str)
1084 cost = 0;
1085 if (str)
1086 tputs (str, 0, evalcost);
1087 cost = - cost;
1088 if (str)
1089 tputs (str, 10, evalcost);
1090 return cost;
1093 /* char_ins_del_cost[n] is cost of inserting N characters.
1094 char_ins_del_cost[-n] is cost of deleting N characters.
1095 The length of this vector is based on max_frame_cols. */
1097 int *char_ins_del_vector;
1099 #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_COLS ((f))])
1101 /* ARGSUSED */
1102 static void
1103 calculate_ins_del_char_costs (struct frame *f)
1105 struct tty_display_info *tty = FRAME_TTY (f);
1106 int ins_startup_cost, del_startup_cost;
1107 int ins_cost_per_char, del_cost_per_char;
1108 register int i;
1109 register int *p;
1111 if (tty->TS_ins_multi_chars)
1113 ins_cost_per_char = 0;
1114 ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars);
1116 else if (tty->TS_ins_char || tty->TS_pad_inserted_char
1117 || (tty->TS_insert_mode && tty->TS_end_insert_mode))
1119 ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode)
1120 + string_cost (tty->TS_end_insert_mode))) / 100;
1121 ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char)
1122 + string_cost_one_line (tty->TS_pad_inserted_char));
1124 else
1126 ins_startup_cost = 9999;
1127 ins_cost_per_char = 0;
1130 if (tty->TS_del_multi_chars)
1132 del_cost_per_char = 0;
1133 del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars);
1135 else if (tty->TS_del_char)
1137 del_startup_cost = (string_cost (tty->TS_delete_mode)
1138 + string_cost (tty->TS_end_delete_mode));
1139 if (tty->delete_in_insert_mode)
1140 del_startup_cost /= 2;
1141 del_cost_per_char = string_cost_one_line (tty->TS_del_char);
1143 else
1145 del_startup_cost = 9999;
1146 del_cost_per_char = 0;
1149 /* Delete costs are at negative offsets */
1150 p = &char_ins_del_cost (f)[0];
1151 for (i = FRAME_COLS (f); --i >= 0;)
1152 *--p = (del_startup_cost += del_cost_per_char);
1154 /* Doing nothing is free */
1155 p = &char_ins_del_cost (f)[0];
1156 *p++ = 0;
1158 /* Insert costs are at positive offsets */
1159 for (i = FRAME_COLS (f); --i >= 0;)
1160 *p++ = (ins_startup_cost += ins_cost_per_char);
1163 void
1164 calculate_costs (struct frame *frame)
1166 FRAME_COST_BAUD_RATE (frame) = baud_rate;
1168 if (FRAME_TERMCAP_P (frame))
1170 struct tty_display_info *tty = FRAME_TTY (frame);
1171 register const char *f = (tty->TS_set_scroll_region
1172 ? tty->TS_set_scroll_region
1173 : tty->TS_set_scroll_region_1);
1175 FRAME_SCROLL_REGION_COST (frame) = string_cost (f);
1177 tty->costs_set = 1;
1179 /* These variables are only used for terminal stuff. They are
1180 allocated once for the terminal frame of X-windows emacs, but not
1181 used afterwards.
1183 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1184 X turns off char_ins_del_ok. */
1186 max_frame_cols = max (max_frame_cols, FRAME_COLS (frame));
1187 if ((min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) - 1) / 2
1188 < max_frame_cols)
1189 memory_full (SIZE_MAX);
1191 char_ins_del_vector =
1192 xrealloc (char_ins_del_vector,
1193 (sizeof (int) + 2 * sizeof (int) * max_frame_cols));
1195 memset (char_ins_del_vector, 0,
1196 (sizeof (int) + 2 * sizeof (int) * max_frame_cols));
1199 if (f && (!tty->TS_ins_line && !tty->TS_del_line))
1200 do_line_insertion_deletion_costs (frame,
1201 tty->TS_rev_scroll, tty->TS_ins_multi_lines,
1202 tty->TS_fwd_scroll, tty->TS_del_multi_lines,
1203 f, f, 1);
1204 else
1205 do_line_insertion_deletion_costs (frame,
1206 tty->TS_ins_line, tty->TS_ins_multi_lines,
1207 tty->TS_del_line, tty->TS_del_multi_lines,
1208 0, 0, 1);
1210 calculate_ins_del_char_costs (frame);
1212 /* Don't use TS_repeat if its padding is worse than sending the chars */
1213 if (tty->TS_repeat && per_line_cost (tty->TS_repeat) * baud_rate < 9000)
1214 tty->RPov = string_cost (tty->TS_repeat);
1215 else
1216 tty->RPov = FRAME_COLS (frame) * 2;
1218 cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */
1222 struct fkey_table {
1223 const char *cap, *name;
1226 /* Termcap capability names that correspond directly to X keysyms.
1227 Some of these (marked "terminfo") aren't supplied by old-style
1228 (Berkeley) termcap entries. They're listed in X keysym order;
1229 except we put the keypad keys first, so that if they clash with
1230 other keys (as on the IBM PC keyboard) they get overridden.
1233 static const struct fkey_table keys[] =
1235 {"kh", "home"}, /* termcap */
1236 {"kl", "left"}, /* termcap */
1237 {"ku", "up"}, /* termcap */
1238 {"kr", "right"}, /* termcap */
1239 {"kd", "down"}, /* termcap */
1240 {"%8", "prior"}, /* terminfo */
1241 {"%5", "next"}, /* terminfo */
1242 {"@7", "end"}, /* terminfo */
1243 {"@1", "begin"}, /* terminfo */
1244 {"*6", "select"}, /* terminfo */
1245 {"%9", "print"}, /* terminfo */
1246 {"@4", "execute"}, /* terminfo --- actually the `command' key */
1248 * "insert" --- see below
1250 {"&8", "undo"}, /* terminfo */
1251 {"%0", "redo"}, /* terminfo */
1252 {"%7", "menu"}, /* terminfo --- actually the `options' key */
1253 {"@0", "find"}, /* terminfo */
1254 {"@2", "cancel"}, /* terminfo */
1255 {"%1", "help"}, /* terminfo */
1257 * "break" goes here, but can't be reliably intercepted with termcap
1259 {"&4", "reset"}, /* terminfo --- actually `restart' */
1261 * "system" and "user" --- no termcaps
1263 {"kE", "clearline"}, /* terminfo */
1264 {"kA", "insertline"}, /* terminfo */
1265 {"kL", "deleteline"}, /* terminfo */
1266 {"kI", "insertchar"}, /* terminfo */
1267 {"kD", "deletechar"}, /* terminfo */
1268 {"kB", "backtab"}, /* terminfo */
1270 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1272 {"@8", "kp-enter"}, /* terminfo */
1274 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1275 * "kp-multiply", "kp-add", "kp-separator",
1276 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1277 * --- no termcaps for any of these.
1279 {"K4", "kp-1"}, /* terminfo */
1281 * "kp-2" --- no termcap
1283 {"K5", "kp-3"}, /* terminfo */
1285 * "kp-4" --- no termcap
1287 {"K2", "kp-5"}, /* terminfo */
1289 * "kp-6" --- no termcap
1291 {"K1", "kp-7"}, /* terminfo */
1293 * "kp-8" --- no termcap
1295 {"K3", "kp-9"}, /* terminfo */
1297 * "kp-equal" --- no termcap
1299 {"k1", "f1"},
1300 {"k2", "f2"},
1301 {"k3", "f3"},
1302 {"k4", "f4"},
1303 {"k5", "f5"},
1304 {"k6", "f6"},
1305 {"k7", "f7"},
1306 {"k8", "f8"},
1307 {"k9", "f9"},
1309 {"&0", "S-cancel"}, /*shifted cancel key*/
1310 {"&9", "S-begin"}, /*shifted begin key*/
1311 {"*0", "S-find"}, /*shifted find key*/
1312 {"*1", "S-execute"}, /*shifted execute? actually shifted command key*/
1313 {"*4", "S-delete"}, /*shifted delete-character key*/
1314 {"*7", "S-end"}, /*shifted end key*/
1315 {"*8", "S-clearline"}, /*shifted clear-to end-of-line key*/
1316 {"#1", "S-help"}, /*shifted help key*/
1317 {"#2", "S-home"}, /*shifted home key*/
1318 {"#3", "S-insert"}, /*shifted insert-character key*/
1319 {"#4", "S-left"}, /*shifted left-arrow key*/
1320 {"%d", "S-menu"}, /*shifted menu? actually shifted options key*/
1321 {"%c", "S-next"}, /*shifted next key*/
1322 {"%e", "S-prior"}, /*shifted previous key*/
1323 {"%f", "S-print"}, /*shifted print key*/
1324 {"%g", "S-redo"}, /*shifted redo key*/
1325 {"%i", "S-right"}, /*shifted right-arrow key*/
1326 {"!3", "S-undo"} /*shifted undo key*/
1329 #ifndef DOS_NT
1330 static char **term_get_fkeys_address;
1331 static KBOARD *term_get_fkeys_kboard;
1332 static Lisp_Object term_get_fkeys_1 (void);
1334 /* Find the escape codes sent by the function keys for Vinput_decode_map.
1335 This function scans the termcap function key sequence entries, and
1336 adds entries to Vinput_decode_map for each function key it finds. */
1338 static void
1339 term_get_fkeys (char **address, KBOARD *kboard)
1341 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1342 errors during the call. The only errors should be from Fdefine_key
1343 when given a key sequence containing an invalid prefix key. If the
1344 termcap defines function keys which use a prefix that is already bound
1345 to a command by the default bindings, we should silently ignore that
1346 function key specification, rather than giving the user an error and
1347 refusing to run at all on such a terminal. */
1349 term_get_fkeys_address = address;
1350 term_get_fkeys_kboard = kboard;
1351 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1354 static Lisp_Object
1355 term_get_fkeys_1 (void)
1357 int i;
1359 char **address = term_get_fkeys_address;
1360 KBOARD *kboard = term_get_fkeys_kboard;
1362 /* This can happen if CANNOT_DUMP or with strange options. */
1363 if (!KEYMAPP (KVAR (kboard, Vinput_decode_map)))
1364 kset_input_decode_map (kboard, Fmake_sparse_keymap (Qnil));
1366 for (i = 0; i < ARRAYELTS (keys); i++)
1368 char *sequence = tgetstr (keys[i].cap, address);
1369 if (sequence)
1370 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
1371 Fmake_vector (make_number (1),
1372 intern (keys[i].name)));
1375 /* The uses of the "k0" capability are inconsistent; sometimes it
1376 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1377 We will attempt to politely accommodate both systems by testing for
1378 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1381 const char *k_semi = tgetstr ("k;", address);
1382 const char *k0 = tgetstr ("k0", address);
1383 const char *k0_name = "f10";
1385 if (k_semi)
1387 if (k0)
1388 /* Define f0 first, so that f10 takes precedence in case the
1389 key sequences happens to be the same. */
1390 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
1391 Fmake_vector (make_number (1), intern ("f0")));
1392 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k_semi),
1393 Fmake_vector (make_number (1), intern ("f10")));
1395 else if (k0)
1396 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
1397 Fmake_vector (make_number (1), intern (k0_name)));
1400 /* Set up cookies for numbered function keys above f10. */
1402 char fcap[3], fkey[4];
1404 fcap[0] = 'F'; fcap[2] = '\0';
1405 for (i = 11; i < 64; i++)
1407 if (i <= 19)
1408 fcap[1] = '1' + i - 11;
1409 else if (i <= 45)
1410 fcap[1] = 'A' + i - 20;
1411 else
1412 fcap[1] = 'a' + i - 46;
1415 char *sequence = tgetstr (fcap, address);
1416 if (sequence)
1418 sprintf (fkey, "f%d", i);
1419 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
1420 Fmake_vector (make_number (1),
1421 intern (fkey)));
1428 * Various mappings to try and get a better fit.
1431 #define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1432 if (!tgetstr (cap1, address)) \
1434 char *sequence = tgetstr (cap2, address); \
1435 if (sequence) \
1436 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence), \
1437 Fmake_vector (make_number (1), \
1438 intern (sym))); \
1441 /* if there's no key_next keycap, map key_npage to `next' keysym */
1442 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1443 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1444 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1445 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1446 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1447 /* if there's no key_end keycap, map key_ll to 'end' keysym */
1448 CONDITIONAL_REASSIGN ("@7", "kH", "end");
1449 #undef CONDITIONAL_REASSIGN
1452 return Qnil;
1454 #endif /* not DOS_NT */
1457 /***********************************************************************
1458 Character Display Information
1459 ***********************************************************************/
1460 static void append_glyph (struct it *);
1461 static void append_composite_glyph (struct it *);
1462 static void produce_composite_glyph (struct it *);
1463 static void append_glyphless_glyph (struct it *, int, const char *);
1464 static void produce_glyphless_glyph (struct it *, Lisp_Object);
1466 /* Append glyphs to IT's glyph_row. Called from produce_glyphs for
1467 terminal frames if IT->glyph_row != NULL. IT->char_to_display is
1468 the character for which to produce glyphs; IT->face_id contains the
1469 character's face. Padding glyphs are appended if IT->c has a
1470 IT->pixel_width > 1. */
1472 static void
1473 append_glyph (struct it *it)
1475 struct glyph *glyph, *end;
1476 int i;
1478 eassert (it->glyph_row);
1479 glyph = (it->glyph_row->glyphs[it->area]
1480 + it->glyph_row->used[it->area]);
1481 end = it->glyph_row->glyphs[1 + it->area];
1483 /* If the glyph row is reversed, we need to prepend the glyph rather
1484 than append it. */
1485 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1487 struct glyph *g;
1488 int move_by = it->pixel_width;
1490 /* Make room for the new glyphs. */
1491 if (move_by > end - glyph) /* don't overstep end of this area */
1492 move_by = end - glyph;
1493 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1494 g[move_by] = *g;
1495 glyph = it->glyph_row->glyphs[it->area];
1496 end = glyph + move_by;
1499 /* BIDI Note: we put the glyphs of a "multi-pixel" character left to
1500 right, even in the REVERSED_P case, since (a) all of its u.ch are
1501 identical, and (b) the PADDING_P flag needs to be set for the
1502 leftmost one, because we write to the terminal left-to-right. */
1503 for (i = 0;
1504 i < it->pixel_width && glyph < end;
1505 ++i)
1507 glyph->type = CHAR_GLYPH;
1508 glyph->pixel_width = 1;
1509 glyph->u.ch = it->char_to_display;
1510 glyph->face_id = it->face_id;
1511 glyph->padding_p = i > 0;
1512 glyph->charpos = CHARPOS (it->position);
1513 glyph->object = it->object;
1514 if (it->bidi_p)
1516 glyph->resolved_level = it->bidi_it.resolved_level;
1517 eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
1518 glyph->bidi_type = it->bidi_it.type;
1520 else
1522 glyph->resolved_level = 0;
1523 glyph->bidi_type = UNKNOWN_BT;
1526 ++it->glyph_row->used[it->area];
1527 ++glyph;
1531 /* For external use. */
1532 void
1533 tty_append_glyph (struct it *it)
1535 append_glyph (it);
1539 /* Produce glyphs for the display element described by IT. *IT
1540 specifies what we want to produce a glyph for (character, image, ...),
1541 and where in the glyph matrix we currently are (glyph row and hpos).
1542 produce_glyphs fills in output fields of *IT with information such as the
1543 pixel width and height of a character, and maybe output actual glyphs at
1544 the same time if IT->glyph_row is non-null. For an overview, see
1545 the explanation in dispextern.h, before the definition of the
1546 display_element_type enumeration.
1548 produce_glyphs also stores the result of glyph width, ascent
1549 etc. computations in *IT.
1551 IT->glyph_row may be null, in which case produce_glyphs does not
1552 actually fill in the glyphs. This is used in the move_* functions
1553 in xdisp.c for text width and height computations.
1555 Callers usually don't call produce_glyphs directly;
1556 instead they use the macro PRODUCE_GLYPHS. */
1558 void
1559 produce_glyphs (struct it *it)
1561 /* If a hook is installed, let it do the work. */
1563 /* Nothing but characters are supported on terminal frames. */
1564 eassert (it->what == IT_CHARACTER
1565 || it->what == IT_COMPOSITION
1566 || it->what == IT_STRETCH
1567 || it->what == IT_GLYPHLESS);
1569 if (it->what == IT_STRETCH)
1571 produce_stretch_glyph (it);
1572 goto done;
1575 if (it->what == IT_COMPOSITION)
1577 produce_composite_glyph (it);
1578 goto done;
1581 if (it->what == IT_GLYPHLESS)
1583 produce_glyphless_glyph (it, Qnil);
1584 goto done;
1587 if (it->char_to_display >= 040 && it->char_to_display < 0177)
1589 it->pixel_width = it->nglyphs = 1;
1590 if (it->glyph_row)
1591 append_glyph (it);
1593 else if (it->char_to_display == '\n')
1594 it->pixel_width = it->nglyphs = 0;
1595 else if (it->char_to_display == '\t')
1597 int absolute_x = (it->current_x
1598 + it->continuation_lines_width);
1599 int next_tab_x
1600 = (((1 + absolute_x + it->tab_width - 1)
1601 / it->tab_width)
1602 * it->tab_width);
1603 int nspaces;
1605 /* If part of the TAB has been displayed on the previous line
1606 which is continued now, continuation_lines_width will have
1607 been incremented already by the part that fitted on the
1608 continued line. So, we will get the right number of spaces
1609 here. */
1610 nspaces = next_tab_x - absolute_x;
1612 if (it->glyph_row)
1614 int n = nspaces;
1616 it->char_to_display = ' ';
1617 it->pixel_width = it->len = 1;
1619 while (n--)
1620 append_glyph (it);
1623 it->pixel_width = nspaces;
1624 it->nglyphs = nspaces;
1626 else if (CHAR_BYTE8_P (it->char_to_display))
1628 /* Coming here means that we must send the raw 8-bit byte as is
1629 to the terminal. Although there's no way to know how many
1630 columns it occupies on a screen, it is a good assumption that
1631 a single byte code has 1-column width. */
1632 it->pixel_width = it->nglyphs = 1;
1633 if (it->glyph_row)
1634 append_glyph (it);
1636 else
1638 Lisp_Object charset_list = FRAME_TERMINAL (it->f)->charset_list;
1640 if (char_charset (it->char_to_display, charset_list, NULL))
1642 it->pixel_width = CHAR_WIDTH (it->char_to_display);
1643 it->nglyphs = it->pixel_width;
1644 if (it->glyph_row)
1645 append_glyph (it);
1647 else
1649 Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
1651 eassert (it->what == IT_GLYPHLESS);
1652 produce_glyphless_glyph (it, acronym);
1656 done:
1657 /* Advance current_x by the pixel width as a convenience for
1658 the caller. */
1659 if (it->area == TEXT_AREA)
1660 it->current_x += it->pixel_width;
1661 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1662 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
1665 /* Append glyphs to IT's glyph_row for the composition IT->cmp_id.
1666 Called from produce_composite_glyph for terminal frames if
1667 IT->glyph_row != NULL. IT->face_id contains the character's
1668 face. */
1670 static void
1671 append_composite_glyph (struct it *it)
1673 struct glyph *glyph;
1675 eassert (it->glyph_row);
1676 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1677 if (glyph < it->glyph_row->glyphs[1 + it->area])
1679 /* If the glyph row is reversed, we need to prepend the glyph
1680 rather than append it. */
1681 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1683 struct glyph *g;
1685 /* Make room for the new glyph. */
1686 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1687 g[1] = *g;
1688 glyph = it->glyph_row->glyphs[it->area];
1690 glyph->type = COMPOSITE_GLYPH;
1691 glyph->pixel_width = it->pixel_width;
1692 glyph->u.cmp.id = it->cmp_it.id;
1693 if (it->cmp_it.ch < 0)
1695 glyph->u.cmp.automatic = 0;
1696 glyph->u.cmp.id = it->cmp_it.id;
1698 else
1700 glyph->u.cmp.automatic = 1;
1701 glyph->u.cmp.id = it->cmp_it.id;
1702 glyph->slice.cmp.from = it->cmp_it.from;
1703 glyph->slice.cmp.to = it->cmp_it.to - 1;
1706 glyph->face_id = it->face_id;
1707 glyph->padding_p = 0;
1708 glyph->charpos = CHARPOS (it->position);
1709 glyph->object = it->object;
1710 if (it->bidi_p)
1712 glyph->resolved_level = it->bidi_it.resolved_level;
1713 eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
1714 glyph->bidi_type = it->bidi_it.type;
1716 else
1718 glyph->resolved_level = 0;
1719 glyph->bidi_type = UNKNOWN_BT;
1722 ++it->glyph_row->used[it->area];
1723 ++glyph;
1728 /* Produce a composite glyph for iterator IT. IT->cmp_id is the ID of
1729 the composition. We simply produces components of the composition
1730 assuming that the terminal has a capability to layout/render it
1731 correctly. */
1733 static void
1734 produce_composite_glyph (struct it *it)
1736 if (it->cmp_it.ch < 0)
1738 struct composition *cmp = composition_table[it->cmp_it.id];
1740 it->pixel_width = cmp->width;
1742 else
1744 Lisp_Object gstring = composition_gstring_from_id (it->cmp_it.id);
1746 it->pixel_width = composition_gstring_width (gstring, it->cmp_it.from,
1747 it->cmp_it.to, NULL);
1749 it->nglyphs = 1;
1750 if (it->glyph_row)
1751 append_composite_glyph (it);
1755 /* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID
1756 is a face ID to be used for the glyph. What is actually appended
1757 are glyphs of type CHAR_GLYPH whose characters are in STR (which
1758 comes from it->nglyphs bytes). */
1760 static void
1761 append_glyphless_glyph (struct it *it, int face_id, const char *str)
1763 struct glyph *glyph, *end;
1764 int i;
1766 eassert (it->glyph_row);
1767 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1768 end = it->glyph_row->glyphs[1 + it->area];
1770 /* If the glyph row is reversed, we need to prepend the glyph rather
1771 than append it. */
1772 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1774 struct glyph *g;
1775 int move_by = it->pixel_width;
1777 /* Make room for the new glyphs. */
1778 if (move_by > end - glyph) /* don't overstep end of this area */
1779 move_by = end - glyph;
1780 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1781 g[move_by] = *g;
1782 glyph = it->glyph_row->glyphs[it->area];
1783 end = glyph + move_by;
1786 if (glyph >= end)
1787 return;
1788 glyph->type = CHAR_GLYPH;
1789 glyph->pixel_width = 1;
1790 glyph->face_id = face_id;
1791 glyph->padding_p = 0;
1792 glyph->charpos = CHARPOS (it->position);
1793 glyph->object = it->object;
1794 if (it->bidi_p)
1796 glyph->resolved_level = it->bidi_it.resolved_level;
1797 eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
1798 glyph->bidi_type = it->bidi_it.type;
1800 else
1802 glyph->resolved_level = 0;
1803 glyph->bidi_type = UNKNOWN_BT;
1806 /* BIDI Note: we put the glyphs of characters left to right, even in
1807 the REVERSED_P case because we write to the terminal
1808 left-to-right. */
1809 for (i = 0; i < it->nglyphs && glyph < end; ++i)
1811 if (i > 0)
1812 glyph[0] = glyph[-1];
1813 glyph->u.ch = str[i];
1814 ++it->glyph_row->used[it->area];
1815 ++glyph;
1819 /* Produce glyphs for a glyphless character for iterator IT.
1820 IT->glyphless_method specifies which method to use for displaying
1821 the character. See the description of enum
1822 glyphless_display_method in dispextern.h for the details.
1824 ACRONYM, if non-nil, is an acronym string for the character.
1826 The glyphs actually produced are of type CHAR_GLYPH. */
1828 static void
1829 produce_glyphless_glyph (struct it *it, Lisp_Object acronym)
1831 int len, face_id = merge_glyphless_glyph_face (it);
1832 char buf[sizeof "\\x" + max (6, (sizeof it->c * CHAR_BIT + 3) / 4)];
1833 char const *str = " ";
1835 if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
1837 /* As there's no way to produce a thin space, we produce a space
1838 of canonical width. */
1839 len = 1;
1841 else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
1843 len = CHAR_WIDTH (it->c);
1844 if (len == 0)
1845 len = 1;
1846 else if (len > 4)
1847 len = 4;
1848 len = sprintf (buf, "[%.*s]", len, str);
1849 str = buf;
1851 else
1853 if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
1855 if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
1856 acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
1857 if (CONSP (acronym))
1858 acronym = XCDR (acronym);
1859 buf[0] = '[';
1860 str = STRINGP (acronym) ? SSDATA (acronym) : "";
1861 for (len = 0; len < 6 && str[len] && ASCII_CHAR_P (str[len]); len++)
1862 buf[1 + len] = str[len];
1863 buf[1 + len] = ']';
1864 len += 2;
1866 else
1868 eassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEX_CODE);
1869 len = (it->c < 0x10000 ? sprintf (buf, "\\u%04X", it->c)
1870 : it->c <= MAX_UNICODE_CHAR ? sprintf (buf, "\\U%06X", it->c)
1871 : sprintf (buf, "\\x%06X", it->c));
1873 str = buf;
1876 it->pixel_width = len;
1877 it->nglyphs = len;
1878 if (it->glyph_row)
1879 append_glyphless_glyph (it, face_id, str);
1883 /***********************************************************************
1884 Faces
1885 ***********************************************************************/
1887 /* Value is non-zero if attribute ATTR may be used. ATTR should be
1888 one of the enumerators from enum no_color_bit, or a bit set built
1889 from them. Some display attributes may not be used together with
1890 color; the termcap capability `NC' specifies which ones. */
1892 #define MAY_USE_WITH_COLORS_P(tty, ATTR) \
1893 (tty->TN_max_colors > 0 \
1894 ? (tty->TN_no_color_video & (ATTR)) == 0 \
1895 : 1)
1897 /* Turn appearances of face FACE_ID on tty frame F on.
1898 FACE_ID is a realized face ID number, in the face cache. */
1900 static void
1901 turn_on_face (struct frame *f, int face_id)
1903 struct face *face = FACE_FROM_ID (f, face_id);
1904 unsigned long fg = face->foreground;
1905 unsigned long bg = face->background;
1906 struct tty_display_info *tty = FRAME_TTY (f);
1908 /* Use reverse video if the face specifies that.
1909 Do this first because TS_end_standout_mode may be the same
1910 as TS_exit_attribute_mode, which turns all appearances off. */
1911 if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE)
1912 && (inverse_video
1913 ? fg == FACE_TTY_DEFAULT_FG_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR
1914 : fg == FACE_TTY_DEFAULT_BG_COLOR || bg == FACE_TTY_DEFAULT_FG_COLOR))
1915 tty_toggle_highlight (tty);
1917 if (face->tty_bold_p && MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
1918 OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
1920 if (face->tty_italic_p && MAY_USE_WITH_COLORS_P (tty, NC_ITALIC))
1922 if (tty->TS_enter_italic_mode)
1923 OUTPUT1 (tty, tty->TS_enter_italic_mode);
1924 else
1925 /* Italics mode is unavailable on many terminals. In that
1926 case, map slant to dimmed text; we want italic text to
1927 appear different and dimming is not otherwise used. */
1928 OUTPUT1 (tty, tty->TS_enter_dim_mode);
1931 if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
1932 OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
1934 if (tty->TN_max_colors > 0)
1936 const char *ts;
1937 char *p;
1939 ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
1940 if (face_tty_specified_color (fg) && ts)
1942 p = tparam (ts, NULL, 0, fg, 0, 0, 0);
1943 OUTPUT (tty, p);
1944 xfree (p);
1947 ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
1948 if (face_tty_specified_color (bg) && ts)
1950 p = tparam (ts, NULL, 0, bg, 0, 0, 0);
1951 OUTPUT (tty, p);
1952 xfree (p);
1958 /* Turn off appearances of face FACE_ID on tty frame F. */
1960 static void
1961 turn_off_face (struct frame *f, int face_id)
1963 struct face *face = FACE_FROM_ID (f, face_id);
1964 struct tty_display_info *tty = FRAME_TTY (f);
1966 eassert (face != NULL);
1968 if (tty->TS_exit_attribute_mode)
1970 /* Capability "me" will turn off appearance modes double-bright,
1971 half-bright, reverse-video, standout, underline. It may or
1972 may not turn off alt-char-mode. */
1973 if (face->tty_bold_p
1974 || face->tty_italic_p
1975 || face->tty_reverse_p
1976 || face->tty_underline_p)
1978 OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
1979 if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0)
1980 tty->standout_mode = 0;
1983 else
1985 /* If we don't have "me" we can only have those appearances
1986 that have exit sequences defined. */
1987 if (face->tty_underline_p)
1988 OUTPUT_IF (tty, tty->TS_exit_underline_mode);
1991 /* Switch back to default colors. */
1992 if (tty->TN_max_colors > 0
1993 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
1994 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
1995 || (face->background != FACE_TTY_DEFAULT_COLOR
1996 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
1997 OUTPUT1_IF (tty, tty->TS_orig_pair);
2001 /* Return true if the terminal on frame F supports all of the
2002 capabilities in CAPS simultaneously. */
2004 bool
2005 tty_capable_p (struct tty_display_info *tty, unsigned int caps)
2007 #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
2008 if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
2009 return 0;
2011 TTY_CAPABLE_P_TRY (tty, TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE);
2012 TTY_CAPABLE_P_TRY (tty, TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode, NC_UNDERLINE);
2013 TTY_CAPABLE_P_TRY (tty, TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
2014 TTY_CAPABLE_P_TRY (tty, TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM);
2015 TTY_CAPABLE_P_TRY (tty, TTY_CAP_ITALIC, tty->TS_enter_italic_mode, NC_ITALIC);
2017 /* We can do it! */
2018 return 1;
2021 /* Return non-zero if the terminal is capable to display colors. */
2023 DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
2024 0, 1, 0,
2025 doc: /* Return non-nil if the tty device TERMINAL can display colors.
2027 TERMINAL can be a terminal object, a frame, or nil (meaning the
2028 selected frame's terminal). This function always returns nil if
2029 TERMINAL does not refer to a text terminal. */)
2030 (Lisp_Object terminal)
2032 struct terminal *t = get_tty_terminal (terminal, 0);
2033 if (!t)
2034 return Qnil;
2035 else
2036 return t->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
2039 /* Return the number of supported colors. */
2040 DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
2041 Stty_display_color_cells, 0, 1, 0,
2042 doc: /* Return the number of colors supported by the tty device TERMINAL.
2044 TERMINAL can be a terminal object, a frame, or nil (meaning the
2045 selected frame's terminal). This function always returns 0 if
2046 TERMINAL does not refer to a text terminal. */)
2047 (Lisp_Object terminal)
2049 struct terminal *t = get_tty_terminal (terminal, 0);
2050 if (!t)
2051 return make_number (0);
2052 else
2053 return make_number (t->display_info.tty->TN_max_colors);
2056 #ifndef DOS_NT
2058 /* Declare here rather than in the function, as in the rest of Emacs,
2059 to work around an HPUX compiler bug (?). See
2060 http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00410.html */
2061 static int default_max_colors;
2062 static int default_max_pairs;
2063 static int default_no_color_video;
2064 static char *default_orig_pair;
2065 static char *default_set_foreground;
2066 static char *default_set_background;
2068 /* Save or restore the default color-related capabilities of this
2069 terminal. */
2070 static void
2071 tty_default_color_capabilities (struct tty_display_info *tty, bool save)
2074 if (save)
2076 dupstring (&default_orig_pair, tty->TS_orig_pair);
2077 dupstring (&default_set_foreground, tty->TS_set_foreground);
2078 dupstring (&default_set_background, tty->TS_set_background);
2079 default_max_colors = tty->TN_max_colors;
2080 default_max_pairs = tty->TN_max_pairs;
2081 default_no_color_video = tty->TN_no_color_video;
2083 else
2085 tty->TS_orig_pair = default_orig_pair;
2086 tty->TS_set_foreground = default_set_foreground;
2087 tty->TS_set_background = default_set_background;
2088 tty->TN_max_colors = default_max_colors;
2089 tty->TN_max_pairs = default_max_pairs;
2090 tty->TN_no_color_video = default_no_color_video;
2094 /* Setup one of the standard tty color schemes according to MODE.
2095 MODE's value is generally the number of colors which we want to
2096 support; zero means set up for the default capabilities, the ones
2097 we saw at init_tty time; -1 means turn off color support. */
2098 static void
2099 tty_setup_colors (struct tty_display_info *tty, int mode)
2101 /* Canonicalize all negative values of MODE. */
2102 if (mode < -1)
2103 mode = -1;
2105 switch (mode)
2107 case -1: /* no colors at all */
2108 tty->TN_max_colors = 0;
2109 tty->TN_max_pairs = 0;
2110 tty->TN_no_color_video = 0;
2111 tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL;
2112 break;
2113 case 0: /* default colors, if any */
2114 default:
2115 tty_default_color_capabilities (tty, 0);
2116 break;
2117 case 8: /* 8 standard ANSI colors */
2118 tty->TS_orig_pair = "\033[0m";
2119 #ifdef TERMINFO
2120 tty->TS_set_foreground = "\033[3%p1%dm";
2121 tty->TS_set_background = "\033[4%p1%dm";
2122 #else
2123 tty->TS_set_foreground = "\033[3%dm";
2124 tty->TS_set_background = "\033[4%dm";
2125 #endif
2126 tty->TN_max_colors = 8;
2127 tty->TN_max_pairs = 64;
2128 tty->TN_no_color_video = 0;
2129 break;
2133 void
2134 set_tty_color_mode (struct tty_display_info *tty, struct frame *f)
2136 Lisp_Object tem, val;
2137 Lisp_Object color_mode;
2138 int mode;
2139 Lisp_Object tty_color_mode_alist
2140 = Fintern_soft (build_string ("tty-color-mode-alist"), Qnil);
2142 tem = assq_no_quit (Qtty_color_mode, f->param_alist);
2143 val = CONSP (tem) ? XCDR (tem) : Qnil;
2145 if (INTEGERP (val))
2146 color_mode = val;
2147 else if (SYMBOLP (tty_color_mode_alist))
2149 tem = Fassq (val, Fsymbol_value (tty_color_mode_alist));
2150 color_mode = CONSP (tem) ? XCDR (tem) : Qnil;
2152 else
2153 color_mode = Qnil;
2155 mode = TYPE_RANGED_INTEGERP (int, color_mode) ? XINT (color_mode) : 0;
2157 if (mode != tty->previous_color_mode)
2159 tty->previous_color_mode = mode;
2160 tty_setup_colors (tty , mode);
2161 /* This recomputes all the faces given the new color definitions. */
2162 safe_call (1, intern ("tty-set-up-initial-frame-faces"));
2166 #endif /* !DOS_NT */
2170 /* Return the tty display object specified by TERMINAL. */
2172 static struct terminal *
2173 get_tty_terminal (Lisp_Object terminal, bool throw)
2175 struct terminal *t = get_terminal (terminal, throw);
2177 if (t && t->type != output_termcap && t->type != output_msdos_raw)
2179 if (throw)
2180 error ("Device %d is not a termcap terminal device", t->id);
2181 else
2182 return NULL;
2185 return t;
2188 /* Return an active termcap device that uses the tty device with the
2189 given name.
2191 This function ignores suspended devices.
2193 Returns NULL if the named terminal device is not opened. */
2195 struct terminal *
2196 get_named_tty (const char *name)
2198 struct terminal *t;
2200 eassert (name);
2202 for (t = terminal_list; t; t = t->next_terminal)
2204 if ((t->type == output_termcap || t->type == output_msdos_raw)
2205 && !strcmp (t->display_info.tty->name, name)
2206 && TERMINAL_ACTIVE_P (t))
2207 return t;
2210 return 0;
2214 DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
2215 doc: /* Return the type of the tty device that TERMINAL uses.
2216 Returns nil if TERMINAL is not on a tty device.
2218 TERMINAL can be a terminal object, a frame, or nil (meaning the
2219 selected frame's terminal). */)
2220 (Lisp_Object terminal)
2222 struct terminal *t = get_terminal (terminal, 1);
2224 if (t->type != output_termcap && t->type != output_msdos_raw)
2225 return Qnil;
2227 if (t->display_info.tty->type)
2228 return build_string (t->display_info.tty->type);
2229 else
2230 return Qnil;
2233 DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
2234 doc: /* Return non-nil if TERMINAL is the controlling tty of the Emacs process.
2236 TERMINAL can be a terminal object, a frame, or nil (meaning the
2237 selected frame's terminal). This function always returns nil if
2238 TERMINAL is not on a tty device. */)
2239 (Lisp_Object terminal)
2241 struct terminal *t = get_terminal (terminal, 1);
2243 if ((t->type != output_termcap && t->type != output_msdos_raw)
2244 || strcmp (t->display_info.tty->name, DEV_TTY) != 0)
2245 return Qnil;
2246 else
2247 return Qt;
2250 DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
2251 doc: /* Declare that the tty used by TERMINAL does not handle underlining.
2252 This is used to override the terminfo data, for certain terminals that
2253 do not really do underlining, but say that they do. This function has
2254 no effect if used on a non-tty terminal.
2256 TERMINAL can be a terminal object, a frame or nil (meaning the
2257 selected frame's terminal). This function always returns nil if
2258 TERMINAL does not refer to a text terminal. */)
2259 (Lisp_Object terminal)
2261 struct terminal *t = get_terminal (terminal, 1);
2263 if (t->type == output_termcap)
2264 t->display_info.tty->TS_enter_underline_mode = 0;
2265 return Qnil;
2268 DEFUN ("tty-top-frame", Ftty_top_frame, Stty_top_frame, 0, 1, 0,
2269 doc: /* Return the topmost terminal frame on TERMINAL.
2270 TERMINAL can be a terminal object, a frame or nil (meaning the
2271 selected frame's terminal). This function returns nil if TERMINAL
2272 does not refer to a text terminal. Otherwise, it returns the
2273 top-most frame on the text terminal. */)
2274 (Lisp_Object terminal)
2276 struct terminal *t = get_terminal (terminal, 1);
2278 if (t->type == output_termcap)
2279 return t->display_info.tty->top_frame;
2280 return Qnil;
2285 DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
2286 doc: /* Suspend the terminal device TTY.
2288 The device is restored to its default state, and Emacs ceases all
2289 access to the tty device. Frames that use the device are not deleted,
2290 but input is not read from them and if they change, their display is
2291 not updated.
2293 TTY may be a terminal object, a frame, or nil for the terminal device
2294 of the currently selected frame.
2296 This function runs `suspend-tty-functions' after suspending the
2297 device. The functions are run with one arg, the id of the suspended
2298 terminal device.
2300 `suspend-tty' does nothing if it is called on a device that is already
2301 suspended.
2303 A suspended tty may be resumed by calling `resume-tty' on it. */)
2304 (Lisp_Object tty)
2306 struct terminal *t = get_tty_terminal (tty, 1);
2307 FILE *f;
2309 if (!t)
2310 error ("Unknown tty device");
2312 f = t->display_info.tty->input;
2314 if (f)
2316 /* First run `suspend-tty-functions' and then clean up the tty
2317 state because `suspend-tty-functions' might need to change
2318 the tty state. */
2319 Lisp_Object args[2];
2320 args[0] = intern ("suspend-tty-functions");
2321 XSETTERMINAL (args[1], t);
2322 Frun_hook_with_args (2, args);
2324 reset_sys_modes (t->display_info.tty);
2325 delete_keyboard_wait_descriptor (fileno (f));
2327 #ifndef MSDOS
2328 fclose (f);
2329 if (f != t->display_info.tty->output)
2330 fclose (t->display_info.tty->output);
2331 #endif
2333 t->display_info.tty->input = 0;
2334 t->display_info.tty->output = 0;
2336 if (FRAMEP (t->display_info.tty->top_frame))
2337 SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
2341 /* Clear display hooks to prevent further output. */
2342 clear_tty_hooks (t);
2344 return Qnil;
2347 DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
2348 doc: /* Resume the previously suspended terminal device TTY.
2349 The terminal is opened and reinitialized. Frames that are on the
2350 suspended terminal are revived.
2352 It is an error to resume a terminal while another terminal is active
2353 on the same device.
2355 This function runs `resume-tty-functions' after resuming the terminal.
2356 The functions are run with one arg, the id of the resumed terminal
2357 device.
2359 `resume-tty' does nothing if it is called on a device that is not
2360 suspended.
2362 TTY may be a terminal object, a frame, or nil (meaning the selected
2363 frame's terminal). */)
2364 (Lisp_Object tty)
2366 struct terminal *t = get_tty_terminal (tty, 1);
2367 int fd;
2369 if (!t)
2370 error ("Unknown tty device");
2372 if (!t->display_info.tty->input)
2374 if (get_named_tty (t->display_info.tty->name))
2375 error ("Cannot resume display while another display is active on the same device");
2377 #ifdef MSDOS
2378 t->display_info.tty->output = stdout;
2379 t->display_info.tty->input = stdin;
2380 #else /* !MSDOS */
2381 fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
2382 t->display_info.tty->input = t->display_info.tty->output
2383 = fd < 0 ? 0 : fdopen (fd, "w+");
2385 if (! t->display_info.tty->input)
2387 int open_errno = errno;
2388 emacs_close (fd);
2389 report_file_errno ("Cannot reopen tty device",
2390 build_string (t->display_info.tty->name),
2391 open_errno);
2394 if (!O_IGNORE_CTTY && strcmp (t->display_info.tty->name, DEV_TTY) != 0)
2395 dissociate_if_controlling_tty (fd);
2396 #endif
2398 add_keyboard_wait_descriptor (fd);
2400 if (FRAMEP (t->display_info.tty->top_frame))
2402 struct frame *f = XFRAME (t->display_info.tty->top_frame);
2403 int width, height;
2404 int old_height = FRAME_COLS (f);
2405 int old_width = FRAME_TOTAL_LINES (f);
2407 /* Check if terminal/window size has changed while the frame
2408 was suspended. */
2409 get_tty_size (fileno (t->display_info.tty->input), &width, &height);
2410 if (width != old_width || height != old_height)
2411 change_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f),
2412 0, 0, 0, 0);
2413 SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
2416 set_tty_hooks (t);
2417 init_sys_modes (t->display_info.tty);
2420 /* Run `resume-tty-functions'. */
2421 Lisp_Object args[2];
2422 args[0] = intern ("resume-tty-functions");
2423 XSETTERMINAL (args[1], t);
2424 Frun_hook_with_args (2, args);
2428 set_tty_hooks (t);
2430 return Qnil;
2434 /***********************************************************************
2435 Mouse
2436 ***********************************************************************/
2438 #ifdef HAVE_GPM
2440 #ifndef HAVE_WINDOW_SYSTEM
2441 void
2442 term_mouse_moveto (int x, int y)
2444 /* TODO: how to set mouse position?
2445 const char *name;
2446 int fd;
2447 name = (const char *) ttyname (0);
2448 fd = emacs_open (name, O_WRONLY, 0);
2449 SOME_FUNCTION (x, y, fd);
2450 emacs_close (fd);
2451 last_mouse_x = x;
2452 last_mouse_y = y; */
2454 #endif /* HAVE_WINDOW_SYSTEM */
2456 /* Implementation of draw_row_with_mouse_face for TTY/GPM. */
2457 void
2458 tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
2459 int start_hpos, int end_hpos,
2460 enum draw_glyphs_face draw)
2462 int nglyphs = end_hpos - start_hpos;
2463 struct frame *f = XFRAME (WINDOW_FRAME (w));
2464 struct tty_display_info *tty = FRAME_TTY (f);
2465 int face_id = tty->mouse_highlight.mouse_face_face_id;
2466 int save_x, save_y, pos_x, pos_y;
2468 if (end_hpos >= row->used[TEXT_AREA])
2469 nglyphs = row->used[TEXT_AREA] - start_hpos;
2471 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
2472 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w);
2474 /* Save current cursor co-ordinates. */
2475 save_y = curY (tty);
2476 save_x = curX (tty);
2477 cursor_to (f, pos_y, pos_x);
2479 if (draw == DRAW_MOUSE_FACE)
2480 tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
2481 nglyphs, face_id);
2482 else if (draw == DRAW_NORMAL_TEXT)
2483 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
2485 cursor_to (f, save_y, save_x);
2488 static bool
2489 term_mouse_movement (struct frame *frame, Gpm_Event *event)
2491 /* Has the mouse moved off the glyph it was on at the last sighting? */
2492 if (event->x != last_mouse_x || event->y != last_mouse_y)
2494 frame->mouse_moved = 1;
2495 note_mouse_highlight (frame, event->x, event->y);
2496 /* Remember which glyph we're now on. */
2497 last_mouse_x = event->x;
2498 last_mouse_y = event->y;
2499 return 1;
2501 return 0;
2504 /* Return the Time that corresponds to T. Wrap around on overflow. */
2505 static Time
2506 timeval_to_Time (struct timeval const *t)
2508 Time s_1000, ms;
2510 s_1000 = t->tv_sec;
2511 s_1000 *= 1000;
2512 ms = t->tv_usec / 1000;
2513 return s_1000 + ms;
2516 /* Return the current position of the mouse.
2518 Set *f to the frame the mouse is in, or zero if the mouse is in no
2519 Emacs frame. If it is set to zero, all the other arguments are
2520 garbage.
2522 Set *bar_window to Qnil, and *x and *y to the column and
2523 row of the character cell the mouse is over.
2525 Set *timeptr to the time the mouse was at the returned position.
2527 This clears mouse_moved until the next motion
2528 event arrives. */
2529 static void
2530 term_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2531 enum scroll_bar_part *part, Lisp_Object *x,
2532 Lisp_Object *y, Time *timeptr)
2534 struct timeval now;
2536 *fp = SELECTED_FRAME ();
2537 (*fp)->mouse_moved = 0;
2539 *bar_window = Qnil;
2540 *part = 0;
2542 XSETINT (*x, last_mouse_x);
2543 XSETINT (*y, last_mouse_y);
2544 gettimeofday(&now, 0);
2545 *timeptr = timeval_to_Time (&now);
2548 /* Prepare a mouse-event in *RESULT for placement in the input queue.
2550 If the event is a button press, then note that we have grabbed
2551 the mouse. */
2553 static Lisp_Object
2554 term_mouse_click (struct input_event *result, Gpm_Event *event,
2555 struct frame *f)
2557 struct timeval now;
2558 int i, j;
2560 result->kind = GPM_CLICK_EVENT;
2561 for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
2563 if (event->buttons & j) {
2564 result->code = i; /* button number */
2565 break;
2568 gettimeofday(&now, 0);
2569 result->timestamp = timeval_to_Time (&now);
2571 if (event->type & GPM_UP)
2572 result->modifiers = up_modifier;
2573 else if (event->type & GPM_DOWN)
2574 result->modifiers = down_modifier;
2575 else
2576 result->modifiers = 0;
2578 if (event->type & GPM_SINGLE)
2579 result->modifiers |= click_modifier;
2581 if (event->type & GPM_DOUBLE)
2582 result->modifiers |= double_modifier;
2584 if (event->type & GPM_TRIPLE)
2585 result->modifiers |= triple_modifier;
2587 if (event->type & GPM_DRAG)
2588 result->modifiers |= drag_modifier;
2590 if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
2592 /* 1 << KG_SHIFT */
2593 if (event->modifiers & (1 << 0))
2594 result->modifiers |= shift_modifier;
2596 /* 1 << KG_CTRL */
2597 if (event->modifiers & (1 << 2))
2598 result->modifiers |= ctrl_modifier;
2600 /* 1 << KG_ALT || KG_ALTGR */
2601 if (event->modifiers & (1 << 3)
2602 || event->modifiers & (1 << 1))
2603 result->modifiers |= meta_modifier;
2606 XSETINT (result->x, event->x);
2607 XSETINT (result->y, event->y);
2608 XSETFRAME (result->frame_or_window, f);
2609 result->arg = Qnil;
2610 return Qnil;
2614 handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event, struct input_event* hold_quit)
2616 struct frame *f = XFRAME (tty->top_frame);
2617 struct input_event ie;
2618 bool do_help = 0;
2619 int count = 0;
2621 EVENT_INIT (ie);
2622 ie.kind = NO_EVENT;
2623 ie.arg = Qnil;
2625 if (event->type & (GPM_MOVE | GPM_DRAG)) {
2626 previous_help_echo_string = help_echo_string;
2627 help_echo_string = Qnil;
2629 Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
2631 if (!term_mouse_movement (f, event))
2632 help_echo_string = previous_help_echo_string;
2634 /* If the contents of the global variable help_echo_string
2635 has changed, generate a HELP_EVENT. */
2636 if (!NILP (help_echo_string)
2637 || !NILP (previous_help_echo_string))
2638 do_help = 1;
2640 goto done;
2642 else {
2643 f->mouse_moved = 0;
2644 term_mouse_click (&ie, event, f);
2647 done:
2648 if (ie.kind != NO_EVENT)
2650 kbd_buffer_store_event_hold (&ie, hold_quit);
2651 count++;
2654 if (do_help
2655 && !(hold_quit && hold_quit->kind != NO_EVENT))
2657 Lisp_Object frame;
2659 if (f)
2660 XSETFRAME (frame, f);
2661 else
2662 frame = Qnil;
2664 gen_help_event (help_echo_string, frame, help_echo_window,
2665 help_echo_object, help_echo_pos);
2666 count++;
2669 return count;
2672 DEFUN ("gpm-mouse-start", Fgpm_mouse_start, Sgpm_mouse_start,
2673 0, 0, 0,
2674 doc: /* Open a connection to Gpm.
2675 Gpm-mouse can only be activated for one tty at a time. */)
2676 (void)
2678 struct frame *f = SELECTED_FRAME ();
2679 struct tty_display_info *tty
2680 = ((f)->output_method == output_termcap
2681 ? (f)->terminal->display_info.tty : NULL);
2682 Gpm_Connect connection;
2684 if (!tty)
2685 error ("Gpm-mouse only works in the GNU/Linux console");
2686 if (gpm_tty == tty)
2687 return Qnil; /* Already activated, nothing to do. */
2688 if (gpm_tty)
2689 error ("Gpm-mouse can only be activated for one tty at a time");
2691 connection.eventMask = ~0;
2692 connection.defaultMask = ~GPM_HARD;
2693 connection.maxMod = ~0;
2694 connection.minMod = 0;
2695 gpm_zerobased = 1;
2697 if (Gpm_Open (&connection, 0) < 0)
2698 error ("Gpm-mouse failed to connect to the gpm daemon");
2699 else
2701 gpm_tty = tty;
2702 /* `init_sys_modes' arranges for mouse movements sent through gpm_fd
2703 to generate SIGIOs. Apparently we need to call reset_sys_modes
2704 before calling init_sys_modes. */
2705 reset_sys_modes (tty);
2706 init_sys_modes (tty);
2707 add_gpm_wait_descriptor (gpm_fd);
2708 return Qnil;
2712 void
2713 close_gpm (int fd)
2715 if (fd >= 0)
2716 delete_gpm_wait_descriptor (fd);
2717 while (Gpm_Close()); /* close all the stack */
2718 gpm_tty = NULL;
2721 DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
2722 0, 0, 0,
2723 doc: /* Close a connection to Gpm. */)
2724 (void)
2726 struct frame *f = SELECTED_FRAME ();
2727 struct tty_display_info *tty
2728 = ((f)->output_method == output_termcap
2729 ? (f)->terminal->display_info.tty : NULL);
2731 if (!tty || gpm_tty != tty)
2732 return Qnil; /* Not activated on this terminal, nothing to do. */
2734 close_gpm (gpm_fd);
2735 return Qnil;
2737 #endif /* HAVE_GPM */
2740 /***********************************************************************
2741 Menus
2742 ***********************************************************************/
2744 #if !defined (MSDOS)
2746 /* TTY menu implementation and main ideas are borrowed from msdos.c.
2748 However, unlike on MSDOS, where the menu text is drawn directly to
2749 the display video memory, on a TTY we use display_string (see
2750 display_tty_menu_item in xdisp.c) to put the glyphs produced from
2751 the menu items into the frame's 'desired_matrix' glyph matrix, and
2752 then call update_frame_with_menu to deliver the results to the
2753 glass. The previous contents of the screen, in the form of the
2754 current_matrix, is stashed away, and used to restore screen
2755 contents when the menu selection changes or when the final
2756 selection is made and the menu should be popped down.
2758 The idea of this implementation was suggested by Gerd Moellmann. */
2760 #define TTYM_FAILURE -1
2761 #define TTYM_SUCCESS 1
2762 #define TTYM_NO_SELECT 2
2763 #define TTYM_IA_SELECT 3
2764 #define TTYM_NEXT 4
2765 #define TTYM_PREV 5
2767 /* These hold text of the current and the previous menu help messages. */
2768 static const char *menu_help_message, *prev_menu_help_message;
2769 /* Pane number and item number of the menu item which generated the
2770 last menu help message. */
2771 static int menu_help_paneno, menu_help_itemno;
2773 static Lisp_Object Qtty_menu_navigation_map, Qtty_menu_exit;
2774 static Lisp_Object Qtty_menu_prev_item, Qtty_menu_next_item;
2775 static Lisp_Object Qtty_menu_next_menu, Qtty_menu_prev_menu;
2776 static Lisp_Object Qtty_menu_select, Qtty_menu_ignore;
2777 static Lisp_Object Qtty_menu_mouse_movement;
2779 typedef struct tty_menu_struct
2781 int count;
2782 char **text;
2783 struct tty_menu_struct **submenu;
2784 int *panenumber; /* Also used as enabled flag. */
2785 ptrdiff_t allocated;
2786 int panecount;
2787 int width;
2788 const char **help_text;
2789 } tty_menu;
2791 /* Create a brand new menu structure. */
2793 static tty_menu *
2794 tty_menu_create (void)
2796 return xzalloc (sizeof *tty_menu_create ());
2799 /* Allocate some (more) memory for MENU ensuring that there is room for one
2800 more item. */
2802 static void
2803 tty_menu_make_room (tty_menu *menu)
2805 if (menu->allocated == menu->count)
2807 ptrdiff_t allocated = menu->allocated;
2808 menu->text = xpalloc (menu->text, &allocated, 1, -1, sizeof *menu->text);
2809 menu->text = xrealloc (menu->text, allocated * sizeof *menu->text);
2810 menu->submenu = xrealloc (menu->submenu,
2811 allocated * sizeof *menu->submenu);
2812 menu->panenumber = xrealloc (menu->panenumber,
2813 allocated * sizeof *menu->panenumber);
2814 menu->help_text = xrealloc (menu->help_text,
2815 allocated * sizeof *menu->help_text);
2816 menu->allocated = allocated;
2820 /* Search the given menu structure for a given pane number. */
2822 static tty_menu *
2823 tty_menu_search_pane (tty_menu *menu, int pane)
2825 int i;
2826 tty_menu *try;
2828 for (i = 0; i < menu->count; i++)
2829 if (menu->submenu[i])
2831 if (pane == menu->panenumber[i])
2832 return menu->submenu[i];
2833 try = tty_menu_search_pane (menu->submenu[i], pane);
2834 if (try)
2835 return try;
2837 return (tty_menu *) 0;
2840 /* Determine how much screen space a given menu needs. */
2842 static void
2843 tty_menu_calc_size (tty_menu *menu, int *width, int *height)
2845 int i, h2, w2, maxsubwidth, maxheight;
2847 maxsubwidth = menu->width;
2848 maxheight = menu->count;
2849 for (i = 0; i < menu->count; i++)
2851 if (menu->submenu[i])
2853 tty_menu_calc_size (menu->submenu[i], &w2, &h2);
2854 if (w2 > maxsubwidth) maxsubwidth = w2;
2855 if (i + h2 > maxheight) maxheight = i + h2;
2858 *width = maxsubwidth;
2859 *height = maxheight;
2862 static void
2863 mouse_get_xy (int *x, int *y)
2865 struct frame *sf = SELECTED_FRAME ();
2866 Lisp_Object lmx = Qnil, lmy = Qnil, lisp_dummy;
2867 enum scroll_bar_part part_dummy;
2868 Time time_dummy;
2870 if (FRAME_TERMINAL (sf)->mouse_position_hook)
2871 (*FRAME_TERMINAL (sf)->mouse_position_hook) (&sf, -1,
2872 &lisp_dummy, &part_dummy,
2873 &lmx, &lmy,
2874 &time_dummy);
2875 if (!NILP (lmx))
2877 *x = XINT (lmx);
2878 *y = XINT (lmy);
2882 /* Display MENU at (X,Y) using FACES, starting with FIRST_ITEM
2883 (zero-based). */
2885 static void
2886 tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
2887 int mx, int my, int first_item, bool disp_help)
2889 int i, face, width, enabled, mousehere, row, col;
2890 struct frame *sf = SELECTED_FRAME ();
2891 struct tty_display_info *tty = FRAME_TTY (sf);
2892 /* Don't try to display more menu items than the console can display
2893 using the available screen lines. Exclude the echo area line, as
2894 it will be overwritten by the help-echo anyway. */
2895 int max_items = min (menu->count - first_item, FRAME_TOTAL_LINES (sf) - 1 - y);
2897 menu_help_message = NULL;
2899 width = menu->width;
2900 col = cursorX (tty);
2901 row = cursorY (tty);
2902 for (i = 0; i < max_items; i++)
2904 int max_width = width + 2; /* +2 for padding blanks on each side */
2905 int j = i + first_item;
2907 if (menu->submenu[j])
2908 max_width += 2; /* for displaying " >" after the item */
2909 enabled
2910 = (!menu->submenu[j] && menu->panenumber[j]) || (menu->submenu[j]);
2911 mousehere = (y + i == my && x <= mx && mx < x + max_width);
2912 face = faces[enabled + mousehere * 2];
2913 /* Display the menu help string for the i-th menu item even if
2914 the menu item is currently disabled. That's what the GUI
2915 code does. */
2916 if (disp_help && enabled + mousehere * 2 >= 2)
2918 menu_help_message = menu->help_text[j];
2919 menu_help_paneno = pn - 1;
2920 menu_help_itemno = j;
2922 /* Take note of the coordinates of the active menu item, to
2923 display the cursor there. */
2924 if (mousehere)
2926 row = y + i;
2927 col = x;
2929 display_tty_menu_item (menu->text[j], max_width, face, x, y + i,
2930 menu->submenu[j] != NULL);
2932 update_frame_with_menu (sf, row, col);
2935 /* --------------------------- X Menu emulation ---------------------- */
2937 /* Create a new pane and place it on the outer-most level. */
2939 static int
2940 tty_menu_add_pane (tty_menu *menu, const char *txt)
2942 int len;
2944 tty_menu_make_room (menu);
2945 menu->submenu[menu->count] = tty_menu_create ();
2946 menu->text[menu->count] = (char *)txt;
2947 menu->panenumber[menu->count] = ++menu->panecount;
2948 menu->help_text[menu->count] = NULL;
2949 menu->count++;
2951 /* Update the menu width, if necessary. */
2952 len = menu_item_width ((const unsigned char *) txt);
2953 if (len > menu->width)
2954 menu->width = len;
2956 return menu->panecount;
2959 /* Create a new item in a menu pane. */
2961 static bool
2962 tty_menu_add_selection (tty_menu *menu, int pane,
2963 char *txt, bool enable, char const *help_text)
2965 int len;
2967 if (pane)
2969 menu = tty_menu_search_pane (menu, pane);
2970 if (! menu)
2971 return 0;
2973 tty_menu_make_room (menu);
2974 menu->submenu[menu->count] = (tty_menu *) 0;
2975 menu->text[menu->count] = txt;
2976 menu->panenumber[menu->count] = enable;
2977 menu->help_text[menu->count] = help_text;
2978 menu->count++;
2980 /* Update the menu width, if necessary. */
2981 len = menu_item_width ((const unsigned char *) txt);
2982 if (len > menu->width)
2983 menu->width = len;
2985 return 1;
2988 /* Decide where the menu would be placed if requested at (X,Y). */
2990 static void
2991 tty_menu_locate (tty_menu *menu, int x, int y,
2992 int *ulx, int *uly, int *width, int *height)
2994 tty_menu_calc_size (menu, width, height);
2995 *ulx = x + 1;
2996 *uly = y;
2997 *width += 2;
3000 struct tty_menu_state
3002 struct glyph_matrix *screen_behind;
3003 tty_menu *menu;
3004 int pane;
3005 int x, y;
3008 /* Save away the contents of frame F's current frame matrix, and
3009 enable all its rows. Value is a glyph matrix holding the contents
3010 of F's current frame matrix with all its glyph rows enabled. */
3012 static struct glyph_matrix *
3013 save_and_enable_current_matrix (struct frame *f)
3015 int i;
3016 struct glyph_matrix *saved = xzalloc (sizeof *saved);
3017 saved->nrows = f->current_matrix->nrows;
3018 saved->rows = xzalloc (saved->nrows * sizeof *saved->rows);
3020 for (i = 0; i < saved->nrows; ++i)
3022 struct glyph_row *from = f->current_matrix->rows + i;
3023 struct glyph_row *to = saved->rows + i;
3024 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
3026 to->glyphs[TEXT_AREA] = xmalloc (nbytes);
3027 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
3028 to->used[TEXT_AREA] = from->used[TEXT_AREA];
3029 /* Make sure every row is enabled, or else update_frame will not
3030 redraw them. (Rows that are identical to what is already on
3031 screen will not be redrawn anyway.) */
3032 to->enabled_p = true;
3033 to->hash = from->hash;
3036 return saved;
3039 /* Restore the contents of frame F's desired frame matrix from SAVED,
3040 and free memory associated with SAVED. */
3042 static void
3043 restore_desired_matrix (struct frame *f, struct glyph_matrix *saved)
3045 int i;
3047 for (i = 0; i < saved->nrows; ++i)
3049 struct glyph_row *from = saved->rows + i;
3050 struct glyph_row *to = f->desired_matrix->rows + i;
3051 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
3053 eassert (to->glyphs[TEXT_AREA] != from->glyphs[TEXT_AREA]);
3054 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
3055 to->used[TEXT_AREA] = from->used[TEXT_AREA];
3056 to->enabled_p = from->enabled_p;
3057 to->hash = from->hash;
3061 static void
3062 free_saved_screen (struct glyph_matrix *saved)
3064 int i;
3066 if (!saved)
3067 return; /* Already freed! */
3069 for (i = 0; i < saved->nrows; ++i)
3071 struct glyph_row *from = saved->rows + i;
3073 xfree (from->glyphs[TEXT_AREA]);
3076 xfree (saved->rows);
3077 xfree (saved);
3080 /* Update the display of frame F from its saved contents. */
3081 static void
3082 screen_update (struct frame *f, struct glyph_matrix *mtx)
3084 restore_desired_matrix (f, mtx);
3085 update_frame_with_menu (f, -1, -1);
3088 typedef enum {
3089 MI_QUIT_MENU = -1,
3090 MI_CONTINUE = 0,
3091 MI_ITEM_SELECTED = 1,
3092 MI_NEXT_ITEM = 2,
3093 MI_PREV_ITEM = 3,
3094 MI_SCROLL_FORWARD = 4,
3095 MI_SCROLL_BACK = 5
3096 } mi_result;
3098 /* Read user input and return X and Y coordinates where that input
3099 puts us. We only consider mouse movement and click events, and
3100 keyboard movement commands; the rest are ignored. */
3101 static mi_result
3102 read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
3103 bool *first_time)
3105 if (*first_time)
3107 *first_time = false;
3108 sf->mouse_moved = 1;
3110 else
3112 Lisp_Object cmd;
3113 bool usable_input = 1;
3114 mi_result st = MI_CONTINUE;
3115 struct tty_display_info *tty = FRAME_TTY (sf);
3116 Lisp_Object saved_mouse_tracking = do_mouse_tracking;
3118 /* Signal the keyboard reading routines we are displaying a menu
3119 on this terminal. */
3120 tty->showing_menu = 1;
3121 /* We want mouse movements be reported by read_menu_command. */
3122 do_mouse_tracking = Qt;
3123 do {
3124 cmd = read_menu_command ();
3125 } while (NILP (cmd));
3126 tty->showing_menu = 0;
3127 do_mouse_tracking = saved_mouse_tracking;
3129 if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit)
3130 /* If some input switched frames under our feet, exit the
3131 menu, since the menu faces are no longer valid, and the
3132 menu is no longer relevant anyway. */
3133 || sf != SELECTED_FRAME ())
3134 return MI_QUIT_MENU;
3135 if (EQ (cmd, Qtty_menu_mouse_movement))
3136 mouse_get_xy (x, y);
3137 else if (EQ (cmd, Qtty_menu_next_menu))
3139 usable_input = 0;
3140 st = MI_NEXT_ITEM;
3142 else if (EQ (cmd, Qtty_menu_prev_menu))
3144 usable_input = 0;
3145 st = MI_PREV_ITEM;
3147 else if (EQ (cmd, Qtty_menu_next_item))
3149 if (*y < max_y)
3150 *y += 1;
3151 else
3152 st = MI_SCROLL_FORWARD;
3154 else if (EQ (cmd, Qtty_menu_prev_item))
3156 if (*y > min_y)
3157 *y -= 1;
3158 else
3159 st = MI_SCROLL_BACK;
3161 else if (EQ (cmd, Qtty_menu_select))
3162 st = MI_ITEM_SELECTED;
3163 else if (!EQ (cmd, Qtty_menu_ignore))
3164 usable_input = 0;
3165 if (usable_input)
3166 sf->mouse_moved = 1;
3167 return st;
3169 return MI_CONTINUE;
3172 /* Display menu, wait for user's response, and return that response. */
3173 static int
3174 tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
3175 int x0, int y0, char **txt,
3176 void (*help_callback)(char const *, int, int),
3177 bool kbd_navigation)
3179 struct tty_menu_state *state;
3180 int statecount, x, y, i;
3181 bool leave, onepane;
3182 int result IF_LINT (= 0);
3183 int title_faces[4]; /* Face to display the menu title. */
3184 int faces[4], buffers_num_deleted = 0;
3185 struct frame *sf = SELECTED_FRAME ();
3186 struct tty_display_info *tty = FRAME_TTY (sf);
3187 bool first_time;
3188 Lisp_Object selectface;
3189 int first_item = 0;
3190 int col, row;
3192 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3193 around the display. */
3194 if (x0 <= 0)
3195 x0 = 1;
3196 if (y0 <= 0)
3197 y0 = 1;
3199 state = alloca (menu->panecount * sizeof (struct tty_menu_state));
3200 memset (state, 0, sizeof (*state));
3201 faces[0]
3202 = lookup_derived_face (sf, intern ("tty-menu-disabled-face"),
3203 DEFAULT_FACE_ID, 1);
3204 faces[1]
3205 = lookup_derived_face (sf, intern ("tty-menu-enabled-face"),
3206 DEFAULT_FACE_ID, 1);
3207 selectface = intern ("tty-menu-selected-face");
3208 faces[2] = lookup_derived_face (sf, selectface,
3209 faces[0], 1);
3210 faces[3] = lookup_derived_face (sf, selectface,
3211 faces[1], 1);
3213 /* Make sure the menu title is always displayed with
3214 `tty-menu-selected-face', no matter where the mouse pointer is. */
3215 for (i = 0; i < 4; i++)
3216 title_faces[i] = faces[3];
3218 statecount = 1;
3220 /* Don't let the title for the "Buffers" popup menu include a
3221 digit (which is ugly).
3223 This is a terrible kludge, but I think the "Buffers" case is
3224 the only one where the title includes a number, so it doesn't
3225 seem to be necessary to make this more general. */
3226 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3228 menu->text[0][7] = '\0';
3229 buffers_num_deleted = 1;
3232 /* Force update of the current frame, so that the desired and the
3233 current matrices are identical. */
3234 update_frame_with_menu (sf, -1, -1);
3235 state[0].menu = menu;
3236 state[0].screen_behind = save_and_enable_current_matrix (sf);
3238 /* Display the menu title. We subtract 1 from x0 and y0 because we
3239 want to interpret them as zero-based column and row coordinates,
3240 and also because we want the first item of the menu, not its
3241 title, to appear at x0,y0. */
3242 tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0, 0);
3244 /* Turn off the cursor. Otherwise it shows through the menu
3245 panes, which is ugly. */
3246 col = cursorX (tty);
3247 row = cursorY (tty);
3248 tty_hide_cursor (tty);
3250 if (buffers_num_deleted)
3251 menu->text[0][7] = ' ';
3252 onepane = menu->count == 1 && menu->submenu[0];
3253 if (onepane)
3255 menu->width = menu->submenu[0]->width;
3256 state[0].menu = menu->submenu[0];
3258 else
3260 state[0].menu = menu;
3262 state[0].x = x0 - 1;
3263 state[0].y = y0;
3264 state[0].pane = onepane;
3266 x = state[0].x;
3267 y = state[0].y;
3268 first_time = true;
3270 leave = 0;
3271 while (!leave)
3273 mi_result input_status;
3274 int min_y = state[0].y;
3275 int max_y = min (min_y + state[0].menu->count, FRAME_TOTAL_LINES (sf) - 1) - 1;
3277 input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
3278 if (input_status)
3280 leave = 1;
3281 switch (input_status)
3283 case MI_QUIT_MENU:
3284 /* Remove the last help-echo, so that it doesn't
3285 re-appear after "Quit". */
3286 show_help_echo (Qnil, Qnil, Qnil, Qnil);
3287 result = TTYM_NO_SELECT;
3288 break;
3289 case MI_NEXT_ITEM:
3290 if (kbd_navigation)
3291 result = TTYM_NEXT;
3292 else
3293 leave = 0;
3294 break;
3295 case MI_PREV_ITEM:
3296 if (kbd_navigation)
3297 result = TTYM_PREV;
3298 else
3299 leave = 0;
3300 break;
3301 case MI_SCROLL_FORWARD:
3302 if (y - min_y == state[0].menu->count - 1 - first_item)
3304 y = min_y;
3305 first_item = 0;
3307 else
3308 first_item++;
3309 leave = 0;
3310 break;
3311 case MI_SCROLL_BACK:
3312 if (first_item == 0)
3314 y = max_y;
3315 first_item = state[0].menu->count - 1 - (y - min_y);
3317 else
3318 first_item--;
3319 leave = 0;
3320 break;
3321 default:
3322 /* MI_ITEM_SELECTED is handled below, so nothing to do. */
3323 break;
3326 if (sf->mouse_moved && input_status != MI_QUIT_MENU)
3328 sf->mouse_moved = 0;
3329 result = TTYM_IA_SELECT;
3330 for (i = 0; i < statecount; i++)
3331 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3333 int dy = y - state[i].y + first_item;
3334 if (0 <= dy && dy < state[i].menu->count)
3336 if (!state[i].menu->submenu[dy])
3338 if (state[i].menu->panenumber[dy])
3339 result = TTYM_SUCCESS;
3340 else
3341 result = TTYM_IA_SELECT;
3343 *pane = state[i].pane - 1;
3344 *selidx = dy;
3345 /* We hit some part of a menu, so drop extra menus that
3346 have been opened. That does not include an open and
3347 active submenu. */
3348 if (i != statecount - 2
3349 || state[i].menu->submenu[dy] != state[i + 1].menu)
3350 while (i != statecount - 1)
3352 statecount--;
3353 screen_update (sf, state[statecount].screen_behind);
3354 state[statecount].screen_behind = NULL;
3356 if (i == statecount - 1 && state[i].menu->submenu[dy])
3358 tty_menu_display (state[i].menu,
3359 state[i].x,
3360 state[i].y,
3361 state[i].pane,
3362 faces, x, y, first_item, 1);
3363 state[statecount].menu = state[i].menu->submenu[dy];
3364 state[statecount].pane = state[i].menu->panenumber[dy];
3365 state[statecount].screen_behind
3366 = save_and_enable_current_matrix (sf);
3367 state[statecount].x
3368 = state[i].x + state[i].menu->width + 2;
3369 state[statecount].y = y;
3370 statecount++;
3374 tty_menu_display (state[statecount - 1].menu,
3375 state[statecount - 1].x,
3376 state[statecount - 1].y,
3377 state[statecount - 1].pane,
3378 faces, x, y, first_item, 1);
3379 /* The call to display help-echo below will move the cursor,
3380 so remember its current position as computed by
3381 tty_menu_display. */
3382 col = cursorX (tty);
3383 row = cursorY (tty);
3386 /* Display the help-echo message for the currently-selected menu
3387 item. */
3388 if ((menu_help_message || prev_menu_help_message)
3389 && menu_help_message != prev_menu_help_message)
3391 help_callback (menu_help_message,
3392 menu_help_paneno, menu_help_itemno);
3393 /* Move the cursor to the beginning of the current menu
3394 item, so that screen readers and other accessibility aids
3395 know where the active region is. */
3396 cursor_to (sf, row, col);
3397 prev_menu_help_message = menu_help_message;
3399 /* Both tty_menu_display and help_callback invoke update_end,
3400 which calls tty_show_cursor. Re-hide it, so it doesn't show
3401 through the menus. */
3402 tty_hide_cursor (tty);
3403 fflush (tty->output);
3406 sf->mouse_moved = 0;
3407 screen_update (sf, state[0].screen_behind);
3408 while (statecount--)
3409 free_saved_screen (state[statecount].screen_behind);
3410 tty_show_cursor (tty); /* Turn cursor back on. */
3411 fflush (tty->output);
3413 /* Clean up any mouse events that are waiting inside Emacs event queue.
3414 These events are likely to be generated before the menu was even
3415 displayed, probably because the user pressed and released the button
3416 (which invoked the menu) too quickly. If we don't remove these events,
3417 Emacs will process them after we return and surprise the user. */
3418 discard_mouse_events ();
3419 if (!kbd_buffer_events_waiting ())
3420 clear_input_pending ();
3421 return result;
3424 /* Dispose of a menu. */
3426 static void
3427 tty_menu_destroy (tty_menu *menu)
3429 int i;
3430 if (menu->allocated)
3432 for (i = 0; i < menu->count; i++)
3433 if (menu->submenu[i])
3434 tty_menu_destroy (menu->submenu[i]);
3435 xfree (menu->text);
3436 xfree (menu->submenu);
3437 xfree (menu->panenumber);
3438 xfree (menu->help_text);
3440 xfree (menu);
3441 menu_help_message = prev_menu_help_message = NULL;
3444 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
3446 PANE is the pane number, and ITEM is the menu item number in
3447 the menu (currently not used). */
3449 static void
3450 tty_menu_help_callback (char const *help_string, int pane, int item)
3452 Lisp_Object *first_item;
3453 Lisp_Object pane_name;
3454 Lisp_Object menu_object;
3456 first_item = XVECTOR (menu_items)->contents;
3457 if (EQ (first_item[0], Qt))
3458 pane_name = first_item[MENU_ITEMS_PANE_NAME];
3459 else if (EQ (first_item[0], Qquote))
3460 /* This shouldn't happen, see xmenu_show. */
3461 pane_name = empty_unibyte_string;
3462 else
3463 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
3465 /* (menu-item MENU-NAME PANE-NUMBER) */
3466 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
3467 show_help_echo (help_string ? build_string (help_string) : Qnil,
3468 Qnil, menu_object, make_number (item));
3471 static void
3472 tty_pop_down_menu (Lisp_Object arg)
3474 tty_menu *menu = XSAVE_POINTER (arg, 0);
3476 block_input ();
3477 tty_menu_destroy (menu);
3478 unblock_input ();
3481 /* Return the zero-based index of the last menu-bar item on frame F. */
3482 static int
3483 tty_menu_last_menubar_item (struct frame *f)
3485 int i = 0;
3487 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3488 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3490 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3492 while (i < ASIZE (items))
3494 Lisp_Object str;
3496 str = AREF (items, i + 1);
3497 if (NILP (str))
3498 break;
3499 i += 4;
3501 i -= 4; /* Went one too far! */
3503 return i;
3506 /* Find in frame F's menu bar the menu item that is next or previous
3507 to the item at X/Y, and return that item's position in X/Y. WHICH
3508 says which one--next or previous--item to look for. X and Y are
3509 measured in character cells. This should only be called on TTY
3510 frames. */
3511 static void
3512 tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
3514 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3515 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3517 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3518 int last_i = tty_menu_last_menubar_item (f);
3519 int i, prev_x;
3521 /* This loop assumes a single menu-bar line, and will fail to
3522 find an item if it is not in the first line. Note that
3523 make_lispy_event in keyboard.c makes the same assumption. */
3524 for (i = 0, prev_x = -1; i < ASIZE (items); i += 4)
3526 Lisp_Object pos, str;
3527 int ix;
3529 str = AREF (items, i + 1);
3530 pos = AREF (items, i + 3);
3531 if (NILP (str))
3532 return;
3533 ix = XINT (pos);
3534 if (ix <= *x
3535 /* We use <= so the blank between 2 items on a TTY is
3536 considered part of the previous item. */
3537 && *x <= ix + menu_item_width (SDATA (str)))
3539 /* Found current item. Now compute the X coordinate of
3540 the previous or next item. */
3541 if (which == TTYM_NEXT)
3543 if (i < last_i)
3544 *x = XINT (AREF (items, i + 4 + 3));
3545 else
3546 *x = 0; /* Wrap around to the first item. */
3548 else if (prev_x < 0)
3550 /* Wrap around to the last item. */
3551 *x = XINT (AREF (items, last_i + 3));
3553 else
3554 *x = prev_x;
3555 return;
3557 prev_x = ix;
3562 /* WINDOWSNT uses this as menu_show_hook, see w32console.c. */
3563 Lisp_Object
3564 tty_menu_show (struct frame *f, int x, int y, int menuflags,
3565 Lisp_Object title, const char **error_name)
3567 tty_menu *menu;
3568 int pane, selidx, lpane, status;
3569 Lisp_Object entry, pane_prefix;
3570 char *datap;
3571 int ulx, uly, width, height;
3572 int item_x, item_y;
3573 int dispwidth, dispheight;
3574 int i, j, lines, maxlines;
3575 int maxwidth;
3576 ptrdiff_t specpdl_count;
3578 eassert (FRAME_TERMCAP_P (f));
3580 *error_name = 0;
3581 if (menu_items_n_panes == 0)
3582 return Qnil;
3584 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
3586 *error_name = "Empty menu";
3587 return Qnil;
3590 /* Make the menu on that window. */
3591 menu = tty_menu_create ();
3593 /* Don't GC while we prepare and show the menu, because we give the
3594 menu functions pointers to the contents of strings. */
3595 specpdl_count = inhibit_garbage_collection ();
3597 /* Avoid crashes if, e.g., another client will connect while we
3598 are in a menu. */
3599 temporarily_switch_to_single_kboard (f);
3601 /* Adjust coordinates to be root-window-relative. */
3602 item_x = x += f->left_pos;
3603 item_y = y += f->top_pos;
3605 /* Create all the necessary panes and their items. */
3606 maxwidth = maxlines = lines = i = 0;
3607 lpane = TTYM_FAILURE;
3608 while (i < menu_items_used)
3610 if (EQ (AREF (menu_items, i), Qt))
3612 /* Create a new pane. */
3613 Lisp_Object pane_name, prefix;
3614 const char *pane_string;
3616 maxlines = max (maxlines, lines);
3617 lines = 0;
3618 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
3619 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
3620 pane_string = (NILP (pane_name)
3621 ? "" : SSDATA (pane_name));
3622 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
3623 pane_string++;
3625 lpane = tty_menu_add_pane (menu, pane_string);
3626 if (lpane == TTYM_FAILURE)
3628 tty_menu_destroy (menu);
3629 *error_name = "Can't create pane";
3630 entry = Qnil;
3631 goto tty_menu_end;
3633 i += MENU_ITEMS_PANE_LENGTH;
3635 /* Find the width of the widest item in this pane. */
3636 j = i;
3637 while (j < menu_items_used)
3639 Lisp_Object item;
3640 item = AREF (menu_items, j);
3641 if (EQ (item, Qt))
3642 break;
3643 if (NILP (item))
3645 j++;
3646 continue;
3648 width = SBYTES (item);
3649 if (width > maxwidth)
3650 maxwidth = width;
3652 j += MENU_ITEMS_ITEM_LENGTH;
3655 /* Ignore a nil in the item list.
3656 It's meaningful only for dialog boxes. */
3657 else if (EQ (AREF (menu_items, i), Qquote))
3658 i += 1;
3659 else
3661 /* Create a new item within current pane. */
3662 Lisp_Object item_name, enable, descrip, help;
3663 char *item_data;
3664 char const *help_string;
3666 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
3667 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
3668 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
3669 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
3670 help_string = STRINGP (help) ? SSDATA (help) : NULL;
3672 if (!NILP (descrip))
3674 /* If alloca is fast, use that to make the space,
3675 to reduce gc needs. */
3676 item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1);
3677 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
3678 for (j = SCHARS (item_name); j < maxwidth; j++)
3679 item_data[j] = ' ';
3680 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
3681 item_data[j + SBYTES (descrip)] = 0;
3683 else
3684 item_data = SSDATA (item_name);
3686 if (lpane == TTYM_FAILURE
3687 || (! tty_menu_add_selection (menu, lpane, item_data,
3688 !NILP (enable), help_string)))
3690 tty_menu_destroy (menu);
3691 *error_name = "Can't add selection to menu";
3692 entry = Qnil;
3693 goto tty_menu_end;
3695 i += MENU_ITEMS_ITEM_LENGTH;
3696 lines++;
3700 maxlines = max (maxlines, lines);
3702 /* All set and ready to fly. */
3703 dispwidth = f->text_cols;
3704 dispheight = f->text_lines;
3705 x = min (x, dispwidth);
3706 y = min (y, dispheight);
3707 x = max (x, 1);
3708 y = max (y, 1);
3709 tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
3710 if (ulx + width > dispwidth)
3712 x -= (ulx + width) - dispwidth;
3713 ulx = dispwidth - width;
3715 if (uly + height > dispheight)
3717 y -= (uly + height) - dispheight;
3718 uly = dispheight - height;
3721 if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 2)
3723 /* Move the menu away of the echo area, to avoid overwriting the
3724 menu with help echo messages or vice versa. */
3725 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
3727 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
3728 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
3730 else
3732 y -= 2;
3733 uly -= 2;
3737 if (ulx < 0) x -= ulx;
3738 if (uly < 0) y -= uly;
3740 #if 0
3741 /* This code doesn't make sense on a TTY, since it can easily annul
3742 the adjustments above that carefully avoid truncation of the menu
3743 items. I think it was written to fix some problem that only
3744 happens on X11. */
3745 if (! for_click)
3747 /* If position was not given by a mouse click, adjust so upper left
3748 corner of the menu as a whole ends up at given coordinates. This
3749 is what x-popup-menu says in its documentation. */
3750 x += width / 2;
3751 y += 1.5 * height / (maxlines + 2);
3753 #endif
3755 pane = selidx = 0;
3757 record_unwind_protect (tty_pop_down_menu, make_save_ptr (menu));
3759 specbind (Qoverriding_terminal_local_map,
3760 Fsymbol_value (Qtty_menu_navigation_map));
3761 status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
3762 tty_menu_help_callback,
3763 menuflags & MENU_KBD_NAVIGATION);
3764 entry = pane_prefix = Qnil;
3766 switch (status)
3768 case TTYM_SUCCESS:
3769 /* Find the item number SELIDX in pane number PANE. */
3770 i = 0;
3771 while (i < menu_items_used)
3773 if (EQ (AREF (menu_items, i), Qt))
3775 if (pane == 0)
3776 pane_prefix
3777 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
3778 pane--;
3779 i += MENU_ITEMS_PANE_LENGTH;
3781 else
3783 if (pane == -1)
3785 if (selidx == 0)
3787 entry
3788 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
3789 if (menuflags & MENU_KEYMAPS)
3791 entry = Fcons (entry, Qnil);
3792 if (!NILP (pane_prefix))
3793 entry = Fcons (pane_prefix, entry);
3795 break;
3797 selidx--;
3799 i += MENU_ITEMS_ITEM_LENGTH;
3802 break;
3804 case TTYM_NEXT:
3805 case TTYM_PREV:
3806 tty_menu_new_item_coords (f, status, &item_x, &item_y);
3807 entry = Fcons (make_number (item_x), make_number (item_y));
3808 break;
3810 case TTYM_FAILURE:
3811 *error_name = "Can't activate menu";
3812 case TTYM_IA_SELECT:
3813 break;
3814 case TTYM_NO_SELECT:
3815 /* If the selected frame was changed while we displayed a menu,
3816 throw to top level in order to undo any temporary settings
3817 made by TTY menu code. */
3818 if (f != SELECTED_FRAME ())
3819 Ftop_level ();
3820 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
3821 the menu was invoked with a mouse event as POSITION). */
3822 if (!(menuflags & MENU_FOR_CLICK))
3823 Fsignal (Qquit, Qnil);
3824 break;
3827 tty_menu_end:
3829 unbind_to (specpdl_count, Qnil);
3830 return entry;
3833 #endif /* !MSDOS */
3836 #ifndef MSDOS
3837 /***********************************************************************
3838 Initialization
3839 ***********************************************************************/
3841 /* Initialize the tty-dependent part of frame F. The frame must
3842 already have its device initialized. */
3844 void
3845 create_tty_output (struct frame *f)
3847 struct tty_output *t = xzalloc (sizeof *t);
3849 eassert (FRAME_TERMCAP_P (f));
3851 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
3853 f->output_data.tty = t;
3856 /* Delete frame F's face cache, and its tty-dependent part. */
3858 static void
3859 tty_free_frame_resources (struct frame *f)
3861 eassert (FRAME_TERMCAP_P (f));
3862 free_frame_faces (f);
3863 xfree (f->output_data.tty);
3866 #else /* MSDOS */
3868 /* Delete frame F's face cache. */
3870 static void
3871 tty_free_frame_resources (struct frame *f)
3873 eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
3874 free_frame_faces (f);
3876 #endif /* MSDOS */
3878 /* Reset the hooks in TERMINAL. */
3880 static void
3881 clear_tty_hooks (struct terminal *terminal)
3883 terminal->rif = 0;
3884 terminal->cursor_to_hook = 0;
3885 terminal->raw_cursor_to_hook = 0;
3886 terminal->clear_to_end_hook = 0;
3887 terminal->clear_frame_hook = 0;
3888 terminal->clear_end_of_line_hook = 0;
3889 terminal->ins_del_lines_hook = 0;
3890 terminal->insert_glyphs_hook = 0;
3891 terminal->write_glyphs_hook = 0;
3892 terminal->delete_glyphs_hook = 0;
3893 terminal->ring_bell_hook = 0;
3894 terminal->reset_terminal_modes_hook = 0;
3895 terminal->set_terminal_modes_hook = 0;
3896 terminal->update_begin_hook = 0;
3897 terminal->update_end_hook = 0;
3898 terminal->set_terminal_window_hook = 0;
3899 terminal->mouse_position_hook = 0;
3900 terminal->frame_rehighlight_hook = 0;
3901 terminal->frame_raise_lower_hook = 0;
3902 terminal->fullscreen_hook = 0;
3903 terminal->menu_show_hook = 0;
3904 terminal->set_vertical_scroll_bar_hook = 0;
3905 terminal->set_horizontal_scroll_bar_hook = 0;
3906 terminal->condemn_scroll_bars_hook = 0;
3907 terminal->redeem_scroll_bar_hook = 0;
3908 terminal->judge_scroll_bars_hook = 0;
3909 terminal->read_socket_hook = 0;
3910 terminal->frame_up_to_date_hook = 0;
3912 /* Leave these two set, or suspended frames are not deleted
3913 correctly. */
3914 terminal->delete_frame_hook = &tty_free_frame_resources;
3915 terminal->delete_terminal_hook = &delete_tty;
3918 /* Initialize hooks in TERMINAL with the values needed for a tty. */
3920 static void
3921 set_tty_hooks (struct terminal *terminal)
3923 terminal->cursor_to_hook = &tty_cursor_to;
3924 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
3925 terminal->clear_to_end_hook = &tty_clear_to_end;
3926 terminal->clear_frame_hook = &tty_clear_frame;
3927 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
3928 terminal->ins_del_lines_hook = &tty_ins_del_lines;
3929 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3930 terminal->write_glyphs_hook = &tty_write_glyphs;
3931 terminal->delete_glyphs_hook = &tty_delete_glyphs;
3932 terminal->ring_bell_hook = &tty_ring_bell;
3933 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3934 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
3935 terminal->update_end_hook = &tty_update_end;
3936 #ifdef MSDOS
3937 terminal->menu_show_hook = &x_menu_show;
3938 #else
3939 terminal->menu_show_hook = &tty_menu_show;
3940 #endif
3941 terminal->set_terminal_window_hook = &tty_set_terminal_window;
3942 terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
3943 terminal->delete_frame_hook = &tty_free_frame_resources;
3944 terminal->delete_terminal_hook = &delete_tty;
3945 /* Other hooks are NULL by default. */
3948 /* If FD is the controlling terminal, drop it. */
3949 static void
3950 dissociate_if_controlling_tty (int fd)
3952 /* If tcgetpgrp succeeds, fd is the controlling terminal,
3953 so dissociate it by invoking setsid. */
3954 if (tcgetpgrp (fd) >= 0 && setsid () < 0)
3956 #ifdef TIOCNOTTY
3957 /* setsid failed, presumably because Emacs is already a process
3958 group leader. Fall back on the obsolescent way to dissociate
3959 a controlling tty. */
3960 sigset_t oldset;
3961 block_tty_out_signal (&oldset);
3962 ioctl (fd, TIOCNOTTY, 0);
3963 unblock_tty_out_signal (&oldset);
3964 #endif
3968 /* Create a termcap display on the tty device with the given name and
3969 type.
3971 If NAME is NULL, then use the controlling tty, i.e., "/dev/tty".
3972 Otherwise NAME should be a path to the tty device file,
3973 e.g. "/dev/pts/7".
3975 TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
3977 If MUST_SUCCEED is true, then all errors are fatal. */
3979 struct terminal *
3980 init_tty (const char *name, const char *terminal_type, bool must_succeed)
3982 char *area;
3983 char **address = &area;
3984 int status;
3985 struct tty_display_info *tty = NULL;
3986 struct terminal *terminal = NULL;
3987 sigset_t oldset;
3988 bool ctty = false; /* True if asked to open controlling tty. */
3990 if (!terminal_type)
3991 maybe_fatal (must_succeed, 0,
3992 "Unknown terminal type",
3993 "Unknown terminal type");
3995 if (name == NULL)
3996 name = DEV_TTY;
3997 if (!strcmp (name, DEV_TTY))
3998 ctty = 1;
4000 /* If we already have a terminal on the given device, use that. If
4001 all such terminals are suspended, create a new one instead. */
4002 /* XXX Perhaps this should be made explicit by having init_tty
4003 always create a new terminal and separating terminal and frame
4004 creation on Lisp level. */
4005 terminal = get_named_tty (name);
4006 if (terminal)
4007 return terminal;
4009 terminal = create_terminal (output_termcap, NULL);
4010 #ifdef MSDOS
4011 if (been_here > 0)
4012 maybe_fatal (0, 0, "Attempt to create another terminal %s", "",
4013 name, "");
4014 been_here = 1;
4015 tty = &the_only_display_info;
4016 #else
4017 tty = xzalloc (sizeof *tty);
4018 #endif
4019 tty->top_frame = Qnil;
4020 tty->next = tty_list;
4021 tty_list = tty;
4023 terminal->display_info.tty = tty;
4024 tty->terminal = terminal;
4026 tty->Wcm = xmalloc (sizeof *tty->Wcm);
4027 Wcm_clear (tty);
4029 encode_terminal_src_size = 0;
4030 encode_terminal_dst_size = 0;
4033 #ifndef DOS_NT
4034 set_tty_hooks (terminal);
4037 /* Open the terminal device. */
4039 /* If !ctty, don't recognize it as our controlling terminal, and
4040 don't make it the controlling tty if we don't have one now.
4042 Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
4043 defined on Hurd. On other systems, we need to explicitly
4044 dissociate ourselves from the controlling tty when we want to
4045 open a frame on the same terminal. */
4046 int flags = O_RDWR | O_NOCTTY | (ctty ? 0 : O_IGNORE_CTTY);
4047 int fd = emacs_open (name, flags, 0);
4048 tty->input = tty->output
4049 = ((fd < 0 || ! isatty (fd))
4050 ? NULL
4051 : fdopen (fd, "w+"));
4053 if (! tty->input)
4055 char const *diagnostic
4056 = (fd < 0) ? "Could not open file: %s" : "Not a tty device: %s";
4057 emacs_close (fd);
4058 maybe_fatal (must_succeed, terminal, diagnostic, diagnostic, name);
4061 tty->name = xstrdup (name);
4062 terminal->name = xstrdup (name);
4064 if (!O_IGNORE_CTTY && !ctty)
4065 dissociate_if_controlling_tty (fd);
4068 tty->type = xstrdup (terminal_type);
4070 add_keyboard_wait_descriptor (fileno (tty->input));
4072 Wcm_clear (tty);
4074 /* On some systems, tgetent tries to access the controlling
4075 terminal. */
4076 block_tty_out_signal (&oldset);
4077 status = tgetent (tty->termcap_term_buffer, terminal_type);
4078 if (tty->termcap_term_buffer[TERMCAP_BUFFER_SIZE - 1])
4079 emacs_abort ();
4080 unblock_tty_out_signal (&oldset);
4082 if (status < 0)
4084 #ifdef TERMINFO
4085 maybe_fatal (must_succeed, terminal,
4086 "Cannot open terminfo database file",
4087 "Cannot open terminfo database file");
4088 #else
4089 maybe_fatal (must_succeed, terminal,
4090 "Cannot open termcap database file",
4091 "Cannot open termcap database file");
4092 #endif
4094 if (status == 0)
4096 maybe_fatal (must_succeed, terminal,
4097 "Terminal type %s is not defined",
4098 "Terminal type %s is not defined.\n\
4099 If that is not the actual type of terminal you have,\n\
4100 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
4101 `setenv TERM ...') to specify the correct type. It may be necessary\n"
4102 #ifdef TERMINFO
4103 "to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
4104 #else
4105 "to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
4106 #endif
4107 terminal_type);
4110 area = tty->termcap_strings_buffer;
4111 tty->TS_ins_line = tgetstr ("al", address);
4112 tty->TS_ins_multi_lines = tgetstr ("AL", address);
4113 tty->TS_bell = tgetstr ("bl", address);
4114 BackTab (tty) = tgetstr ("bt", address);
4115 tty->TS_clr_to_bottom = tgetstr ("cd", address);
4116 tty->TS_clr_line = tgetstr ("ce", address);
4117 tty->TS_clr_frame = tgetstr ("cl", address);
4118 ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
4119 AbsPosition (tty) = tgetstr ("cm", address);
4120 CR (tty) = tgetstr ("cr", address);
4121 tty->TS_set_scroll_region = tgetstr ("cs", address);
4122 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
4123 RowPosition (tty) = tgetstr ("cv", address);
4124 tty->TS_del_char = tgetstr ("dc", address);
4125 tty->TS_del_multi_chars = tgetstr ("DC", address);
4126 tty->TS_del_line = tgetstr ("dl", address);
4127 tty->TS_del_multi_lines = tgetstr ("DL", address);
4128 tty->TS_delete_mode = tgetstr ("dm", address);
4129 tty->TS_end_delete_mode = tgetstr ("ed", address);
4130 tty->TS_end_insert_mode = tgetstr ("ei", address);
4131 Home (tty) = tgetstr ("ho", address);
4132 tty->TS_ins_char = tgetstr ("ic", address);
4133 tty->TS_ins_multi_chars = tgetstr ("IC", address);
4134 tty->TS_insert_mode = tgetstr ("im", address);
4135 tty->TS_pad_inserted_char = tgetstr ("ip", address);
4136 tty->TS_end_keypad_mode = tgetstr ("ke", address);
4137 tty->TS_keypad_mode = tgetstr ("ks", address);
4138 LastLine (tty) = tgetstr ("ll", address);
4139 Right (tty) = tgetstr ("nd", address);
4140 Down (tty) = tgetstr ("do", address);
4141 if (!Down (tty))
4142 Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do". */
4143 if (tgetflag ("bs"))
4144 Left (tty) = "\b"; /* Can't possibly be longer! */
4145 else /* (Actually, "bs" is obsolete...) */
4146 Left (tty) = tgetstr ("le", address);
4147 if (!Left (tty))
4148 Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le". */
4149 tty->TS_pad_char = tgetstr ("pc", address);
4150 tty->TS_repeat = tgetstr ("rp", address);
4151 tty->TS_end_standout_mode = tgetstr ("se", address);
4152 tty->TS_fwd_scroll = tgetstr ("sf", address);
4153 tty->TS_standout_mode = tgetstr ("so", address);
4154 tty->TS_rev_scroll = tgetstr ("sr", address);
4155 tty->Wcm->cm_tab = tgetstr ("ta", address);
4156 tty->TS_end_termcap_modes = tgetstr ("te", address);
4157 tty->TS_termcap_modes = tgetstr ("ti", address);
4158 Up (tty) = tgetstr ("up", address);
4159 tty->TS_visible_bell = tgetstr ("vb", address);
4160 tty->TS_cursor_normal = tgetstr ("ve", address);
4161 tty->TS_cursor_visible = tgetstr ("vs", address);
4162 tty->TS_cursor_invisible = tgetstr ("vi", address);
4163 tty->TS_set_window = tgetstr ("wi", address);
4165 tty->TS_enter_underline_mode = tgetstr ("us", address);
4166 tty->TS_exit_underline_mode = tgetstr ("ue", address);
4167 tty->TS_enter_bold_mode = tgetstr ("md", address);
4168 tty->TS_enter_italic_mode = tgetstr ("ZH", address);
4169 tty->TS_enter_dim_mode = tgetstr ("mh", address);
4170 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
4171 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
4172 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
4173 tty->TS_exit_attribute_mode = tgetstr ("me", address);
4175 MultiUp (tty) = tgetstr ("UP", address);
4176 MultiDown (tty) = tgetstr ("DO", address);
4177 MultiLeft (tty) = tgetstr ("LE", address);
4178 MultiRight (tty) = tgetstr ("RI", address);
4180 /* SVr4/ANSI color support. If "op" isn't available, don't support
4181 color because we can't switch back to the default foreground and
4182 background. */
4183 tty->TS_orig_pair = tgetstr ("op", address);
4184 if (tty->TS_orig_pair)
4186 tty->TS_set_foreground = tgetstr ("AF", address);
4187 tty->TS_set_background = tgetstr ("AB", address);
4188 if (!tty->TS_set_foreground)
4190 /* SVr4. */
4191 tty->TS_set_foreground = tgetstr ("Sf", address);
4192 tty->TS_set_background = tgetstr ("Sb", address);
4195 tty->TN_max_colors = tgetnum ("Co");
4196 tty->TN_max_pairs = tgetnum ("pa");
4198 tty->TN_no_color_video = tgetnum ("NC");
4199 if (tty->TN_no_color_video == -1)
4200 tty->TN_no_color_video = 0;
4203 tty_default_color_capabilities (tty, 1);
4205 MagicWrap (tty) = tgetflag ("xn");
4206 /* Since we make MagicWrap terminals look like AutoWrap, we need to have
4207 the former flag imply the latter. */
4208 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
4209 tty->memory_below_frame = tgetflag ("db");
4210 tty->TF_hazeltine = tgetflag ("hz");
4211 tty->must_write_spaces = tgetflag ("in");
4212 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
4213 tty->TF_insmode_motion = tgetflag ("mi");
4214 tty->TF_standout_motion = tgetflag ("ms");
4215 tty->TF_underscore = tgetflag ("ul");
4216 tty->TF_teleray = tgetflag ("xt");
4218 #else /* DOS_NT */
4219 #ifdef WINDOWSNT
4221 struct frame *f = XFRAME (selected_frame);
4222 int height, width;
4224 initialize_w32_display (terminal, &width, &height);
4226 FrameRows (tty) = height;
4227 FrameCols (tty) = width;
4228 tty->specified_window = height;
4230 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
4231 FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) = 0;
4232 tty->char_ins_del_ok = 1;
4233 baud_rate = 19200;
4235 #else /* MSDOS */
4237 int height, width;
4238 if (strcmp (terminal_type, "internal") == 0)
4239 terminal->type = output_msdos_raw;
4240 initialize_msdos_display (terminal);
4242 get_tty_size (fileno (tty->input), &width, &height);
4243 FrameCols (tty) = width;
4244 FrameRows (tty) = height;
4245 tty->char_ins_del_ok = 0;
4246 init_baud_rate (fileno (tty->input));
4248 #endif /* MSDOS */
4249 tty->output = stdout;
4250 tty->input = stdin;
4251 /* The following two are inaccessible from w32console.c. */
4252 terminal->delete_frame_hook = &tty_free_frame_resources;
4253 terminal->delete_terminal_hook = &delete_tty;
4255 tty->name = xstrdup (name);
4256 terminal->name = xstrdup (name);
4257 tty->type = xstrdup (terminal_type);
4259 add_keyboard_wait_descriptor (0);
4261 tty->delete_in_insert_mode = 1;
4263 UseTabs (tty) = 0;
4264 tty->scroll_region_ok = 0;
4266 /* Seems to insert lines when it's not supposed to, messing up the
4267 display. In doing a trace, it didn't seem to be called much, so I
4268 don't think we're losing anything by turning it off. */
4269 tty->line_ins_del_ok = 0;
4271 tty->TN_max_colors = 16; /* Must be non-zero for tty-display-color-p. */
4272 #endif /* DOS_NT */
4274 #ifdef HAVE_GPM
4275 terminal->mouse_position_hook = term_mouse_position;
4276 tty->mouse_highlight.mouse_face_window = Qnil;
4277 #endif
4279 terminal->kboard = allocate_kboard (Qnil);
4280 terminal->kboard->reference_count++;
4281 /* Don't let the initial kboard remain current longer than necessary.
4282 That would cause problems if a file loaded on startup tries to
4283 prompt in the mini-buffer. */
4284 if (current_kboard == initial_kboard)
4285 current_kboard = terminal->kboard;
4286 #ifndef DOS_NT
4287 term_get_fkeys (address, terminal->kboard);
4289 /* Get frame size from system, or else from termcap. */
4291 int height, width;
4292 get_tty_size (fileno (tty->input), &width, &height);
4293 FrameCols (tty) = width;
4294 FrameRows (tty) = height;
4297 if (FrameCols (tty) <= 0)
4298 FrameCols (tty) = tgetnum ("co");
4299 if (FrameRows (tty) <= 0)
4300 FrameRows (tty) = tgetnum ("li");
4302 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
4303 maybe_fatal (must_succeed, terminal,
4304 "Screen size %dx%d is too small",
4305 "Screen size %dx%d is too small",
4306 FrameCols (tty), FrameRows (tty));
4308 TabWidth (tty) = tgetnum ("tw");
4310 if (!tty->TS_bell)
4311 tty->TS_bell = "\07";
4313 if (!tty->TS_fwd_scroll)
4314 tty->TS_fwd_scroll = Down (tty);
4316 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
4318 if (TabWidth (tty) < 0)
4319 TabWidth (tty) = 8;
4321 /* Turned off since /etc/termcap seems to have :ta= for most terminals
4322 and newer termcap doc does not seem to say there is a default.
4323 if (!tty->Wcm->cm_tab)
4324 tty->Wcm->cm_tab = "\t";
4327 /* We don't support standout modes that use `magic cookies', so
4328 turn off any that do. */
4329 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
4331 tty->TS_standout_mode = 0;
4332 tty->TS_end_standout_mode = 0;
4334 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
4336 tty->TS_enter_underline_mode = 0;
4337 tty->TS_exit_underline_mode = 0;
4340 /* If there's no standout mode, try to use underlining instead. */
4341 if (tty->TS_standout_mode == 0)
4343 tty->TS_standout_mode = tty->TS_enter_underline_mode;
4344 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
4347 /* If no `se' string, try using a `me' string instead.
4348 If that fails, we can't use standout mode at all. */
4349 if (tty->TS_end_standout_mode == 0)
4351 char *s = tgetstr ("me", address);
4352 if (s != 0)
4353 tty->TS_end_standout_mode = s;
4354 else
4355 tty->TS_standout_mode = 0;
4358 if (tty->TF_teleray)
4360 tty->Wcm->cm_tab = 0;
4361 /* We can't support standout mode, because it uses magic cookies. */
4362 tty->TS_standout_mode = 0;
4363 /* But that means we cannot rely on ^M to go to column zero! */
4364 CR (tty) = 0;
4365 /* LF can't be trusted either -- can alter hpos. */
4366 /* If move at column 0 thru a line with TS_standout_mode. */
4367 Down (tty) = 0;
4370 tty->specified_window = FrameRows (tty);
4372 if (Wcm_init (tty) == -1) /* Can't do cursor motion. */
4374 maybe_fatal (must_succeed, terminal,
4375 "Terminal type \"%s\" is not powerful enough to run Emacs",
4376 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
4377 It lacks the ability to position the cursor.\n\
4378 If that is not the actual type of terminal you have,\n\
4379 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
4380 `setenv TERM ...') to specify the correct type. It may be necessary\n"
4381 # ifdef TERMINFO
4382 "to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
4383 # else /* TERMCAP */
4384 "to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
4385 # endif /* TERMINFO */
4386 terminal_type);
4389 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
4390 maybe_fatal (must_succeed, terminal,
4391 "Could not determine the frame size",
4392 "Could not determine the frame size");
4394 tty->delete_in_insert_mode
4395 = tty->TS_delete_mode && tty->TS_insert_mode
4396 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
4398 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
4400 tty->scroll_region_ok
4401 = (tty->Wcm->cm_abs
4402 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
4404 tty->line_ins_del_ok
4405 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
4406 && (tty->TS_del_line || tty->TS_del_multi_lines))
4407 || (tty->scroll_region_ok
4408 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
4410 tty->char_ins_del_ok
4411 = ((tty->TS_ins_char || tty->TS_insert_mode
4412 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
4413 && (tty->TS_del_char || tty->TS_del_multi_chars));
4415 init_baud_rate (fileno (tty->input));
4417 #endif /* not DOS_NT */
4419 /* Init system terminal modes (RAW or CBREAK, etc.). */
4420 init_sys_modes (tty);
4422 return terminal;
4426 static void
4427 vfatal (const char *str, va_list ap)
4429 fprintf (stderr, "emacs: ");
4430 vfprintf (stderr, str, ap);
4431 if (!(strlen (str) > 0 && str[strlen (str) - 1] == '\n'))
4432 fprintf (stderr, "\n");
4433 fflush (stderr);
4434 exit (1);
4438 /* Auxiliary error-handling function for init_tty.
4439 Delete TERMINAL, then call error or fatal with str1 or str2,
4440 respectively, according to whether MUST_SUCCEED is true. */
4442 static void
4443 maybe_fatal (bool must_succeed, struct terminal *terminal,
4444 const char *str1, const char *str2, ...)
4446 va_list ap;
4447 va_start (ap, str2);
4448 if (terminal)
4449 delete_tty (terminal);
4451 if (must_succeed)
4452 vfatal (str2, ap);
4453 else
4454 verror (str1, ap);
4457 void
4458 fatal (const char *str, ...)
4460 va_list ap;
4461 va_start (ap, str);
4462 vfatal (str, ap);
4467 /* Delete the given tty terminal, closing all frames on it. */
4469 static void
4470 delete_tty (struct terminal *terminal)
4472 struct tty_display_info *tty;
4474 /* Protect against recursive calls. delete_frame in
4475 delete_terminal calls us back when it deletes our last frame. */
4476 if (!terminal->name)
4477 return;
4479 eassert (terminal->type == output_termcap);
4481 tty = terminal->display_info.tty;
4483 if (tty == tty_list)
4484 tty_list = tty->next;
4485 else
4487 struct tty_display_info *p;
4488 for (p = tty_list; p && p->next != tty; p = p->next)
4491 if (! p)
4492 /* This should not happen. */
4493 emacs_abort ();
4495 p->next = tty->next;
4496 tty->next = 0;
4499 /* reset_sys_modes needs a valid device, so this call needs to be
4500 before delete_terminal. */
4501 reset_sys_modes (tty);
4503 delete_terminal (terminal);
4505 xfree (tty->name);
4506 xfree (tty->type);
4508 if (tty->input)
4510 delete_keyboard_wait_descriptor (fileno (tty->input));
4511 if (tty->input != stdin)
4512 fclose (tty->input);
4514 if (tty->output && tty->output != stdout && tty->output != tty->input)
4515 fclose (tty->output);
4516 if (tty->termscript)
4517 fclose (tty->termscript);
4519 xfree (tty->old_tty);
4520 xfree (tty->Wcm);
4521 xfree (tty);
4524 void
4525 syms_of_term (void)
4527 DEFVAR_BOOL ("system-uses-terminfo", system_uses_terminfo,
4528 doc: /* Non-nil means the system uses terminfo rather than termcap.
4529 This variable can be used by terminal emulator packages. */);
4530 #ifdef TERMINFO
4531 system_uses_terminfo = 1;
4532 #else
4533 system_uses_terminfo = 0;
4534 #endif
4536 DEFVAR_LISP ("suspend-tty-functions", Vsuspend_tty_functions,
4537 doc: /* Functions run after suspending a tty.
4538 The functions are run with one argument, the terminal object to be suspended.
4539 See `suspend-tty'. */);
4540 Vsuspend_tty_functions = Qnil;
4543 DEFVAR_LISP ("resume-tty-functions", Vresume_tty_functions,
4544 doc: /* Functions run after resuming a tty.
4545 The functions are run with one argument, the terminal object that was revived.
4546 See `resume-tty'. */);
4547 Vresume_tty_functions = Qnil;
4549 DEFVAR_BOOL ("visible-cursor", visible_cursor,
4550 doc: /* Non-nil means to make the cursor very visible.
4551 This only has an effect when running in a text terminal.
4552 What means \"very visible\" is up to your terminal. It may make the cursor
4553 bigger, or it may make it blink, or it may do nothing at all. */);
4554 visible_cursor = 1;
4556 defsubr (&Stty_display_color_p);
4557 defsubr (&Stty_display_color_cells);
4558 defsubr (&Stty_no_underline);
4559 defsubr (&Stty_type);
4560 defsubr (&Scontrolling_tty_p);
4561 defsubr (&Stty_top_frame);
4562 defsubr (&Ssuspend_tty);
4563 defsubr (&Sresume_tty);
4564 #ifdef HAVE_GPM
4565 defsubr (&Sgpm_mouse_start);
4566 defsubr (&Sgpm_mouse_stop);
4567 #endif /* HAVE_GPM */
4569 #ifndef DOS_NT
4570 default_orig_pair = NULL;
4571 default_set_foreground = NULL;
4572 default_set_background = NULL;
4573 #endif /* !DOS_NT */
4575 encode_terminal_src = NULL;
4576 encode_terminal_dst = NULL;
4578 DEFSYM (Qtty_mode_set_strings, "tty-mode-set-strings");
4579 DEFSYM (Qtty_mode_reset_strings, "tty-mode-reset-strings");
4581 #ifndef MSDOS
4582 DEFSYM (Qtty_menu_next_item, "tty-menu-next-item");
4583 DEFSYM (Qtty_menu_prev_item, "tty-menu-prev-item");
4584 DEFSYM (Qtty_menu_next_menu, "tty-menu-next-menu");
4585 DEFSYM (Qtty_menu_prev_menu, "tty-menu-prev-menu");
4586 DEFSYM (Qtty_menu_select, "tty-menu-select");
4587 DEFSYM (Qtty_menu_ignore, "tty-menu-ignore");
4588 DEFSYM (Qtty_menu_exit, "tty-menu-exit");
4589 DEFSYM (Qtty_menu_mouse_movement, "tty-menu-mouse-movement");
4590 DEFSYM (Qtty_menu_navigation_map, "tty-menu-navigation-map");
4591 #endif