Simplify and avoid signal-handling races.
[bpt/emacs.git] / src / msdos.c
... / ...
CommitLineData
1/* MS-DOS specific C utilities. -*- coding: raw-text -*-
2
3Copyright (C) 1993-1997, 1999-2012 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
20/* Contributed by Morten Welinder */
21/* New display, keyboard, and mouse control by Kim F. Storm */
22
23/* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
24
25#include <config.h>
26
27#ifdef MSDOS
28#include <setjmp.h>
29#include "lisp.h"
30#include <stdio.h>
31#include <time.h>
32#include <sys/param.h>
33#include <sys/time.h>
34/* gettime and settime in dos.h clash with their namesakes from
35 gnulib, so we move out of our way the prototypes in dos.h. */
36#define gettime dos_h_gettime_
37#define settime dos_h_settime_
38#include <dos.h>
39#undef gettime
40#undef settime
41#include <errno.h>
42#include <sys/stat.h> /* for _fixpath */
43#include <unistd.h> /* for chdir, dup, dup2, etc. */
44#include <dir.h> /* for getdisk */
45#pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
46#include <fcntl.h>
47#include <io.h> /* for setmode */
48#include <dpmi.h> /* for __dpmi_xxx stuff */
49#include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
50#include <libc/dosio.h> /* for _USE_LFN */
51#include <conio.h> /* for cputs */
52
53#include "msdos.h"
54#include "systime.h"
55#include "frame.h"
56#include "termhooks.h"
57#include "termchar.h"
58#include "dispextern.h"
59#include "dosfns.h"
60#include "termopts.h"
61#include "character.h"
62#include "coding.h"
63#include "disptab.h"
64#include "window.h"
65#include "buffer.h"
66#include "commands.h"
67#include "blockinput.h"
68#include "keyboard.h"
69#include "intervals.h"
70#include <go32.h>
71#include <pc.h>
72#include <ctype.h>
73/* #include <process.h> */
74/* Damn that local process.h! Instead we can define P_WAIT and
75 spawnve ourselves. */
76#define P_WAIT 1
77extern int spawnve (int, const char *, char *const [], char *const []);
78
79#ifndef _USE_LFN
80#define _USE_LFN 0
81#endif
82
83#ifndef _dos_ds
84#define _dos_ds _go32_info_block.selector_for_linear_memory
85#endif
86
87#include <signal.h>
88#include "syssignal.h"
89
90#include "careadlinkat.h"
91#include "allocator.h"
92
93#ifndef SYSTEM_MALLOC
94
95#ifdef GNU_MALLOC
96
97/* If other `malloc' than ours is used, force our `sbrk' behave like
98 Unix programs expect (resize memory blocks to keep them contiguous).
99 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
100 because that's what `gmalloc' expects to get. */
101#include <crt0.h>
102
103#ifdef REL_ALLOC
104int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
105#else /* not REL_ALLOC */
106int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
107#endif /* not REL_ALLOC */
108#endif /* GNU_MALLOC */
109
110#endif /* not SYSTEM_MALLOC */
111
112/* Return the current timestamp in milliseconds since midnight. */
113static unsigned long
114event_timestamp (void)
115{
116 struct timespec t;
117 unsigned long s;
118
119 gettime (&t);
120 s = t.tv_sec;
121 s %= 86400;
122 s *= 1000;
123 s += t.tv_nsec * 1000000;
124
125 return s;
126}
127
128\f
129/* ------------------------ Mouse control ---------------------------
130 *
131 * Coordinates are in screen positions and zero based.
132 * Mouse buttons are numbered from left to right and also zero based.
133 */
134
135/* This used to be in termhooks.h, but mainstream Emacs code no longer
136 uses it, and it was removed... */
137#define NUM_MOUSE_BUTTONS (5)
138
139int have_mouse; /* 0: no, 1: enabled, -1: disabled */
140static int mouse_visible;
141
142static int mouse_last_x;
143static int mouse_last_y;
144
145static int mouse_button_translate[NUM_MOUSE_BUTTONS];
146static int mouse_button_count;
147
148void
149mouse_on (void)
150{
151 union REGS regs;
152
153 if (have_mouse > 0 && !mouse_visible)
154 {
155 struct tty_display_info *tty = CURTTY ();
156
157 if (tty->termscript)
158 fprintf (tty->termscript, "<M_ON>");
159 regs.x.ax = 0x0001;
160 int86 (0x33, &regs, &regs);
161 mouse_visible = 1;
162 }
163}
164
165void
166mouse_off (void)
167{
168 union REGS regs;
169
170 if (have_mouse > 0 && mouse_visible)
171 {
172 struct tty_display_info *tty = CURTTY ();
173
174 if (tty->termscript)
175 fprintf (tty->termscript, "<M_OFF>");
176 regs.x.ax = 0x0002;
177 int86 (0x33, &regs, &regs);
178 mouse_visible = 0;
179 }
180}
181
182static void
183mouse_setup_buttons (int n_buttons)
184{
185 if (n_buttons == 3)
186 {
187 mouse_button_count = 3;
188 mouse_button_translate[0] = 0; /* Left */
189 mouse_button_translate[1] = 2; /* Middle */
190 mouse_button_translate[2] = 1; /* Right */
191 }
192 else /* two, what else? */
193 {
194 mouse_button_count = 2;
195 mouse_button_translate[0] = 0;
196 mouse_button_translate[1] = 1;
197 }
198}
199
200DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
201 1, 1, "NSet number of mouse buttons to: ",
202 doc: /* Set the number of mouse buttons to use by Emacs.
203This is useful with mice that report the number of buttons inconsistently,
204e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
205them. This happens with wheeled mice on Windows 9X, for example. */)
206 (Lisp_Object nbuttons)
207{
208 int n;
209
210 CHECK_NUMBER (nbuttons);
211 n = XINT (nbuttons);
212 if (n < 2 || n > 3)
213 xsignal2 (Qargs_out_of_range,
214 build_string ("only 2 or 3 mouse buttons are supported"),
215 nbuttons);
216 mouse_setup_buttons (n);
217 return Qnil;
218}
219
220static void
221mouse_get_xy (int *x, int *y)
222{
223 union REGS regs;
224
225 regs.x.ax = 0x0003;
226 int86 (0x33, &regs, &regs);
227 *x = regs.x.cx / 8;
228 *y = regs.x.dx / 8;
229}
230
231void
232mouse_moveto (int x, int y)
233{
234 union REGS regs;
235 struct tty_display_info *tty = CURTTY ();
236
237 if (tty->termscript)
238 fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
239 regs.x.ax = 0x0004;
240 mouse_last_x = regs.x.cx = x * 8;
241 mouse_last_y = regs.x.dx = y * 8;
242 int86 (0x33, &regs, &regs);
243}
244
245static int
246mouse_pressed (int b, int *xp, int *yp)
247{
248 union REGS regs;
249
250 if (b >= mouse_button_count)
251 return 0;
252 regs.x.ax = 0x0005;
253 regs.x.bx = mouse_button_translate[b];
254 int86 (0x33, &regs, &regs);
255 if (regs.x.bx)
256 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
257 return (regs.x.bx != 0);
258}
259
260static int
261mouse_released (int b, int *xp, int *yp)
262{
263 union REGS regs;
264
265 if (b >= mouse_button_count)
266 return 0;
267 regs.x.ax = 0x0006;
268 regs.x.bx = mouse_button_translate[b];
269 int86 (0x33, &regs, &regs);
270 if (regs.x.bx)
271 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
272 return (regs.x.bx != 0);
273}
274
275static int
276mouse_button_depressed (int b, int *xp, int *yp)
277{
278 union REGS regs;
279
280 if (b >= mouse_button_count)
281 return 0;
282 regs.x.ax = 0x0003;
283 int86 (0x33, &regs, &regs);
284 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
285 {
286 *xp = regs.x.cx / 8;
287 *yp = regs.x.dx / 8;
288 return 1;
289 }
290 return 0;
291}
292
293void
294mouse_get_pos (FRAME_PTR *f, int insist, Lisp_Object *bar_window,
295 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
296 Time *time)
297{
298 int ix, iy;
299 Lisp_Object frame, tail;
300
301 /* Clear the mouse-moved flag for every frame on this display. */
302 FOR_EACH_FRAME (tail, frame)
303 XFRAME (frame)->mouse_moved = 0;
304
305 *f = SELECTED_FRAME ();
306 *bar_window = Qnil;
307 mouse_get_xy (&ix, &iy);
308 *time = event_timestamp ();
309 *x = make_number (mouse_last_x = ix);
310 *y = make_number (mouse_last_y = iy);
311}
312
313static void
314mouse_check_moved (void)
315{
316 int x, y;
317
318 mouse_get_xy (&x, &y);
319 SELECTED_FRAME ()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
320 mouse_last_x = x;
321 mouse_last_y = y;
322}
323
324/* Force the mouse driver to ``forget'' about any button clicks until
325 now. */
326static void
327mouse_clear_clicks (void)
328{
329 int b;
330
331 for (b = 0; b < mouse_button_count; b++)
332 {
333 int dummy_x, dummy_y;
334
335 (void) mouse_pressed (b, &dummy_x, &dummy_y);
336 (void) mouse_released (b, &dummy_x, &dummy_y);
337 }
338}
339
340void
341mouse_init (void)
342{
343 union REGS regs;
344 struct tty_display_info *tty = CURTTY ();
345
346 if (tty->termscript)
347 fprintf (tty->termscript, "<M_INIT>");
348
349 regs.x.ax = 0x0021;
350 int86 (0x33, &regs, &regs);
351
352 /* Reset the mouse last press/release info. It seems that Windows
353 doesn't do that automatically when function 21h is called, which
354 causes Emacs to ``remember'' the click that switched focus to the
355 window just before Emacs was started from that window. */
356 mouse_clear_clicks ();
357
358 regs.x.ax = 0x0007;
359 regs.x.cx = 0;
360 regs.x.dx = 8 * (ScreenCols () - 1);
361 int86 (0x33, &regs, &regs);
362
363 regs.x.ax = 0x0008;
364 regs.x.cx = 0;
365 regs.x.dx = 8 * (ScreenRows () - 1);
366 int86 (0x33, &regs, &regs);
367
368 mouse_moveto (0, 0);
369 mouse_visible = 0;
370}
371\f
372/* ------------------------- Screen control ----------------------
373 *
374 */
375
376static int internal_terminal = 0;
377
378#ifndef HAVE_X_WINDOWS
379extern unsigned char ScreenAttrib;
380static int screen_face;
381
382static int screen_size_X;
383static int screen_size_Y;
384static int screen_size;
385
386static int current_pos_X;
387static int current_pos_Y;
388static int new_pos_X;
389static int new_pos_Y;
390
391static void *startup_screen_buffer;
392static int startup_screen_size_X;
393static int startup_screen_size_Y;
394static int startup_pos_X;
395static int startup_pos_Y;
396static unsigned char startup_screen_attrib;
397
398static clock_t startup_time;
399
400static int term_setup_done;
401
402static unsigned short outside_cursor;
403
404/* Similar to the_only_frame. */
405struct tty_display_info the_only_display_info;
406
407/* Support for DOS/V (allows Japanese characters to be displayed on
408 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
409
410/* Holds the address of the text-mode screen buffer. */
411static unsigned long screen_old_address = 0;
412/* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
413static unsigned short screen_virtual_segment = 0;
414static unsigned short screen_virtual_offset = 0;
415extern Lisp_Object Qcursor_type;
416extern Lisp_Object Qbar, Qhbar;
417
418/* The screen colors of the current frame, which serve as the default
419 colors for newly-created frames. */
420static int initial_screen_colors[2];
421
422/* Update the screen from a part of relocated DOS/V screen buffer which
423 begins at OFFSET and includes COUNT characters. */
424static void
425dosv_refresh_virtual_screen (int offset, int count)
426{
427 __dpmi_regs regs;
428
429 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
430 return;
431
432 regs.h.ah = 0xff; /* update relocated screen */
433 regs.x.es = screen_virtual_segment;
434 regs.x.di = screen_virtual_offset + offset;
435 regs.x.cx = count;
436 __dpmi_int (0x10, &regs);
437}
438
439static void
440dos_direct_output (int y, int x, char *buf, int len)
441{
442 int t0 = 2 * (x + y * screen_size_X);
443 int t = t0 + (int) ScreenPrimary;
444 int l0 = len;
445
446 /* This is faster. */
447 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
448 _farnspokeb (t, *buf);
449
450 if (screen_virtual_segment)
451 dosv_refresh_virtual_screen (t0, l0);
452}
453#endif
454
455#ifndef HAVE_X_WINDOWS
456
457static int blink_bit = -1; /* the state of the blink bit at startup */
458
459/* Enable bright background colors. */
460static void
461bright_bg (void)
462{
463 union REGS regs;
464
465 /* Remember the original state of the blink/bright-background bit.
466 It is stored at 0040:0065h in the BIOS data area. */
467 if (blink_bit == -1)
468 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
469
470 regs.h.bl = 0;
471 regs.x.ax = 0x1003;
472 int86 (0x10, &regs, &regs);
473}
474
475/* Disable bright background colors (and enable blinking) if we found
476 the video system in that state at startup. */
477static void
478maybe_enable_blinking (void)
479{
480 if (blink_bit == 1)
481 {
482 union REGS regs;
483
484 regs.h.bl = 1;
485 regs.x.ax = 0x1003;
486 int86 (0x10, &regs, &regs);
487 }
488}
489
490/* Return non-zero if the system has a VGA adapter. */
491static int
492vga_installed (void)
493{
494 union REGS regs;
495
496 regs.x.ax = 0x1a00;
497 int86 (0x10, &regs, &regs);
498 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
499 return 1;
500 return 0;
501}
502
503/* Set the screen dimensions so that it can show no less than
504 ROWS x COLS frame. */
505
506void
507dos_set_window_size (int *rows, int *cols)
508{
509 char video_name[30];
510 union REGS regs;
511 Lisp_Object video_mode;
512 int video_mode_value, have_vga = 0;
513 int current_rows = ScreenRows (), current_cols = ScreenCols ();
514
515 if (*rows == current_rows && *cols == current_cols)
516 return;
517
518 mouse_off ();
519 have_vga = vga_installed ();
520
521 /* If the user specified a special video mode for these dimensions,
522 use that mode. */
523 video_mode
524 = Fsymbol_value (Fintern_soft (make_formatted_string
525 (video_name, "screen-dimensions-%dx%d",
526 *rows, *cols), Qnil));
527
528 if (INTEGERP (video_mode)
529 && (video_mode_value = XINT (video_mode)) > 0)
530 {
531 regs.x.ax = video_mode_value;
532 int86 (0x10, &regs, &regs);
533
534 if (have_mouse)
535 {
536 /* Must hardware-reset the mouse, or else it won't update
537 its notion of screen dimensions for some non-standard
538 video modes. This is *painfully* slow... */
539 regs.x.ax = 0;
540 int86 (0x33, &regs, &regs);
541 }
542 }
543
544 /* Find one of the dimensions supported by standard EGA/VGA
545 which gives us at least the required dimensions. */
546 else
547 {
548 static struct {
549 int rows, need_vga;
550 } std_dimension[] = {
551 {25, 0},
552 {28, 1},
553 {35, 0},
554 {40, 1},
555 {43, 0},
556 {50, 1}
557 };
558 int i = 0;
559
560 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
561 {
562 if (std_dimension[i].need_vga <= have_vga
563 && std_dimension[i].rows >= *rows)
564 {
565 if (std_dimension[i].rows != current_rows
566 || *cols != current_cols)
567 _set_screen_lines (std_dimension[i].rows);
568 break;
569 }
570 i++;
571 }
572 }
573
574
575 if (have_mouse)
576 {
577 mouse_init ();
578 mouse_on ();
579 }
580
581 /* Tell the caller what dimensions have been REALLY set. */
582 *rows = ScreenRows ();
583 *cols = ScreenCols ();
584
585 /* Update Emacs' notion of screen dimensions. */
586 screen_size_X = *cols;
587 screen_size_Y = *rows;
588 screen_size = *cols * *rows;
589
590 /* If the dimensions changed, the mouse highlight info is invalid. */
591 if (current_rows != *rows || current_cols != *cols)
592 {
593 struct frame *f = SELECTED_FRAME ();
594 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
595 Lisp_Object window = hlinfo->mouse_face_window;
596
597 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
598 {
599 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
600 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
601 hlinfo->mouse_face_window = Qnil;
602 }
603 }
604
605 /* Enable bright background colors. */
606 bright_bg ();
607
608 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
609 be defensive anyway. */
610 if (screen_virtual_segment)
611 dosv_refresh_virtual_screen (0, *cols * *rows);
612}
613
614/* If we write a character in the position where the mouse is,
615 the mouse cursor may need to be refreshed. */
616
617static void
618mouse_off_maybe (void)
619{
620 int x, y;
621
622 if (!mouse_visible)
623 return;
624
625 mouse_get_xy (&x, &y);
626 if (y != new_pos_Y || x < new_pos_X)
627 return;
628
629 mouse_off ();
630}
631
632#define DEFAULT_CURSOR_START (-1)
633#define DEFAULT_CURSOR_WIDTH (-1)
634#define BOX_CURSOR_WIDTH (-32)
635
636/* Set cursor to begin at scan line START_LINE in the character cell
637 and extend for WIDTH scan lines. Scan lines are counted from top
638 of the character cell, starting from zero. */
639static void
640msdos_set_cursor_shape (struct frame *f, int start_line, int width)
641{
642 unsigned desired_cursor;
643 __dpmi_regs regs;
644 int max_line, top_line, bot_line;
645 struct tty_display_info *tty = FRAME_TTY (f);
646
647 /* Avoid the costly BIOS call if F isn't the currently selected
648 frame. Allow for NULL as unconditionally meaning the selected
649 frame. */
650 if (f && f != SELECTED_FRAME ())
651 return;
652
653 if (tty->termscript)
654 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
655
656 /* The character cell size in scan lines is stored at 40:85 in the
657 BIOS data area. */
658 max_line = _farpeekw (_dos_ds, 0x485) - 1;
659 switch (max_line)
660 {
661 default: /* this relies on CGA cursor emulation being ON! */
662 case 7:
663 bot_line = 7;
664 break;
665 case 9:
666 bot_line = 9;
667 break;
668 case 13:
669 bot_line = 12;
670 break;
671 case 15:
672 bot_line = 14;
673 break;
674 }
675
676 if (width < 0)
677 {
678 if (width == BOX_CURSOR_WIDTH)
679 {
680 top_line = 0;
681 bot_line = max_line;
682 }
683 else if (start_line != DEFAULT_CURSOR_START)
684 {
685 top_line = start_line;
686 bot_line = top_line - width - 1;
687 }
688 else if (width != DEFAULT_CURSOR_WIDTH)
689 {
690 top_line = 0;
691 bot_line = -1 - width;
692 }
693 else
694 top_line = bot_line + 1;
695 }
696 else if (width == 0)
697 {
698 /* [31, 0] seems to DTRT for all screen sizes. */
699 top_line = 31;
700 bot_line = 0;
701 }
702 else /* WIDTH is positive */
703 {
704 if (start_line != DEFAULT_CURSOR_START)
705 bot_line = start_line;
706 top_line = bot_line - (width - 1);
707 }
708
709 /* If the current cursor shape is already what they want, we are
710 history here. */
711 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
712 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
713 return;
714
715 regs.h.ah = 1;
716 regs.x.cx = desired_cursor;
717 __dpmi_int (0x10, &regs);
718}
719
720static void
721IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
722{
723 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
724 {
725 /* Just BAR means the normal EGA/VGA cursor. */
726 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
727 }
728 else if (CONSP (cursor_type)
729 && (EQ (XCAR (cursor_type), Qbar)
730 || EQ (XCAR (cursor_type), Qhbar)))
731 {
732 Lisp_Object bar_parms = XCDR (cursor_type);
733 int width;
734
735 if (INTEGERP (bar_parms))
736 {
737 /* Feature: negative WIDTH means cursor at the top
738 of the character cell, zero means invisible cursor. */
739 width = XINT (bar_parms);
740 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
741 width);
742 }
743 else if (CONSP (bar_parms)
744 && INTEGERP (XCAR (bar_parms))
745 && INTEGERP (XCDR (bar_parms)))
746 {
747 int start_line = XINT (XCDR (bar_parms));
748
749 width = XINT (XCAR (bar_parms));
750 msdos_set_cursor_shape (f, start_line, width);
751 }
752 }
753 else
754 {
755 /* Treat anything unknown as "box cursor". This includes nil, so
756 that a frame which doesn't specify a cursor type gets a box,
757 which is the default in Emacs. */
758 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
759 }
760}
761
762static void
763IT_ring_bell (struct frame *f)
764{
765 if (visible_bell)
766 {
767 mouse_off ();
768 ScreenVisualBell ();
769 }
770 else
771 {
772 union REGS inregs, outregs;
773 inregs.h.ah = 2;
774 inregs.h.dl = 7;
775 intdos (&inregs, &outregs);
776 }
777}
778
779/* Given a face id FACE, extract the face parameters to be used for
780 display until the face changes. The face parameters (actually, its
781 color) are used to construct the video attribute byte for each
782 glyph during the construction of the buffer that is then blitted to
783 the video RAM. */
784static void
785IT_set_face (int face)
786{
787 struct frame *sf = SELECTED_FRAME ();
788 struct face *fp = FACE_FROM_ID (sf, face);
789 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
790 unsigned long fg, bg, dflt_fg, dflt_bg;
791 struct tty_display_info *tty = FRAME_TTY (sf);
792
793 if (!fp)
794 {
795 fp = dfp;
796 /* The default face for the frame should always be realized and
797 cached. */
798 if (!fp)
799 emacs_abort ();
800 }
801 screen_face = face;
802 fg = fp->foreground;
803 bg = fp->background;
804 dflt_fg = dfp->foreground;
805 dflt_bg = dfp->background;
806
807 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
808 mean use the colors of the default face. Note that we assume all
809 16 colors to be available for the background, since Emacs switches
810 on this mode (and loses the blinking attribute) at startup. */
811 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
812 fg = FRAME_FOREGROUND_PIXEL (sf);
813 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
814 fg = FRAME_BACKGROUND_PIXEL (sf);
815 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
816 bg = FRAME_BACKGROUND_PIXEL (sf);
817 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
818 bg = FRAME_FOREGROUND_PIXEL (sf);
819
820 /* Make sure highlighted lines really stand out, come what may. */
821 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
822 {
823 unsigned long tem = fg;
824
825 fg = bg;
826 bg = tem;
827 }
828 /* If the user requested inverse video, obey. */
829 if (inverse_video)
830 {
831 unsigned long tem2 = fg;
832
833 fg = bg;
834 bg = tem2;
835 }
836 if (tty->termscript)
837 fprintf (tty->termscript, "<FACE %d: %lu/%lu[FG:%lu/BG:%lu]>", face,
838 fp->foreground, fp->background, fg, bg);
839 if (fg >= 0 && fg < 16)
840 {
841 ScreenAttrib &= 0xf0;
842 ScreenAttrib |= fg;
843 }
844 if (bg >= 0 && bg < 16)
845 {
846 ScreenAttrib &= 0x0f;
847 ScreenAttrib |= ((bg & 0x0f) << 4);
848 }
849}
850
851/* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
852 width of a DOS display in any known text mode. We multiply by 2 to
853 accommodate the screen attribute byte. */
854#define MAX_SCREEN_BUF 160*2
855
856extern unsigned char *encode_terminal_code (struct glyph *, int,
857 struct coding_system *);
858
859static void
860IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
861{
862 unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
863 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
864 register int sl = str_len;
865 struct tty_display_info *tty = FRAME_TTY (f);
866 struct frame *sf;
867 unsigned char *conversion_buffer;
868
869 /* If terminal_coding does any conversion, use it, otherwise use
870 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
871 because it always returns 1 if terminal_coding.src_multibyte is 1. */
872 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
873
874 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
875 coding = &safe_terminal_coding;
876
877 if (str_len <= 0) return;
878
879 sf = SELECTED_FRAME ();
880
881 /* Since faces get cached and uncached behind our back, we can't
882 rely on their indices in the cache being consistent across
883 invocations. So always reset the screen face to the default
884 face of the frame, before writing glyphs, and let the glyphs
885 set the right face if it's different from the default. */
886 IT_set_face (DEFAULT_FACE_ID);
887
888 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
889 the tail. */
890 coding->mode &= ~CODING_MODE_LAST_BLOCK;
891 screen_bp = &screen_buf[0];
892 while (sl > 0)
893 {
894 int cf;
895 int n;
896
897 /* If the face of this glyph is different from the current
898 screen face, update the screen attribute byte. */
899 cf = str->face_id;
900 if (cf != screen_face)
901 IT_set_face (cf); /* handles invalid faces gracefully */
902
903 /* Identify a run of glyphs with the same face. */
904 for (n = 1; n < sl; ++n)
905 if (str[n].face_id != cf)
906 break;
907
908 if (n >= sl)
909 /* This is the last glyph. */
910 coding->mode |= CODING_MODE_LAST_BLOCK;
911
912 conversion_buffer = encode_terminal_code (str, n, coding);
913 if (coding->produced > 0)
914 {
915 /* Copy the encoded bytes to the screen buffer. */
916 for (bp = conversion_buffer; coding->produced--; bp++)
917 {
918 /* Paranoia: discard bytes that would overrun the end of
919 the screen buffer. */
920 if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
921 {
922 *screen_bp++ = (unsigned char)*bp;
923 *screen_bp++ = ScreenAttrib;
924 }
925 if (tty->termscript)
926 fputc (*bp, tty->termscript);
927 }
928 }
929 /* Update STR and its remaining length. */
930 str += n;
931 sl -= n;
932 }
933
934 /* Dump whatever we have in the screen buffer. */
935 mouse_off_maybe ();
936 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
937 if (screen_virtual_segment)
938 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
939 new_pos_X += (screen_bp - screen_buf) / 2;
940}
941
942/************************************************************************
943 Mouse Highlight (and friends..)
944 ************************************************************************/
945
946/* Last window where we saw the mouse. Used by mouse-autoselect-window. */
947static Lisp_Object last_mouse_window;
948
949static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
950
951int
952popup_activated (void)
953{
954 return mouse_preempted;
955}
956
957/* Draw TEXT_AREA glyphs between START and END of glyph row ROW on
958 window W. X is relative to TEXT_AREA in W. HL is a face override
959 for drawing the glyphs. */
960void
961tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
962 int start_hpos, int end_hpos,
963 enum draw_glyphs_face hl)
964{
965 struct frame *f = XFRAME (WINDOW_FRAME (w));
966 struct tty_display_info *tty = FRAME_TTY (f);
967 Mouse_HLInfo *hlinfo = &tty->mouse_highlight;
968
969 if (hl == DRAW_MOUSE_FACE)
970 {
971 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
972 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
973 int nglyphs = end_hpos - start_hpos;
974 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
975 int start_offset = offset;
976
977 if (tty->termscript)
978 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
979 kstart, kstart + nglyphs - 1, vpos);
980
981 mouse_off ();
982 IT_set_face (hlinfo->mouse_face_face_id);
983 /* Since we are going to change only the _colors_ of already
984 displayed text, there's no need to go through all the pain of
985 generating and encoding the text from the glyphs. Instead,
986 we simply poke the attribute byte of each affected position
987 in video memory with the colors computed by IT_set_face! */
988 _farsetsel (_dos_ds);
989 while (nglyphs--)
990 {
991 _farnspokeb (offset, ScreenAttrib);
992 offset += 2;
993 }
994 if (screen_virtual_segment)
995 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
996 mouse_on ();
997 }
998 else if (hl == DRAW_NORMAL_TEXT)
999 {
1000 /* We are removing a previously-drawn mouse highlight. The
1001 safest way to do so is to redraw the glyphs anew, since all
1002 kinds of faces and display tables could have changed behind
1003 our back. */
1004 int nglyphs = end_hpos - start_hpos;
1005 int save_x = new_pos_X, save_y = new_pos_Y;
1006
1007 if (end_hpos >= row->used[TEXT_AREA])
1008 nglyphs = row->used[TEXT_AREA] - start_hpos;
1009
1010 /* IT_write_glyphs writes at cursor position, so we need to
1011 temporarily move cursor coordinates to the beginning of
1012 the highlight region. */
1013 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1014 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1015
1016 if (tty->termscript)
1017 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1018 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1019 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1020 if (tty->termscript)
1021 fputs ("\n", tty->termscript);
1022 new_pos_X = save_x;
1023 new_pos_Y = save_y;
1024 }
1025}
1026
1027static void
1028IT_clear_end_of_line (struct frame *f, int first_unused)
1029{
1030 char *spaces, *sp;
1031 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1032 struct tty_display_info *tty = FRAME_TTY (f);
1033
1034 if (new_pos_X >= first_unused || fatal_error_in_progress)
1035 return;
1036
1037 IT_set_face (0);
1038 i = (j = first_unused - new_pos_X) * 2;
1039 if (tty->termscript)
1040 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1041 spaces = sp = alloca (i);
1042
1043 while (--j >= 0)
1044 {
1045 *sp++ = ' ';
1046 *sp++ = ScreenAttrib;
1047 }
1048
1049 mouse_off_maybe ();
1050 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1051 if (screen_virtual_segment)
1052 dosv_refresh_virtual_screen (offset, i / 2);
1053
1054 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1055 Let's follow their lead, in case someone relies on this. */
1056 new_pos_X = first_unused;
1057}
1058
1059static void
1060IT_clear_screen (struct frame *f)
1061{
1062 struct tty_display_info *tty = FRAME_TTY (f);
1063
1064 if (tty->termscript)
1065 fprintf (tty->termscript, "<CLR:SCR>");
1066 /* We are sometimes called (from clear_garbaged_frames) when a new
1067 frame is being created, but its faces are not yet realized. In
1068 such a case we cannot call IT_set_face, since it will fail to find
1069 any valid faces and will abort. Instead, use the initial screen
1070 colors; that should mimic what a Unix tty does, which simply clears
1071 the screen with whatever default colors are in use. */
1072 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1073 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1074 else
1075 IT_set_face (0);
1076 mouse_off ();
1077 ScreenClear ();
1078 if (screen_virtual_segment)
1079 dosv_refresh_virtual_screen (0, screen_size);
1080 new_pos_X = new_pos_Y = 0;
1081}
1082
1083static void
1084IT_clear_to_end (struct frame *f)
1085{
1086 struct tty_display_info *tty = FRAME_TTY (f);
1087
1088 if (tty->termscript)
1089 fprintf (tty->termscript, "<CLR:EOS>");
1090
1091 while (new_pos_Y < screen_size_Y) {
1092 new_pos_X = 0;
1093 IT_clear_end_of_line (f, screen_size_X);
1094 new_pos_Y++;
1095 }
1096}
1097
1098static void
1099IT_cursor_to (struct frame *f, int y, int x)
1100{
1101 struct tty_display_info *tty = FRAME_TTY (f);
1102
1103 if (tty->termscript)
1104 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1105 new_pos_X = x;
1106 new_pos_Y = y;
1107}
1108
1109static int cursor_cleared;
1110
1111static void
1112IT_display_cursor (int on)
1113{
1114 struct tty_display_info *tty = CURTTY ();
1115
1116 if (on && cursor_cleared)
1117 {
1118 ScreenSetCursor (current_pos_Y, current_pos_X);
1119 cursor_cleared = 0;
1120 if (tty->termscript)
1121 fprintf (tty->termscript, "\nCURSOR ON (%dx%d)",
1122 current_pos_Y, current_pos_X);
1123 }
1124 else if (!on && !cursor_cleared)
1125 {
1126 ScreenSetCursor (-1, -1);
1127 cursor_cleared = 1;
1128 if (tty->termscript)
1129 fprintf (tty->termscript, "\nCURSOR OFF (%dx%d)",
1130 current_pos_Y, current_pos_X);
1131 }
1132}
1133
1134/* Emacs calls cursor-movement functions a lot when it updates the
1135 display (probably a legacy of old terminals where you cannot
1136 update a screen line without first moving the cursor there).
1137 However, cursor movement is expensive on MSDOS (it calls a slow
1138 BIOS function and requires 2 mode switches), while actual screen
1139 updates access the video memory directly and don't depend on
1140 cursor position. To avoid slowing down the redisplay, we cheat:
1141 all functions that move the cursor only set internal variables
1142 which record the cursor position, whereas the cursor is only
1143 moved to its final position whenever screen update is complete.
1144
1145 `IT_cmgoto' is called from the keyboard reading loop and when the
1146 frame update is complete. This means that we are ready for user
1147 input, so we update the cursor position to show where the point is,
1148 and also make the mouse pointer visible.
1149
1150 Special treatment is required when the cursor is in the echo area,
1151 to put the cursor at the end of the text displayed there. */
1152
1153static void
1154IT_cmgoto (FRAME_PTR f)
1155{
1156 /* Only set the cursor to where it should be if the display is
1157 already in sync with the window contents. */
1158 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1159 struct tty_display_info *tty = FRAME_TTY (f);
1160
1161 /* FIXME: This needs to be rewritten for the new redisplay, or
1162 removed. */
1163#if 0
1164 static int previous_pos_X = -1;
1165
1166 update_cursor_pos = 1; /* temporary!!! */
1167
1168 /* If the display is in sync, forget any previous knowledge about
1169 cursor position. This is primarily for unexpected events like
1170 C-g in the minibuffer. */
1171 if (update_cursor_pos && previous_pos_X >= 0)
1172 previous_pos_X = -1;
1173 /* If we are in the echo area, put the cursor at the
1174 end of the echo area message. */
1175 if (!update_cursor_pos
1176 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1177 {
1178 int tem_X = current_pos_X, dummy;
1179
1180 if (echo_area_glyphs)
1181 {
1182 tem_X = echo_area_glyphs_length;
1183 /* Save current cursor position, to be restored after the
1184 echo area message is erased. Only remember one level
1185 of previous cursor position. */
1186 if (previous_pos_X == -1)
1187 ScreenGetCursor (&dummy, &previous_pos_X);
1188 }
1189 else if (previous_pos_X >= 0)
1190 {
1191 /* We wind up here after the echo area message is erased.
1192 Restore the cursor position we remembered above. */
1193 tem_X = previous_pos_X;
1194 previous_pos_X = -1;
1195 }
1196
1197 if (current_pos_X != tem_X)
1198 {
1199 new_pos_X = tem_X;
1200 update_cursor_pos = 1;
1201 }
1202 }
1203#endif
1204
1205 if (update_cursor_pos
1206 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1207 {
1208 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1209 if (tty->termscript)
1210 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1211 }
1212
1213 /* Maybe cursor is invisible, so make it visible. */
1214 IT_display_cursor (1);
1215
1216 /* Mouse pointer should be always visible if we are waiting for
1217 keyboard input. */
1218 if (!mouse_visible)
1219 mouse_on ();
1220}
1221
1222static void
1223IT_update_begin (struct frame *f)
1224{
1225 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1226 Mouse_HLInfo *hlinfo = &display_info->mouse_highlight;
1227 struct frame *mouse_face_frame = hlinfo->mouse_face_mouse_frame;
1228
1229 if (display_info->termscript)
1230 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1231
1232 block_input ();
1233
1234 if (f && f == mouse_face_frame)
1235 {
1236 /* Don't do highlighting for mouse motion during the update. */
1237 hlinfo->mouse_face_defer = 1;
1238
1239 /* If F needs to be redrawn, simply forget about any prior mouse
1240 highlighting. */
1241 if (FRAME_GARBAGED_P (f))
1242 hlinfo->mouse_face_window = Qnil;
1243
1244 /* Can we tell that this update does not affect the window
1245 where the mouse highlight is? If so, no need to turn off.
1246 Likewise, don't do anything if none of the enabled rows
1247 contains glyphs highlighted in mouse face. */
1248 if (!NILP (hlinfo->mouse_face_window)
1249 && WINDOWP (hlinfo->mouse_face_window))
1250 {
1251 struct window *w = XWINDOW (hlinfo->mouse_face_window);
1252 int i;
1253
1254 /* If the mouse highlight is in the window that was deleted
1255 (e.g., if it was popped by completion), clear highlight
1256 unconditionally. */
1257 if (NILP (w->buffer))
1258 hlinfo->mouse_face_window = Qnil;
1259 else
1260 {
1261 for (i = 0; i < w->desired_matrix->nrows; ++i)
1262 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1263 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1264 break;
1265 }
1266
1267 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1268 clear_mouse_face (hlinfo);
1269 }
1270 }
1271 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1272 {
1273 /* If the frame with mouse highlight was deleted, invalidate the
1274 highlight info. */
1275 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1276 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1277 hlinfo->mouse_face_window = Qnil;
1278 hlinfo->mouse_face_deferred_gc = 0;
1279 hlinfo->mouse_face_mouse_frame = NULL;
1280 }
1281
1282 unblock_input ();
1283}
1284
1285static void
1286IT_update_end (struct frame *f)
1287{
1288 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1289
1290 if (dpyinfo->termscript)
1291 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1292 dpyinfo->mouse_highlight.mouse_face_defer = 0;
1293}
1294
1295static void
1296IT_frame_up_to_date (struct frame *f)
1297{
1298 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1299 Lisp_Object new_cursor, frame_desired_cursor;
1300 struct window *sw;
1301
1302 if (hlinfo->mouse_face_deferred_gc
1303 || (f && f == hlinfo->mouse_face_mouse_frame))
1304 {
1305 block_input ();
1306 if (hlinfo->mouse_face_mouse_frame)
1307 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1308 hlinfo->mouse_face_mouse_x,
1309 hlinfo->mouse_face_mouse_y);
1310 hlinfo->mouse_face_deferred_gc = 0;
1311 unblock_input ();
1312 }
1313
1314 /* Set the cursor type to whatever they wanted. In a minibuffer
1315 window, we want the cursor to appear only if we are reading input
1316 from this window, and we want the cursor to be taken from the
1317 frame parameters. For the selected window, we use either its
1318 buffer-local value or the value from the frame parameters if the
1319 buffer doesn't define its local value for the cursor type. */
1320 sw = XWINDOW (f->selected_window);
1321 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1322 if (cursor_in_echo_area
1323 && FRAME_HAS_MINIBUF_P (f)
1324 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1325 && sw == XWINDOW (echo_area_window))
1326 new_cursor = frame_desired_cursor;
1327 else
1328 {
1329 struct buffer *b = XBUFFER (sw->buffer);
1330
1331 if (EQ (BVAR (b,cursor_type), Qt))
1332 new_cursor = frame_desired_cursor;
1333 else if (NILP (BVAR (b, cursor_type))) /* nil means no cursor */
1334 new_cursor = Fcons (Qbar, make_number (0));
1335 else
1336 new_cursor = BVAR (b, cursor_type);
1337 }
1338
1339 IT_set_cursor_type (f, new_cursor);
1340
1341 IT_cmgoto (f); /* position cursor when update is done */
1342}
1343
1344/* Copy LEN glyphs displayed on a single line whose vertical position
1345 is YPOS, beginning at horizontal position XFROM to horizontal
1346 position XTO, by moving blocks in the video memory. Used by
1347 functions that insert and delete glyphs. */
1348static void
1349IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1350{
1351 /* The offsets of source and destination relative to the
1352 conventional memory selector. */
1353 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1354 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1355
1356 if (from == to || len <= 0)
1357 return;
1358
1359 _farsetsel (_dos_ds);
1360
1361 /* The source and destination might overlap, so we need to move
1362 glyphs non-destructively. */
1363 if (from > to)
1364 {
1365 for ( ; len; from += 2, to += 2, len--)
1366 _farnspokew (to, _farnspeekw (from));
1367 }
1368 else
1369 {
1370 from += (len - 1) * 2;
1371 to += (len - 1) * 2;
1372 for ( ; len; from -= 2, to -= 2, len--)
1373 _farnspokew (to, _farnspeekw (from));
1374 }
1375 if (screen_virtual_segment)
1376 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1377}
1378
1379/* Insert and delete glyphs. */
1380static void
1381IT_insert_glyphs (struct frame *f, struct glyph *start, int len)
1382{
1383 int shift_by_width = screen_size_X - (new_pos_X + len);
1384
1385 /* Shift right the glyphs from the nominal cursor position to the
1386 end of this line. */
1387 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1388
1389 /* Now write the glyphs to be inserted. */
1390 IT_write_glyphs (f, start, len);
1391}
1392
1393static void
1394IT_delete_glyphs (struct frame *f, int n)
1395{
1396 emacs_abort ();
1397}
1398
1399/* set-window-configuration on window.c needs this. */
1400void
1401x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1402{
1403 set_menu_bar_lines (f, value, oldval);
1404}
1405
1406/* This was copied from xfaces.c */
1407
1408extern Lisp_Object Qbackground_color;
1409extern Lisp_Object Qforeground_color;
1410Lisp_Object Qreverse;
1411extern Lisp_Object Qtitle;
1412
1413/* IT_set_terminal_modes is called when emacs is started,
1414 resumed, and whenever the screen is redrawn! */
1415
1416static void
1417IT_set_terminal_modes (struct terminal *term)
1418{
1419 struct tty_display_info *tty;
1420
1421 /* If called with initial terminal, it's too early to do anything
1422 useful. */
1423 if (term->type == output_initial)
1424 return;
1425
1426 tty = term->display_info.tty;
1427
1428 if (tty->termscript)
1429 fprintf (tty->termscript, "\n<SET_TERM>");
1430
1431 screen_size_X = ScreenCols ();
1432 screen_size_Y = ScreenRows ();
1433 screen_size = screen_size_X * screen_size_Y;
1434
1435 new_pos_X = new_pos_Y = 0;
1436 current_pos_X = current_pos_Y = -1;
1437
1438 if (term_setup_done)
1439 return;
1440 term_setup_done = 1;
1441
1442 startup_screen_size_X = screen_size_X;
1443 startup_screen_size_Y = screen_size_Y;
1444 startup_screen_attrib = ScreenAttrib;
1445
1446 /* Is DOS/V (or any other RSIS software which relocates
1447 the screen) installed? */
1448 {
1449 unsigned short es_value;
1450 __dpmi_regs regs;
1451
1452 regs.h.ah = 0xfe; /* get relocated screen address */
1453 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1454 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1455 else if (screen_old_address) /* already switched to Japanese mode once */
1456 regs.x.es = (screen_old_address >> 4) & 0xffff;
1457 else
1458 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1459 regs.x.di = 0;
1460 es_value = regs.x.es;
1461 __dpmi_int (0x10, &regs);
1462
1463 if (regs.x.es != es_value)
1464 {
1465 /* screen_old_address is only set if ScreenPrimary does NOT
1466 already point to the relocated buffer address returned by
1467 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1468 ScreenPrimary to that address at startup under DOS/V. */
1469 if (regs.x.es != ((ScreenPrimary >> 4) & 0xffff))
1470 screen_old_address = ScreenPrimary;
1471 screen_virtual_segment = regs.x.es;
1472 screen_virtual_offset = regs.x.di;
1473 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1474 }
1475 }
1476
1477 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1478 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1479
1480 bright_bg ();
1481}
1482
1483/* IT_reset_terminal_modes is called when emacs is
1484 suspended or killed. */
1485
1486static void
1487IT_reset_terminal_modes (struct terminal *term)
1488{
1489 int display_row_start = (int) ScreenPrimary;
1490 int saved_row_len = startup_screen_size_X * 2;
1491 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
1492 int to_next_row = update_row_len;
1493 unsigned char *saved_row = startup_screen_buffer;
1494 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
1495 struct tty_display_info *tty = term->display_info.tty;
1496
1497 if (tty->termscript)
1498 fprintf (tty->termscript, "\n<RESET_TERM>");
1499
1500 if (!term_setup_done)
1501 return;
1502
1503 mouse_off ();
1504
1505 /* Leave the video system in the same state as we found it,
1506 as far as the blink/bright-background bit is concerned. */
1507 maybe_enable_blinking ();
1508
1509 /* We have a situation here.
1510 We cannot just do ScreenUpdate(startup_screen_buffer) because
1511 the luser could have changed screen dimensions inside Emacs
1512 and failed (or didn't want) to restore them before killing
1513 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1514 thus will happily use memory outside what was allocated for
1515 `startup_screen_buffer'.
1516 Thus we only restore as much as the current screen dimensions
1517 can hold, and clear the rest (if the saved screen is smaller than
1518 the current) with the color attribute saved at startup. The cursor
1519 is also restored within the visible dimensions. */
1520
1521 ScreenAttrib = startup_screen_attrib;
1522
1523 /* Don't restore the screen if we are exiting less than 2 seconds
1524 after startup: we might be crashing, and the screen might show
1525 some vital clues to what's wrong. */
1526 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
1527 {
1528 ScreenClear ();
1529 if (screen_virtual_segment)
1530 dosv_refresh_virtual_screen (0, screen_size);
1531
1532 if (update_row_len > saved_row_len)
1533 update_row_len = saved_row_len;
1534 if (current_rows > startup_screen_size_Y)
1535 current_rows = startup_screen_size_Y;
1536
1537 if (tty->termscript)
1538 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1539 update_row_len / 2, current_rows);
1540
1541 while (current_rows--)
1542 {
1543 dosmemput (saved_row, update_row_len, display_row_start);
1544 if (screen_virtual_segment)
1545 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
1546 update_row_len / 2);
1547 saved_row += saved_row_len;
1548 display_row_start += to_next_row;
1549 }
1550 }
1551 if (startup_pos_X < cursor_pos_X)
1552 cursor_pos_X = startup_pos_X;
1553 if (startup_pos_Y < cursor_pos_Y)
1554 cursor_pos_Y = startup_pos_Y;
1555
1556 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
1557 xfree (startup_screen_buffer);
1558 startup_screen_buffer = NULL;
1559
1560 term_setup_done = 0;
1561}
1562
1563static void
1564IT_set_terminal_window (struct frame *f, int foo)
1565{
1566}
1567
1568/* Remember the screen colors of the current frame, to serve as the
1569 default colors for newly-created frames. */
1570DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
1571 Smsdos_remember_default_colors, 1, 1, 0,
1572 doc: /* Remember the screen colors of the current frame. */)
1573 (Lisp_Object frame)
1574{
1575 struct frame *f;
1576
1577 CHECK_FRAME (frame);
1578 f = XFRAME (frame);
1579
1580 /* This function is called after applying default-frame-alist to the
1581 initial frame. At that time, if reverse-colors option was
1582 specified in default-frame-alist, it was already applied, and
1583 frame colors are reversed. */
1584 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
1585 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
1586
1587 return Qnil;
1588}
1589
1590void
1591IT_set_frame_parameters (struct frame *f, Lisp_Object alist)
1592{
1593 Lisp_Object tail;
1594 int i, j, length = XINT (Flength (alist));
1595 Lisp_Object *parms
1596 = (Lisp_Object *) alloca (length * word_size);
1597 Lisp_Object *values
1598 = (Lisp_Object *) alloca (length * word_size);
1599 /* Do we have to reverse the foreground and background colors? */
1600 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
1601 int redraw = 0, fg_set = 0, bg_set = 0;
1602 unsigned long orig_fg, orig_bg;
1603 struct tty_display_info *tty = FRAME_TTY (f);
1604
1605 /* If we are creating a new frame, begin with the original screen colors
1606 used for the initial frame. */
1607 if (!f->default_face_done_p
1608 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
1609 {
1610 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
1611 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
1612 init_frame_faces (f);
1613 f->default_face_done_p = 1;
1614 }
1615 orig_fg = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
1616 orig_bg = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
1617
1618 /* Extract parm names and values into those vectors. */
1619 i = 0;
1620 for (tail = alist; CONSP (tail); tail = XCDR (tail))
1621 {
1622 Lisp_Object elt = XCAR (tail);
1623 parms[i] = Fcar (elt);
1624 CHECK_SYMBOL (parms[i]);
1625 values[i] = Fcdr (elt);
1626 i++;
1627 }
1628
1629 j = i;
1630
1631 for (i = 0; i < j; i++)
1632 {
1633 Lisp_Object prop, val;
1634
1635 prop = parms[i];
1636 val = values[i];
1637
1638 if (EQ (prop, Qreverse))
1639 reverse = EQ (val, Qt);
1640 }
1641
1642 if (tty->termscript && reverse)
1643 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
1644
1645 /* Now process the alist elements in reverse of specified order. */
1646 for (i--; i >= 0; i--)
1647 {
1648 Lisp_Object prop, val;
1649
1650 prop = parms[i];
1651 val = values[i];
1652
1653 if (EQ (prop, Qforeground_color))
1654 {
1655 unsigned long new_color = load_color (f, NULL, val, reverse
1656 ? LFACE_BACKGROUND_INDEX
1657 : LFACE_FOREGROUND_INDEX);
1658 if (new_color != FACE_TTY_DEFAULT_COLOR
1659 && new_color != FACE_TTY_DEFAULT_FG_COLOR
1660 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
1661 {
1662 if (!reverse)
1663 {
1664 FRAME_FOREGROUND_PIXEL (f) = new_color;
1665 /* Make sure the foreground of the default face for
1666 this frame is changed as well. */
1667 update_face_from_frame_parameter (f, Qforeground_color, val);
1668 fg_set = 1;
1669 if (tty->termscript)
1670 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
1671 }
1672 else
1673 {
1674 FRAME_BACKGROUND_PIXEL (f) = new_color;
1675 update_face_from_frame_parameter (f, Qbackground_color, val);
1676 bg_set = 1;
1677 if (tty->termscript)
1678 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
1679 }
1680 redraw = 1;
1681 }
1682 }
1683 else if (EQ (prop, Qbackground_color))
1684 {
1685 unsigned long new_color = load_color (f, NULL, val, reverse
1686 ? LFACE_FOREGROUND_INDEX
1687 : LFACE_BACKGROUND_INDEX);
1688 if (new_color != FACE_TTY_DEFAULT_COLOR
1689 && new_color != FACE_TTY_DEFAULT_FG_COLOR
1690 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
1691 {
1692 if (!reverse)
1693 {
1694 FRAME_BACKGROUND_PIXEL (f) = new_color;
1695 /* Make sure the background of the default face for
1696 this frame is changed as well. */
1697 bg_set = 1;
1698 update_face_from_frame_parameter (f, Qbackground_color, val);
1699 if (tty->termscript)
1700 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
1701 }
1702 else
1703 {
1704 FRAME_FOREGROUND_PIXEL (f) = new_color;
1705 fg_set = 1;
1706 update_face_from_frame_parameter (f, Qforeground_color, val);
1707 if (tty->termscript)
1708 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
1709 }
1710 redraw = 1;
1711 }
1712 }
1713 else if (EQ (prop, Qtitle))
1714 {
1715 x_set_title (f, val);
1716 if (tty->termscript)
1717 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
1718 }
1719 else if (EQ (prop, Qcursor_type))
1720 {
1721 IT_set_cursor_type (f, val);
1722 if (tty->termscript)
1723 fprintf (tty->termscript, "<CTYPE: %s>\n",
1724 EQ (val, Qbar)
1725 || EQ (val, Qhbar)
1726 || (CONSP (val) && (EQ (XCAR (val), Qbar)
1727 || EQ (XCAR (val), Qhbar)))
1728 ? "bar" : "box");
1729 }
1730 else if (EQ (prop, Qtty_type))
1731 {
1732 internal_terminal_init ();
1733 if (tty->termscript)
1734 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
1735 SBYTES (val), SDATA (val));
1736 }
1737 store_frame_param (f, prop, val);
1738 }
1739
1740 /* If they specified "reverse", but not the colors, we need to swap
1741 the current frame colors. */
1742 if (reverse)
1743 {
1744 if (!fg_set)
1745 {
1746 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
1747 update_face_from_frame_parameter (f, Qforeground_color,
1748 tty_color_name (f, orig_bg));
1749 redraw = 1;
1750 }
1751 if (!bg_set)
1752 {
1753 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
1754 update_face_from_frame_parameter (f, Qbackground_color,
1755 tty_color_name (f, orig_fg));
1756 redraw = 1;
1757 }
1758 }
1759
1760 if (redraw)
1761 {
1762 face_change_count++; /* forces xdisp.c to recompute basic faces */
1763 if (f == SELECTED_FRAME ())
1764 redraw_frame (f);
1765 }
1766}
1767
1768extern void init_frame_faces (FRAME_PTR);
1769
1770#endif /* !HAVE_X_WINDOWS */
1771
1772
1773/* Do we need the internal terminal? */
1774
1775void
1776internal_terminal_init (void)
1777{
1778 static int init_needed = 1;
1779 char *term = getenv ("TERM"), *colors;
1780 struct frame *sf = SELECTED_FRAME ();
1781 struct tty_display_info *tty;
1782
1783#ifdef HAVE_X_WINDOWS
1784 if (!inhibit_window_system)
1785 return;
1786#endif
1787
1788 /* If this is the initial terminal, we are done here. */
1789 if (sf->output_method == output_initial)
1790 return;
1791
1792 internal_terminal
1793 = (!noninteractive) && term && !strcmp (term, "internal");
1794
1795#ifndef HAVE_X_WINDOWS
1796 if (!internal_terminal || inhibit_window_system)
1797 {
1798 sf->output_method = output_termcap;
1799 return;
1800 }
1801
1802 tty = FRAME_TTY (sf);
1803 kset_window_system (current_kboard, Qpc);
1804 sf->output_method = output_msdos_raw;
1805 if (init_needed)
1806 {
1807 if (!tty->termscript && getenv ("EMACSTEST"))
1808 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
1809 if (tty->termscript)
1810 {
1811 time_t now = time (NULL);
1812 struct tm *tnow = localtime (&now);
1813 char tbuf[100];
1814
1815 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
1816 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
1817 fprintf (tty->termscript, "=====================\n\n");
1818 }
1819
1820 Vinitial_window_system = Qpc;
1821 Vwindow_system_version = make_number (24); /* RE Emacs version */
1822 tty->terminal->type = output_msdos_raw;
1823
1824 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
1825 address. */
1826 screen_old_address = 0;
1827
1828 /* Forget the stale screen colors as well. */
1829 initial_screen_colors[0] = initial_screen_colors[1] = -1;
1830
1831 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
1832 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
1833 bright_bg ();
1834 colors = getenv ("EMACSCOLORS");
1835 if (colors && strlen (colors) >= 2)
1836 {
1837 /* The colors use 4 bits each (we enable bright background). */
1838 if (isdigit (colors[0]))
1839 colors[0] -= '0';
1840 else if (isxdigit (colors[0]))
1841 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1842 if (colors[0] >= 0 && colors[0] < 16)
1843 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
1844 if (isdigit (colors[1]))
1845 colors[1] -= '0';
1846 else if (isxdigit (colors[1]))
1847 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1848 if (colors[1] >= 0 && colors[1] < 16)
1849 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
1850 }
1851 the_only_display_info.mouse_highlight.mouse_face_mouse_frame = NULL;
1852 the_only_display_info.mouse_highlight.mouse_face_deferred_gc = 0;
1853 the_only_display_info.mouse_highlight.mouse_face_beg_row =
1854 the_only_display_info.mouse_highlight.mouse_face_beg_col = -1;
1855 the_only_display_info.mouse_highlight.mouse_face_end_row =
1856 the_only_display_info.mouse_highlight.mouse_face_end_col = -1;
1857 the_only_display_info.mouse_highlight.mouse_face_face_id = DEFAULT_FACE_ID;
1858 the_only_display_info.mouse_highlight.mouse_face_window = Qnil;
1859 the_only_display_info.mouse_highlight.mouse_face_mouse_x =
1860 the_only_display_info.mouse_highlight.mouse_face_mouse_y = 0;
1861 the_only_display_info.mouse_highlight.mouse_face_defer = 0;
1862 the_only_display_info.mouse_highlight.mouse_face_hidden = 0;
1863
1864 if (have_mouse) /* detected in dos_ttraw, which see */
1865 {
1866 have_mouse = 1; /* enable mouse */
1867 mouse_visible = 0;
1868 mouse_setup_buttons (mouse_button_count);
1869 tty->terminal->mouse_position_hook = &mouse_get_pos;
1870 mouse_init ();
1871 }
1872
1873 if (tty->termscript && screen_size)
1874 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1875 screen_size_X, screen_size_Y);
1876
1877 init_frame_faces (sf);
1878 init_needed = 0;
1879 }
1880#endif
1881}
1882
1883void
1884initialize_msdos_display (struct terminal *term)
1885{
1886 term->rif = 0; /* we don't support window-based display */
1887 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
1888 term->clear_to_end_hook = IT_clear_to_end;
1889 term->clear_frame_hook = IT_clear_screen;
1890 term->clear_end_of_line_hook = IT_clear_end_of_line;
1891 term->ins_del_lines_hook = 0;
1892 term->insert_glyphs_hook = IT_insert_glyphs;
1893 term->write_glyphs_hook = IT_write_glyphs;
1894 term->delete_glyphs_hook = IT_delete_glyphs;
1895 term->ring_bell_hook = IT_ring_bell;
1896 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
1897 term->set_terminal_modes_hook = IT_set_terminal_modes;
1898 term->set_terminal_window_hook = IT_set_terminal_window;
1899 term->update_begin_hook = IT_update_begin;
1900 term->update_end_hook = IT_update_end;
1901 term->frame_up_to_date_hook = IT_frame_up_to_date;
1902 term->mouse_position_hook = 0; /* set later by dos_ttraw */
1903 term->frame_rehighlight_hook = 0;
1904 term->frame_raise_lower_hook = 0;
1905 term->set_vertical_scroll_bar_hook = 0;
1906 term->condemn_scroll_bars_hook = 0;
1907 term->redeem_scroll_bar_hook = 0;
1908 term->judge_scroll_bars_hook = 0;
1909 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
1910}
1911
1912int
1913dos_get_saved_screen (char **screen, int *rows, int *cols)
1914{
1915#ifndef HAVE_X_WINDOWS
1916 *screen = startup_screen_buffer;
1917 *cols = startup_screen_size_X;
1918 *rows = startup_screen_size_Y;
1919 return *screen != (char *)0;
1920#else
1921 return 0;
1922#endif
1923}
1924
1925#ifndef HAVE_X_WINDOWS
1926
1927/* We are not X, but we can emulate it well enough for our needs... */
1928void
1929check_x (void)
1930{
1931 if (! FRAME_MSDOS_P (SELECTED_FRAME ()))
1932 error ("Not running under a window system");
1933}
1934
1935#endif
1936
1937\f
1938/* ----------------------- Keyboard control ----------------------
1939 *
1940 * Keymaps reflect the following keyboard layout:
1941 *
1942 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1943 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1944 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1945 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1946 * SPACE
1947 */
1948
1949#define Ignore 0x0000
1950#define Normal 0x0000 /* normal key - alt changes scan-code */
1951#define FctKey 0x1000 /* func key if c == 0, else c */
1952#define Special 0x2000 /* func key even if c != 0 */
1953#define ModFct 0x3000 /* special if mod-keys, else 'c' */
1954#define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1955#define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1956#define Grey 0x6000 /* Grey keypad key */
1957
1958#define Alt 0x0100 /* alt scan-code */
1959#define Ctrl 0x0200 /* ctrl scan-code */
1960#define Shift 0x0400 /* shift scan-code */
1961
1962static int extended_kbd; /* 101 (102) keyboard present. */
1963
1964struct kbd_translate {
1965 unsigned char sc;
1966 unsigned char ch;
1967 unsigned short code;
1968};
1969
1970struct dos_keyboard_map
1971{
1972 char *unshifted;
1973 char *shifted;
1974 char *alt_gr;
1975 struct kbd_translate *translate_table;
1976};
1977
1978
1979static struct dos_keyboard_map us_keyboard = {
1980/* 0 1 2 3 4 5 */
1981/* 01234567890123456789012345678901234567890 12345678901234 */
1982 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1983/* 0123456789012345678901234567890123456789 012345678901234 */
1984 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1985 0, /* no Alt-Gr key */
1986 0 /* no translate table */
1987};
1988
1989static struct dos_keyboard_map fr_keyboard = {
1990/* 0 1 2 3 4 5 */
1991/* 012 3456789012345678901234567890123456789012345678901234 */
1992