Changes for separate unspecified foreground and background colors
[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"
1b94449f
RS
63#include <go32.h>
64#include <pc.h>
65#include <ctype.h>
66/* #include <process.h> */
67/* Damn that local process.h! Instead we can define P_WAIT ourselves. */
68#define P_WAIT 1
69
d21e67b5
RS
70#ifndef _USE_LFN
71#define _USE_LFN 0
72#endif
73
b36701cc
RS
74#ifndef _dos_ds
75#define _dos_ds _go32_info_block.selector_for_linear_memory
76#endif
77
1bd7b2c7
RS
78#if __DJGPP__ > 1
79
8748735b 80#include <signal.h>
417a04bb 81#include "syssignal.h"
8748735b 82
1bd7b2c7
RS
83#ifndef SYSTEM_MALLOC
84
85#ifdef GNU_MALLOC
86
87/* If other `malloc' than ours is used, force our `sbrk' behave like
88 Unix programs expect (resize memory blocks to keep them contiguous).
89 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
90 because that's what `gmalloc' expects to get. */
91#include <crt0.h>
92
93#ifdef REL_ALLOC
94int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
95#else /* not REL_ALLOC */
96int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
97#endif /* not REL_ALLOC */
98#endif /* GNU_MALLOC */
99
100#endif /* not SYSTEM_MALLOC */
101#endif /* __DJGPP__ > 1 */
aee81730
RS
102
103static unsigned long
104event_timestamp ()
105{
106 struct time t;
107 unsigned long s;
f32d4091 108
aee81730
RS
109 gettime (&t);
110 s = t.ti_min;
111 s *= 60;
112 s += t.ti_sec;
113 s *= 1000;
114 s += t.ti_hund * 10;
f32d4091 115
aee81730
RS
116 return s;
117}
118
f32d4091
KS
119\f
120/* ------------------------ Mouse control ---------------------------
121 *
122 * Coordinates are in screen positions and zero based.
123 * Mouse buttons are numbered from left to right and also zero based.
124 */
1b94449f 125
f32d4091
KS
126int have_mouse; /* 0: no, 1: enabled, -1: disabled */
127static int mouse_visible;
1b94449f 128
f32d4091
KS
129static int mouse_last_x;
130static int mouse_last_y;
1b94449f 131
f32d4091
KS
132static int mouse_button_translate[NUM_MOUSE_BUTTONS];
133static int mouse_button_count;
1b94449f 134
f32d4091
KS
135void
136mouse_on ()
1b94449f 137{
1b94449f 138 union REGS regs;
1b94449f 139
f32d4091 140 if (have_mouse > 0 && !mouse_visible)
1b94449f 141 {
f32d4091
KS
142 if (termscript)
143 fprintf (termscript, "<M_ON>");
144 regs.x.ax = 0x0001;
145 int86 (0x33, &regs, &regs);
146 mouse_visible = 1;
1b94449f 147 }
1b94449f
RS
148}
149
f32d4091
KS
150void
151mouse_off ()
1b94449f 152{
f32d4091 153 union REGS regs;
1b94449f 154
f32d4091 155 if (have_mouse > 0 && mouse_visible)
1b94449f 156 {
f32d4091
KS
157 if (termscript)
158 fprintf (termscript, "<M_OFF>");
159 regs.x.ax = 0x0002;
160 int86 (0x33, &regs, &regs);
161 mouse_visible = 0;
1b94449f 162 }
1b94449f
RS
163}
164
211c7152
EZ
165static void
166mouse_get_xy (int *x, int *y)
167{
168 union REGS regs;
169
170 regs.x.ax = 0x0003;
171 int86 (0x33, &regs, &regs);
172 *x = regs.x.cx / 8;
173 *y = regs.x.dx / 8;
174}
175
f32d4091
KS
176void
177mouse_moveto (x, y)
178 int x, y;
1b94449f 179{
f32d4091 180 union REGS regs;
1b94449f 181
f32d4091
KS
182 if (termscript)
183 fprintf (termscript, "<M_XY=%dx%d>", x, y);
184 regs.x.ax = 0x0004;
185 mouse_last_x = regs.x.cx = x * 8;
186 mouse_last_y = regs.x.dx = y * 8;
187 int86 (0x33, &regs, &regs);
1b94449f
RS
188}
189
f32d4091
KS
190static int
191mouse_pressed (b, xp, yp)
192 int b, *xp, *yp;
1b94449f 193{
f32d4091 194 union REGS regs;
1b94449f 195
f32d4091
KS
196 if (b >= mouse_button_count)
197 return 0;
198 regs.x.ax = 0x0005;
199 regs.x.bx = mouse_button_translate[b];
200 int86 (0x33, &regs, &regs);
201 if (regs.x.bx)
202 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
203 return (regs.x.bx != 0);
1b94449f
RS
204}
205
f32d4091
KS
206static int
207mouse_released (b, xp, yp)
208 int b, *xp, *yp;
1b94449f
RS
209{
210 union REGS regs;
211
f32d4091
KS
212 if (b >= mouse_button_count)
213 return 0;
214 regs.x.ax = 0x0006;
215 regs.x.bx = mouse_button_translate[b];
216 int86 (0x33, &regs, &regs);
217 if (regs.x.bx)
218 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
219 return (regs.x.bx != 0);
1b94449f
RS
220}
221
0c7bc1aa
EZ
222static int
223mouse_button_depressed (b, xp, yp)
224 int b, *xp, *yp;
225{
226 union REGS regs;
227
228 if (b >= mouse_button_count)
229 return 0;
230 regs.x.ax = 0x0003;
231 int86 (0x33, &regs, &regs);
232 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
233 {
234 *xp = regs.x.cx / 8;
235 *yp = regs.x.dx / 8;
236 return 1;
237 }
238 return 0;
239}
240
f32d4091
KS
241void
242mouse_get_pos (f, insist, bar_window, part, x, y, time)
243 FRAME_PTR *f;
244 int insist;
245 Lisp_Object *bar_window, *x, *y;
246 enum scroll_bar_part *part;
247 unsigned long *time;
248{
249 int ix, iy;
211c7152
EZ
250 Lisp_Object frame, tail;
251
252 /* Clear the mouse-moved flag for every frame on this display. */
253 FOR_EACH_FRAME (tail, frame)
254 XFRAME (frame)->mouse_moved = 0;
f32d4091 255
2d764c78 256 *f = SELECTED_FRAME();
f32d4091
KS
257 *bar_window = Qnil;
258 mouse_get_xy (&ix, &iy);
f32d4091 259 *time = event_timestamp ();
211c7152
EZ
260 *x = make_number (mouse_last_x = ix);
261 *y = make_number (mouse_last_y = iy);
f32d4091 262}
1b94449f 263
f32d4091
KS
264static void
265mouse_check_moved ()
1b94449f 266{
aee81730 267 int x, y;
1b94449f 268
f32d4091 269 mouse_get_xy (&x, &y);
2d764c78 270 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
f32d4091
KS
271 mouse_last_x = x;
272 mouse_last_y = y;
273}
1b94449f 274
f32d4091
KS
275void
276mouse_init ()
277{
278 union REGS regs;
0c7bc1aa 279 int b;
647c32eb 280
f32d4091
KS
281 if (termscript)
282 fprintf (termscript, "<M_INIT>");
1b94449f 283
f32d4091
KS
284 regs.x.ax = 0x0021;
285 int86 (0x33, &regs, &regs);
091d0bdf 286
0c7bc1aa
EZ
287 /* Reset the mouse last press/release info. It seems that Windows
288 doesn't do that automatically when function 21h is called, which
289 causes Emacs to ``remember'' the click that switched focus to the
290 window just before Emacs was started from that window. */
291 for (b = 0; b < mouse_button_count; b++)
292 {
293 int dummy_x, dummy_y;
294
295 (void) mouse_pressed (b, &dummy_x, &dummy_y);
296 (void) mouse_released (b, &dummy_x, &dummy_y);
297 }
298
f32d4091
KS
299 regs.x.ax = 0x0007;
300 regs.x.cx = 0;
301 regs.x.dx = 8 * (ScreenCols () - 1);
302 int86 (0x33, &regs, &regs);
1b94449f 303
f32d4091
KS
304 regs.x.ax = 0x0008;
305 regs.x.cx = 0;
306 regs.x.dx = 8 * (ScreenRows () - 1);
307 int86 (0x33, &regs, &regs);
1b94449f 308
f32d4091
KS
309 mouse_moveto (0, 0);
310 mouse_visible = 0;
311}
3eb1dbb6 312\f
f32d4091
KS
313/* ------------------------- Screen control ----------------------
314 *
315 */
aee81730 316
f32d4091 317static int internal_terminal = 0;
aee81730 318
f32d4091
KS
319#ifndef HAVE_X_WINDOWS
320extern unsigned char ScreenAttrib;
321static int screen_face;
322static int highlight;
aee81730 323
f32d4091
KS
324static int screen_size_X;
325static int screen_size_Y;
326static int screen_size;
1b94449f 327
f32d4091
KS
328static int current_pos_X;
329static int current_pos_Y;
330static int new_pos_X;
331static int new_pos_Y;
1b94449f 332
f32d4091
KS
333static void *startup_screen_buffer;
334static int startup_screen_size_X;
335static int startup_screen_size_Y;
336static int startup_pos_X;
337static int startup_pos_Y;
c9adab25 338static unsigned char startup_screen_attrib;
1b94449f 339
06b1ea13
EZ
340static clock_t startup_time;
341
f32d4091 342static int term_setup_done;
1b94449f 343
f32d4091 344/* Similar to the_only_frame. */
f6816f88 345struct x_output the_only_x_display;
1b94449f 346
039274cf
EZ
347/* Support for DOS/V (allows Japanese characters to be displayed on
348 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
349
350/* Holds the address of the text-mode screen buffer. */
351static unsigned long screen_old_address = 0;
352/* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
353static unsigned short screen_virtual_segment = 0;
354static unsigned short screen_virtual_offset = 0;
68026917
AI
355/* A flag to control how to display unibyte 8-bit characters. */
356extern int unibyte_display_via_language_environment;
039274cf
EZ
357
358#if __DJGPP__ > 1
359/* Update the screen from a part of relocated DOS/V screen buffer which
360 begins at OFFSET and includes COUNT characters. */
361static void
362dosv_refresh_virtual_screen (int offset, int count)
363{
364 __dpmi_regs regs;
365
40437cf5
EZ
366 if (offset < 0 || count < 0) /* paranoia; illegal values crash DOS/V */
367 return;
368
039274cf
EZ
369 regs.h.ah = 0xff; /* update relocated screen */
370 regs.x.es = screen_virtual_segment;
371 regs.x.di = screen_virtual_offset + offset;
372 regs.x.cx = count;
373 __dpmi_int (0x10, &regs);
374}
375#endif
376
d1d5dc19 377static void
f32d4091
KS
378dos_direct_output (y, x, buf, len)
379 int y;
380 int x;
381 char *buf;
382 int len;
1b94449f 383{
40437cf5
EZ
384 int t0 = 2 * (x + y * screen_size_X);
385 int t = t0 + (int) ScreenPrimary;
039274cf 386 int l0 = len;
fc171623
KH
387
388#if (__DJGPP__ < 2)
f32d4091
KS
389 while (--len >= 0) {
390 dosmemput (buf++, 1, t);
391 t += 2;
392 }
fc171623
KH
393#else
394 /* This is faster. */
395 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
396 _farnspokeb (t, *buf);
039274cf
EZ
397
398 if (screen_virtual_segment)
399 dosv_refresh_virtual_screen (t0, l0);
fc171623 400#endif
1b94449f 401}
aee81730 402#endif
1b94449f 403
1b94449f
RS
404/* Flash the screen as a substitute for BEEPs. */
405
f32d4091 406#if (__DJGPP__ < 2)
49a09c76 407static void
fcea9cd4 408do_visible_bell (xorattr)
1b94449f
RS
409 unsigned char xorattr;
410{
49a09c76 411 asm volatile
ca986694 412 (" movb $1,%%dl
1b94449f 413visible_bell_0:
ca986694 414 movl _ScreenPrimary,%%eax
49a09c76 415 call dosmemsetup
ca986694
RS
416 movl %%eax,%%ebx
417 movl %1,%%ecx
418 movb %0,%%al
419 incl %%ebx
1b94449f 420visible_bell_1:
ca986694
RS
421 xorb %%al,%%gs:(%%ebx)
422 addl $2,%%ebx
423 decl %%ecx
49a09c76 424 jne visible_bell_1
ca986694 425 decb %%dl
49a09c76 426 jne visible_bell_3
1b94449f 427visible_bell_2:
ca986694
RS
428 movzwl %%ax,%%eax
429 movzwl %%ax,%%eax
430 movzwl %%ax,%%eax
431 movzwl %%ax,%%eax
432 decw %%cx
49a09c76
RS
433 jne visible_bell_2
434 jmp visible_bell_0
ca986694
RS
435visible_bell_3:"
436 : /* no output */
f32d4091 437 : "m" (xorattr), "g" (screen_size)
ca986694 438 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
1b94449f
RS
439}
440
f32d4091
KS
441static void
442ScreenVisualBell (void)
443{
444 /* This creates an xor-mask that will swap the default fore- and
445 background colors. */
446 do_visible_bell (((the_only_x_display.foreground_pixel
447 ^ the_only_x_display.background_pixel)
448 * 0x11) & 0x7f);
449}
450#endif
451
452#ifndef HAVE_X_WINDOWS
453
b36701cc
RS
454static int blink_bit = -1; /* the state of the blink bit at startup */
455
76ac1508
RS
456/* Enable bright background colors. */
457static void
458bright_bg (void)
459{
460 union REGS regs;
461
b36701cc
RS
462 /* Remember the original state of the blink/bright-background bit.
463 It is stored at 0040:0065h in the BIOS data area. */
464 if (blink_bit == -1)
465 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
466
76ac1508
RS
467 regs.h.bl = 0;
468 regs.x.ax = 0x1003;
469 int86 (0x10, &regs, &regs);
470}
471
b36701cc
RS
472/* Disable bright background colors (and enable blinking) if we found
473 the video system in that state at startup. */
474static void
475maybe_enable_blinking (void)
476{
477 if (blink_bit == 1)
478 {
479 union REGS regs;
480
481 regs.h.bl = 1;
482 regs.x.ax = 0x1003;
483 int86 (0x10, &regs, &regs);
484 }
485}
486
4a96d4d2
KH
487/* Set the screen dimensions so that it can show no less than
488 ROWS x COLS frame. */
48ffe371 489
4a96d4d2
KH
490void
491dos_set_window_size (rows, cols)
492 int *rows, *cols;
493{
494 char video_name[30];
495 Lisp_Object video_mode;
496 int video_mode_value;
497 int have_vga = 0;
498 union REGS regs;
499 int current_rows = ScreenRows (), current_cols = ScreenCols ();
500
501 if (*rows == current_rows && *cols == current_cols)
502 return;
503
504 /* Do we have a VGA? */
505 regs.x.ax = 0x1a00;
506 int86 (0x10, &regs, &regs);
507 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
508 have_vga = 1;
509
510 mouse_off ();
511
48ffe371 512 /* If the user specified a special video mode for these dimensions,
4a96d4d2
KH
513 use that mode. */
514 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
515 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
516 Qnil))-> value;
517
518 if (INTEGERP (video_mode)
519 && (video_mode_value = XINT (video_mode)) > 0)
520 {
521 regs.x.ax = video_mode_value;
522 int86 (0x10, &regs, &regs);
48ffe371
RS
523
524 if (have_mouse)
525 {
526 /* Must hardware-reset the mouse, or else it won't update
527 its notion of screen dimensions for some non-standard
528 video modes. This is *painfully* slow... */
529 regs.x.ax = 0;
530 int86 (0x33, &regs, &regs);
531 }
4a96d4d2
KH
532 }
533
534 /* Find one of the dimensions supported by standard EGA/VGA
535 which gives us at least the required dimensions. */
536
537#if __DJGPP__ > 1
538
539 else
540 {
541 static struct {
542 int rows;
543 int need_vga;
544 } std_dimension[] = {
545 {25, 0},
546 {28, 1},
547 {35, 0},
548 {40, 1},
549 {43, 0},
550 {50, 1}
551 };
552 int i = 0;
553
554 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
555 {
556 if (std_dimension[i].need_vga <= have_vga
557 && std_dimension[i].rows >= *rows)
558 {
559 if (std_dimension[i].rows != current_rows
560 || *cols != current_cols)
48ffe371 561 _set_screen_lines (std_dimension[i].rows);
4a96d4d2
KH
562 break;
563 }
48ffe371 564 i++;
4a96d4d2
KH
565 }
566 }
567
568#else /* not __DJGPP__ > 1 */
569
570 else if (*rows <= 25)
571 {
572 if (current_rows != 25 || current_cols != 80)
573 {
574 regs.x.ax = 3;
575 int86 (0x10, &regs, &regs);
576 regs.x.ax = 0x1101;
577 regs.h.bl = 0;
578 int86 (0x10, &regs, &regs);
579 regs.x.ax = 0x1200;
580 regs.h.bl = 32;
581 int86 (0x10, &regs, &regs);
582 regs.x.ax = 3;
583 int86 (0x10, &regs, &regs);
584 }
585 }
586 else if (*rows <= 50)
587 if (have_vga && (current_rows != 50 || current_cols != 80)
588 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
589 {
590 regs.x.ax = 3;
591 int86 (0x10, &regs, &regs);
592 regs.x.ax = 0x1112;
593 regs.h.bl = 0;
594 int86 (0x10, &regs, &regs);
595 regs.x.ax = 0x1200;
596 regs.h.bl = 32;
597 int86 (0x10, &regs, &regs);
598 regs.x.ax = 0x0100;
599 regs.x.cx = 7;
600 int86 (0x10, &regs, &regs);
601 }
602#endif /* not __DJGPP__ > 1 */
603
604 if (have_mouse)
605 {
4a96d4d2
KH
606 mouse_init ();
607 mouse_on ();
608 }
609
610 /* Tell the caller what dimensions have been REALLY set. */
611 *rows = ScreenRows ();
612 *cols = ScreenCols ();
76ac1508
RS
613
614 /* Enable bright background colors. */
615 bright_bg ();
039274cf
EZ
616
617 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
618 be defensive anyway. */
619 if (screen_virtual_segment)
620 dosv_refresh_virtual_screen (0, *cols * *rows);
4a96d4d2
KH
621}
622
48ffe371
RS
623/* If we write a character in the position where the mouse is,
624 the mouse cursor may need to be refreshed. */
09e2ac30
RS
625
626static void
f32d4091 627mouse_off_maybe ()
09e2ac30 628{
f32d4091
KS
629 int x, y;
630
631 if (!mouse_visible)
632 return;
633
634 mouse_get_xy (&x, &y);
635 if (y != new_pos_Y || x < new_pos_X)
636 return;
637
638 mouse_off ();
639}
640
71f65669
EZ
641static void
642IT_ring_bell (void)
f32d4091
KS
643{
644 if (visible_bell)
aee81730 645 {
f32d4091
KS
646 mouse_off ();
647 ScreenVisualBell ();
aee81730 648 }
f32d4091 649 else
3635be47
RS
650 {
651 union REGS inregs, outregs;
652 inregs.h.ah = 2;
653 inregs.h.dl = 7;
654 intdos (&inregs, &outregs);
655 }
09e2ac30
RS
656}
657
c77f6f1b
EZ
658/* Given a face id FACE, extract the face parameters to be used for
659 display until the face changes. The face parameters (actually, its
660 color) are used to construct the video attribute byte for each
661 glyph during the construction of the buffer that is then blitted to
662 the video RAM. */
f32d4091
KS
663static void
664IT_set_face (int face)
665{
2d764c78
EZ
666 struct frame *sf = SELECTED_FRAME();
667 struct face *fp = FACE_FROM_ID (sf, face);
c77f6f1b 668 unsigned long fg, bg;
f32d4091 669
c77f6f1b 670 if (!fp)
e30aee93 671 {
2d764c78 672 fp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
e30aee93
EZ
673 /* The default face for the frame should always be realized and
674 cached. */
675 if (!fp)
676 abort ();
677 }
f32d4091 678 screen_face = face;
c77f6f1b
EZ
679 fg = fp->foreground;
680 bg = fp->background;
681
682 /* Don't use invalid colors. In particular, a color of -1 means use
683 the colors of the default face, except that if highlight is on,
684 invert the foreground and the background. Note that we assume
685 all 16 colors to be available for the background, since Emacs
686 switches on this mode (and loses the blinking attribute) at
687 startup. */
f9d2fdc4 688 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
2d764c78
EZ
689 fg = highlight || fp->tty_reverse_p ? FRAME_BACKGROUND_PIXEL (sf)
690 : FRAME_FOREGROUND_PIXEL (sf);
f9d2fdc4
EZ
691 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
692 fg = highlight ? FRAME_FOREGROUND_PIXEL (sf) : FRAME_BACKGROUND_PIXEL (sf);
693 if (bg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_BG_COLOR)
2d764c78
EZ
694 bg = highlight || fp->tty_reverse_p ? FRAME_FOREGROUND_PIXEL (sf)
695 : FRAME_BACKGROUND_PIXEL (sf);
f9d2fdc4
EZ
696 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
697 fg = highlight ? FRAME_BACKGROUND_PIXEL (sf) : FRAME_FOREGROUND_PIXEL (sf);
c77f6f1b
EZ
698 if (termscript)
699 fprintf (termscript, "<FACE %d%s: %d/%d>",
700 face, highlight ? "H" : "", fp->foreground, fp->background);
701 if (fg >= 0 && fg < 16)
702 {
703 ScreenAttrib &= 0xf0;
704 ScreenAttrib |= fg;
705 }
706 if (bg >= 0 && bg < 16)
707 {
708 ScreenAttrib &= 0x0f;
709 ScreenAttrib |= ((bg & 0x0f) << 4);
710 }
f32d4091
KS
711}
712
aa9ce936
EZ
713Lisp_Object Vdos_unsupported_char_glyph;
714
71f65669 715static void
c77f6f1b 716IT_write_glyphs (struct glyph *str, int str_len)
f32d4091 717{
aa9ce936
EZ
718 unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
719 int unsupported_face = FAST_GLYPH_FACE (Vdos_unsupported_char_glyph);
720 unsigned unsupported_char= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph);
039274cf 721 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
aa9ce936
EZ
722 register int sl = str_len;
723 register int tlen = GLYPH_TABLE_LENGTH;
724 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
725
e16bf494
AI
726 struct coding_system *coding = (CODING_REQUIRE_ENCODING (&terminal_coding)
727 ? &terminal_coding
728 : &safe_terminal_coding);
2d764c78 729 struct frame *sf;
87485d6f 730
52d38ab2
EZ
731 /* Do we need to consider conversion of unibyte characters to
732 multibyte? */
733 int convert_unibyte_characters
e16bf494
AI
734 = (NILP (current_buffer->enable_multibyte_characters)
735 && unibyte_display_via_language_environment);
52d38ab2 736
aa9ce936 737 if (str_len == 0) return;
aee81730 738
aa9ce936
EZ
739 screen_buf = screen_bp = alloca (str_len * 2);
740 screen_buf_end = screen_buf + str_len * 2;
2d764c78 741 sf = SELECTED_FRAME();
e30aee93
EZ
742
743 /* Since faces get cached and uncached behind our back, we can't
744 rely on their indices in the cache being consistent across
745 invocations. So always reset the screen face to the default
746 face of the frame, before writing glyphs, and let the glyphs
747 set the right face if it's different from the default. */
748 IT_set_face (DEFAULT_FACE_ID);
aee81730 749
aa9ce936
EZ
750 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
751 the tail. */
752 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
753 while (sl)
754 {
c77f6f1b 755 int cf, chlen, enclen;
aa9ce936 756 unsigned char workbuf[4], *buf;
c77f6f1b
EZ
757 unsigned ch;
758 register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
aa9ce936
EZ
759
760 /* Find the actual glyph to display by traversing the entire
761 aliases chain for this glyph. */
762 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
763
764 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
765 only for the redisplay code to know how many columns does
766 this character occupy on the screen. Skip padding glyphs. */
c77f6f1b 767 if (CHAR_GLYPH_PADDING_P (*str))
aa9ce936
EZ
768 {
769 str++;
770 sl--;
771 }
772 else
773 {
774 /* Convert the character code to multibyte, if they
775 requested display via language environment. */
776 ch = FAST_GLYPH_CHAR (g);
aff4381d
EZ
777 /* We only want to convert unibyte characters to multibyte
778 in unibyte buffers! Otherwise, the 8-bit code might come
779 from the display table set up to display foreign characters. */
52d38ab2 780 if (SINGLE_BYTE_CHAR_P (ch) && convert_unibyte_characters
f0dd4c35
EZ
781 && (ch >= 0240
782 || (ch >= 0200 && !NILP (Vnonascii_translation_table))))
aa9ce936
EZ
783 ch = unibyte_char_to_multibyte (ch);
784
785 /* Invalid characters are displayed with a special glyph. */
c77f6f1b 786 if (! GLYPH_CHAR_VALID_P (ch))
aa9ce936
EZ
787 {
788 g = !NILP (Vdos_unsupported_char_glyph)
789 ? Vdos_unsupported_char_glyph
2d764c78 790 : MAKE_GLYPH (sf, '\177', GLYPH_FACE (sf, g));
aa9ce936
EZ
791 ch = FAST_GLYPH_CHAR (g);
792 }
793 if (COMPOSITE_CHAR_P (ch))
794 {
795 /* If CH is a composite character, we can display
796 only the first component. */
797 g = cmpchar_table[COMPOSITE_CHAR_ID (ch)]->glyph[0],
2d764c78 798 ch = GLYPH_CHAR (sf, g);
aa9ce936
EZ
799 cf = FAST_GLYPH_FACE (g);
800 }
801
802 /* If the face of this glyph is different from the current
803 screen face, update the screen attribute byte. */
804 cf = FAST_GLYPH_FACE (g);
805 if (cf != screen_face)
806 IT_set_face (cf); /* handles invalid faces gracefully */
807
808 if (GLYPH_SIMPLE_P (tbase, tlen, g))
809 /* We generate the multi-byte form of CH in BUF. */
810 chlen = CHAR_STRING (ch, workbuf, buf);
811 else
812 {
813 /* We have a string in Vglyph_table. */
814 chlen = GLYPH_LENGTH (tbase, g);
815 buf = GLYPH_STRING (tbase, g);
816 }
817
c77f6f1b 818 /* If the character is not multibyte, don't bother converting it. */
aa9ce936
EZ
819 if (chlen == 1)
820 {
821 *conversion_buffer = (unsigned char)ch;
822 chlen = 0;
823 enclen = 1;
824 }
825 else
826 {
827 encode_coding (coding, buf, conversion_buffer, chlen,
828 conversion_buffer_size);
829 chlen -= coding->consumed;
830 enclen = coding->produced;
831
832 /* Replace glyph codes that cannot be converted by
833 terminal_coding with Vdos_unsupported_char_glyph. */
834 if (*conversion_buffer == '?')
835 {
836 char *cbp = conversion_buffer;
837
838 while (cbp < conversion_buffer + enclen && *cbp == '?')
839 *cbp++ = unsupported_char;
840 if (unsupported_face != screen_face)
841 IT_set_face (unsupported_face);
842 }
843 }
844
845 if (enclen + chlen > screen_buf_end - screen_bp)
846 {
847 /* The allocated buffer for screen writes is too small.
848 Flush it and loop again without incrementing STR, so
849 that the next loop will begin with the same glyph. */
850 int nbytes = screen_bp - screen_buf;
851
852 mouse_off_maybe ();
853 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
854 if (screen_virtual_segment)
855 dosv_refresh_virtual_screen (offset, nbytes / 2);
856 new_pos_X += nbytes / 2;
857 offset += nbytes;
858
859 /* Prepare to reuse the same buffer again. */
860 screen_bp = screen_buf;
861 }
862 else
863 {
864 /* There's enough place in the allocated buffer to add
865 the encoding of this glyph. */
866
867 /* First, copy the encoded bytes. */
868 for (bp = conversion_buffer; enclen--; bp++)
869 {
870 *screen_bp++ = (unsigned char)*bp;
871 *screen_bp++ = ScreenAttrib;
872 if (termscript)
873 fputc (*bp, termscript);
874 }
875
876 /* Now copy the bytes not consumed by the encoding. */
877 if (chlen > 0)
878 {
879 buf += coding->consumed;
880 while (chlen--)
881 {
882 if (termscript)
883 fputc (*buf, termscript);
884 *screen_bp++ = (unsigned char)*buf++;
885 *screen_bp++ = ScreenAttrib;
886 }
887 }
888
889 /* Update STR and its remaining length. */
890 str++;
891 sl--;
892 }
893 }
aee81730
RS
894 }
895
aa9ce936 896 /* Dump whatever is left in the screen buffer. */
f32d4091 897 mouse_off_maybe ();
aa9ce936 898 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
039274cf 899 if (screen_virtual_segment)
aa9ce936
EZ
900 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
901 new_pos_X += (screen_bp - screen_buf) / 2;
902
903 /* We may have to output some codes to terminate the writing. */
904 if (CODING_REQUIRE_FLUSHING (coding))
905 {
906 coding->mode |= CODING_MODE_LAST_BLOCK;
907 encode_coding (coding, "", conversion_buffer, 0, conversion_buffer_size);
908 if (coding->produced > 0)
909 {
910 for (screen_bp = screen_buf, bp = conversion_buffer;
911 coding->produced--; bp++)
912 {
913 *screen_bp++ = (unsigned char)*bp;
914 *screen_bp++ = ScreenAttrib;
915 if (termscript)
916 fputc (*bp, termscript);
917 }
918 offset += screen_bp - screen_buf;
919 mouse_off_maybe ();
920 dosmemput (screen_buf, screen_bp - screen_buf,
921 (int)ScreenPrimary + offset);
922 if (screen_virtual_segment)
923 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
924 new_pos_X += (screen_bp - screen_buf) / 2;
925 }
926 }
f32d4091 927}
aee81730 928
71f65669
EZ
929static void
930IT_clear_end_of_line (int first_unused)
f32d4091
KS
931{
932 char *spaces, *sp;
933 int i, j;
039274cf 934 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
aa9ce936
EZ
935 extern int fatal_error_in_progress;
936
2d764c78 937 if (new_pos_X >= first_unused || fatal_error_in_progress)
aa9ce936 938 return;
f32d4091
KS
939
940 IT_set_face (0);
941 if (termscript)
942 fprintf (termscript, "<CLR:EOL>");
2d764c78 943 i = (j = first_unused - new_pos_X) * 2;
f32d4091 944 spaces = sp = alloca (i);
aee81730 945
f32d4091 946 while (--j >= 0)
aee81730 947 {
f32d4091
KS
948 *sp++ = ' ';
949 *sp++ = ScreenAttrib;
aee81730
RS
950 }
951
f32d4091 952 mouse_off_maybe ();
039274cf
EZ
953 dosmemput (spaces, i, (int)ScreenPrimary + offset);
954 if (screen_virtual_segment)
955 dosv_refresh_virtual_screen (offset, i / 2);
2d764c78
EZ
956
957 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
958 Let's follow their lead, in case someone relies on this. */
959 new_pos_X = first_unused;
aee81730
RS
960}
961
71f65669 962static void
f32d4091
KS
963IT_clear_screen (void)
964{
965 if (termscript)
966 fprintf (termscript, "<CLR:SCR>");
967 IT_set_face (0);
968 mouse_off ();
969 ScreenClear ();
039274cf
EZ
970 if (screen_virtual_segment)
971 dosv_refresh_virtual_screen (0, screen_size);
f32d4091
KS
972 new_pos_X = new_pos_Y = 0;
973}
974
71f65669 975static void
f32d4091
KS
976IT_clear_to_end (void)
977{
978 if (termscript)
979 fprintf (termscript, "<CLR:EOS>");
980
981 while (new_pos_Y < screen_size_Y) {
982 new_pos_X = 0;
983 IT_clear_end_of_line (0);
984 new_pos_Y++;
985 }
986}
987
71f65669 988static void
f32d4091
KS
989IT_cursor_to (int y, int x)
990{
991 if (termscript)
992 fprintf (termscript, "\n<XY=%dx%d>", x, y);
993 new_pos_X = x;
994 new_pos_Y = y;
995}
996
fc171623
KH
997static int cursor_cleared;
998
d1d5dc19 999static void
fc171623
KH
1000IT_display_cursor (int on)
1001{
1002 if (on && cursor_cleared)
1003 {
1004 ScreenSetCursor (current_pos_Y, current_pos_X);
1005 cursor_cleared = 0;
1006 }
1007 else if (!on && !cursor_cleared)
1008 {
1009 ScreenSetCursor (-1, -1);
1010 cursor_cleared = 1;
1011 }
1012}
1013
1014/* Emacs calls cursor-movement functions a lot when it updates the
1015 display (probably a legacy of old terminals where you cannot
1016 update a screen line without first moving the cursor there).
1017 However, cursor movement is expensive on MSDOS (it calls a slow
1018 BIOS function and requires 2 mode switches), while actual screen
1019 updates access the video memory directly and don't depend on
1020 cursor position. To avoid slowing down the redisplay, we cheat:
1021 all functions that move the cursor only set internal variables
1022 which record the cursor position, whereas the cursor is only
1023 moved to its final position whenever screen update is complete.
1024
1025 `IT_cmgoto' is called from the keyboard reading loop and when the
1026 frame update is complete. This means that we are ready for user
1027 input, so we update the cursor position to show where the point is,
1028 and also make the mouse pointer visible.
1029
1030 Special treatment is required when the cursor is in the echo area,
1031 to put the cursor at the end of the text displayed there. */
1032
71f65669
EZ
1033static void
1034IT_cmgoto (FRAME_PTR f)
fc171623
KH
1035{
1036 /* Only set the cursor to where it should be if the display is
1037 already in sync with the window contents. */
2d764c78
EZ
1038 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1039
1040 /* FIXME: This needs to be rewritten for the new redisplay, or
1041 removed. */
1042#if 0
06da1de1
EZ
1043 static int previous_pos_X = -1;
1044
2d764c78
EZ
1045 update_cursor_pos = 1; /* temporary!!! */
1046
06da1de1
EZ
1047 /* If the display is in sync, forget any previous knowledge about
1048 cursor position. This is primarily for unexpected events like
1049 C-g in the minibuffer. */
1050 if (update_cursor_pos && previous_pos_X >= 0)
1051 previous_pos_X = -1;
1052 /* If we are in the echo area, put the cursor at the
1053 end of the echo area message. */
fc171623
KH
1054 if (!update_cursor_pos
1055 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
1056 {
06da1de1
EZ
1057 int tem_X = current_pos_X, dummy;
1058
1059 if (echo_area_glyphs)
1060 {
1061 tem_X = echo_area_glyphs_length;
1062 /* Save current cursor position, to be restored after the
1063 echo area message is erased. Only remember one level
1064 of previous cursor position. */
1065 if (previous_pos_X == -1)
1066 ScreenGetCursor (&dummy, &previous_pos_X);
1067 }
1068 else if (previous_pos_X >= 0)
1069 {
1070 /* We wind up here after the echo area message is erased.
1071 Restore the cursor position we remembered above. */
1072 tem_X = previous_pos_X;
1073 previous_pos_X = -1;
1074 }
9a599a60 1075
06da1de1 1076 if (current_pos_X != tem_X)
9a599a60
EZ
1077 {
1078 new_pos_X = tem_X;
1079 update_cursor_pos = 1;
1080 }
fc171623 1081 }
2d764c78 1082#endif
fc171623
KH
1083
1084 if (update_cursor_pos
1085 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1086 {
1087 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1088 if (termscript)
1089 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1090 }
1091
1092 /* Maybe cursor is invisible, so make it visible. */
1093 IT_display_cursor (1);
1094
1095 /* Mouse pointer should be always visible if we are waiting for
1096 keyboard input. */
1097 if (!mouse_visible)
1098 mouse_on ();
1099}
1100
71f65669
EZ
1101static void
1102IT_reassert_line_highlight (int new, int vpos)
f32d4091
KS
1103{
1104 highlight = new;
f32d4091
KS
1105}
1106
71f65669 1107static void
c77f6f1b 1108IT_change_line_highlight (int new_highlight, int y, int vpos, int first_unused_hpos)
1b94449f 1109{
f32d4091 1110 highlight = new_highlight;
f32d4091
KS
1111 IT_cursor_to (vpos, 0);
1112 IT_clear_end_of_line (first_unused_hpos);
1113}
1114
71f65669
EZ
1115static void
1116IT_update_begin (struct frame *foo)
f32d4091
KS
1117{
1118 highlight = 0;
f32d4091
KS
1119}
1120
71f65669
EZ
1121static void
1122IT_update_end (struct frame *foo)
f32d4091
KS
1123{
1124}
1b94449f 1125
c77f6f1b
EZ
1126/* Copy LEN glyphs displayed on a single line whose vertical position
1127 is YPOS, beginning at horizontal position XFROM to horizontal
1128 position XTO, by moving blocks in the video memory. Used by
1129 functions that insert and delete glyphs. */
1130static void
1131IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1132{
1133 /* The offsets of source and destination relative to the
1134 conventional memorty selector. */
1135 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1136 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1137
1138 if (from == to || len <= 0)
1139 return;
1140
1141 _farsetsel (_dos_ds);
1142
1143 /* The source and destination might overlap, so we need to move
1144 glyphs non-destructively. */
1145 if (from > to)
1146 {
1147 for ( ; len; from += 2, to += 2, len--)
1148 _farnspokew (to, _farnspeekw (from));
1149 }
1150 else
1151 {
1152 from += (len - 1) * 2;
1153 to += (len - 1) * 2;
1154 for ( ; len; from -= 2, to -= 2, len--)
1155 _farnspokew (to, _farnspeekw (from));
1156 }
1157 if (screen_virtual_segment)
1158 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1159}
1160
1161/* Insert and delete glyphs. */
aa9ce936
EZ
1162static void
1163IT_insert_glyphs (start, len)
c77f6f1b 1164 register struct glyph *start;
aa9ce936
EZ
1165 register int len;
1166{
c77f6f1b
EZ
1167 int shift_by_width = screen_size_X - (new_pos_X + len);
1168
1169 /* Shift right the glyphs from the nominal cursor position to the
1170 end of this line. */
1171 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1172
1173 /* Now write the glyphs to be inserted. */
1174 IT_write_glyphs (start, len);
aa9ce936
EZ
1175}
1176
1177static void
1178IT_delete_glyphs (n)
1179 register int n;
1180{
1181 abort ();
1182}
1183
211c7152 1184/* set-window-configuration on window.c needs this. */
3bb1f22f
RS
1185void
1186x_set_menu_bar_lines (f, value, oldval)
1187 struct frame *f;
1188 Lisp_Object value, oldval;
1189{
211c7152
EZ
1190 set_menu_bar_lines (f, value, oldval);
1191}
3bb1f22f 1192
211c7152 1193/* This was copied from xfns.c */
3bb1f22f 1194
211c7152
EZ
1195Lisp_Object Qbackground_color;
1196Lisp_Object Qforeground_color;
1197extern Lisp_Object Qtitle;
3bb1f22f 1198
48ffe371
RS
1199/* IT_set_terminal_modes is called when emacs is started,
1200 resumed, and whenever the screen is redrawn! */
f32d4091 1201
71f65669 1202static void
f32d4091
KS
1203IT_set_terminal_modes (void)
1204{
aee81730 1205 if (termscript)
f32d4091
KS
1206 fprintf (termscript, "\n<SET_TERM>");
1207 highlight = 0;
1208
1209 screen_size_X = ScreenCols ();
1210 screen_size_Y = ScreenRows ();
1211 screen_size = screen_size_X * screen_size_Y;
aee81730 1212
f32d4091
KS
1213 new_pos_X = new_pos_Y = 0;
1214 current_pos_X = current_pos_Y = -1;
1215
1216 if (term_setup_done)
1217 return;
1218 term_setup_done = 1;
aee81730 1219
f32d4091
KS
1220 startup_screen_size_X = screen_size_X;
1221 startup_screen_size_Y = screen_size_Y;
c9adab25 1222 startup_screen_attrib = ScreenAttrib;
f32d4091 1223
039274cf
EZ
1224#if __DJGPP__ > 1
1225 /* Is DOS/V (or any other RSIS software which relocates
1226 the screen) installed? */
1227 {
1228 unsigned short es_value;
1229 __dpmi_regs regs;
1230
1231 regs.h.ah = 0xfe; /* get relocated screen address */
1232 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1233 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1234 else if (screen_old_address) /* already switched to Japanese mode once */
1235 regs.x.es = (screen_old_address >> 4) & 0xffff;
1236 else
1237 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1238 regs.x.di = 0;
1239 es_value = regs.x.es;
1240 __dpmi_int (0x10, &regs);
1241
d1d5dc19 1242 if (regs.x.es != es_value)
039274cf 1243 {
d1d5dc19
EZ
1244 /* screen_old_address is only set if ScreenPrimary does NOT
1245 already point to the relocated buffer address returned by
1246 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1247 ScreenPrimary to that address at startup under DOS/V. */
1248 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
1249 screen_old_address = ScreenPrimary;
039274cf
EZ
1250 screen_virtual_segment = regs.x.es;
1251 screen_virtual_offset = regs.x.di;
1252 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1253 }
1254 }
1255#endif /* __DJGPP__ > 1 */
1256
f32d4091
KS
1257 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1258 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1259
1260 if (termscript)
c9adab25 1261 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
039274cf 1262 screen_size_X, screen_size_Y);
76ac1508
RS
1263
1264 bright_bg ();
f32d4091
KS
1265}
1266
48ffe371
RS
1267/* IT_reset_terminal_modes is called when emacs is
1268 suspended or killed. */
f32d4091 1269
71f65669 1270static void
f32d4091
KS
1271IT_reset_terminal_modes (void)
1272{
c9adab25
KH
1273 int display_row_start = (int) ScreenPrimary;
1274 int saved_row_len = startup_screen_size_X * 2;
1275 int update_row_len = ScreenCols () * 2;
1276 int current_rows = ScreenRows ();
1277 int to_next_row = update_row_len;
1278 unsigned char *saved_row = startup_screen_buffer;
1279 int cursor_pos_X = ScreenCols () - 1;
1280 int cursor_pos_Y = ScreenRows () - 1;
1281
f32d4091 1282 if (termscript)
5063b150 1283 fprintf (termscript, "\n<RESET_TERM>");
f32d4091
KS
1284
1285 highlight = 0;
1286
1287 if (!term_setup_done)
1288 return;
1289
c9adab25 1290 mouse_off ();
b36701cc
RS
1291
1292 /* Leave the video system in the same state as we found it,
1293 as far as the blink/bright-background bit is concerned. */
1294 maybe_enable_blinking ();
06b1ea13 1295
c9adab25
KH
1296 /* We have a situation here.
1297 We cannot just do ScreenUpdate(startup_screen_buffer) because
1298 the luser could have changed screen dimensions inside Emacs
1299 and failed (or didn't want) to restore them before killing
1300 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1301 thus will happily use memory outside what was allocated for
1302 `startup_screen_buffer'.
1303 Thus we only restore as much as the current screen dimensions
1304 can hold, and clear the rest (if the saved screen is smaller than
1305 the current) with the color attribute saved at startup. The cursor
1306 is also restored within the visible dimensions. */
1307
1308 ScreenAttrib = startup_screen_attrib;
c9adab25 1309
06b1ea13
EZ
1310 /* Don't restore the screen if we are exiting less than 2 seconds
1311 after startup: we might be crashing, and the screen might show
1312 some vital clues to what's wrong. */
1313 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
c9adab25 1314 {
06b1ea13 1315 ScreenClear ();
039274cf 1316 if (screen_virtual_segment)
06b1ea13
EZ
1317 dosv_refresh_virtual_screen (0, screen_size);
1318
1319 if (update_row_len > saved_row_len)
1320 update_row_len = saved_row_len;
1321 if (current_rows > startup_screen_size_Y)
1322 current_rows = startup_screen_size_Y;
1323
1324 if (termscript)
1325 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1326 update_row_len / 2, current_rows);
1327
1328 while (current_rows--)
1329 {
1330 dosmemput (saved_row, update_row_len, display_row_start);
1331 if (screen_virtual_segment)
1332 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
1333 update_row_len / 2);
1334 saved_row += saved_row_len;
1335 display_row_start += to_next_row;
1336 }
c9adab25
KH
1337 }
1338 if (startup_pos_X < cursor_pos_X)
1339 cursor_pos_X = startup_pos_X;
1340 if (startup_pos_Y < cursor_pos_Y)
1341 cursor_pos_Y = startup_pos_Y;
1342
1343 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
1344 xfree (startup_screen_buffer);
f32d4091
KS
1345
1346 term_setup_done = 0;
1347}
1348
71f65669
EZ
1349static void
1350IT_set_terminal_window (int foo)
f32d4091
KS
1351{
1352}
1353
2d764c78
EZ
1354/* Remember the screen colors of the curent frame, to serve as the
1355 default colors for newly-created frames. */
1356
1357static int initial_screen_colors[2];
1358
1359DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
1360 Smsdos_remember_default_colors, 1, 1, 0,
1361 "Remember the screen colors of the current frame.")
1362 (frame)
1363 Lisp_Object frame;
1364{
1365 int reverse;
1366 struct frame *f;
1367
1368 CHECK_FRAME (frame, 0);
1369 f= XFRAME (frame);
1370 reverse = EQ (Fcdr (Fassq (intern ("reverse"), f->param_alist)), Qt);
1371
1372 initial_screen_colors[0]
1373 = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
1374 initial_screen_colors[1]
1375 = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
1376}
1377
f32d4091 1378void
3bb1f22f 1379IT_set_frame_parameters (f, alist)
c77f6f1b 1380 struct frame *f;
f32d4091
KS
1381 Lisp_Object alist;
1382{
1383 Lisp_Object tail;
db722735 1384 int length = XINT (Flength (alist));
2d764c78 1385 int i, j;
db722735
RS
1386 Lisp_Object *parms
1387 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1388 Lisp_Object *values
1389 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
2d764c78
EZ
1390 Lisp_Object qreverse = intern ("reverse");
1391 /* Do we have to reverse the foreground and background colors? */
1392 int reverse = EQ (Fcdr (Fassq (qreverse, f->param_alist)), Qt);
1393 int was_reverse = reverse;
1394 int redraw = 0, fg_set = 0, bg_set = 0;
1395 unsigned long orig_fg;
1396 unsigned long orig_bg;
1397
1398 /* If we are creating a new frame, begin with the original screen colors
1399 used for the initial frame. */
1400 if (alist == Vdefault_frame_alist
1401 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
1402 {
1403 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
1404 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
1405 }
1406 orig_fg = FRAME_FOREGROUND_PIXEL (f);
1407 orig_bg = FRAME_BACKGROUND_PIXEL (f);
db722735
RS
1408
1409 /* Extract parm names and values into those vectors. */
1410 i = 0;
f32d4091
KS
1411 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1412 {
db722735 1413 Lisp_Object elt;
f32d4091
KS
1414
1415 elt = Fcar (tail);
db722735
RS
1416 parms[i] = Fcar (elt);
1417 CHECK_SYMBOL (parms[i], 1);
1418 values[i] = Fcdr (elt);
1419 i++;
1420 }
1421
2d764c78 1422 j = i;
db722735 1423
2d764c78
EZ
1424 for (i = 0; i < j; i++)
1425 {
1426 Lisp_Object prop = parms[i];
1427 Lisp_Object val = values[i];
1428
1429 if (EQ (prop, qreverse))
1430 reverse = EQ (val, Qt);
1431 }
1432
1433 if (termscript && reverse && !was_reverse)
1434 fprintf (termscript, "<INVERSE-VIDEO>\n");
1435
1436 /* Now process the alist elements in reverse of specified order. */
db722735
RS
1437 for (i--; i >= 0; i--)
1438 {
1439 Lisp_Object prop = parms[i];
1440 Lisp_Object val = values[i];
f32d4091 1441
4e825084 1442 if (EQ (prop, Qforeground_color))
f32d4091 1443 {
2d764c78
EZ
1444 unsigned long new_color = load_color (f, NULL, val, reverse
1445 ? LFACE_BACKGROUND_INDEX
1446 : LFACE_FOREGROUND_INDEX);
f32d4091
KS
1447 if (new_color != ~0)
1448 {
2d764c78
EZ
1449 if (reverse)
1450 /* FIXME: should the fore-/background of the default
1451 face change here as well? */
1452 FRAME_BACKGROUND_PIXEL (f) = new_color;
1453 else
1454 FRAME_FOREGROUND_PIXEL (f) = new_color;
f32d4091 1455 redraw = 1;
2d764c78 1456 fg_set = 1;
76ac1508 1457 if (termscript)
a7cf9151 1458 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
f32d4091
KS
1459 }
1460 }
4e825084 1461 else if (EQ (prop, Qbackground_color))
f32d4091 1462 {
2d764c78
EZ
1463 unsigned long new_color = load_color (f, NULL, val, reverse
1464 ? LFACE_FOREGROUND_INDEX
1465 : LFACE_BACKGROUND_INDEX);
f32d4091
KS
1466 if (new_color != ~0)
1467 {
2d764c78
EZ
1468 if (reverse)
1469 FRAME_FOREGROUND_PIXEL (f) = new_color;
1470 else
1471 FRAME_BACKGROUND_PIXEL (f) = new_color;
f32d4091 1472 redraw = 1;
2d764c78 1473 bg_set = 1;
76ac1508 1474 if (termscript)
a7cf9151 1475 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
f32d4091
KS
1476 }
1477 }
211c7152
EZ
1478 else if (EQ (prop, Qtitle))
1479 {
1480 x_set_title (f, val);
1481 if (termscript)
1482 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
1483 }
db722735 1484 store_frame_param (f, prop, val);
2d764c78 1485 }
db722735 1486
2d764c78
EZ
1487 /* If they specified "reverse", but not the colors, we need to swap
1488 the current frame colors. */
1489 if (reverse && !was_reverse)
1490 {
1491 if (!fg_set)
1492 {
1493 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
1494 redraw = 1;
1495 }
1496 if (!bg_set)
1497 {
1498 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
1499 redraw = 1;
1500 }
f32d4091
KS
1501 }
1502
1503 if (redraw)
1504 {
2d764c78
EZ
1505 face_change_count++; /* forces xdisp.c to recompute basic faces */
1506 if (f == SELECTED_FRAME())
3bb1f22f 1507 redraw_frame (f);
f32d4091
KS
1508 }
1509}
1510
a7cf9151
EZ
1511extern void init_frame_faces (FRAME_PTR);
1512
f32d4091
KS
1513#endif /* !HAVE_X_WINDOWS */
1514
1515
48ffe371
RS
1516/* Do we need the internal terminal? */
1517
f32d4091
KS
1518void
1519internal_terminal_init ()
1520{
1521 char *term = getenv ("TERM");
1522 char *colors;
2d764c78 1523 struct frame *sf = SELECTED_FRAME();
f32d4091
KS
1524
1525#ifdef HAVE_X_WINDOWS
1526 if (!inhibit_window_system)
1527 return;
1528#endif
1529
1530 internal_terminal
1531 = (!noninteractive) && term && !strcmp (term, "internal");
1532
1533 if (getenv ("EMACSTEST"))
5063b150 1534 termscript = fopen (getenv ("EMACSTEST"), "wt");
f32d4091
KS
1535
1536#ifndef HAVE_X_WINDOWS
1537 if (!internal_terminal || inhibit_window_system)
1538 {
2d764c78 1539 sf->output_method = output_termcap;
f32d4091
KS
1540 return;
1541 }
1542
1543 Vwindow_system = intern ("pc");
1544 Vwindow_system_version = make_number (1);
2d764c78 1545 sf->output_method = output_msdos_raw;
039274cf
EZ
1546
1547 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1548 screen_old_address = 0;
1549
2d764c78
EZ
1550 /* Forget the stale screen colors as well. */
1551 initial_screen_colors[0] = initial_screen_colors[1] = -1;
1552
f32d4091
KS
1553 bzero (&the_only_x_display, sizeof the_only_x_display);
1554 the_only_x_display.background_pixel = 7; /* White */
1555 the_only_x_display.foreground_pixel = 0; /* Black */
76ac1508 1556 bright_bg ();
5063b150 1557 colors = getenv ("EMACSCOLORS");
f32d4091
KS
1558 if (colors && strlen (colors) >= 2)
1559 {
76ac1508
RS
1560 /* The colors use 4 bits each (we enable bright background). */
1561 if (isdigit (colors[0]))
1562 colors[0] -= '0';
1563 else if (isxdigit (colors[0]))
1564 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1bd7b2c7
RS
1565 if (colors[0] >= 0 && colors[0] < 16)
1566 the_only_x_display.foreground_pixel = colors[0];
76ac1508
RS
1567 if (isdigit (colors[1]))
1568 colors[1] -= '0';
1569 else if (isxdigit (colors[1]))
1570 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1571 if (colors[1] >= 0 && colors[1] < 16)
1bd7b2c7 1572 the_only_x_display.background_pixel = colors[1];
f32d4091
KS
1573 }
1574 the_only_x_display.line_height = 1;
64ec6a02 1575 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
f32d4091 1576
2d764c78 1577 init_frame_faces (sf);
f32d4091
KS
1578
1579 ring_bell_hook = IT_ring_bell;
aa9ce936
EZ
1580 insert_glyphs_hook = IT_insert_glyphs;
1581 delete_glyphs_hook = IT_delete_glyphs;
f32d4091
KS
1582 write_glyphs_hook = IT_write_glyphs;
1583 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1584 clear_to_end_hook = IT_clear_to_end;
1585 clear_end_of_line_hook = IT_clear_end_of_line;
1586 clear_frame_hook = IT_clear_screen;
1587 change_line_highlight_hook = IT_change_line_highlight;
1588 update_begin_hook = IT_update_begin;
1589 update_end_hook = IT_update_end;
1590 reassert_line_highlight_hook = IT_reassert_line_highlight;
fc171623 1591 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
f32d4091
KS
1592
1593 /* These hooks are called by term.c without being checked. */
1594 set_terminal_modes_hook = IT_set_terminal_modes;
1595 reset_terminal_modes_hook = IT_reset_terminal_modes;
1596 set_terminal_window_hook = IT_set_terminal_window;
c77f6f1b 1597 char_ins_del_ok = 0;
f32d4091
KS
1598#endif
1599}
1600
1601dos_get_saved_screen (screen, rows, cols)
1602 char **screen;
1603 int *rows;
1604 int *cols;
1605{
1606#ifndef HAVE_X_WINDOWS
1607 *screen = startup_screen_buffer;
1608 *cols = startup_screen_size_X;
1609 *rows = startup_screen_size_Y;
039274cf 1610 return *screen != (char *)0;
f32d4091
KS
1611#else
1612 return 0;
1613#endif
1614}
3bb1f22f
RS
1615
1616#ifndef HAVE_X_WINDOWS
1617
1618/* We are not X, but we can emulate it well enough for our needs... */
1619void
1620check_x (void)
1621{
2d764c78
EZ
1622 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
1623 error ("Not running under a window system");
3bb1f22f
RS
1624}
1625
1626#endif
1627
5063b150 1628\f
f32d4091
KS
1629/* ----------------------- Keyboard control ----------------------
1630 *
1631 * Keymaps reflect the following keyboard layout:
1632 *
1633 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1634 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1635 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1636 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1637 * SPACE
1638 */
1639
d1d5dc19
EZ
1640#define Ignore 0x0000
1641#define Normal 0x0000 /* normal key - alt changes scan-code */
1642#define FctKey 0x1000 /* func key if c == 0, else c */
1643#define Special 0x2000 /* func key even if c != 0 */
1644#define ModFct 0x3000 /* special if mod-keys, else 'c' */
1645#define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1646#define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1647#define Grey 0x6000 /* Grey keypad key */
1648
1649#define Alt 0x0100 /* alt scan-code */
1650#define Ctrl 0x0200 /* ctrl scan-code */
1651#define Shift 0x0400 /* shift scan-code */
1652
f32d4091
KS
1653static int extended_kbd; /* 101 (102) keyboard present. */
1654
d1d5dc19
EZ
1655struct kbd_translate {
1656 unsigned char sc;
1657 unsigned char ch;
1658 unsigned short code;
1659};
1660
f32d4091
KS
1661struct dos_keyboard_map
1662{
1663 char *unshifted;
1664 char *shifted;
1665 char *alt_gr;
d1d5dc19 1666 struct kbd_translate *translate_table;
f32d4091
KS
1667};
1668
1669
1670static struct dos_keyboard_map us_keyboard = {
1671/* 0 1 2 3 4 5 */
1672/* 01234567890123456789012345678901234567890 12345678901234 */
1673 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1674/* 0123456789012345678901234567890123456789 012345678901234 */
1675 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
d1d5dc19
EZ
1676 0, /* no Alt-Gr key */
1677 0 /* no translate table */
f32d4091
KS
1678};
1679
1680static struct dos_keyboard_map fr_keyboard = {
1681/* 0 1 2 3 4 5 */
1682/* 012 3456789012345678901234567890123456789012345678901234 */
1683