* coding.c (make_conversion_work_buffer): Disable buffer modification
[bpt/emacs.git] / src / msdos.c
... / ...
CommitLineData
1/* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2008
4 Free Software Foundation, Inc.
5
6This file is part of GNU Emacs.
7
8GNU Emacs is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20
21/* Contributed by Morten Welinder */
22/* New display, keyboard, and mouse control by Kim F. Storm */
23
24/* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
25
26#include <config.h>
27
28#ifdef MSDOS
29#include "lisp.h"
30#include <stdio.h>
31#include <stdlib.h>
32#include <time.h>
33#include <sys/param.h>
34#include <sys/time.h>
35#include <dos.h>
36#include <errno.h>
37#include <string.h> /* for bzero and string functions */
38#include <sys/stat.h> /* for _fixpath */
39#include <unistd.h> /* for chdir, dup, dup2, etc. */
40#include <dir.h> /* for getdisk */
41#if __DJGPP__ >= 2
42#pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
43#include <fcntl.h>
44#include <io.h> /* for setmode */
45#include <dpmi.h> /* for __dpmi_xxx stuff */
46#include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
47#include <libc/dosio.h> /* for _USE_LFN */
48#include <conio.h> /* for cputs */
49#endif
50
51#include "msdos.h"
52#include "systime.h"
53#include "frame.h"
54#include "termhooks.h"
55#include "termchar.h"
56#include "dispextern.h"
57#include "dosfns.h"
58#include "termopts.h"
59#include "character.h"
60#include "coding.h"
61#include "disptab.h"
62#include "window.h"
63#include "buffer.h"
64#include "commands.h"
65#include "blockinput.h"
66#include "keyboard.h"
67#include "intervals.h"
68#include <go32.h>
69#include <pc.h>
70#include <ctype.h>
71/* #include <process.h> */
72/* Damn that local process.h! Instead we can define P_WAIT ourselves. */
73#define P_WAIT 1
74
75#ifndef _USE_LFN
76#define _USE_LFN 0
77#endif
78
79#ifndef _dos_ds
80#define _dos_ds _go32_info_block.selector_for_linear_memory
81#endif
82
83#if __DJGPP__ > 1
84
85#include <signal.h>
86#include "syssignal.h"
87
88#ifndef SYSTEM_MALLOC
89
90#ifdef GNU_MALLOC
91
92/* If other `malloc' than ours is used, force our `sbrk' behave like
93 Unix programs expect (resize memory blocks to keep them contiguous).
94 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
95 because that's what `gmalloc' expects to get. */
96#include <crt0.h>
97
98#ifdef REL_ALLOC
99int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
100#else /* not REL_ALLOC */
101int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
102#endif /* not REL_ALLOC */
103#endif /* GNU_MALLOC */
104
105#endif /* not SYSTEM_MALLOC */
106#endif /* __DJGPP__ > 1 */
107
108static unsigned long
109event_timestamp ()
110{
111 struct time t;
112 unsigned long s;
113
114 gettime (&t);
115 s = t.ti_min;
116 s *= 60;
117 s += t.ti_sec;
118 s *= 1000;
119 s += t.ti_hund * 10;
120
121 return s;
122}
123
124\f
125/* ------------------------ Mouse control ---------------------------
126 *
127 * Coordinates are in screen positions and zero based.
128 * Mouse buttons are numbered from left to right and also zero based.
129 */
130
131/* This used to be in termhooks.h, but mainstream Emacs code no longer
132 uses it, and it was removed... */
133#define NUM_MOUSE_BUTTONS (5)
134
135int have_mouse; /* 0: no, 1: enabled, -1: disabled */
136static int mouse_visible;
137
138static int mouse_last_x;
139static int mouse_last_y;
140
141static int mouse_button_translate[NUM_MOUSE_BUTTONS];
142static int mouse_button_count;
143
144void
145mouse_on ()
146{
147 union REGS regs;
148
149 if (have_mouse > 0 && !mouse_visible)
150 {
151 struct tty_display_info *tty = CURTTY ();
152
153 if (tty->termscript)
154 fprintf (tty->termscript, "<M_ON>");
155 regs.x.ax = 0x0001;
156 int86 (0x33, &regs, &regs);
157 mouse_visible = 1;
158 }
159}
160
161void
162mouse_off ()
163{
164 union REGS regs;
165
166 if (have_mouse > 0 && mouse_visible)
167 {
168 struct tty_display_info *tty = CURTTY ();
169
170 if (tty->termscript)
171 fprintf (tty->termscript, "<M_OFF>");
172 regs.x.ax = 0x0002;
173 int86 (0x33, &regs, &regs);
174 mouse_visible = 0;
175 }
176}
177
178static void
179mouse_setup_buttons (int n_buttons)
180{
181 if (n_buttons == 3)
182 {
183 mouse_button_count = 3;
184 mouse_button_translate[0] = 0; /* Left */
185 mouse_button_translate[1] = 2; /* Middle */
186 mouse_button_translate[2] = 1; /* Right */
187 }
188 else /* two, what else? */
189 {
190 mouse_button_count = 2;
191 mouse_button_translate[0] = 0;
192 mouse_button_translate[1] = 1;
193 }
194}
195
196DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons, Smsdos_set_mouse_buttons,
197 1, 1, "NSet number of mouse buttons to: ",
198 doc: /* Set the number of mouse buttons to use by Emacs.
199This is useful with mice that report the number of buttons inconsistently,
200e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
201them. This happens with wheeled mice on Windows 9X, for example. */)
202 (nbuttons)
203 Lisp_Object nbuttons;
204{
205 int n;
206
207 CHECK_NUMBER (nbuttons);
208 n = XINT (nbuttons);
209 if (n < 2 || n > 3)
210 xsignal2 (Qargs_out_of_range,
211 build_string ("only 2 or 3 mouse buttons are supported"),
212 nbuttons);
213 mouse_setup_buttons (n);
214 return Qnil;
215}
216
217static void
218mouse_get_xy (int *x, int *y)
219{
220 union REGS regs;
221
222 regs.x.ax = 0x0003;
223 int86 (0x33, &regs, &regs);
224 *x = regs.x.cx / 8;
225 *y = regs.x.dx / 8;
226}
227
228void
229mouse_moveto (x, y)
230 int x, y;
231{
232 union REGS regs;
233 struct tty_display_info *tty = CURTTY ();
234
235 if (tty->termscript)
236 fprintf (tty->termscript, "<M_XY=%dx%d>", x, y);
237 regs.x.ax = 0x0004;
238 mouse_last_x = regs.x.cx = x * 8;
239 mouse_last_y = regs.x.dx = y * 8;
240 int86 (0x33, &regs, &regs);
241}
242
243static int
244mouse_pressed (b, xp, yp)
245 int b, *xp, *yp;
246{
247 union REGS regs;
248
249 if (b >= mouse_button_count)
250 return 0;
251 regs.x.ax = 0x0005;
252 regs.x.bx = mouse_button_translate[b];
253 int86 (0x33, &regs, &regs);
254 if (regs.x.bx)
255 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
256 return (regs.x.bx != 0);
257}
258
259static int
260mouse_released (b, xp, yp)
261 int b, *xp, *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 (b, xp, yp)
277 int b, *xp, *yp;
278{
279 union REGS regs;
280
281 if (b >= mouse_button_count)
282 return 0;
283 regs.x.ax = 0x0003;
284 int86 (0x33, &regs, &regs);
285 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
286 {
287 *xp = regs.x.cx / 8;
288 *yp = regs.x.dx / 8;
289 return 1;
290 }
291 return 0;
292}
293
294void
295mouse_get_pos (f, insist, bar_window, part, x, y, time)
296 FRAME_PTR *f;
297 int insist;
298 Lisp_Object *bar_window, *x, *y;
299 enum scroll_bar_part *part;
300 unsigned long *time;
301{
302 int ix, iy;
303 Lisp_Object frame, tail;
304
305 /* Clear the mouse-moved flag for every frame on this display. */
306 FOR_EACH_FRAME (tail, frame)
307 XFRAME (frame)->mouse_moved = 0;
308
309 *f = SELECTED_FRAME();
310 *bar_window = Qnil;
311 mouse_get_xy (&ix, &iy);
312 *time = event_timestamp ();
313 *x = make_number (mouse_last_x = ix);
314 *y = make_number (mouse_last_y = iy);
315}
316
317static void
318mouse_check_moved ()
319{
320 int x, y;
321
322 mouse_get_xy (&x, &y);
323 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
324 mouse_last_x = x;
325 mouse_last_y = y;
326}
327
328/* Force the mouse driver to ``forget'' about any button clicks until
329 now. */
330static void
331mouse_clear_clicks (void)
332{
333 int b;
334
335 for (b = 0; b < mouse_button_count; b++)
336 {
337 int dummy_x, dummy_y;
338
339 (void) mouse_pressed (b, &dummy_x, &dummy_y);
340 (void) mouse_released (b, &dummy_x, &dummy_y);
341 }
342}
343
344void
345mouse_init ()
346{
347 union REGS regs;
348 struct tty_display_info *tty = CURTTY ();
349
350 if (tty->termscript)
351 fprintf (tty->termscript, "<M_INIT>");
352
353 regs.x.ax = 0x0021;
354 int86 (0x33, &regs, &regs);
355
356 /* Reset the mouse last press/release info. It seems that Windows
357 doesn't do that automatically when function 21h is called, which
358 causes Emacs to ``remember'' the click that switched focus to the
359 window just before Emacs was started from that window. */
360 mouse_clear_clicks ();
361
362 regs.x.ax = 0x0007;
363 regs.x.cx = 0;
364 regs.x.dx = 8 * (ScreenCols () - 1);
365 int86 (0x33, &regs, &regs);
366
367 regs.x.ax = 0x0008;
368 regs.x.cx = 0;
369 regs.x.dx = 8 * (ScreenRows () - 1);
370 int86 (0x33, &regs, &regs);
371
372 mouse_moveto (0, 0);
373 mouse_visible = 0;
374}
375\f
376/* ------------------------- Screen control ----------------------
377 *
378 */
379
380static int internal_terminal = 0;
381
382#ifndef HAVE_X_WINDOWS
383extern unsigned char ScreenAttrib;
384static int screen_face;
385
386static int screen_size_X;
387static int screen_size_Y;
388static int screen_size;
389
390static int current_pos_X;
391static int current_pos_Y;
392static int new_pos_X;
393static int new_pos_Y;
394
395static void *startup_screen_buffer;
396static int startup_screen_size_X;
397static int startup_screen_size_Y;
398static int startup_pos_X;
399static int startup_pos_Y;
400static unsigned char startup_screen_attrib;
401
402static clock_t startup_time;
403
404static int term_setup_done;
405
406static unsigned short outside_cursor;
407
408/* Similar to the_only_frame. */
409struct tty_display_info the_only_display_info;
410
411/* Support for DOS/V (allows Japanese characters to be displayed on
412 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
413
414/* Holds the address of the text-mode screen buffer. */
415static unsigned long screen_old_address = 0;
416/* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
417static unsigned short screen_virtual_segment = 0;
418static unsigned short screen_virtual_offset = 0;
419/* A flag to control how to display unibyte 8-bit characters. */
420extern int unibyte_display_via_language_environment;
421
422extern Lisp_Object Qcursor_type;
423extern Lisp_Object Qbar, Qhbar;
424
425/* The screen colors of the current frame, which serve as the default
426 colors for newly-created frames. */
427static int initial_screen_colors[2];
428
429#if __DJGPP__ > 1
430/* Update the screen from a part of relocated DOS/V screen buffer which
431 begins at OFFSET and includes COUNT characters. */
432static void
433dosv_refresh_virtual_screen (int offset, int count)
434{
435 __dpmi_regs regs;
436
437 if (offset < 0 || count < 0) /* paranoia; invalid values crash DOS/V */
438 return;
439
440 regs.h.ah = 0xff; /* update relocated screen */
441 regs.x.es = screen_virtual_segment;
442 regs.x.di = screen_virtual_offset + offset;
443 regs.x.cx = count;
444 __dpmi_int (0x10, &regs);
445}
446#endif
447
448static void
449dos_direct_output (y, x, buf, len)
450 int x, y;
451 char *buf;
452 int len;
453{
454 int t0 = 2 * (x + y * screen_size_X);
455 int t = t0 + (int) ScreenPrimary;
456 int l0 = len;
457
458#if (__DJGPP__ < 2)
459 while (--len >= 0) {
460 dosmemput (buf++, 1, t);
461 t += 2;
462 }
463#else
464 /* This is faster. */
465 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
466 _farnspokeb (t, *buf);
467
468 if (screen_virtual_segment)
469 dosv_refresh_virtual_screen (t0, l0);
470#endif
471}
472#endif
473
474/* Flash the screen as a substitute for BEEPs. */
475
476#if (__DJGPP__ < 2)
477static void
478do_visible_bell (xorattr)
479 unsigned char xorattr;
480{
481 asm volatile
482 (" movb $1,%%dl \n\
483visible_bell_0: \n\
484 movl _ScreenPrimary,%%eax \n\
485 call dosmemsetup \n\
486 movl %%eax,%%ebx \n\
487 movl %1,%%ecx \n\
488 movb %0,%%al \n\
489 incl %%ebx \n\
490visible_bell_1: \n\
491 xorb %%al,%%gs:(%%ebx) \n\
492 addl $2,%%ebx \n\
493 decl %%ecx \n\
494 jne visible_bell_1 \n\
495 decb %%dl \n\
496 jne visible_bell_3 \n\
497visible_bell_2: \n\
498 movzwl %%ax,%%eax \n\
499 movzwl %%ax,%%eax \n\
500 movzwl %%ax,%%eax \n\
501 movzwl %%ax,%%eax \n\
502 decw %%cx \n\
503 jne visible_bell_2 \n\
504 jmp visible_bell_0 \n\
505visible_bell_3:"
506 : /* no output */
507 : "m" (xorattr), "g" (screen_size)
508 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
509}
510
511static void
512ScreenVisualBell (void)
513{
514 /* This creates an xor-mask that will swap the default fore- and
515 background colors. */
516 do_visible_bell (((FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ())
517 ^ FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()))
518 * 0x11) & 0x7f);
519}
520#endif
521
522#ifndef HAVE_X_WINDOWS
523
524static int blink_bit = -1; /* the state of the blink bit at startup */
525
526/* Enable bright background colors. */
527static void
528bright_bg (void)
529{
530 union REGS regs;
531
532 /* Remember the original state of the blink/bright-background bit.
533 It is stored at 0040:0065h in the BIOS data area. */
534 if (blink_bit == -1)
535 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
536
537 regs.h.bl = 0;
538 regs.x.ax = 0x1003;
539 int86 (0x10, &regs, &regs);
540}
541
542/* Disable bright background colors (and enable blinking) if we found
543 the video system in that state at startup. */
544static void
545maybe_enable_blinking (void)
546{
547 if (blink_bit == 1)
548 {
549 union REGS regs;
550
551 regs.h.bl = 1;
552 regs.x.ax = 0x1003;
553 int86 (0x10, &regs, &regs);
554 }
555}
556
557/* Return non-zero if the system has a VGA adapter. */
558static int
559vga_installed (void)
560{
561 union REGS regs;
562
563 regs.x.ax = 0x1a00;
564 int86 (0x10, &regs, &regs);
565 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
566 return 1;
567 return 0;
568}
569
570/* Set the screen dimensions so that it can show no less than
571 ROWS x COLS frame. */
572
573void
574dos_set_window_size (rows, cols)
575 int *rows, *cols;
576{
577 char video_name[30];
578 union REGS regs;
579 Lisp_Object video_mode;
580 int video_mode_value, have_vga = 0;
581 int current_rows = ScreenRows (), current_cols = ScreenCols ();
582
583 if (*rows == current_rows && *cols == current_cols)
584 return;
585
586 mouse_off ();
587 have_vga = vga_installed ();
588
589 /* If the user specified a special video mode for these dimensions,
590 use that mode. */
591 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
592 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
593 Qnil))-> value;
594
595 if (INTEGERP (video_mode)
596 && (video_mode_value = XINT (video_mode)) > 0)
597 {
598 regs.x.ax = video_mode_value;
599 int86 (0x10, &regs, &regs);
600
601 if (have_mouse)
602 {
603 /* Must hardware-reset the mouse, or else it won't update
604 its notion of screen dimensions for some non-standard
605 video modes. This is *painfully* slow... */
606 regs.x.ax = 0;
607 int86 (0x33, &regs, &regs);
608 }
609 }
610
611 /* Find one of the dimensions supported by standard EGA/VGA
612 which gives us at least the required dimensions. */
613
614#if __DJGPP__ > 1
615
616 else
617 {
618 static struct {
619 int rows, need_vga;
620 } std_dimension[] = {
621 {25, 0},
622 {28, 1},
623 {35, 0},
624 {40, 1},
625 {43, 0},
626 {50, 1}
627 };
628 int i = 0;
629
630 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
631 {
632 if (std_dimension[i].need_vga <= have_vga
633 && std_dimension[i].rows >= *rows)
634 {
635 if (std_dimension[i].rows != current_rows
636 || *cols != current_cols)
637 _set_screen_lines (std_dimension[i].rows);
638 break;
639 }
640 i++;
641 }
642 }
643
644#else /* not __DJGPP__ > 1 */
645
646 else if (*rows <= 25)
647 {
648 if (current_rows != 25 || current_cols != 80)
649 {
650 regs.x.ax = 3;
651 int86 (0x10, &regs, &regs);
652 regs.x.ax = 0x1101;
653 regs.h.bl = 0;
654 int86 (0x10, &regs, &regs);
655 regs.x.ax = 0x1200;
656 regs.h.bl = 32;
657 int86 (0x10, &regs, &regs);
658 regs.x.ax = 3;
659 int86 (0x10, &regs, &regs);
660 }
661 }
662 else if (*rows <= 50)
663 if (have_vga && (current_rows != 50 || current_cols != 80)
664 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
665 {
666 regs.x.ax = 3;
667 int86 (0x10, &regs, &regs);
668 regs.x.ax = 0x1112;
669 regs.h.bl = 0;
670 int86 (0x10, &regs, &regs);
671 regs.x.ax = 0x1200;
672 regs.h.bl = 32;
673 int86 (0x10, &regs, &regs);
674 regs.x.ax = 0x0100;
675 regs.x.cx = 7;
676 int86 (0x10, &regs, &regs);
677 }
678#endif /* not __DJGPP__ > 1 */
679
680 if (have_mouse)
681 {
682 mouse_init ();
683 mouse_on ();
684 }
685
686 /* Tell the caller what dimensions have been REALLY set. */
687 *rows = ScreenRows ();
688 *cols = ScreenCols ();
689
690 /* Update Emacs' notion of screen dimensions. */
691 screen_size_X = *cols;
692 screen_size_Y = *rows;
693 screen_size = *cols * *rows;
694
695#if __DJGPP__ > 1
696 /* If the dimensions changed, the mouse highlight info is invalid. */
697 if (current_rows != *rows || current_cols != *cols)
698 {
699 struct frame *f = SELECTED_FRAME();
700 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
701 Lisp_Object window = dpyinfo->mouse_face_window;
702
703 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
704 {
705 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
706 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
707 dpyinfo->mouse_face_window = Qnil;
708 }
709 }
710#endif
711
712 /* Enable bright background colors. */
713 bright_bg ();
714
715 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
716 be defensive anyway. */
717 if (screen_virtual_segment)
718 dosv_refresh_virtual_screen (0, *cols * *rows);
719}
720
721/* If we write a character in the position where the mouse is,
722 the mouse cursor may need to be refreshed. */
723
724static void
725mouse_off_maybe ()
726{
727 int x, y;
728
729 if (!mouse_visible)
730 return;
731
732 mouse_get_xy (&x, &y);
733 if (y != new_pos_Y || x < new_pos_X)
734 return;
735
736 mouse_off ();
737}
738
739#define DEFAULT_CURSOR_START (-1)
740#define DEFAULT_CURSOR_WIDTH (-1)
741#define BOX_CURSOR_WIDTH (-32)
742
743/* Set cursor to begin at scan line START_LINE in the character cell
744 and extend for WIDTH scan lines. Scan lines are counted from top
745 of the character cell, starting from zero. */
746static void
747msdos_set_cursor_shape (struct frame *f, int start_line, int width)
748{
749#if __DJGPP__ > 1
750 unsigned desired_cursor;
751 __dpmi_regs regs;
752 int max_line, top_line, bot_line;
753 struct tty_display_info *tty = FRAME_TTY (f);
754
755 /* Avoid the costly BIOS call if F isn't the currently selected
756 frame. Allow for NULL as unconditionally meaning the selected
757 frame. */
758 if (f && f != SELECTED_FRAME())
759 return;
760
761 if (tty->termscript)
762 fprintf (tty->termscript, "\nCURSOR SHAPE=(%d,%d)", start_line, width);
763
764 /* The character cell size in scan lines is stored at 40:85 in the
765 BIOS data area. */
766 max_line = _farpeekw (_dos_ds, 0x485) - 1;
767 switch (max_line)
768 {
769 default: /* this relies on CGA cursor emulation being ON! */
770 case 7:
771 bot_line = 7;
772 break;
773 case 9:
774 bot_line = 9;
775 break;
776 case 13:
777 bot_line = 12;
778 break;
779 case 15:
780 bot_line = 14;
781 break;
782 }
783
784 if (width < 0)
785 {
786 if (width == BOX_CURSOR_WIDTH)
787 {
788 top_line = 0;
789 bot_line = max_line;
790 }
791 else if (start_line != DEFAULT_CURSOR_START)
792 {
793 top_line = start_line;
794 bot_line = top_line - width - 1;
795 }
796 else if (width != DEFAULT_CURSOR_WIDTH)
797 {
798 top_line = 0;
799 bot_line = -1 - width;
800 }
801 else
802 top_line = bot_line + 1;
803 }
804 else if (width == 0)
805 {
806 /* [31, 0] seems to DTRT for all screen sizes. */
807 top_line = 31;
808 bot_line = 0;
809 }
810 else /* WIDTH is positive */
811 {
812 if (start_line != DEFAULT_CURSOR_START)
813 bot_line = start_line;
814 top_line = bot_line - (width - 1);
815 }
816
817 /* If the current cursor shape is already what they want, we are
818 history here. */
819 desired_cursor = ((top_line & 0x1f) << 8) | (bot_line & 0x1f);
820 if (desired_cursor == _farpeekw (_dos_ds, 0x460))
821 return;
822
823 regs.h.ah = 1;
824 regs.x.cx = desired_cursor;
825 __dpmi_int (0x10, &regs);
826#endif /* __DJGPP__ > 1 */
827}
828
829static void
830IT_set_cursor_type (struct frame *f, Lisp_Object cursor_type)
831{
832 if (EQ (cursor_type, Qbar) || EQ (cursor_type, Qhbar))
833 {
834 /* Just BAR means the normal EGA/VGA cursor. */
835 msdos_set_cursor_shape (f, DEFAULT_CURSOR_START, DEFAULT_CURSOR_WIDTH);
836 }
837 else if (CONSP (cursor_type)
838 && (EQ (XCAR (cursor_type), Qbar)
839 || EQ (XCAR (cursor_type), Qhbar)))
840 {
841 Lisp_Object bar_parms = XCDR (cursor_type);
842 int width;
843
844 if (INTEGERP (bar_parms))
845 {
846 /* Feature: negative WIDTH means cursor at the top
847 of the character cell, zero means invisible cursor. */
848 width = XINT (bar_parms);
849 msdos_set_cursor_shape (f, width >= 0 ? DEFAULT_CURSOR_START : 0,
850 width);
851 }
852 else if (CONSP (bar_parms)
853 && INTEGERP (XCAR (bar_parms))
854 && INTEGERP (XCDR (bar_parms)))
855 {
856 int start_line = XINT (XCDR (bar_parms));
857
858 width = XINT (XCAR (bar_parms));
859 msdos_set_cursor_shape (f, start_line, width);
860 }
861 }
862 else
863 {
864 /* Treat anything unknown as "box cursor". This includes nil, so
865 that a frame which doesn't specify a cursor type gets a box,
866 which is the default in Emacs. */
867 msdos_set_cursor_shape (f, 0, BOX_CURSOR_WIDTH);
868 }
869}
870
871static void
872IT_ring_bell (struct frame *f)
873{
874 if (visible_bell)
875 {
876 mouse_off ();
877 ScreenVisualBell ();
878 }
879 else
880 {
881 union REGS inregs, outregs;
882 inregs.h.ah = 2;
883 inregs.h.dl = 7;
884 intdos (&inregs, &outregs);
885 }
886}
887
888/* Given a face id FACE, extract the face parameters to be used for
889 display until the face changes. The face parameters (actually, its
890 color) are used to construct the video attribute byte for each
891 glyph during the construction of the buffer that is then blitted to
892 the video RAM. */
893static void
894IT_set_face (int face)
895{
896 struct frame *sf = SELECTED_FRAME();
897 struct face *fp = FACE_FROM_ID (sf, face);
898 struct face *dfp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
899 unsigned long fg, bg, dflt_fg, dflt_bg;
900 struct tty_display_info *tty = FRAME_TTY (sf);
901
902 if (!fp)
903 {
904 fp = dfp;
905 /* The default face for the frame should always be realized and
906 cached. */
907 if (!fp)
908 abort ();
909 }
910 screen_face = face;
911 fg = fp->foreground;
912 bg = fp->background;
913 dflt_fg = dfp->foreground;
914 dflt_bg = dfp->background;
915
916 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
917 mean use the colors of the default face. Note that we assume all
918 16 colors to be available for the background, since Emacs switches
919 on this mode (and loses the blinking attribute) at startup. */
920 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
921 fg = FRAME_FOREGROUND_PIXEL (sf);
922 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
923 fg = FRAME_BACKGROUND_PIXEL (sf);
924 if (bg == FACE_TTY_DEFAULT_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR)
925 bg = FRAME_BACKGROUND_PIXEL (sf);
926 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
927 bg = FRAME_FOREGROUND_PIXEL (sf);
928
929 /* Make sure highlighted lines really stand out, come what may. */
930 if (fp->tty_reverse_p && (fg == dflt_fg && bg == dflt_bg))
931 {
932 unsigned long tem = fg;
933
934 fg = bg;
935 bg = tem;
936 }
937 /* If the user requested inverse video, obey. */
938 if (inverse_video)
939 {
940 unsigned long tem2 = fg;
941
942 fg = bg;
943 bg = tem2;
944 }
945 if (tty->termscript)
946 fprintf (tty->termscript, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face,
947 fp->foreground, fp->background, fg, bg);
948 if (fg >= 0 && fg < 16)
949 {
950 ScreenAttrib &= 0xf0;
951 ScreenAttrib |= fg;
952 }
953 if (bg >= 0 && bg < 16)
954 {
955 ScreenAttrib &= 0x0f;
956 ScreenAttrib |= ((bg & 0x0f) << 4);
957 }
958}
959
960Lisp_Object Vdos_unsupported_char_glyph;
961extern unsigned char *encode_terminal_code (struct glyph *, int,
962 struct coding_system *);
963static void
964IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
965{
966 unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
967 int unsupported_face = 0;
968 unsigned unsupported_char = '\177';
969 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
970 register int sl = str_len;
971 register int tlen = GLYPH_TABLE_LENGTH;
972 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
973 struct tty_display_info *tty = FRAME_TTY (f);
974 struct frame *sf;
975 unsigned char *conversion_buffer;
976
977 /* Do we need to consider conversion of unibyte characters to
978 multibyte? */
979 int convert_unibyte_characters
980 = (NILP (current_buffer->enable_multibyte_characters)
981 && unibyte_display_via_language_environment);
982
983 /* If terminal_coding does any conversion, use it, otherwise use
984 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
985 because it always returns 1 if terminal_coding.src_multibyte is 1. */
986 struct coding_system *coding = FRAME_TERMINAL_CODING (f);
987
988 if (!(coding->common_flags & CODING_REQUIRE_ENCODING_MASK))
989 coding = &safe_terminal_coding;
990
991 if (str_len <= 0) return;
992
993 screen_buf = screen_bp = alloca (str_len * 2);
994 screen_buf_end = screen_buf + str_len * 2;
995 sf = SELECTED_FRAME();
996
997 /* Since faces get cached and uncached behind our back, we can't
998 rely on their indices in the cache being consistent across
999 invocations. So always reset the screen face to the default
1000 face of the frame, before writing glyphs, and let the glyphs
1001 set the right face if it's different from the default. */
1002 IT_set_face (DEFAULT_FACE_ID);
1003
1004 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
1005 the tail. */
1006 coding->mode &= ~CODING_MODE_LAST_BLOCK;
1007 while (sl > 0)
1008 {
1009 int cf;
1010
1011 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
1012 only for the redisplay code to know how many columns does
1013 this character occupy on the screen. Skip padding glyphs. */
1014 if (CHAR_GLYPH_PADDING_P (*str))
1015 {
1016 str++;
1017 sl--;
1018 }
1019 else
1020 {
1021 /* If the face of this glyph is different from the current
1022 screen face, update the screen attribute byte. */
1023 cf = str->face_id;
1024 if (cf != screen_face)
1025 IT_set_face (cf); /* handles invalid faces gracefully */
1026
1027 if (sl <= 1)
1028 /* This is the last glyph. */
1029 coding->mode |= CODING_MODE_LAST_BLOCK;
1030
1031 conversion_buffer = encode_terminal_code (str, 1, coding);
1032 if (coding->produced > 0)
1033 {
1034 if (2*coding->produced > screen_buf_end - screen_bp)
1035 {
1036 /* The allocated buffer for screen writes is too small.
1037 Flush it and loop again without incrementing STR, so
1038 that the next loop will begin with the same glyph. */
1039 int nbytes = screen_bp - screen_buf;
1040
1041 mouse_off_maybe ();
1042 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
1043 if (screen_virtual_segment)
1044 dosv_refresh_virtual_screen (offset, nbytes / 2);
1045 new_pos_X += nbytes / 2;
1046 offset += nbytes;
1047
1048 /* Prepare to reuse the same buffer again. */
1049 screen_bp = screen_buf;
1050 continue;
1051 }
1052 else
1053 {
1054 /* There's enough place in the allocated buffer to add
1055 the encoding of this glyph. */
1056
1057 /* Copy the encoded bytes to the allocated buffer. */
1058 for (bp = conversion_buffer; coding->produced--; bp++)
1059 {
1060 *screen_bp++ = (unsigned char)*bp;
1061 *screen_bp++ = ScreenAttrib;
1062 if (tty->termscript)
1063 fputc (*bp, tty->termscript);
1064 }
1065 }
1066 }
1067 /* Update STR and its remaining length. */
1068 str++;
1069 sl--;
1070 }
1071 }
1072
1073 /* Dump whatever is left in the screen buffer. */
1074 mouse_off_maybe ();
1075 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
1076 if (screen_virtual_segment)
1077 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
1078 new_pos_X += (screen_bp - screen_buf) / 2;
1079}
1080
1081/************************************************************************
1082 Mouse Highlight (and friends..)
1083 ************************************************************************/
1084
1085/* Last window where we saw the mouse. Used by mouse-autoselect-window. */
1086static Lisp_Object last_mouse_window;
1087
1088static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
1089
1090/* Set the mouse pointer shape according to whether it is in the
1091 area where the mouse highlight is in effect. */
1092static void
1093IT_set_mouse_pointer (int mode)
1094{
1095 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1096 many possibilities to change its shape, and the available
1097 functionality pretty much sucks (e.g., almost every reasonable
1098 shape will conceal the character it is on). Since the color of
1099 the pointer changes in the highlighted area, it is not clear to
1100 me whether anything else is required, anyway. */
1101}
1102
1103/* Display the active region described by mouse_face_*
1104 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1105static void
1106show_mouse_face (struct tty_display_info *dpyinfo, int hl)
1107{
1108 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
1109 struct frame *f = XFRAME (WINDOW_FRAME (w));
1110 int i;
1111 struct face *fp;
1112 struct tty_display_info *tty = FRAME_TTY (f);
1113
1114
1115 /* If window is in the process of being destroyed, don't bother
1116 doing anything. */
1117 if (w->current_matrix == NULL)
1118 goto set_cursor_shape;
1119
1120 /* Recognize when we are called to operate on rows that don't exist
1121 anymore. This can happen when a window is split. */
1122 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
1123 goto set_cursor_shape;
1124
1125 /* There's no sense to do anything if the mouse face isn't realized. */
1126 if (hl > 0)
1127 {
1128 if (dpyinfo->mouse_face_hidden)
1129 goto set_cursor_shape;
1130
1131 fp = FACE_FROM_ID (SELECTED_FRAME(), dpyinfo->mouse_face_face_id);
1132 if (!fp)
1133 goto set_cursor_shape;
1134 }
1135
1136 /* Note that mouse_face_beg_row etc. are window relative. */
1137 for (i = dpyinfo->mouse_face_beg_row;
1138 i <= dpyinfo->mouse_face_end_row;
1139 i++)
1140 {
1141 int start_hpos, end_hpos;
1142 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
1143
1144 /* Don't do anything if row doesn't have valid contents. */
1145 if (!row->enabled_p)
1146 continue;
1147
1148 /* For all but the first row, the highlight starts at column 0. */
1149 if (i == dpyinfo->mouse_face_beg_row)
1150 start_hpos = dpyinfo->mouse_face_beg_col;
1151 else
1152 start_hpos = 0;
1153
1154 if (i == dpyinfo->mouse_face_end_row)
1155 end_hpos = dpyinfo->mouse_face_end_col;
1156 else
1157 end_hpos = row->used[TEXT_AREA];
1158
1159 if (end_hpos <= start_hpos)
1160 continue;
1161 /* Record that some glyphs of this row are displayed in
1162 mouse-face. */
1163 row->mouse_face_p = hl > 0;
1164 if (hl > 0)
1165 {
1166 int vpos = row->y + WINDOW_TOP_EDGE_Y (w);
1167 int kstart = start_hpos + WINDOW_LEFT_EDGE_X (w);
1168 int nglyphs = end_hpos - start_hpos;
1169 int offset = ScreenPrimary + 2*(vpos*screen_size_X + kstart) + 1;
1170 int start_offset = offset;
1171
1172 if (tty->termscript)
1173 fprintf (tty->termscript, "\n<MH+ %d-%d:%d>",
1174 kstart, kstart + nglyphs - 1, vpos);
1175
1176 mouse_off ();
1177 IT_set_face (dpyinfo->mouse_face_face_id);
1178 /* Since we are going to change only the _colors_ of the
1179 displayed text, there's no need to go through all the
1180 pain of generating and encoding the text from the glyphs.
1181 Instead, we simply poke the attribute byte of each
1182 affected position in video memory with the colors
1183 computed by IT_set_face! */
1184 _farsetsel (_dos_ds);
1185 while (nglyphs--)
1186 {
1187 _farnspokeb (offset, ScreenAttrib);
1188 offset += 2;
1189 }
1190 if (screen_virtual_segment)
1191 dosv_refresh_virtual_screen (start_offset, end_hpos - start_hpos);
1192 mouse_on ();
1193 }
1194 else
1195 {
1196 /* We are removing a previously-drawn mouse highlight. The
1197 safest way to do so is to redraw the glyphs anew, since
1198 all kinds of faces and display tables could have changed
1199 behind our back. */
1200 int nglyphs = end_hpos - start_hpos;
1201 int save_x = new_pos_X, save_y = new_pos_Y;
1202
1203 if (end_hpos >= row->used[TEXT_AREA])
1204 nglyphs = row->used[TEXT_AREA] - start_hpos;
1205
1206 /* IT_write_glyphs writes at cursor position, so we need to
1207 temporarily move cursor coordinates to the beginning of
1208 the highlight region. */
1209 new_pos_X = start_hpos + WINDOW_LEFT_EDGE_X (w);
1210 new_pos_Y = row->y + WINDOW_TOP_EDGE_Y (w);
1211
1212 if (tty->termscript)
1213 fprintf (tty->termscript, "<MH- %d-%d:%d>",
1214 new_pos_X, new_pos_X + nglyphs - 1, new_pos_Y);
1215 IT_write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
1216 if (tty->termscript)
1217 fputs ("\n", tty->termscript);
1218 new_pos_X = save_x;
1219 new_pos_Y = save_y;
1220 }
1221 }
1222
1223 set_cursor_shape:
1224 /* Change the mouse pointer shape. */
1225 IT_set_mouse_pointer (hl);
1226}
1227
1228/* Clear out the mouse-highlighted active region.
1229 Redraw it un-highlighted first. */
1230static void
1231clear_mouse_face (struct tty_display_info *dpyinfo)
1232{
1233 if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window))
1234 show_mouse_face (dpyinfo, 0);
1235
1236 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1237 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1238 dpyinfo->mouse_face_window = Qnil;
1239}
1240
1241/* Find the glyph matrix position of buffer position POS in window W.
1242 *HPOS and *VPOS are set to the positions found. W's current glyphs
1243 must be up to date. If POS is above window start return (0, 0).
1244 If POS is after end of W, return end of last line in W. */
1245static int
1246fast_find_position (struct window *w, int pos, int *hpos, int *vpos)
1247{
1248 int i, lastcol, line_start_position, maybe_next_line_p = 0;
1249 int yb = window_text_bottom_y (w);
1250 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row;
1251
1252 while (row->y < yb)
1253 {
1254 if (row->used[TEXT_AREA])
1255 line_start_position = row->glyphs[TEXT_AREA]->charpos;
1256 else
1257 line_start_position = 0;
1258
1259 if (line_start_position > pos)
1260 break;
1261 /* If the position sought is the end of the buffer,
1262 don't include the blank lines at the bottom of the window. */
1263 else if (line_start_position == pos
1264 && pos == BUF_ZV (XBUFFER (w->buffer)))
1265 {
1266 maybe_next_line_p = 1;
1267 break;
1268 }
1269 else if (line_start_position > 0)
1270 best_row = row;
1271
1272 /* Don't overstep the last matrix row, lest we get into the
1273 never-never land... */
1274 if (row->y + 1 >= yb)
1275 break;
1276
1277 ++row;
1278 }
1279
1280 /* Find the right column within BEST_ROW. */
1281 lastcol = 0;
1282 row = best_row;
1283 for (i = 0; i < row->used[TEXT_AREA]; i++)
1284 {
1285 struct glyph *glyph = row->glyphs[TEXT_AREA] + i;
1286 int charpos;
1287
1288 charpos = glyph->charpos;
1289 if (charpos == pos)
1290 {
1291 *hpos = i;
1292 *vpos = row->y;
1293 return 1;
1294 }
1295 else if (charpos > pos)
1296 break;
1297 else if (charpos > 0)
1298 lastcol = i;
1299 }
1300
1301 /* If we're looking for the end of the buffer,
1302 and we didn't find it in the line we scanned,
1303 use the start of the following line. */
1304 if (maybe_next_line_p)
1305 {
1306 ++row;
1307 lastcol = 0;
1308 }
1309
1310 *vpos = row->y;
1311 *hpos = lastcol + 1;
1312 return 0;
1313}
1314
1315/* Take proper action when mouse has moved to the mode or top line of
1316 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1317 mode line. X is relative to the start of the text display area of
1318 W, so the width of fringes and scroll bars must be subtracted
1319 to get a position relative to the start of the mode line. */
1320static void
1321IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p)
1322{
1323 struct frame *f = XFRAME (w->frame);
1324 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1325 struct glyph_row *row;
1326
1327 if (mode_line_p)
1328 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
1329 else
1330 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
1331
1332 if (row->enabled_p)
1333 {
1334 extern Lisp_Object Qhelp_echo;
1335 struct glyph *glyph, *end;
1336 Lisp_Object help, map;
1337
1338 /* Find the glyph under X. */
1339 glyph = (row->glyphs[TEXT_AREA]
1340 + x
1341 /* in case someone implements scroll bars some day... */
1342 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w));
1343 end = glyph + row->used[TEXT_AREA];
1344 if (glyph < end
1345 && STRINGP (glyph->object)
1346 && STRING_INTERVALS (glyph->object)
1347 && glyph->charpos >= 0
1348 && glyph->charpos < SCHARS (glyph->object))
1349 {
1350 /* If we're on a string with `help-echo' text property,
1351 arrange for the help to be displayed. This is done by
1352 setting the global variable help_echo to the help string. */
1353 help = Fget_text_property (make_number (glyph->charpos),
1354 Qhelp_echo, glyph->object);
1355 if (!NILP (help))
1356 {
1357 help_echo_string = help;
1358 XSETWINDOW (help_echo_window, w);
1359 help_echo_object = glyph->object;
1360 help_echo_pos = glyph->charpos;
1361 }
1362 }
1363 }
1364}
1365
1366/* Take proper action when the mouse has moved to position X, Y on
1367 frame F as regards highlighting characters that have mouse-face
1368 properties. Also de-highlighting chars where the mouse was before.
1369 X and Y can be negative or out of range. */
1370static void
1371IT_note_mouse_highlight (struct frame *f, int x, int y)
1372{
1373 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1374 enum window_part part = ON_NOTHING;
1375 Lisp_Object window;
1376 struct window *w;
1377
1378 /* When a menu is active, don't highlight because this looks odd. */
1379 if (mouse_preempted)
1380 return;
1381
1382 if (NILP (Vmouse_highlight)
1383 || !f->glyphs_initialized_p)
1384 return;
1385
1386 dpyinfo->mouse_face_mouse_x = x;
1387 dpyinfo->mouse_face_mouse_y = y;
1388 dpyinfo->mouse_face_mouse_frame = f;
1389
1390 if (dpyinfo->mouse_face_defer)
1391 return;
1392
1393 if (gc_in_progress)
1394 {
1395 dpyinfo->mouse_face_deferred_gc = 1;
1396 return;
1397 }
1398
1399 /* Which window is that in? */
1400 window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
1401
1402 /* If we were displaying active text in another window, clear that. */
1403 if (! EQ (window, dpyinfo->mouse_face_window))
1404 clear_mouse_face (dpyinfo);
1405
1406 /* Not on a window -> return. */
1407 if (!WINDOWP (window))
1408 return;
1409
1410 /* Convert to window-relative coordinates. */
1411 w = XWINDOW (window);
1412
1413 if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
1414 {
1415 /* Mouse is on the mode or top line. */
1416 IT_note_mode_line_highlight (w, x, part == ON_MODE_LINE);
1417 return;
1418 }
1419
1420 IT_set_mouse_pointer (0);
1421
1422 /* Are we in a window whose display is up to date?
1423 And verify the buffer's text has not changed. */
1424 if (part == ON_TEXT
1425 && EQ (w->window_end_valid, w->buffer)
1426 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
1427 && (XFASTINT (w->last_overlay_modified)
1428 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
1429 {
1430 int pos, i, nrows = w->current_matrix->nrows;
1431 struct glyph_row *row;
1432 struct glyph *glyph;
1433
1434 /* Find the glyph under X/Y. */
1435 glyph = NULL;
1436 if (y >= 0 && y < nrows)
1437 {
1438 row = MATRIX_ROW (w->current_matrix, y);
1439 /* Give up if some row before the one we are looking for is
1440 not enabled. */
1441 for (i = 0; i <= y; i++)
1442 if (!MATRIX_ROW (w->current_matrix, i)->enabled_p)
1443 break;
1444 if (i > y /* all rows upto and including the one at Y are enabled */
1445 && row->displays_text_p
1446 && x < window_box_width (w, TEXT_AREA))
1447 {
1448 glyph = row->glyphs[TEXT_AREA];
1449 if (x >= row->used[TEXT_AREA])
1450 glyph = NULL;
1451 else
1452 {
1453 glyph += x;
1454 if (!BUFFERP (glyph->object))
1455 glyph = NULL;
1456 }
1457 }
1458 }
1459
1460 /* Clear mouse face if X/Y not over text. */
1461 if (glyph == NULL)
1462 {
1463 clear_mouse_face (dpyinfo);
1464 return;
1465 }
1466
1467 if (!BUFFERP (glyph->object))
1468 abort ();
1469 pos = glyph->charpos;
1470
1471 /* Check for mouse-face and help-echo. */
1472 {
1473 extern Lisp_Object Qmouse_face;
1474 Lisp_Object mouse_face, overlay, position, *overlay_vec;
1475 int noverlays, obegv, ozv;
1476 struct buffer *obuf;
1477
1478 /* If we get an out-of-range value, return now; avoid an error. */
1479 if (pos > BUF_Z (XBUFFER (w->buffer)))
1480 return;
1481
1482 /* Make the window's buffer temporarily current for
1483 overlays_at and compute_char_face. */
1484 obuf = current_buffer;
1485 current_buffer = XBUFFER (w->buffer);
1486 obegv = BEGV;
1487 ozv = ZV;
1488 BEGV = BEG;
1489 ZV = Z;
1490
1491 /* Is this char mouse-active or does it have help-echo? */
1492 XSETINT (position, pos);
1493
1494 /* Put all the overlays we want in a vector in overlay_vec. */
1495 GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
1496 /* Sort overlays into increasing priority order. */
1497 noverlays = sort_overlays (overlay_vec, noverlays, w);
1498
1499 /* Check mouse-face highlighting. */
1500 if (! (EQ (window, dpyinfo->mouse_face_window)
1501 && y >= dpyinfo->mouse_face_beg_row
1502 && y <= dpyinfo->mouse_face_end_row
1503 && (y > dpyinfo->mouse_face_beg_row
1504 || x >= dpyinfo->mouse_face_beg_col)
1505 && (y < dpyinfo->mouse_face_end_row
1506 || x < dpyinfo->mouse_face_end_col
1507 || dpyinfo->mouse_face_past_end)))
1508 {
1509 /* Clear the display of the old active region, if any. */
1510 clear_mouse_face (dpyinfo);
1511
1512 /* Find highest priority overlay that has a mouse-face prop. */
1513 overlay = Qnil;
1514 for (i = noverlays - 1; i >= 0; --i)
1515 {
1516 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1517 if (!NILP (mouse_face))
1518 {
1519 overlay = overlay_vec[i];
1520 break;
1521 }
1522 }
1523
1524 /* If no overlay applies, get a text property. */
1525 if (NILP (overlay))
1526 mouse_face = Fget_text_property (position, Qmouse_face,
1527 w->buffer);
1528
1529 /* Handle the overlay case. */
1530 if (! NILP (overlay))
1531 {
1532 /* Find the range of text around this char that
1533 should be active. */
1534 Lisp_Object before, after;
1535 EMACS_INT ignore;
1536
1537 before = Foverlay_start (overlay);
1538 after = Foverlay_end (overlay);
1539 /* Record this as the current active region. */
1540 fast_find_position (w, XFASTINT (before),
1541 &dpyinfo->mouse_face_beg_col,
1542 &dpyinfo->mouse_face_beg_row);
1543 dpyinfo->mouse_face_past_end
1544 = !fast_find_position (w, XFASTINT (after),
1545 &dpyinfo->mouse_face_end_col,
1546 &dpyinfo->mouse_face_end_row);
1547 dpyinfo->mouse_face_window = window;
1548 dpyinfo->mouse_face_face_id
1549 = face_at_buffer_position (w, pos, 0, 0,
1550 &ignore, pos + 1,
1551 !dpyinfo->mouse_face_hidden);
1552
1553 /* Display it as active. */
1554 show_mouse_face (dpyinfo, 1);
1555 }
1556 /* Handle the text property case. */
1557 else if (! NILP (mouse_face))
1558 {
1559 /* Find the range of text around this char that
1560 should be active. */
1561 Lisp_Object before, after, beginning, end;
1562 EMACS_INT ignore;
1563
1564 beginning = Fmarker_position (w->start);
1565 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1566 - XFASTINT (w->window_end_pos)));
1567 before
1568 = Fprevious_single_property_change (make_number (pos + 1),
1569 Qmouse_face,
1570 w->buffer, beginning);
1571 after
1572 = Fnext_single_property_change (position, Qmouse_face,
1573 w->buffer, end);
1574 /* Record this as the current active region. */
1575 fast_find_position (w, XFASTINT (before),
1576 &dpyinfo->mouse_face_beg_col,
1577 &dpyinfo->mouse_face_beg_row);
1578 dpyinfo->mouse_face_past_end
1579 = !fast_find_position (w, XFASTINT (after),
1580 &dpyinfo->mouse_face_end_col,
1581 &dpyinfo->mouse_face_end_row);
1582 dpyinfo->mouse_face_window = window;
1583 dpyinfo->mouse_face_face_id
1584 = face_at_buffer_position (w, pos, 0, 0,
1585 &ignore, pos + 1,
1586 !dpyinfo->mouse_face_hidden);
1587
1588 /* Display it as active. */
1589 show_mouse_face (dpyinfo, 1);
1590 }
1591 }
1592
1593 /* Look for a `help-echo' property. */
1594 {
1595 Lisp_Object help;
1596 extern Lisp_Object Qhelp_echo;
1597
1598 /* Check overlays first. */
1599 help = Qnil;
1600 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
1601 {
1602 overlay = overlay_vec[i];
1603 help = Foverlay_get (overlay, Qhelp_echo);
1604 }
1605
1606 if (!NILP (help))
1607 {
1608 help_echo_string = help;
1609 help_echo_window = window;
1610 help_echo_object = overlay;
1611 help_echo_pos = pos;
1612 }
1613 /* Try text properties. */
1614 else if (NILP (help)
1615 && ((STRINGP (glyph->object)
1616 && glyph->charpos >= 0
1617 && glyph->charpos < SCHARS (glyph->object))
1618 || (BUFFERP (glyph->object)
1619 && glyph->charpos >= BEGV
1620 && glyph->charpos < ZV)))
1621 {
1622 help = Fget_text_property (make_number (glyph->charpos),
1623 Qhelp_echo, glyph->object);
1624 if (!NILP (help))
1625 {
1626 help_echo_string = help;
1627 help_echo_window = window;
1628 help_echo_object = glyph->object;
1629 help_echo_pos = glyph->charpos;
1630 }
1631 }
1632 }
1633
1634 BEGV = obegv;
1635 ZV = ozv;
1636 current_buffer = obuf;
1637 }
1638 }
1639}
1640
1641static void
1642IT_clear_end_of_line (struct frame *f, int first_unused)
1643{
1644 char *spaces, *sp;
1645 int i, j, offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
1646 extern int fatal_error_in_progress;
1647 struct tty_display_info *tty = FRAME_TTY (f);
1648
1649 if (new_pos_X >= first_unused || fatal_error_in_progress)
1650 return;
1651
1652 IT_set_face (0);
1653 i = (j = first_unused - new_pos_X) * 2;
1654 if (tty->termscript)
1655 fprintf (tty->termscript, "<CLR:EOL[%d..%d)>", new_pos_X, first_unused);
1656 spaces = sp = alloca (i);
1657
1658 while (--j >= 0)
1659 {
1660 *sp++ = ' ';
1661 *sp++ = ScreenAttrib;
1662 }
1663
1664 mouse_off_maybe ();
1665 dosmemput (spaces, i, (int)ScreenPrimary + offset);
1666 if (screen_virtual_segment)
1667 dosv_refresh_virtual_screen (offset, i / 2);
1668
1669 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1670 Let's follow their lead, in case someone relies on this. */
1671 new_pos_X = first_unused;
1672}
1673
1674static void
1675IT_clear_screen (struct frame *f)
1676{
1677 struct tty_display_info *tty = FRAME_TTY (f);
1678
1679 if (tty->termscript)
1680 fprintf (tty->termscript, "<CLR:SCR>");
1681 /* We are sometimes called (from clear_garbaged_frames) when a new
1682 frame is being created, but its faces are not yet realized. In
1683 such a case we cannot call IT_set_face, since it will fail to find
1684 any valid faces and will abort. Instead, use the initial screen
1685 colors; that should mimic what a Unix tty does, which simply clears
1686 the screen with whatever default colors are in use. */
1687 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID) == NULL)
1688 ScreenAttrib = (initial_screen_colors[0] << 4) | initial_screen_colors[1];
1689 else
1690 IT_set_face (0);
1691 mouse_off ();
1692 ScreenClear ();
1693 if (screen_virtual_segment)
1694 dosv_refresh_virtual_screen (0, screen_size);
1695 new_pos_X = new_pos_Y = 0;
1696}
1697
1698static void
1699IT_clear_to_end (struct frame *f)
1700{
1701 struct tty_display_info *tty = FRAME_TTY (f);
1702
1703 if (tty->termscript)
1704 fprintf (tty->termscript, "<CLR:EOS>");
1705
1706 while (new_pos_Y < screen_size_Y) {
1707 new_pos_X = 0;
1708 IT_clear_end_of_line (f, screen_size_X);
1709 new_pos_Y++;
1710 }
1711}
1712
1713static void
1714IT_cursor_to (struct frame *f, int y, int x)
1715{
1716 struct tty_display_info *tty = FRAME_TTY (f);
1717
1718 if (tty->termscript)
1719 fprintf (tty->termscript, "\n<XY=%dx%d>", x, y);
1720 new_pos_X = x;
1721 new_pos_Y = y;
1722}
1723
1724static int cursor_cleared;
1725
1726static void
1727IT_display_cursor (int on)
1728{
1729 struct tty_display_info *tty = CURTTY ();
1730
1731 if (on && cursor_cleared)
1732 {
1733 ScreenSetCursor (current_pos_Y, current_pos_X);
1734 cursor_cleared = 0;
1735 if (tty->termscript)
1736 fprintf (tty->termscript, "\nCURSOR ON");
1737 }
1738 else if (!on && !cursor_cleared)
1739 {
1740 ScreenSetCursor (-1, -1);
1741 cursor_cleared = 1;
1742 if (tty->termscript)
1743 fprintf (tty->termscript, "\nCURSOR OFF");
1744 }
1745}
1746
1747/* Emacs calls cursor-movement functions a lot when it updates the
1748 display (probably a legacy of old terminals where you cannot
1749 update a screen line without first moving the cursor there).
1750 However, cursor movement is expensive on MSDOS (it calls a slow
1751 BIOS function and requires 2 mode switches), while actual screen
1752 updates access the video memory directly and don't depend on
1753 cursor position. To avoid slowing down the redisplay, we cheat:
1754 all functions that move the cursor only set internal variables
1755 which record the cursor position, whereas the cursor is only
1756 moved to its final position whenever screen update is complete.
1757
1758 `IT_cmgoto' is called from the keyboard reading loop and when the
1759 frame update is complete. This means that we are ready for user
1760 input, so we update the cursor position to show where the point is,
1761 and also make the mouse pointer visible.
1762
1763 Special treatment is required when the cursor is in the echo area,
1764 to put the cursor at the end of the text displayed there. */
1765
1766static void
1767IT_cmgoto (FRAME_PTR f)
1768{
1769 /* Only set the cursor to where it should be if the display is
1770 already in sync with the window contents. */
1771 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1772 struct tty_display_info *tty = FRAME_TTY (f);
1773
1774 /* FIXME: This needs to be rewritten for the new redisplay, or
1775 removed. */
1776#if 0
1777 static int previous_pos_X = -1;
1778
1779 update_cursor_pos = 1; /* temporary!!! */
1780
1781 /* If the display is in sync, forget any previous knowledge about
1782 cursor position. This is primarily for unexpected events like
1783 C-g in the minibuffer. */
1784 if (update_cursor_pos && previous_pos_X >= 0)
1785 previous_pos_X = -1;
1786 /* If we are in the echo area, put the cursor at the
1787 end of the echo area message. */
1788 if (!update_cursor_pos
1789 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))) <= new_pos_Y)
1790 {
1791 int tem_X = current_pos_X, dummy;
1792
1793 if (echo_area_glyphs)
1794 {
1795 tem_X = echo_area_glyphs_length;
1796 /* Save current cursor position, to be restored after the
1797 echo area message is erased. Only remember one level
1798 of previous cursor position. */
1799 if (previous_pos_X == -1)
1800 ScreenGetCursor (&dummy, &previous_pos_X);
1801 }
1802 else if (previous_pos_X >= 0)
1803 {
1804 /* We wind up here after the echo area message is erased.
1805 Restore the cursor position we remembered above. */
1806 tem_X = previous_pos_X;
1807 previous_pos_X = -1;
1808 }
1809
1810 if (current_pos_X != tem_X)
1811 {
1812 new_pos_X = tem_X;
1813 update_cursor_pos = 1;
1814 }
1815 }
1816#endif
1817
1818 if (update_cursor_pos
1819 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1820 {
1821 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1822 if (tty->termscript)
1823 fprintf (tty->termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1824 }
1825
1826 /* Maybe cursor is invisible, so make it visible. */
1827 IT_display_cursor (1);
1828
1829 /* Mouse pointer should be always visible if we are waiting for
1830 keyboard input. */
1831 if (!mouse_visible)
1832 mouse_on ();
1833}
1834
1835static void
1836IT_update_begin (struct frame *f)
1837{
1838 struct tty_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
1839 struct frame *mouse_face_frame = display_info->mouse_face_mouse_frame;
1840
1841 if (display_info->termscript)
1842 fprintf (display_info->termscript, "\n\n<UPDATE_BEGIN");
1843
1844 BLOCK_INPUT;
1845
1846 if (f && f == mouse_face_frame)
1847 {
1848 /* Don't do highlighting for mouse motion during the update. */
1849 display_info->mouse_face_defer = 1;
1850
1851 /* If F needs to be redrawn, simply forget about any prior mouse
1852 highlighting. */
1853 if (FRAME_GARBAGED_P (f))
1854 display_info->mouse_face_window = Qnil;
1855
1856 /* Can we tell that this update does not affect the window
1857 where the mouse highlight is? If so, no need to turn off.
1858 Likewise, don't do anything if none of the enabled rows
1859 contains glyphs highlighted in mouse face. */
1860 if (!NILP (display_info->mouse_face_window)
1861 && WINDOWP (display_info->mouse_face_window))
1862 {
1863 struct window *w = XWINDOW (display_info->mouse_face_window);
1864 int i;
1865
1866 /* If the mouse highlight is in the window that was deleted
1867 (e.g., if it was popped by completion), clear highlight
1868 unconditionally. */
1869 if (NILP (w->buffer))
1870 display_info->mouse_face_window = Qnil;
1871 else
1872 {
1873 for (i = 0; i < w->desired_matrix->nrows; ++i)
1874 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)
1875 && MATRIX_ROW (w->current_matrix, i)->mouse_face_p)
1876 break;
1877 }
1878
1879 if (NILP (w->buffer) || i < w->desired_matrix->nrows)
1880 clear_mouse_face (display_info);
1881 }
1882 }
1883 else if (mouse_face_frame && !FRAME_LIVE_P (mouse_face_frame))
1884 {
1885 /* If the frame with mouse highlight was deleted, invalidate the
1886 highlight info. */
1887 display_info->mouse_face_beg_row = display_info->mouse_face_beg_col = -1;
1888 display_info->mouse_face_end_row = display_info->mouse_face_end_col = -1;
1889 display_info->mouse_face_window = Qnil;
1890 display_info->mouse_face_deferred_gc = 0;
1891 display_info->mouse_face_mouse_frame = NULL;
1892 }
1893
1894 UNBLOCK_INPUT;
1895}
1896
1897static void
1898IT_update_end (struct frame *f)
1899{
1900 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1901
1902 if (dpyinfo->termscript)
1903 fprintf (dpyinfo->termscript, "\n<UPDATE_END\n");
1904 dpyinfo->mouse_face_defer = 0;
1905}
1906
1907static void
1908IT_frame_up_to_date (struct frame *f)
1909{
1910 struct tty_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1911 Lisp_Object new_cursor, frame_desired_cursor;
1912 struct window *sw;
1913
1914 if (dpyinfo->mouse_face_deferred_gc
1915 || (f && f == dpyinfo->mouse_face_mouse_frame))
1916 {
1917 BLOCK_INPUT;
1918 if (dpyinfo->mouse_face_mouse_frame)
1919 IT_note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1920 dpyinfo->mouse_face_mouse_x,
1921 dpyinfo->mouse_face_mouse_y);
1922 dpyinfo->mouse_face_deferred_gc = 0;
1923 UNBLOCK_INPUT;
1924 }
1925
1926 /* Set the cursor type to whatever they wanted. In a minibuffer
1927 window, we want the cursor to appear only if we are reading input
1928 from this window, and we want the cursor to be taken from the
1929 frame parameters. For the selected window, we use either its
1930 buffer-local value or the value from the frame parameters if the
1931 buffer doesn't define its local value for the cursor type. */
1932 sw = XWINDOW (f->selected_window);
1933 frame_desired_cursor = Fcdr (Fassq (Qcursor_type, f->param_alist));
1934 if (cursor_in_echo_area
1935 && FRAME_HAS_MINIBUF_P (f)
1936 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)
1937 && sw == XWINDOW (echo_area_window))
1938 new_cursor = frame_desired_cursor;
1939 else
1940 {
1941 struct buffer *b = XBUFFER (sw->buffer);
1942
1943 if (EQ (b->cursor_type, Qt))
1944 new_cursor = frame_desired_cursor;
1945 else if (NILP (b->cursor_type)) /* nil means no cursor */
1946 new_cursor = Fcons (Qbar, make_number (0));
1947 else
1948 new_cursor = b->cursor_type;
1949 }
1950
1951 IT_set_cursor_type (f, new_cursor);
1952
1953 IT_cmgoto (f); /* position cursor when update is done */
1954}
1955
1956/* Copy LEN glyphs displayed on a single line whose vertical position
1957 is YPOS, beginning at horizontal position XFROM to horizontal
1958 position XTO, by moving blocks in the video memory. Used by
1959 functions that insert and delete glyphs. */
1960static void
1961IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1962{
1963 /* The offsets of source and destination relative to the
1964 conventional memorty selector. */
1965 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1966 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1967
1968 if (from == to || len <= 0)
1969 return;
1970
1971 _farsetsel (_dos_ds);
1972
1973 /* The source and destination might overlap, so we need to move
1974 glyphs non-destructively. */
1975 if (from > to)
1976 {
1977 for ( ; len; from += 2, to += 2, len--)
1978 _farnspokew (to, _farnspeekw (from));
1979 }
1980 else
1981 {
1982 from += (len - 1) * 2;
1983 to += (len - 1) * 2;
1984 for ( ; len; from -= 2, to -= 2, len--)
1985 _farnspokew (to, _farnspeekw (from));
1986 }
1987 if (screen_virtual_segment)
1988 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1989}
1990
1991/* Insert and delete glyphs. */
1992static void
1993IT_insert_glyphs (f, start, len)
1994 struct frame *f;
1995 register struct glyph *start;
1996 register int len;
1997{
1998 int shift_by_width = screen_size_X - (new_pos_X + len);
1999
2000 /* Shift right the glyphs from the nominal cursor position to the
2001 end of this line. */
2002 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
2003
2004 /* Now write the glyphs to be inserted. */
2005 IT_write_glyphs (f, start, len);
2006}
2007
2008static void
2009IT_delete_glyphs (f, n)
2010 struct frame *f;
2011 register int n;
2012{
2013 abort ();
2014}
2015
2016/* set-window-configuration on window.c needs this. */
2017void
2018x_set_menu_bar_lines (f, value, oldval)
2019 struct frame *f;
2020 Lisp_Object value, oldval;
2021{
2022 set_menu_bar_lines (f, value, oldval);
2023}
2024
2025/* This was copied from xfaces.c */
2026
2027extern Lisp_Object Qbackground_color;
2028extern Lisp_Object Qforeground_color;
2029Lisp_Object Qreverse;
2030extern Lisp_Object Qtitle;
2031
2032/* IT_set_terminal_modes is called when emacs is started,
2033 resumed, and whenever the screen is redrawn! */
2034
2035static void
2036IT_set_terminal_modes (struct terminal *term)
2037{
2038 struct tty_display_info *tty;
2039
2040 /* If called with initial terminal, it's too early to do anything
2041 useful. */
2042 if (term->type == output_initial)
2043 return;
2044
2045 tty = term->display_info.tty;
2046
2047 if (tty->termscript)
2048 fprintf (tty->termscript, "\n<SET_TERM>");
2049
2050 screen_size_X = ScreenCols ();
2051 screen_size_Y = ScreenRows ();
2052 screen_size = screen_size_X * screen_size_Y;
2053
2054 new_pos_X = new_pos_Y = 0;
2055 current_pos_X = current_pos_Y = -1;
2056
2057 if (term_setup_done)
2058 return;
2059 term_setup_done = 1;
2060
2061 startup_screen_size_X = screen_size_X;
2062 startup_screen_size_Y = screen_size_Y;
2063 startup_screen_attrib = ScreenAttrib;
2064
2065#if __DJGPP__ > 1
2066 /* Is DOS/V (or any other RSIS software which relocates
2067 the screen) installed? */
2068 {
2069 unsigned short es_value;
2070 __dpmi_regs regs;
2071
2072 regs.h.ah = 0xfe; /* get relocated screen address */
2073 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
2074 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
2075 else if (screen_old_address) /* already switched to Japanese mode once */
2076 regs.x.es = (screen_old_address >> 4) & 0xffff;
2077 else
2078 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
2079 regs.x.di = 0;
2080 es_value = regs.x.es;
2081 __dpmi_int (0x10, &regs);
2082
2083 if (regs.x.es != es_value)
2084 {
2085 /* screen_old_address is only set if ScreenPrimary does NOT
2086 already point to the relocated buffer address returned by
2087 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2088 ScreenPrimary to that address at startup under DOS/V. */
2089 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
2090 screen_old_address = ScreenPrimary;
2091 screen_virtual_segment = regs.x.es;
2092 screen_virtual_offset = regs.x.di;
2093 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
2094 }
2095 }
2096#endif /* __DJGPP__ > 1 */
2097
2098 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
2099 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
2100
2101 bright_bg ();
2102}
2103
2104/* IT_reset_terminal_modes is called when emacs is
2105 suspended or killed. */
2106
2107static void
2108IT_reset_terminal_modes (struct terminal *term)
2109{
2110 int display_row_start = (int) ScreenPrimary;
2111 int saved_row_len = startup_screen_size_X * 2;
2112 int update_row_len = ScreenCols () * 2, current_rows = ScreenRows ();
2113 int to_next_row = update_row_len;
2114 unsigned char *saved_row = startup_screen_buffer;
2115 int cursor_pos_X = ScreenCols () - 1, cursor_pos_Y = ScreenRows () - 1;
2116 struct tty_display_info *tty = term->display_info.tty;
2117
2118 if (tty->termscript)
2119 fprintf (tty->termscript, "\n<RESET_TERM>");
2120
2121 if (!term_setup_done)
2122 return;
2123
2124 mouse_off ();
2125
2126 /* Leave the video system in the same state as we found it,
2127 as far as the blink/bright-background bit is concerned. */
2128 maybe_enable_blinking ();
2129
2130 /* We have a situation here.
2131 We cannot just do ScreenUpdate(startup_screen_buffer) because
2132 the luser could have changed screen dimensions inside Emacs
2133 and failed (or didn't want) to restore them before killing
2134 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2135 thus will happily use memory outside what was allocated for
2136 `startup_screen_buffer'.
2137 Thus we only restore as much as the current screen dimensions
2138 can hold, and clear the rest (if the saved screen is smaller than
2139 the current) with the color attribute saved at startup. The cursor
2140 is also restored within the visible dimensions. */
2141
2142 ScreenAttrib = startup_screen_attrib;
2143
2144 /* Don't restore the screen if we are exiting less than 2 seconds
2145 after startup: we might be crashing, and the screen might show
2146 some vital clues to what's wrong. */
2147 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
2148 {
2149 ScreenClear ();
2150 if (screen_virtual_segment)
2151 dosv_refresh_virtual_screen (0, screen_size);
2152
2153 if (update_row_len > saved_row_len)
2154 update_row_len = saved_row_len;
2155 if (current_rows > startup_screen_size_Y)
2156 current_rows = startup_screen_size_Y;
2157
2158 if (tty->termscript)
2159 fprintf (tty->termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2160 update_row_len / 2, current_rows);
2161
2162 while (current_rows--)
2163 {
2164 dosmemput (saved_row, update_row_len, display_row_start);
2165 if (screen_virtual_segment)
2166 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
2167 update_row_len / 2);
2168 saved_row += saved_row_len;
2169 display_row_start += to_next_row;
2170 }
2171 }
2172 if (startup_pos_X < cursor_pos_X)
2173 cursor_pos_X = startup_pos_X;
2174 if (startup_pos_Y < cursor_pos_Y)
2175 cursor_pos_Y = startup_pos_Y;
2176
2177 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
2178 xfree (startup_screen_buffer);
2179 startup_screen_buffer = NULL;
2180
2181 term_setup_done = 0;
2182}
2183
2184static void
2185IT_set_terminal_window (struct frame *f, int foo)
2186{
2187}
2188
2189/* Remember the screen colors of the curent frame, to serve as the
2190 default colors for newly-created frames. */
2191DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
2192 Smsdos_remember_default_colors, 1, 1, 0,
2193 doc: /* Remember the screen colors of the current frame. */)
2194 (frame)
2195 Lisp_Object frame;
2196{
2197 struct frame *f;
2198
2199 CHECK_FRAME (frame);
2200 f = XFRAME (frame);
2201
2202 /* This function is called after applying default-frame-alist to the
2203 initial frame. At that time, if reverse-colors option was
2204 specified in default-frame-alist, it was already applied, and
2205 frame colors are reversed. */
2206 initial_screen_colors[0] = FRAME_FOREGROUND_PIXEL (f);
2207 initial_screen_colors[1] = FRAME_BACKGROUND_PIXEL (f);
2208}
2209
2210void
2211IT_set_frame_parameters (f, alist)
2212 struct frame *f;
2213 Lisp_Object alist;
2214{
2215 Lisp_Object tail;
2216 int i, j, length = XINT (Flength (alist));
2217 Lisp_Object *parms
2218 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2219 Lisp_Object *values
2220 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2221 /* Do we have to reverse the foreground and background colors? */
2222 int reverse = EQ (Fcdr (Fassq (Qreverse, f->param_alist)), Qt);
2223 int need_to_reverse, was_reverse = reverse;
2224 int redraw = 0, fg_set = 0, bg_set = 0;
2225 unsigned long orig_fg, orig_bg;
2226 Lisp_Object frame_bg, frame_fg;
2227 extern Lisp_Object Qdefault, QCforeground, QCbackground;
2228 struct tty_display_info *tty = FRAME_TTY (f);
2229
2230 /* If we are creating a new frame, begin with the original screen colors
2231 used for the initial frame. */
2232 if (EQ (alist, Vdefault_frame_alist)
2233 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
2234 {
2235 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
2236 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
2237 init_frame_faces (f);
2238 }
2239 orig_fg = FRAME_FOREGROUND_PIXEL (f);
2240 orig_bg = FRAME_BACKGROUND_PIXEL (f);
2241 frame_fg = Fcdr (Fassq (Qforeground_color, f->param_alist));
2242 frame_bg = Fcdr (Fassq (Qbackground_color, f->param_alist));
2243 /* frame_fg and frame_bg could be nil if, for example,
2244 f->param_alist is nil, e.g. if we are called from
2245 Fmake_terminal_frame. */
2246 if (NILP (frame_fg))
2247 frame_fg = build_string (unspecified_fg);
2248 if (NILP (frame_bg))
2249 frame_bg = build_string (unspecified_bg);
2250
2251 /* Extract parm names and values into those vectors. */
2252 i = 0;
2253 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
2254 {
2255 Lisp_Object elt;
2256
2257 elt = Fcar (tail);
2258 parms[i] = Fcar (elt);
2259 CHECK_SYMBOL (parms[i]);
2260 values[i] = Fcdr (elt);
2261 i++;
2262 }
2263
2264 j = i;
2265
2266 for (i = 0; i < j; i++)
2267 {
2268 Lisp_Object prop, val;
2269
2270 prop = parms[i];
2271 val = values[i];
2272
2273 if (EQ (prop, Qreverse))
2274 reverse = EQ (val, Qt);
2275 }
2276
2277 need_to_reverse = reverse && !was_reverse;
2278 if (tty->termscript && need_to_reverse)
2279 fprintf (tty->termscript, "<INVERSE-VIDEO>\n");
2280
2281 /* Now process the alist elements in reverse of specified order. */
2282 for (i--; i >= 0; i--)
2283 {
2284 Lisp_Object prop, val, frame;
2285
2286 prop = parms[i];
2287 val = values[i];
2288
2289 if (EQ (prop, Qforeground_color))
2290 {
2291 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2292 ? LFACE_BACKGROUND_INDEX
2293 : LFACE_FOREGROUND_INDEX);
2294 if (new_color != FACE_TTY_DEFAULT_COLOR
2295 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2296 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2297 {
2298 FRAME_FOREGROUND_PIXEL (f) = new_color;
2299 /* Make sure the foreground of the default face for this
2300 frame is changed as well. */
2301 XSETFRAME (frame, f);
2302 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2303 val, frame);
2304 fg_set = 1;
2305 redraw = 1;
2306 if (tty->termscript)
2307 fprintf (tty->termscript, "<FGCOLOR %lu>\n", new_color);
2308 }
2309 }
2310 else if (EQ (prop, Qbackground_color))
2311 {
2312 unsigned long new_color = load_color (f, NULL, val, need_to_reverse
2313 ? LFACE_FOREGROUND_INDEX
2314 : LFACE_BACKGROUND_INDEX);
2315 if (new_color != FACE_TTY_DEFAULT_COLOR
2316 && new_color != FACE_TTY_DEFAULT_FG_COLOR
2317 && new_color != FACE_TTY_DEFAULT_BG_COLOR)
2318 {
2319 FRAME_BACKGROUND_PIXEL (f) = new_color;
2320 /* Make sure the background of the default face for this
2321 frame is changed as well. */
2322 XSETFRAME (frame, f);
2323 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2324 val, frame);
2325 bg_set = 1;
2326 redraw = 1;
2327 if (tty->termscript)
2328 fprintf (tty->termscript, "<BGCOLOR %lu>\n", new_color);
2329 }
2330 }
2331 else if (EQ (prop, Qtitle))
2332 {
2333 x_set_title (f, val);
2334 if (tty->termscript)
2335 fprintf (tty->termscript, "<TITLE: %s>\n", SDATA (val));
2336 }
2337 else if (EQ (prop, Qcursor_type))
2338 {
2339 IT_set_cursor_type (f, val);
2340 if (tty->termscript)
2341 fprintf (tty->termscript, "<CTYPE: %s>\n",
2342 EQ (val, Qbar) || EQ (val, Qhbar)
2343 || CONSP (val) && (EQ (XCAR (val), Qbar)
2344 || EQ (XCAR (val), Qhbar))
2345 ? "bar" : "box");
2346 }
2347 else if (EQ (prop, Qtty_type))
2348 {
2349 internal_terminal_init ();
2350 if (tty->termscript)
2351 fprintf (tty->termscript, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2352 SBYTES (val), SDATA (val));
2353 }
2354 store_frame_param (f, prop, val);
2355 }
2356
2357 /* If they specified "reverse", but not the colors, we need to swap
2358 the current frame colors. */
2359 if (need_to_reverse)
2360 {
2361 Lisp_Object frame;
2362
2363 if (!fg_set)
2364 {
2365 XSETFRAME (frame, f);
2366 Finternal_set_lisp_face_attribute (Qdefault, QCforeground,
2367 tty_color_name (f, orig_bg),
2368 frame);
2369 redraw = 1;
2370 }
2371 if (!bg_set)
2372 {
2373 XSETFRAME (frame, f);
2374 Finternal_set_lisp_face_attribute (Qdefault, QCbackground,
2375 tty_color_name (f, orig_fg),
2376 frame);
2377 redraw = 1;
2378 }
2379 }
2380
2381 if (redraw)
2382 {
2383 face_change_count++; /* forces xdisp.c to recompute basic faces */
2384 if (f == SELECTED_FRAME())
2385 redraw_frame (f);
2386 }
2387}
2388
2389extern void init_frame_faces (FRAME_PTR);
2390
2391#endif /* !HAVE_X_WINDOWS */
2392
2393
2394/* Do we need the internal terminal? */
2395
2396void
2397internal_terminal_init ()
2398{
2399 static int init_needed = 1;
2400 char *term = getenv ("TERM"), *colors;
2401 struct frame *sf = SELECTED_FRAME();
2402 struct tty_display_info *tty;
2403
2404#ifdef HAVE_X_WINDOWS
2405 if (!inhibit_window_system)
2406 return;
2407#endif
2408
2409 /* If this is the initial terminal, we are done here. */
2410 if (sf->output_method == output_initial)
2411 return;
2412
2413 internal_terminal
2414 = (!noninteractive) && term && !strcmp (term, "internal");
2415
2416#ifndef HAVE_X_WINDOWS
2417 if (!internal_terminal || inhibit_window_system)
2418 {
2419 sf->output_method = output_termcap;
2420 return;
2421 }
2422
2423 tty = FRAME_TTY (sf);
2424 current_kboard->Vwindow_system = Qpc;
2425 sf->output_method = output_msdos_raw;
2426 if (init_needed)
2427 {
2428 if (!tty->termscript && getenv ("EMACSTEST"))
2429 tty->termscript = fopen (getenv ("EMACSTEST"), "wt");
2430 if (tty->termscript)
2431 {
2432 time_t now = time (NULL);
2433 struct tm *tnow = localtime (&now);
2434 char tbuf[100];
2435
2436 strftime (tbuf, sizeof (tbuf) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow);
2437 fprintf (tty->termscript, "\nEmacs session started at %s\n", tbuf);
2438 fprintf (tty->termscript, "=====================\n\n");
2439 }
2440
2441 Vinitial_window_system = Qpc;
2442 Vwindow_system_version = make_number (23); /* RE Emacs version */
2443 tty->terminal->type = output_msdos_raw;
2444
2445 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2446 address. */
2447 screen_old_address = 0;
2448
2449 /* Forget the stale screen colors as well. */
2450 initial_screen_colors[0] = initial_screen_colors[1] = -1;
2451
2452 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2453 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2454 bright_bg ();
2455 colors = getenv ("EMACSCOLORS");
2456 if (colors && strlen (colors) >= 2)
2457 {
2458 /* The colors use 4 bits each (we enable bright background). */
2459 if (isdigit (colors[0]))
2460 colors[0] -= '0';
2461 else if (isxdigit (colors[0]))
2462 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
2463 if (colors[0] >= 0 && colors[0] < 16)
2464 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors[0];
2465 if (isdigit (colors[1]))
2466 colors[1] -= '0';
2467 else if (isxdigit (colors[1]))
2468 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
2469 if (colors[1] >= 0 && colors[1] < 16)
2470 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors[1];
2471 }
2472 the_only_display_info.mouse_face_mouse_frame = NULL;
2473 the_only_display_info.mouse_face_deferred_gc = 0;
2474 the_only_display_info.mouse_face_beg_row =
2475 the_only_display_info.mouse_face_beg_col = -1;
2476 the_only_display_info.mouse_face_end_row =
2477 the_only_display_info.mouse_face_end_col = -1;
2478 the_only_display_info.mouse_face_face_id = DEFAULT_FACE_ID;
2479 the_only_display_info.mouse_face_window = Qnil;
2480 the_only_display_info.mouse_face_mouse_x =
2481 the_only_display_info.mouse_face_mouse_y = 0;
2482 the_only_display_info.mouse_face_defer = 0;
2483 the_only_display_info.mouse_face_hidden = 0;
2484
2485 if (have_mouse) /* detected in dos_ttraw, which see */
2486 {
2487 have_mouse = 1; /* enable mouse */
2488 mouse_visible = 0;
2489 mouse_setup_buttons (mouse_button_count);
2490 tty->terminal->mouse_position_hook = &mouse_get_pos;
2491 mouse_init ();
2492 }
2493
2494 if (tty->termscript && screen_size)
2495 fprintf (tty->termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2496 screen_size_X, screen_size_Y);
2497
2498 init_frame_faces (sf);
2499 init_needed = 0;
2500 }
2501#endif
2502}
2503
2504void
2505initialize_msdos_display (struct terminal *term)
2506{
2507 term->rif = 0; /* we don't support window-based display */
2508 term->cursor_to_hook = term->raw_cursor_to_hook = IT_cursor_to;
2509 term->clear_to_end_hook = IT_clear_to_end;
2510 term->clear_frame_hook = IT_clear_screen;
2511 term->clear_end_of_line_hook = IT_clear_end_of_line;
2512 term->ins_del_lines_hook = 0;
2513 term->insert_glyphs_hook = IT_insert_glyphs;
2514 term->write_glyphs_hook = IT_write_glyphs;
2515 term->delete_glyphs_hook = IT_delete_glyphs;
2516 term->ring_bell_hook = IT_ring_bell;
2517 term->reset_terminal_modes_hook = IT_reset_terminal_modes;
2518 term->set_terminal_modes_hook = IT_set_terminal_modes;
2519 term->set_terminal_window_hook = IT_set_terminal_window;
2520 term->update_begin_hook = IT_update_begin;
2521 term->update_end_hook = IT_update_end;
2522 term->frame_up_to_date_hook = IT_frame_up_to_date;
2523 term->mouse_position_hook = 0; /* set later by dos_ttraw */
2524 term->frame_rehighlight_hook = 0;
2525 term->frame_raise_lower_hook = 0;
2526 term->set_vertical_scroll_bar_hook = 0;
2527 term->condemn_scroll_bars_hook = 0;
2528 term->redeem_scroll_bar_hook = 0;
2529 term->judge_scroll_bars_hook = 0;
2530 term->read_socket_hook = &tty_read_avail_input; /* from keyboard.c */
2531}
2532
2533dos_get_saved_screen (screen, rows, cols)
2534 char **screen;
2535 int *rows;
2536 int *cols;
2537{
2538#ifndef HAVE_X_WINDOWS
2539 *screen = startup_screen_buffer;
2540 *cols = startup_screen_size_X;
2541 *rows = startup_screen_size_Y;
2542 return *screen != (char *)0;
2543#else
2544 return 0;
2545#endif
2546}
2547
2548#ifndef HAVE_X_WINDOWS
2549
2550/* We are not X, but we can emulate it well enough for our needs... */
2551void
2552check_x (void)
2553{
2554 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2555 error ("Not running under a window system");
2556}
2557
2558#endif
2559
2560\f
2561/* ----------------------- Keyboard control ----------------------
2562 *
2563 * Keymaps reflect the following keyboard layout:
2564 *
2565 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2566 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2567 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2568 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2569 * SPACE
2570 */
2571
2572#define Ignore 0x0000
2573#define Normal 0x0000 /* normal key - alt changes scan-code */
2574#define FctKey 0x1000 /* func key if c == 0, else c */
2575#define Special 0x2000 /* func key even if c != 0 */
2576#define ModFct 0x3000 /* special if mod-keys, else 'c' */
2577#define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2578#define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2579#define Grey 0x6000 /* Grey keypad key */
2580
2581#define Alt 0x0100 /* alt scan-code */
2582#define Ctrl 0x0200 /* ctrl scan-code */
2583#define Shift 0x0400 /* shift scan-code */
2584
2585static int extended_kbd; /* 101 (102) keyboard present. */
2586
2587struct kbd_translate {
2588 unsigned char sc;
2589 unsigned char ch;
2590 unsigned short code;
2591};
2592
2593struct dos_keyboard_map
2594{
2595 char *unshifted;
2596 char *shifted;
2597 char *alt_gr;
2598 struct kbd_translate *translate_table;
2599};
2600
2601
2602static struct dos_keyboard_map us_keyboard = {
2603/* 0 1 2 3 4 5 */
2604/* 01234567890123456789012345678901234567890 12345678901234 */
2605 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2606/* 0123456789012345678901234567890123456789 012345678901234 */
2607 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2608 0, /* no Alt-Gr key */
2609 0 /* no translate table */
2610};
2611
2612static struct dos_keyboard_map fr_keyboard = {
2613/* 0 1 2 3 4 5 */
2614/* 012 3456789012345678901234567890123456789012345678901234 */
2615