This source file includes following definitions.
- tty_ring_bell
- tty_send_additional_strings
- tty_set_terminal_modes
- tty_reset_terminal_modes
- tty_update_end
- tty_set_terminal_window
- tty_set_scroll_region
- tty_turn_on_insert
- tty_turn_off_insert
- tty_turn_off_highlight
- tty_turn_on_highlight
- tty_toggle_highlight
- tty_hide_cursor
- tty_show_cursor
- tty_background_highlight
- tty_highlight_if_desired
- tty_cursor_to
- tty_raw_cursor_to
- tty_clear_to_end
- tty_clear_frame
- tty_clear_end_of_line
- encode_terminal_code
- tty_write_glyphs
- tty_write_glyphs_with_face
- tty_insert_glyphs
- tty_delete_glyphs
- tty_ins_del_lines
- string_cost
- string_cost_one_line
- per_line_cost
- calculate_ins_del_char_costs
- calculate_costs
- term_get_fkeys
- term_get_fkeys_1
- append_glyph
- tty_append_glyph
- produce_glyphs
- append_composite_glyph
- produce_composite_glyph
- append_glyphless_glyph
- produce_glyphless_glyph
- turn_on_face
- turn_off_face
- tty_capable_p
- DEFUN
- DEFUN
- tty_default_color_capabilities
- tty_setup_colors
- set_tty_color_mode
- tty_type_name
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- tty_draw_row_with_mouse_face
- term_mouse_moveto
- current_Time
- term_mouse_position
- term_mouse_click
- handle_one_term_event
- DEFUN
- close_gpm
- DEFUN
- tty_menu_create
- tty_menu_make_room
- tty_menu_search_pane
- tty_menu_calc_size
- mouse_get_xy
- tty_menu_display
- tty_menu_add_pane
- tty_menu_add_selection
- tty_menu_locate
- save_and_enable_current_matrix
- restore_desired_matrix
- free_saved_screen
- screen_update
- read_menu_input
- tty_menu_activate
- tty_menu_destroy
- tty_menu_help_callback
- tty_pop_down_menu
- tty_menu_last_menubar_item
- tty_menu_new_item_coords
- tty_menu_show
- create_tty_output
- tty_free_frame_resources
- tty_free_frame_resources
- clear_tty_hooks
- set_tty_hooks
- dissociate_if_controlling_tty
- init_tty
- vfatal
- maybe_fatal
- fatal
- delete_tty
- syms_of_term
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include <config.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <sys/file.h>
27 #include <sys/time.h>
28 #include <unistd.h>
29
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 "sysstdio.h"
48 #ifdef MSDOS
49 #include "msdos.h"
50 static int been_here = -1;
51 #endif
52
53 #ifdef USE_X_TOOLKIT
54 #include "../lwlib/lwlib.h"
55 #endif
56
57 #include "cm.h"
58 #include "menu.h"
59
60
61 #ifdef WINDOWSNT
62 #include "w32term.h"
63 #endif
64
65 static void tty_set_scroll_region (struct frame *f, int start, int stop);
66 static void turn_on_face (struct frame *, int face_id);
67 static void turn_off_face (struct frame *, int face_id);
68 static void tty_turn_off_highlight (struct tty_display_info *);
69 static void tty_show_cursor (struct tty_display_info *);
70 static void tty_hide_cursor (struct tty_display_info *);
71 static void tty_background_highlight (struct tty_display_info *tty);
72 static void clear_tty_hooks (struct terminal *terminal);
73 static void set_tty_hooks (struct terminal *terminal);
74 static void dissociate_if_controlling_tty (int fd);
75 static void delete_tty (struct terminal *);
76 static AVOID maybe_fatal (bool, struct terminal *, const char *, const char *,
77 ...)
78 ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5);
79 static AVOID vfatal (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0);
80
81
82 #define OUTPUT(tty, a) \
83 emacs_tputs ((tty), a, \
84 FRAME_TOTAL_LINES (XFRAME (selected_frame)) - curY (tty), \
85 cmputc)
86
87 #define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
88 #define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
89
90 #define OUTPUT_IF(tty, a) \
91 do { \
92 if (a) \
93 OUTPUT (tty, a); \
94 } while (0)
95
96 #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
97
98
99
100
101 struct tty_display_info *tty_list;
102
103
104
105
106 enum no_color_bit
107 {
108 NC_STANDOUT = 1 << 0,
109 NC_UNDERLINE = 1 << 1,
110 NC_REVERSE = 1 << 2,
111 NC_ITALIC = 1 << 3,
112 NC_DIM = 1 << 4,
113 NC_BOLD = 1 << 5,
114 NC_STRIKE_THROUGH = 1 << 6,
115 NC_PROTECT = 1 << 7
116 };
117
118
119
120
121
122 static int max_frame_cols;
123
124
125
126 #ifdef HAVE_GPM
127 #include <sys/fcntl.h>
128
129
130 struct tty_display_info *gpm_tty = NULL;
131
132
133 static int last_mouse_x, last_mouse_y;
134 #endif
135
136
137
138 static void
139 tty_ring_bell (struct frame *f)
140 {
141 struct tty_display_info *tty = FRAME_TTY (f);
142
143 if (tty->output)
144 {
145 OUTPUT (tty, (tty->TS_visible_bell && visible_bell
146 ? tty->TS_visible_bell
147 : tty->TS_bell));
148 fflush (tty->output);
149 }
150 }
151
152
153
154 static void
155 tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
156 {
157
158
159
160
161 if (! terminal->name)
162 return;
163 struct tty_display_info *tty = terminal->display_info.tty;
164
165 for (Lisp_Object extra_codes
166 = CDR_SAFE (assq_no_quit (sym, terminal->param_alist));
167 CONSP (extra_codes);
168 extra_codes = XCDR (extra_codes))
169 {
170 Lisp_Object string = XCAR (extra_codes);
171 if (STRINGP (string))
172 {
173 fwrite (SDATA (string), 1, SBYTES (string), tty->output);
174 if (tty->termscript)
175 fwrite (SDATA (string), 1, SBYTES (string), tty->termscript);
176 }
177 }
178 }
179
180 static void
181 tty_set_terminal_modes (struct terminal *terminal)
182 {
183 struct tty_display_info *tty = terminal->display_info.tty;
184
185 if (tty->output)
186 {
187 if (tty->TS_termcap_modes)
188 OUTPUT (tty, tty->TS_termcap_modes);
189 else
190 {
191
192
193 int i;
194 current_tty = tty;
195 for (i = 0; i < FRAME_TOTAL_LINES (XFRAME (selected_frame)); i++)
196 cmputc ('\n');
197 }
198
199 OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
200 OUTPUT_IF (tty, tty->TS_keypad_mode);
201 losecursor (tty);
202 tty_send_additional_strings (terminal, Qtty_mode_set_strings);
203 fflush (tty->output);
204 }
205 }
206
207
208
209 static void
210 tty_reset_terminal_modes (struct terminal *terminal)
211 {
212 struct tty_display_info *tty = terminal->display_info.tty;
213
214 if (tty->output)
215 {
216 tty_send_additional_strings (terminal, Qtty_mode_reset_strings);
217 tty_turn_off_highlight (tty);
218 tty_turn_off_insert (tty);
219 OUTPUT_IF (tty, tty->TS_end_keypad_mode);
220 OUTPUT_IF (tty, tty->TS_cursor_normal);
221 OUTPUT_IF (tty, tty->TS_end_termcap_modes);
222 OUTPUT_IF (tty, tty->TS_orig_pair);
223
224 current_tty = tty;
225 cmputc ('\r');
226 fflush (tty->output);
227 }
228 }
229
230
231
232 static void
233 tty_update_end (struct frame *f)
234 {
235 struct tty_display_info *tty = FRAME_TTY (f);
236
237 if (!XWINDOW (selected_window)->cursor_off_p)
238 tty_show_cursor (tty);
239 tty_turn_off_insert (tty);
240 tty_background_highlight (tty);
241 fflush (tty->output);
242 }
243
244
245
246 static void
247 tty_set_terminal_window (struct frame *f, int size)
248 {
249 struct tty_display_info *tty = FRAME_TTY (f);
250
251 tty->specified_window = size ? size : FRAME_TOTAL_LINES (f);
252 if (FRAME_SCROLL_REGION_OK (f))
253 tty_set_scroll_region (f, 0, tty->specified_window);
254 }
255
256 static void
257 tty_set_scroll_region (struct frame *f, int start, int stop)
258 {
259 char *buf;
260 struct tty_display_info *tty = FRAME_TTY (f);
261
262 if (tty->TS_set_scroll_region)
263 buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1, 0, 0);
264 else if (tty->TS_set_scroll_region_1)
265 buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
266 FRAME_TOTAL_LINES (f), start,
267 FRAME_TOTAL_LINES (f) - stop,
268 FRAME_TOTAL_LINES (f));
269 else
270 buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
271
272 OUTPUT (tty, buf);
273 xfree (buf);
274 losecursor (tty);
275 }
276
277
278 static void
279 tty_turn_on_insert (struct tty_display_info *tty)
280 {
281 if (!tty->insert_mode)
282 OUTPUT (tty, tty->TS_insert_mode);
283 tty->insert_mode = 1;
284 }
285
286 void
287 tty_turn_off_insert (struct tty_display_info *tty)
288 {
289 if (tty->insert_mode)
290 OUTPUT (tty, tty->TS_end_insert_mode);
291 tty->insert_mode = 0;
292 }
293
294
295
296 static void
297 tty_turn_off_highlight (struct tty_display_info *tty)
298 {
299 if (tty->standout_mode)
300 OUTPUT_IF (tty, tty->TS_end_standout_mode);
301 tty->standout_mode = 0;
302 }
303
304 static void
305 tty_turn_on_highlight (struct tty_display_info *tty)
306 {
307 if (!tty->standout_mode)
308 OUTPUT_IF (tty, tty->TS_standout_mode);
309 tty->standout_mode = 1;
310 }
311
312 static void
313 tty_toggle_highlight (struct tty_display_info *tty)
314 {
315 if (tty->standout_mode)
316 tty_turn_off_highlight (tty);
317 else
318 tty_turn_on_highlight (tty);
319 }
320
321
322
323
324 static void
325 tty_hide_cursor (struct tty_display_info *tty)
326 {
327 if (tty->cursor_hidden == 0)
328 {
329 tty->cursor_hidden = 1;
330 #ifdef WINDOWSNT
331 w32con_hide_cursor ();
332 #else
333 OUTPUT_IF (tty, tty->TS_cursor_invisible);
334 #endif
335 }
336 }
337
338
339
340
341 static void
342 tty_show_cursor (struct tty_display_info *tty)
343 {
344 if (tty->cursor_hidden)
345 {
346 tty->cursor_hidden = 0;
347 #ifdef WINDOWSNT
348 w32con_show_cursor ();
349 #else
350 OUTPUT_IF (tty, tty->TS_cursor_normal);
351 if (visible_cursor)
352 OUTPUT_IF (tty, tty->TS_cursor_visible);
353 #endif
354 }
355 }
356
357
358
359
360
361
362 static void
363 tty_background_highlight (struct tty_display_info *tty)
364 {
365 if (inverse_video)
366 tty_turn_on_highlight (tty);
367 else
368 tty_turn_off_highlight (tty);
369 }
370
371
372
373 static void
374 tty_highlight_if_desired (struct tty_display_info *tty)
375 {
376 if (inverse_video)
377 tty_turn_on_highlight (tty);
378 else
379 tty_turn_off_highlight (tty);
380 }
381
382
383
384
385
386 static void
387 tty_cursor_to (struct frame *f, int vpos, int hpos)
388 {
389 struct tty_display_info *tty = FRAME_TTY (f);
390
391
392
393 if (! tty->costs_set)
394 return;
395
396 if (curY (tty) == vpos
397 && curX (tty) == hpos)
398 return;
399 if (!tty->TF_standout_motion)
400 tty_background_highlight (tty);
401 if (!tty->TF_insmode_motion)
402 tty_turn_off_insert (tty);
403 cmgoto (tty, vpos, hpos);
404 }
405
406
407
408 static void
409 tty_raw_cursor_to (struct frame *f, int row, int col)
410 {
411 struct tty_display_info *tty = FRAME_TTY (f);
412
413 if (curY (tty) == row
414 && curX (tty) == col)
415 return;
416 if (!tty->TF_standout_motion)
417 tty_background_highlight (tty);
418 if (!tty->TF_insmode_motion)
419 tty_turn_off_insert (tty);
420 cmgoto (tty, row, col);
421 }
422
423
424
425
426
427 static void
428 tty_clear_to_end (struct frame *f)
429 {
430 register int i;
431 struct tty_display_info *tty = FRAME_TTY (f);
432
433 if (tty->TS_clr_to_bottom)
434 {
435 tty_background_highlight (tty);
436 OUTPUT (tty, tty->TS_clr_to_bottom);
437 }
438 else
439 {
440 for (i = curY (tty); i < FRAME_TOTAL_LINES (f); i++)
441 {
442 cursor_to (f, i, 0);
443 clear_end_of_line (f, FRAME_COLS (f));
444 }
445 }
446 }
447
448
449
450 static void
451 tty_clear_frame (struct frame *f)
452 {
453 struct tty_display_info *tty = FRAME_TTY (f);
454
455 if (tty->TS_clr_frame)
456 {
457 tty_background_highlight (tty);
458 OUTPUT (tty, tty->TS_clr_frame);
459 cmat (tty, 0, 0);
460 }
461 else
462 {
463 cursor_to (f, 0, 0);
464 clear_to_end (f);
465 }
466 }
467
468
469
470
471
472 static void
473 tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
474 {
475 register int i;
476 struct tty_display_info *tty = FRAME_TTY (f);
477
478
479
480 if (! tty->costs_set)
481 return;
482
483 if (curX (tty) >= first_unused_hpos)
484 return;
485 tty_background_highlight (tty);
486 if (tty->TS_clr_line)
487 {
488 OUTPUT1 (tty, tty->TS_clr_line);
489 }
490 else
491 {
492 tty_turn_off_insert (tty);
493
494
495 if (AutoWrap (tty)
496 && curY (tty) == FrameRows (tty) - 1
497 && first_unused_hpos == FrameCols (tty))
498 first_unused_hpos--;
499
500 for (i = curX (tty); i < first_unused_hpos; i++)
501 {
502 if (tty->termscript)
503 putc (' ', tty->termscript);
504 putc (' ', tty->output);
505 }
506 cmplus (tty, first_unused_hpos - curX (tty));
507 }
508 }
509
510
511 static unsigned char *encode_terminal_src;
512 static unsigned char *encode_terminal_dst;
513
514 static ptrdiff_t encode_terminal_src_size;
515 static ptrdiff_t encode_terminal_dst_size;
516
517
518
519
520
521 unsigned char *
522 encode_terminal_code (struct glyph *src, int src_len,
523 struct coding_system *coding)
524 {
525 struct glyph *src_end = src + src_len;
526 unsigned char *buf;
527 ptrdiff_t nchars, nbytes, required;
528 ptrdiff_t tlen = GLYPH_TABLE_LENGTH;
529 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
530 Lisp_Object charset_list;
531
532
533
534
535
536 if (INT_MULTIPLY_WRAPV (src_len, MAX_MULTIBYTE_LENGTH, &required))
537 memory_full (SIZE_MAX);
538 if (encode_terminal_src_size < required)
539 encode_terminal_src = xpalloc (encode_terminal_src,
540 &encode_terminal_src_size,
541 required - encode_terminal_src_size,
542 -1, sizeof *encode_terminal_src);
543
544 charset_list = coding_charset_list (coding);
545
546 buf = encode_terminal_src;
547 nchars = 0;
548 while (src < src_end)
549 {
550 if (src->type == COMPOSITE_GLYPH)
551 {
552 struct composition *cmp;
553 Lisp_Object gstring UNINIT;
554 int i;
555
556 nbytes = buf - encode_terminal_src;
557 if (src->u.cmp.automatic)
558 {
559 cmp = NULL;
560 gstring = composition_gstring_from_id (src->u.cmp.id);
561 required = src->slice.cmp.to - src->slice.cmp.from + 1;
562 }
563 else
564 {
565 cmp = composition_table[src->u.cmp.id];
566 required = cmp->glyph_len;
567 }
568 required *= MAX_MULTIBYTE_LENGTH;
569
570 if (encode_terminal_src_size - nbytes < required)
571 {
572 encode_terminal_src =
573 xpalloc (encode_terminal_src, &encode_terminal_src_size,
574 required - (encode_terminal_src_size - nbytes),
575 -1, 1);
576 buf = encode_terminal_src + nbytes;
577 }
578
579 if (!cmp)
580 for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
581 {
582 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
583 int c = LGLYPH_CHAR (g);
584
585 if (! char_charset (c, charset_list, NULL))
586 c = '?';
587 buf += CHAR_STRING (c, buf);
588 nchars++;
589 }
590 else
591 for (i = 0; i < cmp->glyph_len; i++)
592 {
593 int c = COMPOSITION_GLYPH (cmp, i);
594
595
596
597 if (c == '\t')
598 continue;
599 if (char_charset (c, charset_list, NULL))
600 {
601 if (CHARACTER_WIDTH (c) == 0
602 && i > 0 && COMPOSITION_GLYPH (cmp, i - 1) == '\t')
603
604 {
605 buf += CHAR_STRING (' ', buf);
606 nchars++;
607 }
608 }
609 else
610 c = '?';
611 buf += CHAR_STRING (c, buf);
612 nchars++;
613 }
614 }
615
616 else if (! CHAR_GLYPH_PADDING_P (*src))
617 {
618 GLYPH g;
619 int c UNINIT;
620 Lisp_Object string;
621
622 string = Qnil;
623 SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
624
625 if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
626 {
627
628 c = src->u.ch;
629 }
630 else
631 {
632
633
634 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
635
636 if (GLYPH_SIMPLE_P (tbase, tlen, g))
637
638
639 c = GLYPH_CHAR (g);
640 else
641
642 string = tbase[GLYPH_CHAR (g)];
643 }
644
645 if (NILP (string))
646 {
647 nbytes = buf - encode_terminal_src;
648 if (encode_terminal_src_size - nbytes < MAX_MULTIBYTE_LENGTH)
649 {
650 encode_terminal_src =
651 xpalloc (encode_terminal_src, &encode_terminal_src_size,
652 MAX_MULTIBYTE_LENGTH, -1, 1);
653 buf = encode_terminal_src + nbytes;
654 }
655 if (CHAR_BYTE8_P (c)
656 || char_charset (c, charset_list, NULL))
657 {
658
659 buf += CHAR_STRING (c, buf);
660 nchars++;
661 }
662 else
663 {
664
665 *buf++ = '?';
666 nchars++;
667 while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
668 {
669 *buf++ = '?';
670 nchars++;
671 src++;
672 }
673 }
674 }
675 else
676 {
677 if (! STRING_MULTIBYTE (string))
678 string = string_to_multibyte (string);
679 nbytes = buf - encode_terminal_src;
680 if (encode_terminal_src_size - nbytes < SBYTES (string))
681 {
682 encode_terminal_src =
683 xpalloc (encode_terminal_src, &encode_terminal_src_size,
684 (SBYTES (string)
685 - (encode_terminal_src_size - nbytes)),
686 -1, 1);
687 buf = encode_terminal_src + nbytes;
688 }
689 memcpy (buf, SDATA (string), SBYTES (string));
690 buf += SBYTES (string);
691 nchars += SCHARS (string);
692 }
693 }
694 src++;
695 }
696
697 if (nchars == 0)
698 {
699 coding->produced = 0;
700 return NULL;
701 }
702
703 nbytes = buf - encode_terminal_src;
704 coding->source = encode_terminal_src;
705 if (encode_terminal_dst_size == 0)
706 {
707 encode_terminal_dst = xrealloc (encode_terminal_dst,
708 encode_terminal_src_size);
709 encode_terminal_dst_size = encode_terminal_src_size;
710 }
711 coding->destination = encode_terminal_dst;
712 coding->dst_bytes = encode_terminal_dst_size;
713 encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
714
715 encode_terminal_dst = coding->destination;
716 encode_terminal_dst_size = coding->dst_bytes;
717
718 return (encode_terminal_dst);
719 }
720
721
722
723
724
725 static void
726 tty_write_glyphs (struct frame *f, struct glyph *string, int len)
727 {
728 unsigned char *conversion_buffer;
729 struct coding_system *coding;
730 int n, stringlen;
731
732 struct tty_display_info *tty = FRAME_TTY (f);
733
734 tty_turn_off_insert (tty);
735 tty_hide_cursor (tty);
736
737
738
739
740 if (AutoWrap (tty)
741 && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
742 && (curX (tty) + len) == FRAME_COLS (f))
743 len --;
744 if (len <= 0)
745 return;
746
747 cmplus (tty, len);
748
749
750
751
752 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
753 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
754
755
756 coding->mode &= ~CODING_MODE_LAST_BLOCK;
757
758 for (stringlen = len; stringlen != 0; stringlen -= n)
759 {
760
761 int face_id = string->face_id;
762
763 for (n = 1; n < stringlen; ++n)
764 if (string[n].face_id != face_id)
765 break;
766
767
768 tty_highlight_if_desired (tty);
769 turn_on_face (f, face_id);
770
771 if (n == stringlen)
772
773 coding->mode |= CODING_MODE_LAST_BLOCK;
774 conversion_buffer = encode_terminal_code (string, n, coding);
775 if (coding->produced > 0)
776 {
777 block_input ();
778 fwrite (conversion_buffer, 1, coding->produced, tty->output);
779 clearerr (tty->output);
780 if (tty->termscript)
781 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
782 unblock_input ();
783 }
784 string += n;
785
786
787 turn_off_face (f, face_id);
788 tty_turn_off_highlight (tty);
789 }
790
791 cmcheckmagic (tty);
792 }
793
794 #ifndef DOS_NT
795
796 static void
797 tty_write_glyphs_with_face (register struct frame *f, register struct glyph *string,
798 register int len, register int face_id)
799 {
800 unsigned char *conversion_buffer;
801 struct coding_system *coding;
802
803 struct tty_display_info *tty = FRAME_TTY (f);
804
805 tty_turn_off_insert (tty);
806 tty_hide_cursor (tty);
807
808
809
810
811 if (AutoWrap (tty)
812 && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
813 && (curX (tty) + len) == FRAME_COLS (f))
814 len --;
815 if (len <= 0)
816 return;
817
818 cmplus (tty, len);
819
820
821
822
823 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
824 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
825
826
827 coding->mode &= ~CODING_MODE_LAST_BLOCK;
828
829
830 tty_highlight_if_desired (tty);
831 turn_on_face (f, face_id);
832
833 coding->mode |= CODING_MODE_LAST_BLOCK;
834 conversion_buffer = encode_terminal_code (string, len, coding);
835 if (coding->produced > 0)
836 {
837 block_input ();
838 fwrite (conversion_buffer, 1, coding->produced, tty->output);
839 clearerr (tty->output);
840 if (tty->termscript)
841 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
842 unblock_input ();
843 }
844
845
846 turn_off_face (f, face_id);
847 tty_turn_off_highlight (tty);
848
849 cmcheckmagic (tty);
850 }
851
852 #endif
853
854
855
856 static void
857 tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
858 {
859 char *buf;
860 struct glyph *glyph = NULL;
861 unsigned char *conversion_buffer;
862 unsigned char space[1];
863 struct coding_system *coding;
864
865 struct tty_display_info *tty = FRAME_TTY (f);
866
867 if (tty->TS_ins_multi_chars)
868 {
869 buf = tparam (tty->TS_ins_multi_chars, 0, 0, len, 0, 0, 0);
870 OUTPUT1 (tty, buf);
871 xfree (buf);
872 if (start)
873 write_glyphs (f, start, len);
874 return;
875 }
876
877 tty_turn_on_insert (tty);
878 cmplus (tty, len);
879
880 if (! start)
881 space[0] = SPACEGLYPH;
882
883
884
885
886 coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
887 ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
888
889
890 coding->mode &= ~CODING_MODE_LAST_BLOCK;
891
892 while (len-- > 0)
893 {
894 OUTPUT1_IF (tty, tty->TS_ins_char);
895 if (!start)
896 {
897 conversion_buffer = space;
898 coding->produced = 1;
899 }
900 else
901 {
902 tty_highlight_if_desired (tty);
903 turn_on_face (f, start->face_id);
904 glyph = start;
905 ++start;
906
907
908 while (len && CHAR_GLYPH_PADDING_P (*start))
909 {
910 OUTPUT1_IF (tty, tty->TS_ins_char);
911 start++, len--;
912 }
913
914 if (len <= 0)
915
916 coding->mode |= CODING_MODE_LAST_BLOCK;
917
918 conversion_buffer = encode_terminal_code (glyph, 1, coding);
919 }
920
921 if (coding->produced > 0)
922 {
923 block_input ();
924 fwrite (conversion_buffer, 1, coding->produced, tty->output);
925 clearerr (tty->output);
926 if (tty->termscript)
927 fwrite (conversion_buffer, 1, coding->produced, tty->termscript);
928 unblock_input ();
929 }
930
931 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
932 if (start)
933 {
934 turn_off_face (f, glyph->face_id);
935 tty_turn_off_highlight (tty);
936 }
937 }
938
939 cmcheckmagic (tty);
940 }
941
942
943
944 static void
945 tty_delete_glyphs (struct frame *f, int n)
946 {
947 char *buf;
948 register int i;
949
950 struct tty_display_info *tty = FRAME_TTY (f);
951
952 if (tty->delete_in_insert_mode)
953 {
954 tty_turn_on_insert (tty);
955 }
956 else
957 {
958 tty_turn_off_insert (tty);
959 OUTPUT_IF (tty, tty->TS_delete_mode);
960 }
961
962 if (tty->TS_del_multi_chars)
963 {
964 buf = tparam (tty->TS_del_multi_chars, 0, 0, n, 0, 0, 0);
965 OUTPUT1 (tty, buf);
966 xfree (buf);
967 }
968 else
969 for (i = 0; i < n; i++)
970 OUTPUT1 (tty, tty->TS_del_char);
971 if (!tty->delete_in_insert_mode)
972 OUTPUT_IF (tty, tty->TS_end_delete_mode);
973 }
974
975
976
977 static void
978 tty_ins_del_lines (struct frame *f, int vpos, int n)
979 {
980 struct tty_display_info *tty = FRAME_TTY (f);
981 const char *multi =
982 n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
983 const char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
984 const char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
985
986 int i = eabs (n);
987 char *buf;
988
989
990
991
992
993
994
995
996 if (FRAME_SCROLL_REGION_OK (f)
997 && vpos + i >= tty->specified_window)
998 return;
999 if (!FRAME_MEMORY_BELOW_FRAME (f)
1000 && vpos + i >= FRAME_TOTAL_LINES (f))
1001 return;
1002
1003 if (multi)
1004 {
1005 raw_cursor_to (f, vpos, 0);
1006 tty_background_highlight (tty);
1007 buf = tparam (multi, 0, 0, i, 0, 0, 0);
1008 OUTPUT (tty, buf);
1009 xfree (buf);
1010 }
1011 else if (single)
1012 {
1013 raw_cursor_to (f, vpos, 0);
1014 tty_background_highlight (tty);
1015 while (--i >= 0)
1016 OUTPUT (tty, single);
1017 if (tty->TF_teleray)
1018 curX (tty) = 0;
1019 }
1020 else
1021 {
1022 tty_set_scroll_region (f, vpos, tty->specified_window);
1023 if (n < 0)
1024 raw_cursor_to (f, tty->specified_window - 1, 0);
1025 else
1026 raw_cursor_to (f, vpos, 0);
1027 tty_background_highlight (tty);
1028 while (--i >= 0)
1029 OUTPUTL (tty, scroll, tty->specified_window - vpos);
1030 tty_set_scroll_region (f, 0, tty->specified_window);
1031 }
1032
1033 if (!FRAME_SCROLL_REGION_OK (f)
1034 && FRAME_MEMORY_BELOW_FRAME (f)
1035 && n < 0)
1036 {
1037 cursor_to (f, FRAME_TOTAL_LINES (f) + n, 0);
1038 clear_to_end (f);
1039 }
1040 }
1041
1042
1043
1044
1045 int
1046 string_cost (const char *str)
1047 {
1048 cost = 0;
1049 if (str)
1050 tputs (str, 0, evalcost);
1051 return cost;
1052 }
1053
1054
1055
1056
1057 static int
1058 string_cost_one_line (const char *str)
1059 {
1060 cost = 0;
1061 if (str)
1062 tputs (str, 1, evalcost);
1063 return cost;
1064 }
1065
1066
1067
1068
1069 int
1070 per_line_cost (const char *str)
1071 {
1072 cost = 0;
1073 if (str)
1074 tputs (str, 0, evalcost);
1075 cost = - cost;
1076 if (str)
1077 tputs (str, 10, evalcost);
1078 return cost;
1079 }
1080
1081
1082
1083
1084
1085 int *char_ins_del_vector;
1086
1087 #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_COLS ((f))])
1088
1089 static void
1090 calculate_ins_del_char_costs (struct frame *f)
1091 {
1092 struct tty_display_info *tty = FRAME_TTY (f);
1093 int ins_startup_cost, del_startup_cost;
1094 int ins_cost_per_char, del_cost_per_char;
1095 register int i;
1096 register int *p;
1097
1098 if (tty->TS_ins_multi_chars)
1099 {
1100 ins_cost_per_char = 0;
1101 ins_startup_cost = string_cost_one_line (tty->TS_ins_multi_chars);
1102 }
1103 else if (tty->TS_ins_char || tty->TS_pad_inserted_char
1104 || (tty->TS_insert_mode && tty->TS_end_insert_mode))
1105 {
1106 ins_startup_cost = (30 * (string_cost (tty->TS_insert_mode)
1107 + string_cost (tty->TS_end_insert_mode))) / 100;
1108 ins_cost_per_char = (string_cost_one_line (tty->TS_ins_char)
1109 + string_cost_one_line (tty->TS_pad_inserted_char));
1110 }
1111 else
1112 {
1113 ins_startup_cost = 9999;
1114 ins_cost_per_char = 0;
1115 }
1116
1117 if (tty->TS_del_multi_chars)
1118 {
1119 del_cost_per_char = 0;
1120 del_startup_cost = string_cost_one_line (tty->TS_del_multi_chars);
1121 }
1122 else if (tty->TS_del_char)
1123 {
1124 del_startup_cost = (string_cost (tty->TS_delete_mode)
1125 + string_cost (tty->TS_end_delete_mode));
1126 if (tty->delete_in_insert_mode)
1127 del_startup_cost /= 2;
1128 del_cost_per_char = string_cost_one_line (tty->TS_del_char);
1129 }
1130 else
1131 {
1132 del_startup_cost = 9999;
1133 del_cost_per_char = 0;
1134 }
1135
1136
1137 p = &char_ins_del_cost (f)[0];
1138 for (i = FRAME_COLS (f); --i >= 0;)
1139 *--p = (del_startup_cost += del_cost_per_char);
1140
1141
1142 p = &char_ins_del_cost (f)[0];
1143 *p++ = 0;
1144
1145
1146 for (i = FRAME_COLS (f); --i >= 0;)
1147 *p++ = (ins_startup_cost += ins_cost_per_char);
1148 }
1149
1150 void
1151 calculate_costs (struct frame *frame)
1152 {
1153 FRAME_COST_BAUD_RATE (frame) = baud_rate;
1154
1155 if (FRAME_TERMCAP_P (frame))
1156 {
1157 struct tty_display_info *tty = FRAME_TTY (frame);
1158 register const char *f = (tty->TS_set_scroll_region
1159 ? tty->TS_set_scroll_region
1160 : tty->TS_set_scroll_region_1);
1161
1162 FRAME_SCROLL_REGION_COST (frame) = string_cost (f);
1163
1164 tty->costs_set = 1;
1165
1166
1167
1168
1169
1170
1171
1172
1173 max_frame_cols = max (max_frame_cols, FRAME_COLS (frame));
1174 if ((min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) - 1) / 2
1175 < max_frame_cols)
1176 memory_full (SIZE_MAX);
1177
1178 char_ins_del_vector =
1179 xrealloc (char_ins_del_vector,
1180 (sizeof (int) + 2 * sizeof (int) * max_frame_cols));
1181
1182 memset (char_ins_del_vector, 0,
1183 (sizeof (int) + 2 * sizeof (int) * max_frame_cols));
1184
1185
1186 if (f && (!tty->TS_ins_line && !tty->TS_del_line))
1187 do_line_insertion_deletion_costs (frame,
1188 tty->TS_rev_scroll, tty->TS_ins_multi_lines,
1189 tty->TS_fwd_scroll, tty->TS_del_multi_lines,
1190 f, f, 1);
1191 else
1192 do_line_insertion_deletion_costs (frame,
1193 tty->TS_ins_line, tty->TS_ins_multi_lines,
1194 tty->TS_del_line, tty->TS_del_multi_lines,
1195 0, 0, 1);
1196
1197 calculate_ins_del_char_costs (frame);
1198
1199
1200 if (tty->TS_repeat
1201 && (baud_rate <= 0
1202 || per_line_cost (tty->TS_repeat) < 9000 / baud_rate))
1203 tty->RPov = string_cost (tty->TS_repeat);
1204 else
1205 tty->RPov = FRAME_COLS (frame) * 2;
1206
1207 cmcostinit (FRAME_TTY (frame));
1208 }
1209 }
1210
1211 struct fkey_table {
1212 const char *cap, *name;
1213 };
1214
1215 #ifndef DOS_NT
1216
1217
1218
1219
1220
1221
1222
1223 static const struct fkey_table keys[] =
1224 {
1225 {"kh", "home"},
1226 {"kl", "left"},
1227 {"ku", "up"},
1228 {"kr", "right"},
1229 {"kd", "down"},
1230 {"%8", "prior"},
1231 {"%5", "next"},
1232 {"@7", "end"},
1233 {"@1", "begin"},
1234 {"*6", "select"},
1235 {"%9", "print"},
1236 {"@4", "execute"},
1237
1238
1239
1240 {"&8", "undo"},
1241 {"%0", "redo"},
1242 {"%7", "menu"},
1243 {"@0", "find"},
1244 {"@2", "cancel"},
1245 {"%1", "help"},
1246
1247
1248
1249 {"&4", "reset"},
1250
1251
1252
1253 {"kE", "clearline"},
1254 {"kA", "insertline"},
1255 {"kL", "deleteline"},
1256 {"kI", "insertchar"},
1257 {"kD", "deletechar"},
1258 {"kB", "backtab"},
1259
1260
1261
1262 {"@8", "kp-enter"},
1263
1264
1265
1266
1267
1268
1269 {"K4", "kp-1"},
1270
1271
1272
1273 {"K5", "kp-3"},
1274
1275
1276
1277 {"K2", "kp-5"},
1278
1279
1280
1281 {"K1", "kp-7"},
1282
1283
1284
1285 {"K3", "kp-9"},
1286
1287
1288
1289 {"k1", "f1"},
1290 {"k2", "f2"},
1291 {"k3", "f3"},
1292 {"k4", "f4"},
1293 {"k5", "f5"},
1294 {"k6", "f6"},
1295 {"k7", "f7"},
1296 {"k8", "f8"},
1297 {"k9", "f9"},
1298
1299 {"&0", "S-cancel"},
1300 {"&9", "S-begin"},
1301 {"*0", "S-find"},
1302 {"*1", "S-execute"},
1303 {"*4", "S-delete"},
1304 {"*7", "S-end"},
1305 {"*8", "S-clearline"},
1306 {"#1", "S-help"},
1307 {"#2", "S-home"},
1308 {"#3", "S-insert"},
1309 {"#4", "S-left"},
1310 {"%d", "S-menu"},
1311 {"%c", "S-next"},
1312 {"%e", "S-prior"},
1313 {"%f", "S-print"},
1314 {"%g", "S-redo"},
1315 {"%i", "S-right"},
1316 {"!3", "S-undo"}
1317 };
1318
1319 static char **term_get_fkeys_address;
1320 static KBOARD *term_get_fkeys_kboard;
1321 static Lisp_Object term_get_fkeys_1 (void);
1322
1323
1324
1325
1326
1327 static void
1328 term_get_fkeys (char **address, KBOARD *kboard)
1329 {
1330
1331
1332
1333
1334
1335
1336
1337
1338 term_get_fkeys_address = address;
1339 term_get_fkeys_kboard = kboard;
1340 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1341 }
1342
1343 static Lisp_Object
1344 term_get_fkeys_1 (void)
1345 {
1346 int i;
1347
1348 char **address = term_get_fkeys_address;
1349 KBOARD *kboard = term_get_fkeys_kboard;
1350
1351
1352
1353 if (!KEYMAPP (KVAR (kboard, Vinput_decode_map)))
1354 kset_input_decode_map (kboard, Fmake_sparse_keymap (Qnil));
1355
1356 for (i = 0; i < ARRAYELTS (keys); i++)
1357 {
1358 char *sequence = tgetstr (keys[i].cap, address);
1359 if (sequence)
1360 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
1361 make_vector (1, intern (keys[i].name)), Qnil);
1362 }
1363
1364
1365
1366
1367
1368
1369 {
1370 const char *k_semi = tgetstr ("k;", address);
1371 const char *k0 = tgetstr ("k0", address);
1372 const char *k0_name = "f10";
1373
1374 if (k_semi)
1375 {
1376 if (k0)
1377
1378
1379 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
1380 make_vector (1, intern ("f0")), Qnil);
1381 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k_semi),
1382 make_vector (1, intern ("f10")), Qnil);
1383 }
1384 else if (k0)
1385 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
1386 make_vector (1, intern (k0_name)), Qnil);
1387 }
1388
1389
1390 {
1391 char fcap[3], fkey[4];
1392
1393 fcap[0] = 'F'; fcap[2] = '\0';
1394 for (i = 11; i < 64; i++)
1395 {
1396 if (i <= 19)
1397 fcap[1] = '1' + i - 11;
1398 else if (i <= 45)
1399 fcap[1] = 'A' + i - 20;
1400 else
1401 fcap[1] = 'a' + i - 46;
1402
1403 {
1404 char *sequence = tgetstr (fcap, address);
1405 if (sequence)
1406 {
1407 sprintf (fkey, "f%d", i);
1408 Fdefine_key (KVAR (kboard, Vinput_decode_map),
1409 build_string (sequence),
1410 make_vector (1, intern (fkey)),
1411 Qnil);
1412 }
1413 }
1414 }
1415 }
1416
1417
1418
1419
1420 {
1421 #define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1422 if (!tgetstr (cap1, address)) \
1423 { \
1424 char *sequence = tgetstr (cap2, address); \
1425 if (sequence) \
1426 Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence), \
1427 make_vector (1, intern (sym)), Qnil); \
1428 }
1429
1430
1431 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1432
1433 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1434
1435 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1436
1437 CONDITIONAL_REASSIGN ("@7", "kH", "end");
1438 #undef CONDITIONAL_REASSIGN
1439 }
1440
1441 return Qnil;
1442 }
1443 #endif
1444
1445
1446
1447
1448
1449 static void append_glyph (struct it *);
1450 static void append_composite_glyph (struct it *);
1451 static void produce_composite_glyph (struct it *);
1452 static void append_glyphless_glyph (struct it *, int, const char *);
1453 static void produce_glyphless_glyph (struct it *, Lisp_Object);
1454
1455
1456
1457
1458
1459
1460
1461 static void
1462 append_glyph (struct it *it)
1463 {
1464 struct glyph *glyph, *end;
1465 int i;
1466
1467 eassert (it->glyph_row);
1468 glyph = (it->glyph_row->glyphs[it->area]
1469 + it->glyph_row->used[it->area]);
1470 end = it->glyph_row->glyphs[1 + it->area];
1471
1472
1473
1474 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1475 {
1476 struct glyph *g;
1477 int move_by = it->pixel_width;
1478
1479
1480 if (move_by > end - glyph)
1481 move_by = end - glyph;
1482 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1483 g[move_by] = *g;
1484 glyph = it->glyph_row->glyphs[it->area];
1485 end = glyph + move_by;
1486 }
1487
1488
1489
1490
1491
1492 for (i = 0;
1493 i < it->pixel_width && glyph < end;
1494 ++i)
1495 {
1496 glyph->type = CHAR_GLYPH;
1497 glyph->pixel_width = 1;
1498 glyph->u.ch = it->char_to_display;
1499 glyph->face_id = it->face_id;
1500 glyph->avoid_cursor_p = it->avoid_cursor_p;
1501 glyph->multibyte_p = it->multibyte_p;
1502 glyph->padding_p = i > 0;
1503 glyph->charpos = CHARPOS (it->position);
1504 glyph->object = it->object;
1505 if (it->bidi_p)
1506 {
1507 glyph->resolved_level = it->bidi_it.resolved_level;
1508 eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
1509 glyph->bidi_type = it->bidi_it.type;
1510 }
1511 else
1512 {
1513 glyph->resolved_level = 0;
1514 glyph->bidi_type = UNKNOWN_BT;
1515 }
1516
1517 ++it->glyph_row->used[it->area];
1518 ++glyph;
1519 }
1520 }
1521
1522
1523 void
1524 tty_append_glyph (struct it *it)
1525 {
1526 append_glyph (it);
1527 }
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549 void
1550 produce_glyphs (struct it *it)
1551 {
1552
1553
1554
1555 eassert (it->what == IT_CHARACTER
1556 || it->what == IT_COMPOSITION
1557 || it->what == IT_STRETCH
1558 || it->what == IT_GLYPHLESS);
1559
1560 if (it->what == IT_STRETCH)
1561 {
1562 produce_stretch_glyph (it);
1563 goto done;
1564 }
1565
1566 if (it->what == IT_COMPOSITION)
1567 {
1568 produce_composite_glyph (it);
1569 goto done;
1570 }
1571
1572 if (it->what == IT_GLYPHLESS)
1573 {
1574 produce_glyphless_glyph (it, Qnil);
1575 goto done;
1576 }
1577
1578 if (it->char_to_display >= 040 && it->char_to_display < 0177)
1579 {
1580 it->pixel_width = it->nglyphs = 1;
1581 if (it->glyph_row)
1582 append_glyph (it);
1583 }
1584 else if (it->char_to_display == '\n')
1585 it->pixel_width = it->nglyphs = 0;
1586 else if (it->char_to_display == '\t')
1587 {
1588 int absolute_x = (it->current_x
1589 + it->continuation_lines_width);
1590 int x0 = absolute_x;
1591
1592 if (!NILP (Vdisplay_line_numbers) && it->line_number_produced_p)
1593 absolute_x -= it->lnum_pixel_width;
1594 int next_tab_x
1595 = (((1 + absolute_x + it->tab_width - 1)
1596 / it->tab_width)
1597 * it->tab_width);
1598 if (!NILP (Vdisplay_line_numbers) && it->line_number_produced_p)
1599 next_tab_x += it->lnum_pixel_width;
1600 int nspaces;
1601
1602
1603
1604
1605
1606
1607 nspaces = next_tab_x - x0;
1608
1609 if (it->glyph_row)
1610 {
1611 int n = nspaces;
1612
1613 it->char_to_display = ' ';
1614 it->pixel_width = it->len = 1;
1615
1616 while (n--)
1617 append_glyph (it);
1618 }
1619
1620 it->pixel_width = nspaces;
1621 it->nglyphs = nspaces;
1622 }
1623 else if (CHAR_BYTE8_P (it->char_to_display))
1624 {
1625
1626
1627
1628
1629 it->pixel_width = it->nglyphs = 1;
1630 if (it->glyph_row)
1631 append_glyph (it);
1632 }
1633 else
1634 {
1635 struct terminal *t = FRAME_TERMINAL (it->f);
1636 Lisp_Object charset_list = t->charset_list, char_glyph;
1637
1638 if (char_charset (it->char_to_display, charset_list, NULL)
1639 && (char_glyph = terminal_glyph_code (t, it->char_to_display),
1640 NILP (char_glyph)
1641 || (FIXNUMP (char_glyph) && XFIXNUM (char_glyph) >= 0)))
1642 {
1643 it->pixel_width = CHARACTER_WIDTH (it->char_to_display);
1644 it->nglyphs = it->pixel_width;
1645 if (it->glyph_row)
1646 append_glyph (it);
1647 }
1648 else
1649 {
1650 Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
1651
1652 eassert (it->what == IT_GLYPHLESS);
1653 produce_glyphless_glyph (it, acronym);
1654 }
1655 }
1656
1657 done:
1658
1659
1660 if (it->area == TEXT_AREA)
1661 it->current_x += it->pixel_width;
1662 it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
1663 it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
1664 }
1665
1666
1667
1668
1669
1670
1671 static void
1672 append_composite_glyph (struct it *it)
1673 {
1674 struct glyph *glyph;
1675
1676 eassert (it->glyph_row);
1677 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1678 if (glyph < it->glyph_row->glyphs[1 + it->area])
1679 {
1680
1681
1682 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1683 {
1684 struct glyph *g;
1685
1686
1687 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1688 g[1] = *g;
1689 glyph = it->glyph_row->glyphs[it->area];
1690 }
1691 glyph->type = COMPOSITE_GLYPH;
1692 eassert (it->pixel_width <= SHRT_MAX);
1693 glyph->pixel_width = it->pixel_width;
1694 glyph->u.cmp.id = it->cmp_it.id;
1695 if (it->cmp_it.ch < 0)
1696 {
1697 glyph->u.cmp.automatic = 0;
1698 glyph->u.cmp.id = it->cmp_it.id;
1699 }
1700 else
1701 {
1702 glyph->u.cmp.automatic = 1;
1703 glyph->u.cmp.id = it->cmp_it.id;
1704 glyph->slice.cmp.from = it->cmp_it.from;
1705 glyph->slice.cmp.to = it->cmp_it.to - 1;
1706 }
1707
1708 glyph->avoid_cursor_p = it->avoid_cursor_p;
1709 glyph->multibyte_p = it->multibyte_p;
1710 glyph->face_id = it->face_id;
1711 glyph->padding_p = false;
1712 glyph->charpos = CHARPOS (it->position);
1713 glyph->object = it->object;
1714 if (it->bidi_p)
1715 {
1716 glyph->resolved_level = it->bidi_it.resolved_level;
1717 eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
1718 glyph->bidi_type = it->bidi_it.type;
1719 }
1720 else
1721 {
1722 glyph->resolved_level = 0;
1723 glyph->bidi_type = UNKNOWN_BT;
1724 }
1725
1726 ++it->glyph_row->used[it->area];
1727 ++glyph;
1728 }
1729 }
1730
1731
1732
1733
1734
1735
1736
1737 static void
1738 produce_composite_glyph (struct it *it)
1739 {
1740 if (it->cmp_it.ch < 0)
1741 {
1742 struct composition *cmp = composition_table[it->cmp_it.id];
1743
1744 it->pixel_width = cmp->width;
1745 }
1746 else
1747 {
1748 Lisp_Object gstring = composition_gstring_from_id (it->cmp_it.id);
1749
1750 it->pixel_width = composition_gstring_width (gstring, it->cmp_it.from,
1751 it->cmp_it.to, NULL);
1752 }
1753 it->nglyphs = 1;
1754 if (it->glyph_row)
1755 append_composite_glyph (it);
1756 }
1757
1758
1759
1760
1761
1762
1763
1764 static void
1765 append_glyphless_glyph (struct it *it, int face_id, const char *str)
1766 {
1767 struct glyph *glyph, *end;
1768 int i;
1769
1770 eassert (it->glyph_row);
1771 glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
1772 end = it->glyph_row->glyphs[1 + it->area];
1773
1774
1775
1776 if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
1777 {
1778 struct glyph *g;
1779 int move_by = it->pixel_width;
1780
1781
1782 if (move_by > end - glyph)
1783 move_by = end - glyph;
1784 for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
1785 g[move_by] = *g;
1786 glyph = it->glyph_row->glyphs[it->area];
1787 end = glyph + move_by;
1788 }
1789
1790 if (glyph >= end)
1791 return;
1792 glyph->type = CHAR_GLYPH;
1793 glyph->pixel_width = 1;
1794 glyph->avoid_cursor_p = it->avoid_cursor_p;
1795 glyph->multibyte_p = it->multibyte_p;
1796 glyph->face_id = face_id;
1797 glyph->padding_p = false;
1798 glyph->charpos = CHARPOS (it->position);
1799 glyph->object = it->object;
1800 if (it->bidi_p)
1801 {
1802 glyph->resolved_level = it->bidi_it.resolved_level;
1803 eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
1804 glyph->bidi_type = it->bidi_it.type;
1805 }
1806 else
1807 {
1808 glyph->resolved_level = 0;
1809 glyph->bidi_type = UNKNOWN_BT;
1810 }
1811
1812
1813
1814
1815 for (i = 0; i < it->nglyphs && glyph < end; ++i)
1816 {
1817 if (i > 0)
1818 glyph[0] = glyph[-1];
1819 glyph->u.ch = str[i];
1820 ++it->glyph_row->used[it->area];
1821 ++glyph;
1822 }
1823 }
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834 static void
1835 produce_glyphless_glyph (struct it *it, Lisp_Object acronym)
1836 {
1837 int len, face_id = merge_glyphless_glyph_face (it);
1838 char buf[sizeof "\\x" + max (6, (INT_WIDTH + 3) / 4)];
1839 char const *str = " ";
1840
1841 if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
1842 {
1843
1844
1845 len = 1;
1846 }
1847 else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
1848 {
1849 len = CHARACTER_WIDTH (it->c);
1850 if (len == 0)
1851 len = 1;
1852 else if (len > 4)
1853 len = 4;
1854 len = sprintf (buf, "[%.*s]", len, str);
1855 str = buf;
1856 }
1857 else
1858 {
1859 if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
1860 {
1861 if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
1862 acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
1863 if (CONSP (acronym))
1864 acronym = XCDR (acronym);
1865 str = STRINGP (acronym) ? SSDATA (acronym) : "";
1866
1867
1868
1869 if (STRINGP (acronym) && SCHARS (acronym) == 1)
1870 {
1871 buf[0] = str[0];
1872 len = 1;
1873 }
1874 else
1875 {
1876 buf[0] = '[';
1877 for (len = 0;
1878 len < 6 && str[len] && ASCII_CHAR_P (str[len]); len++)
1879 buf[1 + len] = str[len];
1880 buf[1 + len] = ']';
1881 len += 2;
1882 }
1883 }
1884 else
1885 {
1886 eassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEX_CODE);
1887 len = sprintf (buf,
1888 (it->c < 0x10000 ? "\\u%04X"
1889 : it->c <= MAX_UNICODE_CHAR ? "\\U%06X"
1890 : "\\x%06X"),
1891 it->c + 0u);
1892 }
1893 str = buf;
1894 }
1895
1896 it->pixel_width = len;
1897 it->nglyphs = len;
1898 if (it->glyph_row)
1899 append_glyphless_glyph (it, face_id, str);
1900 }
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912 #define MAY_USE_WITH_COLORS_P(tty, ATTR) \
1913 (tty->TN_max_colors > 0 \
1914 ? (tty->TN_no_color_video & (ATTR)) == 0 \
1915 : 1)
1916
1917
1918
1919
1920 static void
1921 turn_on_face (struct frame *f, int face_id)
1922 {
1923 struct face *face = FACE_FROM_ID (f, face_id);
1924 unsigned long fg = face->foreground;
1925 unsigned long bg = face->background;
1926 struct tty_display_info *tty = FRAME_TTY (f);
1927
1928
1929
1930
1931 if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE)
1932 && (inverse_video
1933 ? fg == FACE_TTY_DEFAULT_FG_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR
1934 : fg == FACE_TTY_DEFAULT_BG_COLOR || bg == FACE_TTY_DEFAULT_FG_COLOR))
1935 tty_toggle_highlight (tty);
1936
1937 if (face->tty_bold_p && MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
1938 OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
1939
1940 if (face->tty_italic_p && MAY_USE_WITH_COLORS_P (tty, NC_ITALIC))
1941 {
1942 if (tty->TS_enter_italic_mode)
1943 OUTPUT1 (tty, tty->TS_enter_italic_mode);
1944 else
1945
1946
1947
1948 OUTPUT1 (tty, tty->TS_enter_dim_mode);
1949 }
1950
1951 if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
1952 OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
1953
1954 if (face->tty_strike_through_p
1955 && MAY_USE_WITH_COLORS_P (tty, NC_STRIKE_THROUGH))
1956 OUTPUT1_IF (tty, tty->TS_enter_strike_through_mode);
1957
1958 if (tty->TN_max_colors > 0)
1959 {
1960 const char *ts;
1961 char *p;
1962
1963 ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
1964 if (face_tty_specified_color (fg) && ts)
1965 {
1966 p = tparam (ts, NULL, 0, fg, 0, 0, 0);
1967 OUTPUT (tty, p);
1968 xfree (p);
1969 }
1970
1971 ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
1972 if (face_tty_specified_color (bg) && ts)
1973 {
1974 p = tparam (ts, NULL, 0, bg, 0, 0, 0);
1975 OUTPUT (tty, p);
1976 xfree (p);
1977 }
1978 }
1979 }
1980
1981
1982
1983
1984 static void
1985 turn_off_face (struct frame *f, int face_id)
1986 {
1987 struct face *face = FACE_FROM_ID (f, face_id);
1988 struct tty_display_info *tty = FRAME_TTY (f);
1989
1990 if (tty->TS_exit_attribute_mode)
1991 {
1992
1993
1994
1995 if (face->tty_bold_p
1996 || face->tty_italic_p
1997 || face->tty_reverse_p
1998 || face->tty_underline_p
1999 || face->tty_strike_through_p)
2000 {
2001 OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
2002 if (strcmp (tty->TS_exit_attribute_mode, tty->TS_end_standout_mode) == 0)
2003 tty->standout_mode = 0;
2004 }
2005 }
2006 else
2007 {
2008
2009
2010 if (face->tty_underline_p)
2011 OUTPUT_IF (tty, tty->TS_exit_underline_mode);
2012 }
2013
2014
2015 if (tty->TN_max_colors > 0
2016 && ((face->foreground != FACE_TTY_DEFAULT_COLOR
2017 && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
2018 || (face->background != FACE_TTY_DEFAULT_COLOR
2019 && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
2020 OUTPUT1_IF (tty, tty->TS_orig_pair);
2021 }
2022
2023
2024
2025
2026
2027 bool
2028 tty_capable_p (struct tty_display_info *tty, unsigned int caps)
2029 {
2030 #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
2031 if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
2032 return 0;
2033
2034 TTY_CAPABLE_P_TRY (tty,
2035 TTY_CAP_INVERSE, tty->TS_standout_mode, NC_REVERSE);
2036 TTY_CAPABLE_P_TRY (tty,
2037 TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode,
2038 NC_UNDERLINE);
2039 TTY_CAPABLE_P_TRY (tty,
2040 TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
2041 TTY_CAPABLE_P_TRY (tty,
2042 TTY_CAP_DIM, tty->TS_enter_dim_mode, NC_DIM);
2043 TTY_CAPABLE_P_TRY (tty,
2044 TTY_CAP_ITALIC, tty->TS_enter_italic_mode, NC_ITALIC);
2045 TTY_CAPABLE_P_TRY (tty,
2046 TTY_CAP_STRIKE_THROUGH, tty->TS_enter_strike_through_mode,
2047 NC_STRIKE_THROUGH);
2048
2049
2050 return 1;
2051 }
2052
2053
2054
2055 DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
2056 0, 1, 0,
2057 doc:
2058
2059
2060
2061 )
2062 (Lisp_Object terminal)
2063 {
2064 struct terminal *t = decode_tty_terminal (terminal);
2065
2066 return (t && t->display_info.tty->TN_max_colors > 0) ? Qt : Qnil;
2067 }
2068
2069
2070 DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
2071 Stty_display_color_cells, 0, 1, 0,
2072 doc:
2073
2074
2075
2076 )
2077 (Lisp_Object terminal)
2078 {
2079 struct terminal *t = decode_tty_terminal (terminal);
2080
2081 return make_fixnum (t ? t->display_info.tty->TN_max_colors : 0);
2082 }
2083
2084 #ifndef DOS_NT
2085
2086
2087
2088
2089 static int default_max_colors;
2090 static int default_no_color_video;
2091 static char *default_orig_pair;
2092 static char *default_set_foreground;
2093 static char *default_set_background;
2094
2095
2096
2097 static void
2098 tty_default_color_capabilities (struct tty_display_info *tty, bool save)
2099 {
2100
2101 if (save)
2102 {
2103 dupstring (&default_orig_pair, tty->TS_orig_pair);
2104 dupstring (&default_set_foreground, tty->TS_set_foreground);
2105 dupstring (&default_set_background, tty->TS_set_background);
2106 default_max_colors = tty->TN_max_colors;
2107 default_no_color_video = tty->TN_no_color_video;
2108 }
2109 else
2110 {
2111 tty->TS_orig_pair = default_orig_pair;
2112 tty->TS_set_foreground = default_set_foreground;
2113 tty->TS_set_background = default_set_background;
2114 tty->TN_max_colors = default_max_colors;
2115 tty->TN_no_color_video = default_no_color_video;
2116 }
2117 }
2118
2119
2120
2121
2122
2123 static void
2124 tty_setup_colors (struct tty_display_info *tty, int mode)
2125 {
2126
2127 if (mode < -1)
2128 mode = -1;
2129
2130 switch (mode)
2131 {
2132 case -1:
2133 tty->TN_max_colors = 0;
2134 tty->TN_no_color_video = 0;
2135 tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL;
2136 break;
2137 case 0:
2138 default:
2139 tty_default_color_capabilities (tty, 0);
2140 break;
2141 case 8:
2142 tty->TS_orig_pair = "\033[0m";
2143 #ifdef TERMINFO
2144 tty->TS_set_foreground = "\033[3%p1%dm";
2145 tty->TS_set_background = "\033[4%p1%dm";
2146 #else
2147 tty->TS_set_foreground = "\033[3%dm";
2148 tty->TS_set_background = "\033[4%dm";
2149 #endif
2150 tty->TN_max_colors = 8;
2151 tty->TN_no_color_video = 0;
2152 break;
2153 }
2154 }
2155
2156 void
2157 set_tty_color_mode (struct tty_display_info *tty, struct frame *f)
2158 {
2159 Lisp_Object tem, val;
2160 Lisp_Object color_mode;
2161 int mode;
2162 Lisp_Object tty_color_mode_alist
2163 = Fintern_soft (build_string ("tty-color-mode-alist"), Qnil);
2164
2165 tem = assq_no_quit (Qtty_color_mode, f->param_alist);
2166 val = CONSP (tem) ? XCDR (tem) : Qnil;
2167
2168 if (FIXNUMP (val))
2169 color_mode = val;
2170 else if (SYMBOLP (tty_color_mode_alist))
2171 {
2172 tem = Fassq (val, Fsymbol_value (tty_color_mode_alist));
2173 color_mode = CONSP (tem) ? XCDR (tem) : Qnil;
2174 }
2175 else
2176 color_mode = Qnil;
2177
2178 mode = TYPE_RANGED_FIXNUMP (int, color_mode) ? XFIXNUM (color_mode) : 0;
2179
2180 if (mode != tty->previous_color_mode)
2181 {
2182 tty->previous_color_mode = mode;
2183 tty_setup_colors (tty , mode);
2184
2185 safe_call (1, intern ("tty-set-up-initial-frame-faces"));
2186 }
2187 }
2188
2189 #endif
2190
2191 char *
2192 tty_type_name (Lisp_Object terminal)
2193 {
2194 struct terminal *t = decode_tty_terminal (terminal);
2195
2196 return t? t->display_info.tty->type: NULL;
2197 }
2198
2199 DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
2200 doc:
2201
2202
2203
2204 )
2205 (Lisp_Object terminal)
2206 {
2207 char *name = tty_type_name (terminal);
2208
2209 return (name? build_string (name) : Qnil);
2210 }
2211
2212 DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
2213 doc:
2214
2215
2216
2217 )
2218 (Lisp_Object terminal)
2219 {
2220 struct terminal *t = decode_tty_terminal (terminal);
2221
2222 return (t && !strcmp (t->display_info.tty->name, DEV_TTY) ? Qt : Qnil);
2223 }
2224
2225 DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
2226 doc:
2227
2228
2229
2230
2231
2232
2233 )
2234 (Lisp_Object terminal)
2235 {
2236 struct terminal *t = decode_live_terminal (terminal);
2237
2238 if (t->type == output_termcap)
2239 t->display_info.tty->TS_enter_underline_mode = 0;
2240 return Qnil;
2241 }
2242
2243 DEFUN ("tty-top-frame", Ftty_top_frame, Stty_top_frame, 0, 1, 0,
2244 doc:
2245
2246
2247
2248 )
2249 (Lisp_Object terminal)
2250 {
2251 struct terminal *t = decode_live_terminal (terminal);
2252
2253 if (t->type == output_termcap)
2254 return t->display_info.tty->top_frame;
2255 return Qnil;
2256 }
2257
2258
2259
2260 DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
2261 doc:
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278 )
2279 (Lisp_Object tty)
2280 {
2281 struct terminal *t = decode_tty_terminal (tty);
2282 FILE *f;
2283
2284 if (!t)
2285 error ("Attempt to suspend a non-text terminal device");
2286
2287 f = t->display_info.tty->input;
2288
2289 if (f)
2290 {
2291
2292
2293
2294 Lisp_Object term;
2295 XSETTERMINAL (term, t);
2296 CALLN (Frun_hook_with_args, intern ("suspend-tty-functions"), term);
2297
2298 reset_sys_modes (t->display_info.tty);
2299 delete_keyboard_wait_descriptor (fileno (f));
2300
2301 #ifndef MSDOS
2302 if (f != t->display_info.tty->output)
2303 fclose (t->display_info.tty->output);
2304 fclose (f);
2305 #endif
2306
2307 t->display_info.tty->input = 0;
2308 t->display_info.tty->output = 0;
2309
2310 if (FRAMEP (t->display_info.tty->top_frame))
2311 SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
2312
2313 }
2314
2315
2316 clear_tty_hooks (t);
2317
2318 return Qnil;
2319 }
2320
2321 DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
2322 doc:
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337 )
2338 (Lisp_Object tty)
2339 {
2340 struct terminal *t = decode_tty_terminal (tty);
2341 int fd;
2342
2343 if (!t)
2344 error ("Attempt to resume a non-text terminal device");
2345
2346 if (!t->display_info.tty->input)
2347 {
2348 if (get_named_terminal (t->display_info.tty->name))
2349 error ("Cannot resume display while another display is active on the same device");
2350
2351 #ifdef MSDOS
2352 t->display_info.tty->output = stdout;
2353 t->display_info.tty->input = stdin;
2354 #else
2355 fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
2356 t->display_info.tty->input = t->display_info.tty->output
2357 = fd < 0 ? 0 : fdopen (fd, "w+");
2358
2359 if (! t->display_info.tty->input)
2360 {
2361 int open_errno = errno;
2362 emacs_close (fd);
2363 report_file_errno ("Cannot reopen tty device",
2364 build_string (t->display_info.tty->name),
2365 open_errno);
2366 }
2367
2368 if (!O_IGNORE_CTTY && strcmp (t->display_info.tty->name, DEV_TTY) != 0)
2369 dissociate_if_controlling_tty (fd);
2370 #endif
2371
2372 add_keyboard_wait_descriptor (fd);
2373
2374 if (FRAMEP (t->display_info.tty->top_frame))
2375 {
2376 struct frame *f = XFRAME (t->display_info.tty->top_frame);
2377 int width, height;
2378 int old_height = FRAME_COLS (f);
2379 int old_width = FRAME_TOTAL_LINES (f);
2380
2381
2382
2383 get_tty_size (fileno (t->display_info.tty->input), &width, &height);
2384 if (width != old_width || height != old_height)
2385 change_frame_size (f, width, height, false, false, false);
2386 SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
2387 }
2388
2389 set_tty_hooks (t);
2390 init_sys_modes (t->display_info.tty);
2391
2392
2393 Lisp_Object term;
2394 XSETTERMINAL (term, t);
2395 CALLN (Frun_hook_with_args, intern ("resume-tty-functions"), term);
2396 }
2397
2398 set_tty_hooks (t);
2399
2400 return Qnil;
2401 }
2402
2403 DEFUN ("tty--set-output-buffer-size", Ftty__set_output_buffer_size,
2404 Stty__set_output_buffer_size, 1, 2, 0, doc:
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414 )
2415 (Lisp_Object size, Lisp_Object tty)
2416 {
2417 if (!TYPE_RANGED_FIXNUMP (size_t, size))
2418 error ("Invalid output buffer size");
2419 Fsuspend_tty (tty);
2420 struct terminal *terminal = decode_tty_terminal (tty);
2421 terminal->display_info.tty->output_buffer_size = XFIXNUM (size);
2422 return Fresume_tty (tty);
2423 }
2424
2425 DEFUN ("tty--output-buffer-size", Ftty__output_buffer_size,
2426 Stty__output_buffer_size, 0, 1, 0, doc:
2427
2428
2429
2430
2431
2432 )
2433 (Lisp_Object tty)
2434 {
2435 struct terminal *terminal = decode_tty_terminal (tty);
2436 if (terminal)
2437 return make_fixnum (terminal->display_info.tty->output_buffer_size);
2438 error ("Not a tty terminal");
2439 }
2440
2441
2442
2443
2444
2445
2446 #ifndef DOS_NT
2447
2448
2449 void
2450 tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
2451 int start_hpos, int end_hpos,
2452 enum draw_glyphs_face draw)
2453 {
2454 int nglyphs = end_hpos - start_hpos;
2455 struct frame *f = XFRAME (WINDOW_FRAME (w));
2456 struct tty_display_info *tty = FRAME_TTY (f);
2457 int face_id = tty->mouse_highlight.mouse_face_face_id;
2458 int save_x, save_y, pos_x, pos_y;
2459
2460 if (end_hpos >= row->used[TEXT_AREA])
2461 nglyphs = row->used[TEXT_AREA] - start_hpos;
2462
2463 pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
2464 pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w);
2465
2466
2467 save_y = curY (tty);
2468 save_x = curX (tty);
2469 cursor_to (f, pos_y, pos_x);
2470
2471 if (draw == DRAW_MOUSE_FACE)
2472 tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
2473 nglyphs, face_id);
2474 else if (draw == DRAW_NORMAL_TEXT)
2475 write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
2476
2477 cursor_to (f, save_y, save_x);
2478 }
2479
2480 #endif
2481
2482 #ifdef HAVE_GPM
2483
2484 void
2485 term_mouse_moveto (int x, int y)
2486 {
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496 }
2497
2498
2499 static Time
2500 current_Time (void)
2501 {
2502 struct timespec now = current_timespec ();
2503 Time s_1000 = now.tv_sec;
2504 s_1000 *= 1000;
2505 Time ms = now.tv_nsec / 1000000;
2506 return s_1000 + ms;
2507 }
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522 static void
2523 term_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2524 enum scroll_bar_part *part, Lisp_Object *x,
2525 Lisp_Object *y, Time *timeptr)
2526 {
2527 *fp = SELECTED_FRAME ();
2528 (*fp)->mouse_moved = 0;
2529
2530 *bar_window = Qnil;
2531 *part = scroll_bar_above_handle;
2532
2533 XSETINT (*x, last_mouse_x);
2534 XSETINT (*y, last_mouse_y);
2535 *timeptr = current_Time ();
2536 }
2537
2538
2539
2540
2541
2542
2543 static Lisp_Object
2544 term_mouse_click (struct input_event *result, Gpm_Event *event,
2545 struct frame *f)
2546 {
2547 int i, j;
2548
2549 result->kind = MOUSE_CLICK_EVENT;
2550 for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
2551 {
2552 if (event->buttons & j) {
2553 result->code = i;
2554 break;
2555 }
2556 }
2557 result->timestamp = current_Time ();
2558
2559 if (event->type & GPM_UP)
2560 result->modifiers = up_modifier;
2561 else if (event->type & GPM_DOWN)
2562 result->modifiers = down_modifier;
2563 else
2564 result->modifiers = 0;
2565
2566 if (event->type & GPM_SINGLE)
2567 result->modifiers |= click_modifier;
2568
2569 if (event->type & GPM_DOUBLE)
2570 result->modifiers |= double_modifier;
2571
2572 if (event->type & GPM_TRIPLE)
2573 result->modifiers |= triple_modifier;
2574
2575 if (event->type & GPM_DRAG)
2576 result->modifiers |= drag_modifier;
2577
2578 if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
2579
2580
2581 if (event->modifiers & (1 << 0))
2582 result->modifiers |= shift_modifier;
2583
2584
2585 if (event->modifiers & (1 << 2))
2586 result->modifiers |= ctrl_modifier;
2587
2588
2589 if (event->modifiers & (1 << 3)
2590 || event->modifiers & (1 << 1))
2591 result->modifiers |= meta_modifier;
2592 }
2593
2594 XSETINT (result->x, event->x);
2595 XSETINT (result->y, event->y);
2596 XSETFRAME (result->frame_or_window, f);
2597 result->arg = Qnil;
2598 return Qnil;
2599 }
2600
2601 int
2602 handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event)
2603 {
2604 struct frame *f = XFRAME (tty->top_frame);
2605 struct input_event ie;
2606 int count = 0;
2607
2608 EVENT_INIT (ie);
2609 ie.kind = NO_EVENT;
2610 ie.arg = Qnil;
2611
2612 if (event->type & (GPM_MOVE | GPM_DRAG))
2613 {
2614 Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
2615
2616
2617
2618 if (event->x != last_mouse_x || event->y != last_mouse_y)
2619 {
2620
2621
2622
2623
2624 last_mouse_x = event->x;
2625 last_mouse_y = event->y;
2626 f->mouse_moved = 1;
2627
2628 count += update_mouse_position (f, event->x, event->y);
2629 }
2630 }
2631 else
2632 {
2633 f->mouse_moved = 0;
2634 term_mouse_click (&ie, event, f);
2635 ie.arg = tty_handle_tab_bar_click (f, event->x, event->y,
2636 (ie.modifiers & down_modifier) != 0, &ie);
2637 kbd_buffer_store_event (&ie);
2638 count++;
2639 }
2640
2641 return count;
2642 }
2643
2644 DEFUN ("gpm-mouse-start", Fgpm_mouse_start, Sgpm_mouse_start,
2645 0, 0, 0,
2646 doc:
2647 )
2648 (void)
2649 {
2650 struct frame *f = SELECTED_FRAME ();
2651 struct tty_display_info *tty
2652 = ((f)->output_method == output_termcap
2653 ? (f)->terminal->display_info.tty : NULL);
2654 Gpm_Connect connection;
2655
2656 if (!tty)
2657 error ("Gpm-mouse only works in the GNU/Linux console");
2658 if (gpm_tty == tty)
2659 return Qnil;
2660 if (gpm_tty)
2661 error ("Gpm-mouse can only be activated for one tty at a time");
2662
2663 connection.eventMask = ~0;
2664 connection.defaultMask = ~GPM_HARD;
2665 connection.maxMod = ~0;
2666 connection.minMod = 0;
2667 gpm_zerobased = 1;
2668
2669 if (Gpm_Open (&connection, 0) < 0)
2670 error ("Gpm-mouse failed to connect to the gpm daemon");
2671 else
2672 {
2673 gpm_tty = tty;
2674
2675
2676
2677 reset_sys_modes (tty);
2678 init_sys_modes (tty);
2679 add_gpm_wait_descriptor (gpm_fd);
2680 return Qnil;
2681 }
2682 }
2683
2684 void
2685 close_gpm (int fd)
2686 {
2687 if (fd >= 0)
2688 delete_gpm_wait_descriptor (fd);
2689 while (Gpm_Close());
2690 gpm_tty = NULL;
2691 }
2692
2693 DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
2694 0, 0, 0,
2695 doc: )
2696 (void)
2697 {
2698 struct frame *f = SELECTED_FRAME ();
2699 struct tty_display_info *tty
2700 = ((f)->output_method == output_termcap
2701 ? (f)->terminal->display_info.tty : NULL);
2702
2703 if (!tty || gpm_tty != tty)
2704 return Qnil;
2705
2706 close_gpm (gpm_fd);
2707 return Qnil;
2708 }
2709 #endif
2710
2711
2712
2713
2714
2715
2716 #if !defined (MSDOS)
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732 #define TTYM_FAILURE -1
2733 #define TTYM_SUCCESS 1
2734 #define TTYM_NO_SELECT 2
2735 #define TTYM_IA_SELECT 3
2736 #define TTYM_NEXT 4
2737 #define TTYM_PREV 5
2738
2739
2740 static const char *menu_help_message, *prev_menu_help_message;
2741
2742
2743 static int menu_help_paneno, menu_help_itemno;
2744
2745 typedef struct tty_menu_struct
2746 {
2747 int count;
2748 char **text;
2749 struct tty_menu_struct **submenu;
2750 int *panenumber;
2751 ptrdiff_t allocated;
2752 int panecount;
2753 int width;
2754 const char **help_text;
2755 } tty_menu;
2756
2757
2758
2759 static tty_menu * ATTRIBUTE_MALLOC
2760 tty_menu_create (void)
2761 {
2762 return xzalloc (sizeof *tty_menu_create ());
2763 }
2764
2765
2766
2767
2768 static void
2769 tty_menu_make_room (tty_menu *menu)
2770 {
2771 if (menu->allocated == menu->count)
2772 {
2773 ptrdiff_t allocated = menu->allocated;
2774 menu->text = xpalloc (menu->text, &allocated, 1, -1, sizeof *menu->text);
2775 menu->text = xrealloc (menu->text, allocated * sizeof *menu->text);
2776 menu->submenu = xrealloc (menu->submenu,
2777 allocated * sizeof *menu->submenu);
2778 menu->panenumber = xrealloc (menu->panenumber,
2779 allocated * sizeof *menu->panenumber);
2780 menu->help_text = xrealloc (menu->help_text,
2781 allocated * sizeof *menu->help_text);
2782 menu->allocated = allocated;
2783 }
2784 }
2785
2786
2787
2788 static tty_menu *
2789 tty_menu_search_pane (tty_menu *menu, int pane)
2790 {
2791 int i;
2792 tty_menu *try;
2793
2794 for (i = 0; i < menu->count; i++)
2795 if (menu->submenu[i])
2796 {
2797 if (pane == menu->panenumber[i])
2798 return menu->submenu[i];
2799 try = tty_menu_search_pane (menu->submenu[i], pane);
2800 if (try)
2801 return try;
2802 }
2803 return (tty_menu *) 0;
2804 }
2805
2806
2807
2808 static void
2809 tty_menu_calc_size (tty_menu *menu, int *width, int *height)
2810 {
2811 int i, h2, w2, maxsubwidth, maxheight;
2812
2813 maxsubwidth = menu->width;
2814 maxheight = menu->count;
2815 for (i = 0; i < menu->count; i++)
2816 {
2817 if (menu->submenu[i])
2818 {
2819 tty_menu_calc_size (menu->submenu[i], &w2, &h2);
2820 if (w2 > maxsubwidth) maxsubwidth = w2;
2821 if (i + h2 > maxheight) maxheight = i + h2;
2822 }
2823 }
2824 *width = maxsubwidth;
2825 *height = maxheight;
2826 }
2827
2828 static void
2829 mouse_get_xy (int *x, int *y)
2830 {
2831 Lisp_Object lmx = Qnil, lmy = Qnil;
2832 Lisp_Object mouse = mouse_position (tty_menu_calls_mouse_position_function);
2833
2834 if (EQ (selected_frame, XCAR (mouse)))
2835 {
2836 lmx = XCAR (XCDR (mouse));
2837 lmy = XCDR (XCDR (mouse));
2838 }
2839
2840 if (!NILP (lmx))
2841 {
2842 *x = XFIXNUM (lmx);
2843 *y = XFIXNUM (lmy);
2844 }
2845 }
2846
2847
2848
2849
2850 static void
2851 tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
2852 int mx, int my, int first_item, bool disp_help)
2853 {
2854 int i, face, width, enabled, mousehere, row, col;
2855 struct frame *sf = SELECTED_FRAME ();
2856 struct tty_display_info *tty = FRAME_TTY (sf);
2857
2858
2859
2860 int max_items = min (menu->count - first_item, FRAME_TOTAL_LINES (sf) - 1 - y);
2861
2862 menu_help_message = NULL;
2863
2864 width = menu->width;
2865 col = cursorX (tty);
2866 row = cursorY (tty);
2867 for (i = 0; i < max_items; i++)
2868 {
2869 int max_width = width + 2;
2870 int j = i + first_item;
2871
2872 if (menu->submenu[j])
2873 max_width += 2;
2874 enabled
2875 = (!menu->submenu[j] && menu->panenumber[j]) || (menu->submenu[j]);
2876 mousehere = (y + i == my && x <= mx && mx < x + max_width);
2877 face = faces[enabled + mousehere * 2];
2878
2879
2880
2881 if (disp_help && enabled + mousehere * 2 >= 2)
2882 {
2883 menu_help_message = menu->help_text[j];
2884 menu_help_paneno = pn - 1;
2885 menu_help_itemno = j;
2886 }
2887
2888
2889 if (mousehere)
2890 {
2891 row = y + i;
2892 col = x;
2893 }
2894 display_tty_menu_item (menu->text[j], max_width, face, x, y + i,
2895 menu->submenu[j] != NULL);
2896 }
2897 update_frame_with_menu (sf, row, col);
2898 }
2899
2900
2901
2902
2903
2904 static int
2905 tty_menu_add_pane (tty_menu *menu, const char *txt)
2906 {
2907 int len;
2908
2909 tty_menu_make_room (menu);
2910 menu->submenu[menu->count] = tty_menu_create ();
2911 menu->text[menu->count] = (char *)txt;
2912 menu->panenumber[menu->count] = ++menu->panecount;
2913 menu->help_text[menu->count] = NULL;
2914 menu->count++;
2915
2916
2917 len = menu_item_width ((const unsigned char *) txt);
2918 if (len > menu->width)
2919 menu->width = len;
2920
2921 return menu->panecount;
2922 }
2923
2924
2925
2926 static bool
2927 tty_menu_add_selection (tty_menu *menu, int pane,
2928 char *txt, bool enable, char const *help_text)
2929 {
2930 int len;
2931
2932 if (pane)
2933 {
2934 menu = tty_menu_search_pane (menu, pane);
2935 if (! menu)
2936 return 0;
2937 }
2938 tty_menu_make_room (menu);
2939 menu->submenu[menu->count] = (tty_menu *) 0;
2940 menu->text[menu->count] = txt;
2941 menu->panenumber[menu->count] = enable;
2942 menu->help_text[menu->count] = help_text;
2943 menu->count++;
2944
2945
2946 len = menu_item_width ((const unsigned char *) txt);
2947 if (len > menu->width)
2948 menu->width = len;
2949
2950 return 1;
2951 }
2952
2953
2954
2955 static void
2956 tty_menu_locate (tty_menu *menu, int x, int y,
2957 int *ulx, int *uly, int *width, int *height)
2958 {
2959 tty_menu_calc_size (menu, width, height);
2960 *ulx = x + 1;
2961 *uly = y;
2962 *width += 2;
2963 }
2964
2965 struct tty_menu_state
2966 {
2967 struct glyph_matrix *screen_behind;
2968 tty_menu *menu;
2969 int pane;
2970 int x, y;
2971 };
2972
2973
2974
2975
2976
2977 static struct glyph_matrix *
2978 save_and_enable_current_matrix (struct frame *f)
2979 {
2980 int i;
2981 struct glyph_matrix *saved = xzalloc (sizeof *saved);
2982 saved->nrows = f->current_matrix->nrows;
2983 saved->rows = xzalloc (saved->nrows * sizeof *saved->rows);
2984
2985 for (i = 0; i < saved->nrows; ++i)
2986 {
2987 struct glyph_row *from = f->current_matrix->rows + i;
2988 struct glyph_row *to = saved->rows + i;
2989 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
2990
2991 to->glyphs[TEXT_AREA] = xmalloc (nbytes);
2992 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
2993 to->used[TEXT_AREA] = from->used[TEXT_AREA];
2994
2995
2996
2997 to->enabled_p = true;
2998 to->hash = from->hash;
2999 }
3000
3001 return saved;
3002 }
3003
3004
3005
3006
3007 static void
3008 restore_desired_matrix (struct frame *f, struct glyph_matrix *saved)
3009 {
3010 int i;
3011
3012 for (i = 0; i < saved->nrows; ++i)
3013 {
3014 struct glyph_row *from = saved->rows + i;
3015 struct glyph_row *to = f->desired_matrix->rows + i;
3016 ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
3017
3018 eassert (to->glyphs[TEXT_AREA] != from->glyphs[TEXT_AREA]);
3019 memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
3020 to->used[TEXT_AREA] = from->used[TEXT_AREA];
3021 to->enabled_p = from->enabled_p;
3022 to->hash = from->hash;
3023 }
3024 }
3025
3026 static void
3027 free_saved_screen (struct glyph_matrix *saved)
3028 {
3029 int i;
3030
3031 if (!saved)
3032 return;
3033
3034 for (i = 0; i < saved->nrows; ++i)
3035 {
3036 struct glyph_row *from = saved->rows + i;
3037
3038 xfree (from->glyphs[TEXT_AREA]);
3039 }
3040
3041 xfree (saved->rows);
3042 xfree (saved);
3043 }
3044
3045
3046 static void
3047 screen_update (struct frame *f, struct glyph_matrix *mtx)
3048 {
3049 restore_desired_matrix (f, mtx);
3050 update_frame_with_menu (f, -1, -1);
3051 }
3052
3053 typedef enum {
3054 MI_QUIT_MENU = -1,
3055 MI_CONTINUE = 0,
3056 MI_ITEM_SELECTED = 1,
3057 MI_NEXT_ITEM = 2,
3058 MI_PREV_ITEM = 3,
3059 MI_SCROLL_FORWARD = 4,
3060 MI_SCROLL_BACK = 5
3061 } mi_result;
3062
3063
3064
3065
3066 static mi_result
3067 read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
3068 bool *first_time)
3069 {
3070 if (*first_time)
3071 {
3072 *first_time = false;
3073 sf->mouse_moved = 1;
3074 }
3075 else
3076 {
3077 Lisp_Object cmd;
3078 bool usable_input = 1;
3079 mi_result st = MI_CONTINUE;
3080 struct tty_display_info *tty = FRAME_TTY (sf);
3081 Lisp_Object old_track_mouse = track_mouse;
3082
3083
3084
3085 tty->showing_menu = 1;
3086
3087 track_mouse = Qt;
3088 do {
3089 cmd = read_menu_command ();
3090 } while (NILP (cmd));
3091 tty->showing_menu = 0;
3092 track_mouse = old_track_mouse;
3093
3094 if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit)
3095
3096
3097
3098 || sf != SELECTED_FRAME ())
3099 return MI_QUIT_MENU;
3100 if (EQ (cmd, Qtty_menu_mouse_movement))
3101 mouse_get_xy (x, y);
3102 else if (EQ (cmd, Qtty_menu_next_menu))
3103 {
3104 usable_input = 0;
3105 st = MI_NEXT_ITEM;
3106 }
3107 else if (EQ (cmd, Qtty_menu_prev_menu))
3108 {
3109 usable_input = 0;
3110 st = MI_PREV_ITEM;
3111 }
3112 else if (EQ (cmd, Qtty_menu_next_item))
3113 {
3114 if (*y < max_y)
3115 *y += 1;
3116 else
3117 st = MI_SCROLL_FORWARD;
3118 }
3119 else if (EQ (cmd, Qtty_menu_prev_item))
3120 {
3121 if (*y > min_y)
3122 *y -= 1;
3123 else
3124 st = MI_SCROLL_BACK;
3125 }
3126 else if (EQ (cmd, Qtty_menu_select))
3127 st = MI_ITEM_SELECTED;
3128 else if (!EQ (cmd, Qtty_menu_ignore))
3129 usable_input = 0;
3130 if (usable_input)
3131 sf->mouse_moved = 1;
3132 return st;
3133 }
3134 return MI_CONTINUE;
3135 }
3136
3137
3138 static int
3139 tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
3140 int x0, int y0, char **txt,
3141 void (*help_callback)(char const *, int, int),
3142 bool kbd_navigation)
3143 {
3144 struct tty_menu_state *state;
3145 int statecount, x, y, i;
3146 bool leave, onepane;
3147 int result UNINIT;
3148 int title_faces[4];
3149 int faces[4], buffers_num_deleted = 0;
3150 struct frame *sf = SELECTED_FRAME ();
3151 struct tty_display_info *tty = FRAME_TTY (sf);
3152 bool first_time;
3153 Lisp_Object selectface;
3154 int first_item = 0;
3155 int col, row;
3156 Lisp_Object prev_inhibit_redisplay = Vinhibit_redisplay;
3157 USE_SAFE_ALLOCA;
3158
3159
3160
3161 if (x0 <= 0)
3162 x0 = 1;
3163 if (y0 <= 0)
3164 y0 = 1;
3165
3166 SAFE_NALLOCA (state, 1, menu->panecount);
3167 memset (state, 0, sizeof (*state));
3168 faces[0]
3169 = lookup_derived_face (NULL, sf, intern ("tty-menu-disabled-face"),
3170 DEFAULT_FACE_ID, 1);
3171 faces[1]
3172 = lookup_derived_face (NULL, sf, intern ("tty-menu-enabled-face"),
3173 DEFAULT_FACE_ID, 1);
3174 selectface = intern ("tty-menu-selected-face");
3175 faces[2] = lookup_derived_face (NULL, sf, selectface,
3176 faces[0], 1);
3177 faces[3] = lookup_derived_face (NULL, sf, selectface,
3178 faces[1], 1);
3179
3180
3181
3182 for (i = 0; i < 4; i++)
3183 title_faces[i] = faces[3];
3184
3185 statecount = 1;
3186
3187
3188
3189
3190
3191
3192
3193 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
3194 {
3195 menu->text[0][7] = '\0';
3196 buffers_num_deleted = 1;
3197 }
3198
3199
3200
3201
3202 Vinhibit_redisplay = Qt;
3203
3204
3205
3206 update_frame_with_menu (sf, -1, -1);
3207 state[0].menu = menu;
3208 state[0].screen_behind = save_and_enable_current_matrix (sf);
3209
3210
3211
3212
3213
3214 tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0, 0);
3215
3216
3217
3218 col = cursorX (tty);
3219 row = cursorY (tty);
3220 tty_hide_cursor (tty);
3221
3222 if (buffers_num_deleted)
3223 menu->text[0][7] = ' ';
3224 onepane = menu->count == 1 && menu->submenu[0];
3225 if (onepane)
3226 {
3227 menu->width = menu->submenu[0]->width;
3228 state[0].menu = menu->submenu[0];
3229 }
3230 else
3231 {
3232 state[0].menu = menu;
3233 }
3234 state[0].x = x0 - 1;
3235 state[0].y = y0;
3236 state[0].pane = onepane;
3237
3238 x = state[0].x;
3239 y = state[0].y;
3240 first_time = true;
3241
3242 leave = 0;
3243 while (!leave)
3244 {
3245 mi_result input_status;
3246 int min_y = state[0].y;
3247 int max_y = min (min_y + state[0].menu->count, FRAME_TOTAL_LINES (sf) - 1) - 1;
3248
3249 input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
3250 if (input_status)
3251 {
3252 leave = 1;
3253 switch (input_status)
3254 {
3255 case MI_QUIT_MENU:
3256
3257
3258 show_help_echo (Qnil, Qnil, Qnil, Qnil);
3259 result = TTYM_NO_SELECT;
3260 break;
3261 case MI_NEXT_ITEM:
3262 if (kbd_navigation)
3263 result = TTYM_NEXT;
3264 else
3265 leave = 0;
3266 break;
3267 case MI_PREV_ITEM:
3268 if (kbd_navigation)
3269 result = TTYM_PREV;
3270 else
3271 leave = 0;
3272 break;
3273 case MI_SCROLL_FORWARD:
3274 if (y - min_y == state[0].menu->count - 1 - first_item)
3275 {
3276 y = min_y;
3277 first_item = 0;
3278 }
3279 else
3280 first_item++;
3281 leave = 0;
3282 break;
3283 case MI_SCROLL_BACK:
3284 if (first_item == 0)
3285 {
3286 y = max_y;
3287 first_item = state[0].menu->count - 1 - (y - min_y);
3288 }
3289 else
3290 first_item--;
3291 leave = 0;
3292 break;
3293 default:
3294
3295 break;
3296 }
3297 }
3298 if (sf->mouse_moved && input_status != MI_QUIT_MENU)
3299 {
3300 sf->mouse_moved = 0;
3301 result = TTYM_IA_SELECT;
3302 for (i = 0; i < statecount; i++)
3303 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
3304 {
3305 int dy = y - state[i].y + first_item;
3306 if (0 <= dy && dy < state[i].menu->count)
3307 {
3308 if (!state[i].menu->submenu[dy])
3309 {
3310 if (state[i].menu->panenumber[dy])
3311 result = TTYM_SUCCESS;
3312 else
3313 result = TTYM_IA_SELECT;
3314 }
3315 *pane = state[i].pane - 1;
3316 *selidx = dy;
3317
3318
3319
3320 if (i != statecount - 2
3321 || state[i].menu->submenu[dy] != state[i + 1].menu)
3322 while (i != statecount - 1)
3323 {
3324 statecount--;
3325 screen_update (sf, state[statecount].screen_behind);
3326 state[statecount].screen_behind = NULL;
3327 }
3328 if (i == statecount - 1 && state[i].menu->submenu[dy])
3329 {
3330 tty_menu_display (state[i].menu,
3331 state[i].x,
3332 state[i].y,
3333 state[i].pane,
3334 faces, x, y, first_item, 1);
3335 state[statecount].menu = state[i].menu->submenu[dy];
3336 state[statecount].pane = state[i].menu->panenumber[dy];
3337 state[statecount].screen_behind
3338 = save_and_enable_current_matrix (sf);
3339 state[statecount].x
3340 = state[i].x + state[i].menu->width + 2;
3341 state[statecount].y = y;
3342 statecount++;
3343 }
3344 }
3345 }
3346 tty_menu_display (state[statecount - 1].menu,
3347 state[statecount - 1].x,
3348 state[statecount - 1].y,
3349 state[statecount - 1].pane,
3350 faces, x, y, first_item, 1);
3351
3352
3353
3354 col = cursorX (tty);
3355 row = cursorY (tty);
3356 }
3357
3358
3359
3360 if ((menu_help_message || prev_menu_help_message)
3361 && menu_help_message != prev_menu_help_message)
3362 {
3363 help_callback (menu_help_message,
3364 menu_help_paneno, menu_help_itemno);
3365
3366
3367
3368 cursor_to (sf, row, col);
3369 prev_menu_help_message = menu_help_message;
3370 }
3371
3372
3373
3374 tty_hide_cursor (tty);
3375 fflush (tty->output);
3376 }
3377
3378 sf->mouse_moved = 0;
3379 screen_update (sf, state[0].screen_behind);
3380 while (statecount--)
3381 free_saved_screen (state[statecount].screen_behind);
3382 tty_show_cursor (tty);
3383 fflush (tty->output);
3384
3385
3386
3387
3388
3389
3390 discard_mouse_events ();
3391 if (!kbd_buffer_events_waiting ())
3392 clear_input_pending ();
3393 SAFE_FREE ();
3394 Vinhibit_redisplay = prev_inhibit_redisplay;
3395 return result;
3396 }
3397
3398
3399
3400 static void
3401 tty_menu_destroy (tty_menu *menu)
3402 {
3403 int i;
3404 if (menu->allocated)
3405 {
3406 for (i = 0; i < menu->count; i++)
3407 if (menu->submenu[i])
3408 tty_menu_destroy (menu->submenu[i]);
3409 xfree (menu->text);
3410 xfree (menu->submenu);
3411 xfree (menu->panenumber);
3412 xfree (menu->help_text);
3413 }
3414 xfree (menu);
3415 menu_help_message = prev_menu_help_message = NULL;
3416 }
3417
3418
3419
3420
3421
3422
3423 static void
3424 tty_menu_help_callback (char const *help_string, int pane, int item)
3425 {
3426 Lisp_Object *first_item;
3427 Lisp_Object pane_name;
3428 Lisp_Object menu_object;
3429
3430 first_item = XVECTOR (menu_items)->contents;
3431 if (EQ (first_item[0], Qt))
3432 pane_name = first_item[MENU_ITEMS_PANE_NAME];
3433 else if (EQ (first_item[0], Qquote))
3434
3435 pane_name = empty_unibyte_string;
3436 else
3437 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
3438
3439
3440 menu_object = list3 (Qmenu_item, pane_name, make_fixnum (pane));
3441 show_help_echo (help_string ? build_string (help_string) : Qnil,
3442 Qnil, menu_object, make_fixnum (item));
3443 }
3444
3445 struct tty_pop_down_menu
3446 {
3447 tty_menu *menu;
3448 struct buffer *buffer;
3449 };
3450
3451 static void
3452 tty_pop_down_menu (void *arg)
3453 {
3454 struct tty_pop_down_menu *data = arg;
3455
3456 block_input ();
3457 tty_menu_destroy (data->menu);
3458 set_buffer_internal (data->buffer);
3459 unblock_input ();
3460 }
3461
3462
3463 static int
3464 tty_menu_last_menubar_item (struct frame *f)
3465 {
3466 int i = 0;
3467
3468 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3469 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3470 {
3471 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3472
3473 while (i < ASIZE (items))
3474 {
3475 Lisp_Object str;
3476
3477 str = AREF (items, i + 1);
3478 if (NILP (str))
3479 break;
3480 i += 4;
3481 }
3482 i -= 4;
3483 }
3484 return i;
3485 }
3486
3487
3488
3489
3490
3491
3492 static void
3493 tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
3494 {
3495 eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
3496 if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
3497 {
3498 Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
3499 int last_i = tty_menu_last_menubar_item (f);
3500 int i, prev_x;
3501
3502
3503
3504
3505 for (i = 0, prev_x = -1; i < ASIZE (items); i += 4)
3506 {
3507 Lisp_Object pos, str;
3508 int ix;
3509
3510 str = AREF (items, i + 1);
3511 pos = AREF (items, i + 3);
3512 if (NILP (str))
3513 return;
3514 ix = XFIXNUM (pos);
3515 if (ix <= *x
3516
3517
3518 && *x <= ix + menu_item_width (SDATA (str)))
3519 {
3520
3521
3522 if (which == TTYM_NEXT)
3523 {
3524 if (i < last_i)
3525 *x = XFIXNUM (AREF (items, i + 4 + 3));
3526 else
3527 *x = 0;
3528 }
3529 else if (prev_x < 0)
3530 {
3531
3532 *x = XFIXNUM (AREF (items, last_i + 3));
3533 }
3534 else
3535 *x = prev_x;
3536 return;
3537 }
3538 prev_x = ix;
3539 }
3540 }
3541 }
3542
3543
3544 Lisp_Object
3545 tty_menu_show (struct frame *f, int x, int y, int menuflags,
3546 Lisp_Object title, const char **error_name)
3547 {
3548 tty_menu *menu;
3549 int pane, selidx, lpane, status;
3550 Lisp_Object entry, pane_prefix;
3551 char *datap;
3552 int ulx, uly, width, height;
3553 int item_x, item_y;
3554 int dispwidth, dispheight;
3555 int i, j, lines, maxlines;
3556 int maxwidth;
3557 specpdl_ref specpdl_count;
3558
3559 eassert (FRAME_TERMCAP_P (f));
3560
3561 *error_name = 0;
3562 if (menu_items_n_panes == 0)
3563 return Qnil;
3564
3565 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
3566 {
3567 *error_name = "Empty menu";
3568 return Qnil;
3569 }
3570
3571
3572 menu = tty_menu_create ();
3573
3574
3575
3576 specpdl_count = inhibit_garbage_collection ();
3577
3578
3579
3580 temporarily_switch_to_single_kboard (f);
3581
3582
3583 item_x = x += f->left_pos;
3584 item_y = y += f->top_pos;
3585
3586
3587 USE_SAFE_ALLOCA;
3588 maxwidth = maxlines = lines = i = 0;
3589 lpane = TTYM_FAILURE;
3590 while (i < menu_items_used)
3591 {
3592 if (EQ (AREF (menu_items, i), Qt))
3593 {
3594
3595 Lisp_Object pane_name, prefix;
3596 const char *pane_string;
3597
3598 maxlines = max (maxlines, lines);
3599 lines = 0;
3600 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
3601 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
3602 pane_string = (NILP (pane_name)
3603 ? "" : SSDATA (pane_name));
3604 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
3605 pane_string++;
3606
3607 lpane = tty_menu_add_pane (menu, pane_string);
3608 if (lpane == TTYM_FAILURE)
3609 {
3610 tty_menu_destroy (menu);
3611 *error_name = "Can't create pane";
3612 entry = Qnil;
3613 goto tty_menu_end;
3614 }
3615 i += MENU_ITEMS_PANE_LENGTH;
3616
3617
3618 j = i;
3619 while (j < menu_items_used)
3620 {
3621 Lisp_Object item;
3622 item = AREF (menu_items, j);
3623 if (EQ (item, Qt))
3624 break;
3625 if (NILP (item))
3626 {
3627 j++;
3628 continue;
3629 }
3630 width = SBYTES (item);
3631 if (width > maxwidth)
3632 maxwidth = width;
3633
3634 j += MENU_ITEMS_ITEM_LENGTH;
3635 }
3636 }
3637
3638
3639 else if (EQ (AREF (menu_items, i), Qquote))
3640 i += 1;
3641 else
3642 {
3643
3644 Lisp_Object item_name, enable, descrip, help;
3645 char *item_data;
3646 char const *help_string;
3647
3648 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
3649 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
3650 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
3651 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
3652 help_string = STRINGP (help) ? SSDATA (help) : NULL;
3653
3654 if (!NILP (descrip))
3655 {
3656 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
3657 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
3658 for (j = SCHARS (item_name); j < maxwidth; j++)
3659 item_data[j] = ' ';
3660 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
3661 item_data[j + SBYTES (descrip)] = 0;
3662 }
3663 else
3664 item_data = SSDATA (item_name);
3665
3666 if (lpane == TTYM_FAILURE
3667 || (! tty_menu_add_selection (menu, lpane, item_data,
3668 !NILP (enable), help_string)))
3669 {
3670 tty_menu_destroy (menu);
3671 *error_name = "Can't add selection to menu";
3672 entry = Qnil;
3673 goto tty_menu_end;
3674 }
3675 i += MENU_ITEMS_ITEM_LENGTH;
3676 lines++;
3677 }
3678 }
3679
3680 maxlines = max (maxlines, lines);
3681
3682
3683 dispwidth = f->text_cols;
3684 dispheight = f->text_lines;
3685 x = min (x, dispwidth);
3686 y = min (y, dispheight);
3687 x = max (x, 1);
3688 y = max (y, 1);
3689 tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
3690 if (ulx + width > dispwidth)
3691 {
3692 x -= (ulx + width) - dispwidth;
3693 ulx = dispwidth - width;
3694 }
3695 if (uly + height > dispheight)
3696 {
3697 y -= (uly + height) - dispheight;
3698 uly = dispheight - height;
3699 }
3700
3701 if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 2)
3702 {
3703
3704
3705 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
3706 {
3707 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
3708 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
3709 }
3710 else
3711 {
3712 y -= 2;
3713 uly -= 2;
3714 }
3715 }
3716
3717 if (ulx < 0) x -= ulx;
3718 if (uly < 0) y -= uly;
3719
3720 #if 0
3721
3722
3723
3724
3725 if (! for_click)
3726 {
3727
3728
3729
3730 x += width / 2;
3731 y += 1.5 * height / (maxlines + 2);
3732 }
3733 #endif
3734
3735 pane = selidx = 0;
3736
3737
3738
3739 record_unwind_protect_ptr (tty_pop_down_menu,
3740 &((struct tty_pop_down_menu)
3741 {menu, current_buffer}));
3742
3743 specbind (Qoverriding_terminal_local_map,
3744 Fsymbol_value (Qtty_menu_navigation_map));
3745 status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
3746 tty_menu_help_callback,
3747 menuflags & MENU_KBD_NAVIGATION);
3748 entry = pane_prefix = Qnil;
3749
3750 switch (status)
3751 {
3752 case TTYM_SUCCESS:
3753
3754 i = 0;
3755 while (i < menu_items_used)
3756 {
3757 if (EQ (AREF (menu_items, i), Qt))
3758 {
3759 if (pane == 0)
3760 pane_prefix
3761 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
3762 pane--;
3763 i += MENU_ITEMS_PANE_LENGTH;
3764 }
3765 else
3766 {
3767 if (pane == -1)
3768 {
3769 if (selidx == 0)
3770 {
3771 entry
3772 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
3773 if (menuflags & MENU_KEYMAPS)
3774 {
3775 entry = Fcons (entry, Qnil);
3776 if (!NILP (pane_prefix))
3777 entry = Fcons (pane_prefix, entry);
3778 }
3779 break;
3780 }
3781 selidx--;
3782 }
3783 i += MENU_ITEMS_ITEM_LENGTH;
3784 }
3785 }
3786 break;
3787
3788 case TTYM_NEXT:
3789 case TTYM_PREV:
3790 tty_menu_new_item_coords (f, status, &item_x, &item_y);
3791 entry = Fcons (make_fixnum (item_x), make_fixnum (item_y));
3792 break;
3793
3794 case TTYM_FAILURE:
3795 *error_name = "Can't activate menu";
3796 case TTYM_IA_SELECT:
3797 break;
3798 case TTYM_NO_SELECT:
3799
3800
3801
3802 if (f != SELECTED_FRAME ())
3803 Ftop_level ();
3804
3805
3806 if (!(menuflags & MENU_FOR_CLICK))
3807 quit ();
3808 break;
3809 }
3810
3811 tty_menu_end:
3812
3813 return SAFE_FREE_UNBIND_TO (specpdl_count, entry);
3814 }
3815
3816 #endif
3817
3818
3819 #ifndef MSDOS
3820
3821
3822
3823
3824
3825
3826
3827 void
3828 create_tty_output (struct frame *f)
3829 {
3830 struct tty_output *t = xzalloc (sizeof *t);
3831
3832 eassert (FRAME_TERMCAP_P (f));
3833
3834 t->display_info = FRAME_TERMINAL (f)->display_info.tty;
3835
3836 f->output_data.tty = t;
3837 }
3838
3839
3840
3841 static void
3842 tty_free_frame_resources (struct frame *f)
3843 {
3844 eassert (FRAME_TERMCAP_P (f));
3845 free_frame_faces (f);
3846 xfree (f->output_data.tty);
3847 }
3848
3849 #else
3850
3851
3852
3853 static void
3854 tty_free_frame_resources (struct frame *f)
3855 {
3856 eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
3857 free_frame_faces (f);
3858 }
3859 #endif
3860
3861
3862
3863 static void
3864 clear_tty_hooks (struct terminal *terminal)
3865 {
3866 terminal->rif = 0;
3867 terminal->cursor_to_hook = 0;
3868 terminal->raw_cursor_to_hook = 0;
3869 terminal->clear_to_end_hook = 0;
3870 terminal->clear_frame_hook = 0;
3871 terminal->clear_end_of_line_hook = 0;
3872 terminal->ins_del_lines_hook = 0;
3873 terminal->insert_glyphs_hook = 0;
3874 terminal->write_glyphs_hook = 0;
3875 terminal->delete_glyphs_hook = 0;
3876 terminal->ring_bell_hook = 0;
3877 terminal->reset_terminal_modes_hook = 0;
3878 terminal->set_terminal_modes_hook = 0;
3879 terminal->update_begin_hook = 0;
3880 terminal->update_end_hook = 0;
3881 terminal->set_terminal_window_hook = 0;
3882
3883
3884
3885 terminal->mouse_position_hook = 0;
3886 terminal->frame_rehighlight_hook = 0;
3887 terminal->frame_raise_lower_hook = 0;
3888 terminal->fullscreen_hook = 0;
3889 terminal->menu_show_hook = 0;
3890 terminal->set_vertical_scroll_bar_hook = 0;
3891 terminal->set_horizontal_scroll_bar_hook = 0;
3892 terminal->condemn_scroll_bars_hook = 0;
3893 terminal->redeem_scroll_bar_hook = 0;
3894 terminal->judge_scroll_bars_hook = 0;
3895 terminal->read_socket_hook = 0;
3896 terminal->frame_up_to_date_hook = 0;
3897
3898
3899
3900 terminal->delete_frame_hook = &tty_free_frame_resources;
3901 terminal->delete_terminal_hook = &delete_tty;
3902 }
3903
3904
3905
3906 static void
3907 set_tty_hooks (struct terminal *terminal)
3908 {
3909 terminal->cursor_to_hook = &tty_cursor_to;
3910 terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
3911 terminal->clear_to_end_hook = &tty_clear_to_end;
3912 terminal->clear_frame_hook = &tty_clear_frame;
3913 terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
3914 terminal->ins_del_lines_hook = &tty_ins_del_lines;
3915 terminal->insert_glyphs_hook = &tty_insert_glyphs;
3916 terminal->write_glyphs_hook = &tty_write_glyphs;
3917 terminal->delete_glyphs_hook = &tty_delete_glyphs;
3918 terminal->ring_bell_hook = &tty_ring_bell;
3919 terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
3920 terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
3921 terminal->update_end_hook = &tty_update_end;
3922 #ifdef MSDOS
3923 terminal->menu_show_hook = &x_menu_show;
3924 #else
3925 terminal->menu_show_hook = &tty_menu_show;
3926 #endif
3927 terminal->set_terminal_window_hook = &tty_set_terminal_window;
3928 terminal->defined_color_hook = &tty_defined_color;
3929 terminal->read_socket_hook = &tty_read_avail_input;
3930 terminal->delete_frame_hook = &tty_free_frame_resources;
3931 terminal->delete_terminal_hook = &delete_tty;
3932
3933 }
3934
3935
3936 static void
3937 dissociate_if_controlling_tty (int fd)
3938 {
3939
3940
3941 if (tcgetpgrp (fd) >= 0 && setsid () < 0)
3942 {
3943 #ifdef TIOCNOTTY
3944
3945
3946
3947 sigset_t oldset;
3948 block_tty_out_signal (&oldset);
3949 ioctl (fd, TIOCNOTTY, 0);
3950 unblock_tty_out_signal (&oldset);
3951 #endif
3952 }
3953 }
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966 struct terminal *
3967 init_tty (const char *name, const char *terminal_type, bool must_succeed)
3968 {
3969 struct tty_display_info *tty = NULL;
3970 struct terminal *terminal = NULL;
3971 #ifndef DOS_NT
3972 char *area;
3973 char **address = &area;
3974 int status;
3975 sigset_t oldset;
3976 bool ctty = false;
3977 #endif
3978
3979 if (!terminal_type)
3980 maybe_fatal (must_succeed, 0,
3981 "Unknown terminal type",
3982 "Unknown terminal type");
3983
3984 if (name == NULL)
3985 name = DEV_TTY;
3986 #ifndef DOS_NT
3987 if (!strcmp (name, DEV_TTY))
3988 ctty = 1;
3989 #endif
3990
3991
3992
3993
3994
3995
3996 terminal = get_named_terminal (name);
3997 if (terminal)
3998 return terminal;
3999
4000 terminal = create_terminal (output_termcap, NULL);
4001 #ifdef MSDOS
4002 if (been_here > 0)
4003 maybe_fatal (0, 0, "Attempt to create another terminal %s", "",
4004 name, "");
4005 been_here = 1;
4006 tty = &the_only_display_info;
4007 #else
4008 tty = xzalloc (sizeof *tty);
4009 #endif
4010 tty->top_frame = Qnil;
4011 tty->next = tty_list;
4012 tty_list = tty;
4013
4014 terminal->display_info.tty = tty;
4015 tty->terminal = terminal;
4016
4017 tty->Wcm = xmalloc (sizeof *tty->Wcm);
4018 Wcm_clear (tty);
4019
4020 encode_terminal_src_size = 0;
4021 encode_terminal_dst_size = 0;
4022
4023
4024 #ifndef DOS_NT
4025 set_tty_hooks (terminal);
4026
4027 {
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037 int flags = O_RDWR | O_NOCTTY | (ctty ? 0 : O_IGNORE_CTTY);
4038 int fd = emacs_open (name, flags, 0);
4039 tty->input = tty->output
4040 = ((fd < 0 || ! isatty (fd))
4041 ? NULL
4042 : fdopen (fd, "w+"));
4043
4044 if (! tty->input)
4045 {
4046 char const *diagnostic
4047 = (fd < 0) ? "Could not open file: %s" : "Not a tty device: %s";
4048 emacs_close (fd);
4049 delete_terminal_internal (terminal);
4050 maybe_fatal (must_succeed, terminal, diagnostic, diagnostic, name);
4051 }
4052
4053 tty->name = xstrdup (name);
4054 terminal->name = xstrdup (name);
4055
4056 if (!O_IGNORE_CTTY && !ctty)
4057 dissociate_if_controlling_tty (fd);
4058 }
4059
4060 tty->type = xstrdup (terminal_type);
4061
4062 add_keyboard_wait_descriptor (fileno (tty->input));
4063
4064 Wcm_clear (tty);
4065
4066
4067
4068 block_tty_out_signal (&oldset);
4069 status = tgetent (tty->termcap_term_buffer, terminal_type);
4070 if (tty->termcap_term_buffer[TERMCAP_BUFFER_SIZE - 1])
4071 emacs_abort ();
4072 unblock_tty_out_signal (&oldset);
4073
4074 if (status < 0)
4075 {
4076 #ifdef TERMINFO
4077 maybe_fatal (must_succeed, terminal,
4078 "Cannot open terminfo database file",
4079 "Cannot open terminfo database file");
4080 #else
4081 maybe_fatal (must_succeed, terminal,
4082 "Cannot open termcap database file",
4083 "Cannot open termcap database file");
4084 #endif
4085 }
4086 if (status == 0)
4087 {
4088 maybe_fatal (must_succeed, terminal,
4089 "Terminal type %s is not defined",
4090 "Terminal type %s is not defined.\n\
4091 If that is not the actual type of terminal you have,\n\
4092 use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\
4093 'setenv TERM ...') to specify the correct type. It may be necessary\n"
4094 #ifdef TERMINFO
4095 "to do 'unset TERMINFO' (C-shell: 'unsetenv TERMINFO') as well.",
4096 #else
4097 "to do 'unset TERMCAP' (C-shell: 'unsetenv TERMCAP') as well.",
4098 #endif
4099 terminal_type);
4100 }
4101
4102 area = tty->termcap_strings_buffer;
4103 tty->TS_ins_line = tgetstr ("al", address);
4104 tty->TS_ins_multi_lines = tgetstr ("AL", address);
4105 tty->TS_bell = tgetstr ("bl", address);
4106 BackTab (tty) = tgetstr ("bt", address);
4107 tty->TS_clr_to_bottom = tgetstr ("cd", address);
4108 tty->TS_clr_line = tgetstr ("ce", address);
4109 tty->TS_clr_frame = tgetstr ("cl", address);
4110 ColPosition (tty) = NULL;
4111 AbsPosition (tty) = tgetstr ("cm", address);
4112 CR (tty) = tgetstr ("cr", address);
4113 tty->TS_set_scroll_region = tgetstr ("cs", address);
4114 tty->TS_set_scroll_region_1 = tgetstr ("cS", address);
4115 RowPosition (tty) = tgetstr ("cv", address);
4116 tty->TS_del_char = tgetstr ("dc", address);
4117 tty->TS_del_multi_chars = tgetstr ("DC", address);
4118 tty->TS_del_line = tgetstr ("dl", address);
4119 tty->TS_del_multi_lines = tgetstr ("DL", address);
4120 tty->TS_delete_mode = tgetstr ("dm", address);
4121 tty->TS_end_delete_mode = tgetstr ("ed", address);
4122 tty->TS_end_insert_mode = tgetstr ("ei", address);
4123 Home (tty) = tgetstr ("ho", address);
4124 tty->TS_ins_char = tgetstr ("ic", address);
4125 tty->TS_ins_multi_chars = tgetstr ("IC", address);
4126 tty->TS_insert_mode = tgetstr ("im", address);
4127 tty->TS_pad_inserted_char = tgetstr ("ip", address);
4128 tty->TS_end_keypad_mode = tgetstr ("ke", address);
4129 tty->TS_keypad_mode = tgetstr ("ks", address);
4130 LastLine (tty) = tgetstr ("ll", address);
4131 Right (tty) = tgetstr ("nd", address);
4132 Down (tty) = tgetstr ("do", address);
4133 if (!Down (tty))
4134 Down (tty) = tgetstr ("nl", address);
4135 if (tgetflag ("bs"))
4136 Left (tty) = "\b";
4137 else
4138 Left (tty) = tgetstr ("le", address);
4139 if (!Left (tty))
4140 Left (tty) = tgetstr ("bc", address);
4141 tty->TS_pad_char = tgetstr ("pc", address);
4142 tty->TS_repeat = tgetstr ("rp", address);
4143 tty->TS_end_standout_mode = tgetstr ("se", address);
4144 tty->TS_fwd_scroll = tgetstr ("sf", address);
4145 tty->TS_standout_mode = tgetstr ("so", address);
4146 tty->TS_rev_scroll = tgetstr ("sr", address);
4147 tty->Wcm->cm_tab = tgetstr ("ta", address);
4148 tty->TS_end_termcap_modes = tgetstr ("te", address);
4149 tty->TS_termcap_modes = tgetstr ("ti", address);
4150 Up (tty) = tgetstr ("up", address);
4151 tty->TS_visible_bell = tgetstr ("vb", address);
4152 tty->TS_cursor_normal = tgetstr ("ve", address);
4153 tty->TS_cursor_visible = tgetstr ("vs", address);
4154 tty->TS_cursor_invisible = tgetstr ("vi", address);
4155 tty->TS_set_window = tgetstr ("wi", address);
4156
4157 tty->TS_enter_underline_mode = tgetstr ("us", address);
4158 tty->TS_exit_underline_mode = tgetstr ("ue", address);
4159 tty->TS_enter_bold_mode = tgetstr ("md", address);
4160 tty->TS_enter_italic_mode = tgetstr ("ZH", address);
4161 tty->TS_enter_dim_mode = tgetstr ("mh", address);
4162 tty->TS_enter_reverse_mode = tgetstr ("mr", address);
4163 tty->TS_enter_alt_charset_mode = tgetstr ("as", address);
4164 tty->TS_exit_alt_charset_mode = tgetstr ("ae", address);
4165 tty->TS_exit_attribute_mode = tgetstr ("me", address);
4166 #ifdef TERMINFO
4167 tty->TS_enter_strike_through_mode = tigetstr ("smxx");
4168 if (tty->TS_enter_strike_through_mode == (char *) (intptr_t) -1)
4169 tty->TS_enter_strike_through_mode = NULL;
4170 #else
4171
4172
4173 tty->TS_enter_strike_through_mode = tgetstr ("smxx", address);
4174 #endif
4175
4176 MultiUp (tty) = tgetstr ("UP", address);
4177 MultiDown (tty) = tgetstr ("DO", address);
4178 MultiLeft (tty) = tgetstr ("LE", address);
4179 MultiRight (tty) = tgetstr ("RI", address);
4180
4181
4182
4183
4184 tty->TS_orig_pair = tgetstr ("op", address);
4185 if (tty->TS_orig_pair)
4186 {
4187 tty->TS_set_foreground = tgetstr ("AF", address);
4188 tty->TS_set_background = tgetstr ("AB", address);
4189 if (!tty->TS_set_foreground)
4190 {
4191
4192 tty->TS_set_foreground = tgetstr ("Sf", address);
4193 tty->TS_set_background = tgetstr ("Sb", address);
4194 }
4195
4196 tty->TN_max_colors = tgetnum ("Co");
4197
4198 #ifdef TERMINFO
4199 {
4200 const char *fg = tigetstr ("setf24");
4201 const char *bg = tigetstr ("setb24");
4202
4203 if (fg && bg
4204 && fg != (char *) (intptr_t) -1
4205 && bg != (char *) (intptr_t) -1)
4206 {
4207 tty->TS_set_foreground = fg;
4208 tty->TS_set_background = bg;
4209 tty->TN_max_colors = 16777216;
4210 }
4211
4212 else if (tigetflag ("RGB") > 0)
4213 {
4214
4215
4216
4217 tty->TN_max_colors = 16777216;
4218 }
4219
4220
4221
4222 else if ((tigetflag ("Tc") > 0)
4223 || ((bg = getenv ("COLORTERM")) != NULL
4224 && strcasecmp (bg, "truecolor") == 0))
4225 {
4226 tty->TS_set_foreground = "\033[%?%p1%{8}%<%t3%p1%d%e38;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%d%;m";
4227 tty->TS_set_background = "\033[%?%p1%{8}%<%t4%p1%d%e48;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%d%;m";
4228 tty->TN_max_colors = 16777216;
4229 }
4230 }
4231 #endif
4232
4233 tty->TN_no_color_video = tgetnum ("NC");
4234 if (tty->TN_no_color_video == -1)
4235 tty->TN_no_color_video = 0;
4236 }
4237
4238 tty_default_color_capabilities (tty, 1);
4239
4240 MagicWrap (tty) = tgetflag ("xn");
4241
4242
4243 AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
4244 tty->memory_below_frame = tgetflag ("db");
4245 tty->TF_hazeltine = tgetflag ("hz");
4246 tty->must_write_spaces = tgetflag ("in");
4247 tty->meta_key = tgetflag ("km") || tgetflag ("MT");
4248 tty->TF_insmode_motion = tgetflag ("mi");
4249 tty->TF_standout_motion = tgetflag ("ms");
4250 tty->TF_underscore = tgetflag ("ul");
4251 tty->TF_teleray = tgetflag ("xt");
4252
4253 #else
4254 #ifdef WINDOWSNT
4255 {
4256 struct frame *f = XFRAME (selected_frame);
4257 int height, width;
4258
4259 initialize_w32_display (terminal, &width, &height);
4260
4261 FrameRows (tty) = height;
4262 FrameCols (tty) = width;
4263 tty->specified_window = height;
4264
4265 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
4266 FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) = 0;
4267 tty->char_ins_del_ok = 1;
4268 baud_rate = 19200;
4269 }
4270 #else
4271 {
4272 int height, width;
4273 if (strcmp (terminal_type, "internal") == 0)
4274 terminal->type = output_msdos_raw;
4275 initialize_msdos_display (terminal);
4276
4277 get_tty_size (fileno (tty->input), &width, &height);
4278 FrameCols (tty) = width;
4279 FrameRows (tty) = height;
4280 tty->char_ins_del_ok = 0;
4281 init_baud_rate (fileno (tty->input));
4282 }
4283 #endif
4284 tty->output = stdout;
4285 tty->input = stdin;
4286
4287 terminal->delete_frame_hook = &tty_free_frame_resources;
4288 terminal->delete_terminal_hook = &delete_tty;
4289
4290 tty->name = xstrdup (name);
4291 terminal->name = xstrdup (name);
4292 tty->type = xstrdup (terminal_type);
4293
4294 add_keyboard_wait_descriptor (0);
4295
4296 tty->delete_in_insert_mode = 1;
4297
4298 UseTabs (tty) = 0;
4299 tty->scroll_region_ok = 0;
4300
4301
4302
4303
4304 tty->line_ins_del_ok = 0;
4305
4306 tty->TN_max_colors = 16;
4307 #endif
4308
4309 #ifdef HAVE_GPM
4310 terminal->mouse_position_hook = term_mouse_position;
4311 #endif
4312 tty->mouse_highlight.mouse_face_window = Qnil;
4313
4314 terminal->kboard = allocate_kboard (Qnil);
4315 terminal->kboard->reference_count++;
4316
4317
4318
4319 if (current_kboard == initial_kboard)
4320 current_kboard = terminal->kboard;
4321 #ifndef DOS_NT
4322 term_get_fkeys (address, terminal->kboard);
4323
4324
4325 {
4326 int height, width;
4327 get_tty_size (fileno (tty->input), &width, &height);
4328 FrameCols (tty) = width;
4329 FrameRows (tty) = height;
4330 }
4331
4332 if (FrameCols (tty) <= 0)
4333 FrameCols (tty) = tgetnum ("co");
4334 if (FrameRows (tty) <= 0)
4335 FrameRows (tty) = tgetnum ("li");
4336
4337 if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
4338 maybe_fatal (must_succeed, terminal,
4339 "Screen size %dx%d is too small",
4340 "Screen size %dx%d is too small",
4341 FrameCols (tty), FrameRows (tty));
4342
4343 TabWidth (tty) = tgetnum ("tw");
4344
4345 if (!tty->TS_bell)
4346 tty->TS_bell = "\07";
4347
4348 if (!tty->TS_fwd_scroll)
4349 tty->TS_fwd_scroll = Down (tty);
4350
4351 PC = tty->TS_pad_char ? *tty->TS_pad_char : 0;
4352
4353 if (TabWidth (tty) < 0)
4354 TabWidth (tty) = 8;
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364 if (tty->TS_standout_mode && tgetnum ("sg") >= 0)
4365 {
4366 tty->TS_standout_mode = 0;
4367 tty->TS_end_standout_mode = 0;
4368 }
4369 if (tty->TS_enter_underline_mode && tgetnum ("ug") >= 0)
4370 {
4371 tty->TS_enter_underline_mode = 0;
4372 tty->TS_exit_underline_mode = 0;
4373 }
4374
4375
4376 if (tty->TS_standout_mode == 0)
4377 {
4378 tty->TS_standout_mode = tty->TS_enter_underline_mode;
4379 tty->TS_end_standout_mode = tty->TS_exit_underline_mode;
4380 }
4381
4382
4383
4384 if (tty->TS_end_standout_mode == 0)
4385 {
4386 char *s = tgetstr ("me", address);
4387 if (s != 0)
4388 tty->TS_end_standout_mode = s;
4389 else
4390 tty->TS_standout_mode = 0;
4391 }
4392
4393 if (tty->TF_teleray)
4394 {
4395 tty->Wcm->cm_tab = 0;
4396
4397 tty->TS_standout_mode = 0;
4398
4399 CR (tty) = 0;
4400
4401
4402 Down (tty) = 0;
4403 }
4404
4405 tty->specified_window = FrameRows (tty);
4406
4407 if (Wcm_init (tty) == -1)
4408 {
4409 maybe_fatal (must_succeed, terminal,
4410 "Terminal type \"%s\" is not powerful enough to run Emacs",
4411 "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
4412 It lacks the ability to position the cursor.\n\
4413 If that is not the actual type of terminal you have,\n\
4414 use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\
4415 'setenv TERM ...') to specify the correct type. It may be necessary\n"
4416 # ifdef TERMINFO
4417 "to do 'unset TERMINFO' (C-shell: 'unsetenv TERMINFO') as well.",
4418 # else
4419 "to do 'unset TERMCAP' (C-shell: 'unsetenv TERMCAP') as well.",
4420 # endif
4421 terminal_type);
4422 }
4423
4424 if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
4425 maybe_fatal (must_succeed, terminal,
4426 "Could not determine the frame size",
4427 "Could not determine the frame size");
4428
4429 tty->delete_in_insert_mode
4430 = tty->TS_delete_mode && tty->TS_insert_mode
4431 && !strcmp (tty->TS_delete_mode, tty->TS_insert_mode);
4432
4433 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
4434
4435 tty->scroll_region_ok
4436 = (tty->Wcm->cm_abs
4437 && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
4438
4439 tty->line_ins_del_ok
4440 = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
4441 && (tty->TS_del_line || tty->TS_del_multi_lines))
4442 || (tty->scroll_region_ok
4443 && tty->TS_fwd_scroll && tty->TS_rev_scroll));
4444
4445 tty->char_ins_del_ok
4446 = ((tty->TS_ins_char || tty->TS_insert_mode
4447 || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
4448 && (tty->TS_del_char || tty->TS_del_multi_chars));
4449
4450 init_baud_rate (fileno (tty->input));
4451
4452 #endif
4453
4454
4455 init_sys_modes (tty);
4456
4457 return terminal;
4458 }
4459
4460
4461 static void
4462 vfatal (const char *str, va_list ap)
4463 {
4464 fputs ("emacs: ", stderr);
4465 vfprintf (stderr, str, ap);
4466 if (! (str[0] && str[strlen (str) - 1] == '\n'))
4467 putc ('\n', stderr);
4468 exit (1);
4469 }
4470
4471
4472
4473
4474
4475
4476 static void
4477 maybe_fatal (bool must_succeed, struct terminal *terminal,
4478 const char *str1, const char *str2, ...)
4479 {
4480 va_list ap;
4481 va_start (ap, str2);
4482 if (terminal)
4483 delete_tty (terminal);
4484
4485 if (must_succeed)
4486 vfatal (str2, ap);
4487 else
4488 verror (str1, ap);
4489 }
4490
4491 void
4492 fatal (const char *str, ...)
4493 {
4494 va_list ap;
4495 va_start (ap, str);
4496 vfatal (str, ap);
4497 }
4498
4499
4500
4501
4502
4503 static void
4504 delete_tty (struct terminal *terminal)
4505 {
4506 struct tty_display_info *tty;
4507
4508
4509
4510 if (!terminal->name)
4511 return;
4512
4513 eassert (terminal->type == output_termcap);
4514
4515 tty = terminal->display_info.tty;
4516
4517 if (tty == tty_list)
4518 tty_list = tty->next;
4519 else
4520 {
4521 struct tty_display_info *p;
4522 for (p = tty_list; p && p->next != tty; p = p->next)
4523 ;
4524
4525 if (! p)
4526
4527 emacs_abort ();
4528
4529 p->next = tty->next;
4530 tty->next = 0;
4531 }
4532
4533
4534
4535 reset_sys_modes (tty);
4536
4537 delete_terminal (terminal);
4538
4539 xfree (tty->name);
4540 xfree (tty->type);
4541
4542 if (tty->input)
4543 {
4544 delete_keyboard_wait_descriptor (fileno (tty->input));
4545 if (tty->input != stdin)
4546 fclose (tty->input);
4547 }
4548 if (tty->output && tty->output != stdout && tty->output != tty->input)
4549 fclose (tty->output);
4550 if (tty->termscript)
4551 fclose (tty->termscript);
4552
4553 xfree (tty->old_tty);
4554 xfree (tty->Wcm);
4555 xfree (tty);
4556 }
4557
4558 void
4559 syms_of_term (void)
4560 {
4561 DEFVAR_BOOL ("system-uses-terminfo", system_uses_terminfo,
4562 doc:
4563 );
4564 #ifdef TERMINFO
4565 system_uses_terminfo = 1;
4566 #else
4567 system_uses_terminfo = 0;
4568 #endif
4569
4570 DEFVAR_LISP ("suspend-tty-functions", Vsuspend_tty_functions,
4571 doc:
4572
4573 );
4574 Vsuspend_tty_functions = Qnil;
4575
4576
4577 DEFVAR_LISP ("resume-tty-functions", Vresume_tty_functions,
4578 doc:
4579
4580 );
4581 Vresume_tty_functions = Qnil;
4582
4583 DEFVAR_BOOL ("visible-cursor", visible_cursor,
4584 doc:
4585
4586
4587 );
4588 visible_cursor = 1;
4589
4590 DEFVAR_BOOL ("tty-menu-calls-mouse-position-function",
4591 tty_menu_calls_mouse_position_function,
4592 doc:
4593
4594 );
4595 tty_menu_calls_mouse_position_function = 0;
4596
4597 defsubr (&Stty_display_color_p);
4598 defsubr (&Stty_display_color_cells);
4599 defsubr (&Stty_no_underline);
4600 defsubr (&Stty_type);
4601 defsubr (&Scontrolling_tty_p);
4602 defsubr (&Stty_top_frame);
4603 defsubr (&Ssuspend_tty);
4604 defsubr (&Sresume_tty);
4605 defsubr (&Stty__set_output_buffer_size);
4606 defsubr (&Stty__output_buffer_size);
4607 #ifdef HAVE_GPM
4608 defsubr (&Sgpm_mouse_start);
4609 defsubr (&Sgpm_mouse_stop);
4610 #endif
4611
4612 #ifndef DOS_NT
4613 default_orig_pair = NULL;
4614 default_set_foreground = NULL;
4615 default_set_background = NULL;
4616 #endif
4617
4618 encode_terminal_src = NULL;
4619 encode_terminal_dst = NULL;
4620
4621 DEFSYM (Qtty_mode_set_strings, "tty-mode-set-strings");
4622 DEFSYM (Qtty_mode_reset_strings, "tty-mode-reset-strings");
4623
4624 #ifndef MSDOS
4625 DEFSYM (Qtty_menu_next_item, "tty-menu-next-item");
4626 DEFSYM (Qtty_menu_prev_item, "tty-menu-prev-item");
4627 DEFSYM (Qtty_menu_next_menu, "tty-menu-next-menu");
4628 DEFSYM (Qtty_menu_prev_menu, "tty-menu-prev-menu");
4629 DEFSYM (Qtty_menu_select, "tty-menu-select");
4630 DEFSYM (Qtty_menu_ignore, "tty-menu-ignore");
4631 DEFSYM (Qtty_menu_exit, "tty-menu-exit");
4632 DEFSYM (Qtty_menu_mouse_movement, "tty-menu-mouse-movement");
4633 DEFSYM (Qtty_menu_navigation_map, "tty-menu-navigation-map");
4634 #endif
4635 }