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