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