(setup-latin1-environment): Set code 222 in special-microsoft-code-table.
[bpt/emacs.git] / src / msdos.c
CommitLineData
9da6e765 1/* MS-DOS specific C utilities.
48ffe371 2 Copyright (C) 1993, 1994, 1995, 1996 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>
32#include <sys/param.h>
33#include <sys/time.h>
34#include <dos.h>
d21e67b5 35#include <errno.h>
a7cf9151 36#include <string.h> /* for bzero and string functions */
d21e67b5 37#include <sys/stat.h> /* for _fixpath */
a7cf9151 38#include <unistd.h> /* for chdir, dup, dup2, etc. */
1bd7b2c7
RS
39#if __DJGPP__ >= 2
40#include <fcntl.h>
a7cf9151 41#include <io.h> /* for setmode */
fc171623
KH
42#include <dpmi.h> /* for __dpmi_xxx stuff */
43#include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
d21e67b5 44#include <libc/dosio.h> /* for _USE_LFN */
a7cf9151 45#include <conio.h> /* for cputs */
1bd7b2c7
RS
46#endif
47
1b94449f
RS
48#include "dosfns.h"
49#include "msdos.h"
50#include "systime.h"
51#include "termhooks.h"
87485d6f
MW
52#include "dispextern.h"
53#include "termopts.h"
1b94449f 54#include "frame.h"
87485d6f 55#include "window.h"
fc171623
KH
56#include "buffer.h"
57#include "commands.h"
1b94449f
RS
58#include <go32.h>
59#include <pc.h>
60#include <ctype.h>
61/* #include <process.h> */
62/* Damn that local process.h! Instead we can define P_WAIT ourselves. */
63#define P_WAIT 1
64
d21e67b5
RS
65#ifndef _USE_LFN
66#define _USE_LFN 0
67#endif
68
b36701cc
RS
69#ifndef _dos_ds
70#define _dos_ds _go32_info_block.selector_for_linear_memory
71#endif
72
1bd7b2c7
RS
73#if __DJGPP__ > 1
74
8748735b 75#include <signal.h>
417a04bb 76#include "syssignal.h"
8748735b 77
1bd7b2c7
RS
78#ifndef SYSTEM_MALLOC
79
80#ifdef GNU_MALLOC
81
82/* If other `malloc' than ours is used, force our `sbrk' behave like
83 Unix programs expect (resize memory blocks to keep them contiguous).
84 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
85 because that's what `gmalloc' expects to get. */
86#include <crt0.h>
87
88#ifdef REL_ALLOC
89int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
90#else /* not REL_ALLOC */
91int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
92#endif /* not REL_ALLOC */
93#endif /* GNU_MALLOC */
94
95#endif /* not SYSTEM_MALLOC */
96#endif /* __DJGPP__ > 1 */
aee81730
RS
97
98static unsigned long
99event_timestamp ()
100{
101 struct time t;
102 unsigned long s;
f32d4091 103
aee81730
RS
104 gettime (&t);
105 s = t.ti_min;
106 s *= 60;
107 s += t.ti_sec;
108 s *= 1000;
109 s += t.ti_hund * 10;
f32d4091 110
aee81730
RS
111 return s;
112}
113
f32d4091
KS
114\f
115/* ------------------------ Mouse control ---------------------------
116 *
117 * Coordinates are in screen positions and zero based.
118 * Mouse buttons are numbered from left to right and also zero based.
119 */
1b94449f 120
f32d4091
KS
121int have_mouse; /* 0: no, 1: enabled, -1: disabled */
122static int mouse_visible;
1b94449f 123
f32d4091
KS
124static int mouse_last_x;
125static int mouse_last_y;
1b94449f 126
f32d4091
KS
127static int mouse_button_translate[NUM_MOUSE_BUTTONS];
128static int mouse_button_count;
1b94449f 129
f32d4091
KS
130void
131mouse_on ()
1b94449f 132{
1b94449f 133 union REGS regs;
1b94449f 134
f32d4091 135 if (have_mouse > 0 && !mouse_visible)
1b94449f 136 {
f32d4091
KS
137 if (termscript)
138 fprintf (termscript, "<M_ON>");
139 regs.x.ax = 0x0001;
140 int86 (0x33, &regs, &regs);
141 mouse_visible = 1;
1b94449f 142 }
1b94449f
RS
143}
144
f32d4091
KS
145void
146mouse_off ()
1b94449f 147{
f32d4091 148 union REGS regs;
1b94449f 149
f32d4091 150 if (have_mouse > 0 && mouse_visible)
1b94449f 151 {
f32d4091
KS
152 if (termscript)
153 fprintf (termscript, "<M_OFF>");
154 regs.x.ax = 0x0002;
155 int86 (0x33, &regs, &regs);
156 mouse_visible = 0;
1b94449f 157 }
1b94449f
RS
158}
159
f32d4091
KS
160void
161mouse_moveto (x, y)
162 int x, y;
1b94449f 163{
f32d4091 164 union REGS regs;
1b94449f 165
f32d4091
KS
166 if (termscript)
167 fprintf (termscript, "<M_XY=%dx%d>", x, y);
168 regs.x.ax = 0x0004;
169 mouse_last_x = regs.x.cx = x * 8;
170 mouse_last_y = regs.x.dx = y * 8;
171 int86 (0x33, &regs, &regs);
1b94449f
RS
172}
173
f32d4091
KS
174static int
175mouse_pressed (b, xp, yp)
176 int b, *xp, *yp;
1b94449f 177{
f32d4091 178 union REGS regs;
1b94449f 179
f32d4091
KS
180 if (b >= mouse_button_count)
181 return 0;
182 regs.x.ax = 0x0005;
183 regs.x.bx = mouse_button_translate[b];
184 int86 (0x33, &regs, &regs);
185 if (regs.x.bx)
186 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
187 return (regs.x.bx != 0);
1b94449f
RS
188}
189
f32d4091
KS
190static int
191mouse_released (b, xp, yp)
192 int b, *xp, *yp;
1b94449f
RS
193{
194 union REGS regs;
195
f32d4091
KS
196 if (b >= mouse_button_count)
197 return 0;
198 regs.x.ax = 0x0006;
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 void
207mouse_get_xy (int *x, int *y)
1b94449f 208{
f32d4091 209 union REGS regs;
1b94449f 210
f32d4091
KS
211 regs.x.ax = 0x0003;
212 int86 (0x33, &regs, &regs);
213 *x = regs.x.cx / 8;
214 *y = regs.x.dx / 8;
1b94449f
RS
215}
216
f32d4091
KS
217void
218mouse_get_pos (f, insist, bar_window, part, x, y, time)
219 FRAME_PTR *f;
220 int insist;
221 Lisp_Object *bar_window, *x, *y;
222 enum scroll_bar_part *part;
223 unsigned long *time;
224{
225 int ix, iy;
226 union REGS regs;
227
228 regs.x.ax = 0x0003;
229 int86 (0x33, &regs, &regs);
230 *f = selected_frame;
231 *bar_window = Qnil;
232 mouse_get_xy (&ix, &iy);
233 selected_frame->mouse_moved = 0;
234 *x = make_number (ix);
235 *y = make_number (iy);
236 *time = event_timestamp ();
237}
1b94449f 238
f32d4091
KS
239static void
240mouse_check_moved ()
1b94449f 241{
aee81730 242 int x, y;
1b94449f 243
f32d4091
KS
244 mouse_get_xy (&x, &y);
245 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
246 mouse_last_x = x;
247 mouse_last_y = y;
248}
1b94449f 249
f32d4091
KS
250void
251mouse_init ()
252{
253 union REGS regs;
647c32eb 254
f32d4091
KS
255 if (termscript)
256 fprintf (termscript, "<M_INIT>");
1b94449f 257
f32d4091
KS
258 regs.x.ax = 0x0021;
259 int86 (0x33, &regs, &regs);
091d0bdf 260
f32d4091
KS
261 regs.x.ax = 0x0007;
262 regs.x.cx = 0;
263 regs.x.dx = 8 * (ScreenCols () - 1);
264 int86 (0x33, &regs, &regs);
1b94449f 265
f32d4091
KS
266 regs.x.ax = 0x0008;
267 regs.x.cx = 0;
268 regs.x.dx = 8 * (ScreenRows () - 1);
269 int86 (0x33, &regs, &regs);
1b94449f 270
f32d4091
KS
271 mouse_moveto (0, 0);
272 mouse_visible = 0;
273}
3eb1dbb6 274\f
f32d4091
KS
275/* ------------------------- Screen control ----------------------
276 *
277 */
aee81730 278
f32d4091 279static int internal_terminal = 0;
aee81730 280
f32d4091
KS
281#ifndef HAVE_X_WINDOWS
282extern unsigned char ScreenAttrib;
283static int screen_face;
284static int highlight;
aee81730 285
f32d4091
KS
286static int screen_size_X;
287static int screen_size_Y;
288static int screen_size;
1b94449f 289
f32d4091
KS
290static int current_pos_X;
291static int current_pos_Y;
292static int new_pos_X;
293static int new_pos_Y;
1b94449f 294
f32d4091
KS
295static void *startup_screen_buffer;
296static int startup_screen_size_X;
297static int startup_screen_size_Y;
298static int startup_pos_X;
299static int startup_pos_Y;
c9adab25 300static unsigned char startup_screen_attrib;
1b94449f 301
f32d4091 302static int term_setup_done;
1b94449f 303
f32d4091 304/* Similar to the_only_frame. */
f6816f88 305struct x_output the_only_x_display;
1b94449f 306
f32d4091
KS
307/* This is never dereferenced. */
308Display *x_current_display;
1b94449f 309
f32d4091
KS
310static
311dos_direct_output (y, x, buf, len)
312 int y;
313 int x;
314 char *buf;
315 int len;
1b94449f 316{
f32d4091 317 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
fc171623
KH
318
319#if (__DJGPP__ < 2)
f32d4091
KS
320 while (--len >= 0) {
321 dosmemput (buf++, 1, t);
322 t += 2;
323 }
fc171623
KH
324#else
325 /* This is faster. */
326 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
327 _farnspokeb (t, *buf);
328#endif
1b94449f 329}
aee81730 330#endif
1b94449f 331
1b94449f
RS
332/* Flash the screen as a substitute for BEEPs. */
333
f32d4091 334#if (__DJGPP__ < 2)
49a09c76 335static void
fcea9cd4 336do_visible_bell (xorattr)
1b94449f
RS
337 unsigned char xorattr;
338{
49a09c76 339 asm volatile
ca986694 340 (" movb $1,%%dl
1b94449f 341visible_bell_0:
ca986694 342 movl _ScreenPrimary,%%eax
49a09c76 343 call dosmemsetup
ca986694
RS
344 movl %%eax,%%ebx
345 movl %1,%%ecx
346 movb %0,%%al
347 incl %%ebx
1b94449f 348visible_bell_1:
ca986694
RS
349 xorb %%al,%%gs:(%%ebx)
350 addl $2,%%ebx
351 decl %%ecx
49a09c76 352 jne visible_bell_1
ca986694 353 decb %%dl
49a09c76 354 jne visible_bell_3
1b94449f 355visible_bell_2:
ca986694
RS
356 movzwl %%ax,%%eax
357 movzwl %%ax,%%eax
358 movzwl %%ax,%%eax
359 movzwl %%ax,%%eax
360 decw %%cx
49a09c76
RS
361 jne visible_bell_2
362 jmp visible_bell_0
ca986694
RS
363visible_bell_3:"
364 : /* no output */
f32d4091 365 : "m" (xorattr), "g" (screen_size)
ca986694 366 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
1b94449f
RS
367}
368
f32d4091
KS
369static void
370ScreenVisualBell (void)
371{
372 /* This creates an xor-mask that will swap the default fore- and
373 background colors. */
374 do_visible_bell (((the_only_x_display.foreground_pixel
375 ^ the_only_x_display.background_pixel)
376 * 0x11) & 0x7f);
377}
378#endif
379
380#ifndef HAVE_X_WINDOWS
381
b36701cc
RS
382static int blink_bit = -1; /* the state of the blink bit at startup */
383
76ac1508
RS
384/* Enable bright background colors. */
385static void
386bright_bg (void)
387{
388 union REGS regs;
389
b36701cc
RS
390 /* Remember the original state of the blink/bright-background bit.
391 It is stored at 0040:0065h in the BIOS data area. */
392 if (blink_bit == -1)
393 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
394
76ac1508
RS
395 regs.h.bl = 0;
396 regs.x.ax = 0x1003;
397 int86 (0x10, &regs, &regs);
398}
399
b36701cc
RS
400/* Disable bright background colors (and enable blinking) if we found
401 the video system in that state at startup. */
402static void
403maybe_enable_blinking (void)
404{
405 if (blink_bit == 1)
406 {
407 union REGS regs;
408
409 regs.h.bl = 1;
410 regs.x.ax = 0x1003;
411 int86 (0x10, &regs, &regs);
412 }
413}
414
4a96d4d2
KH
415/* Set the screen dimensions so that it can show no less than
416 ROWS x COLS frame. */
48ffe371 417
4a96d4d2
KH
418void
419dos_set_window_size (rows, cols)
420 int *rows, *cols;
421{
422 char video_name[30];
423 Lisp_Object video_mode;
424 int video_mode_value;
425 int have_vga = 0;
426 union REGS regs;
427 int current_rows = ScreenRows (), current_cols = ScreenCols ();
428
429 if (*rows == current_rows && *cols == current_cols)
430 return;
431
432 /* Do we have a VGA? */
433 regs.x.ax = 0x1a00;
434 int86 (0x10, &regs, &regs);
435 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
436 have_vga = 1;
437
438 mouse_off ();
439
48ffe371 440 /* If the user specified a special video mode for these dimensions,
4a96d4d2
KH
441 use that mode. */
442 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
443 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
444 Qnil))-> value;
445
446 if (INTEGERP (video_mode)
447 && (video_mode_value = XINT (video_mode)) > 0)
448 {
449 regs.x.ax = video_mode_value;
450 int86 (0x10, &regs, &regs);
48ffe371
RS
451
452 if (have_mouse)
453 {
454 /* Must hardware-reset the mouse, or else it won't update
455 its notion of screen dimensions for some non-standard
456 video modes. This is *painfully* slow... */
457 regs.x.ax = 0;
458 int86 (0x33, &regs, &regs);
459 }
4a96d4d2
KH
460 }
461
462 /* Find one of the dimensions supported by standard EGA/VGA
463 which gives us at least the required dimensions. */
464
465#if __DJGPP__ > 1
466
467 else
468 {
469 static struct {
470 int rows;
471 int need_vga;
472 } std_dimension[] = {
473 {25, 0},
474 {28, 1},
475 {35, 0},
476 {40, 1},
477 {43, 0},
478 {50, 1}
479 };
480 int i = 0;
481
482 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
483 {
484 if (std_dimension[i].need_vga <= have_vga
485 && std_dimension[i].rows >= *rows)
486 {
487 if (std_dimension[i].rows != current_rows
488 || *cols != current_cols)
48ffe371 489 _set_screen_lines (std_dimension[i].rows);
4a96d4d2
KH
490 break;
491 }
48ffe371 492 i++;
4a96d4d2
KH
493 }
494 }
495
496#else /* not __DJGPP__ > 1 */
497
498 else if (*rows <= 25)
499 {
500 if (current_rows != 25 || current_cols != 80)
501 {
502 regs.x.ax = 3;
503 int86 (0x10, &regs, &regs);
504 regs.x.ax = 0x1101;
505 regs.h.bl = 0;
506 int86 (0x10, &regs, &regs);
507 regs.x.ax = 0x1200;
508 regs.h.bl = 32;
509 int86 (0x10, &regs, &regs);
510 regs.x.ax = 3;
511 int86 (0x10, &regs, &regs);
512 }
513 }
514 else if (*rows <= 50)
515 if (have_vga && (current_rows != 50 || current_cols != 80)
516 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
517 {
518 regs.x.ax = 3;
519 int86 (0x10, &regs, &regs);
520 regs.x.ax = 0x1112;
521 regs.h.bl = 0;
522 int86 (0x10, &regs, &regs);
523 regs.x.ax = 0x1200;
524 regs.h.bl = 32;
525 int86 (0x10, &regs, &regs);
526 regs.x.ax = 0x0100;
527 regs.x.cx = 7;
528 int86 (0x10, &regs, &regs);
529 }
530#endif /* not __DJGPP__ > 1 */
531
532 if (have_mouse)
533 {
4a96d4d2
KH
534 mouse_init ();
535 mouse_on ();
536 }
537
538 /* Tell the caller what dimensions have been REALLY set. */
539 *rows = ScreenRows ();
540 *cols = ScreenCols ();
76ac1508
RS
541
542 /* Enable bright background colors. */
543 bright_bg ();
4a96d4d2
KH
544}
545
48ffe371
RS
546/* If we write a character in the position where the mouse is,
547 the mouse cursor may need to be refreshed. */
09e2ac30
RS
548
549static void
f32d4091 550mouse_off_maybe ()
09e2ac30 551{
f32d4091
KS
552 int x, y;
553
554 if (!mouse_visible)
555 return;
556
557 mouse_get_xy (&x, &y);
558 if (y != new_pos_Y || x < new_pos_X)
559 return;
560
561 mouse_off ();
562}
563
564static
565IT_ring_bell ()
566{
567 if (visible_bell)
aee81730 568 {
f32d4091
KS
569 mouse_off ();
570 ScreenVisualBell ();
aee81730 571 }
f32d4091 572 else
3635be47
RS
573 {
574 union REGS inregs, outregs;
575 inregs.h.ah = 2;
576 inregs.h.dl = 7;
577 intdos (&inregs, &outregs);
578 }
09e2ac30
RS
579}
580
f32d4091
KS
581static void
582IT_set_face (int face)
583{
584 struct face *fp;
585 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
586
587 if (face == 1 || (face == 0 && highlight))
588 fp = FRAME_MODE_LINE_FACE (foo);
589 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
590 fp = FRAME_DEFAULT_FACE (foo);
591 else
592 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
593 if (termscript)
594 fprintf (termscript, "<FACE:%d:%d>", FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
595 screen_face = face;
596 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
597}
598
599static
600IT_write_glyphs (GLYPH *str, int len)
601{
602 int newface;
603 int ch, l = len;
604 unsigned char *buf, *bp;
87485d6f 605
f32d4091 606 if (len == 0) return;
aee81730 607
f32d4091 608 buf = bp = alloca (len * 2);
aee81730 609
f32d4091 610 while (--l >= 0)
aee81730 611 {
f32d4091
KS
612 newface = FAST_GLYPH_FACE (*str);
613 if (newface != screen_face)
614 IT_set_face (newface);
615 ch = FAST_GLYPH_CHAR (*str);
616 *bp++ = (unsigned char)ch;
617 *bp++ = ScreenAttrib;
618
619 if (termscript)
620 fputc (ch, termscript);
621 str++;
aee81730
RS
622 }
623
f32d4091
KS
624 mouse_off_maybe ();
625 dosmemput (buf, 2 * len,
626 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
627 new_pos_X += len;
628}
aee81730 629
f32d4091
KS
630static
631IT_clear_end_of_line (first_unused)
632{
633 char *spaces, *sp;
634 int i, j;
635
636 IT_set_face (0);
637 if (termscript)
638 fprintf (termscript, "<CLR:EOL>");
639 i = (j = screen_size_X - new_pos_X) * 2;
640 spaces = sp = alloca (i);
aee81730 641
f32d4091 642 while (--j >= 0)
aee81730 643 {
f32d4091
KS
644 *sp++ = ' ';
645 *sp++ = ScreenAttrib;
aee81730
RS
646 }
647
f32d4091
KS
648 mouse_off_maybe ();
649 dosmemput (spaces, i,
650 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
aee81730
RS
651}
652
f32d4091
KS
653static
654IT_clear_screen (void)
655{
656 if (termscript)
657 fprintf (termscript, "<CLR:SCR>");
658 IT_set_face (0);
659 mouse_off ();
660 ScreenClear ();
661 new_pos_X = new_pos_Y = 0;
662}
663
664static
665IT_clear_to_end (void)
666{
667 if (termscript)
668 fprintf (termscript, "<CLR:EOS>");
669
670 while (new_pos_Y < screen_size_Y) {
671 new_pos_X = 0;
672 IT_clear_end_of_line (0);
673 new_pos_Y++;
674 }
675}
676
677static
678IT_cursor_to (int y, int x)
679{
680 if (termscript)
681 fprintf (termscript, "\n<XY=%dx%d>", x, y);
682 new_pos_X = x;
683 new_pos_Y = y;
684}
685
fc171623
KH
686static int cursor_cleared;
687
688static
689IT_display_cursor (int on)
690{
691 if (on && cursor_cleared)
692 {
693 ScreenSetCursor (current_pos_Y, current_pos_X);
694 cursor_cleared = 0;
695 }
696 else if (!on && !cursor_cleared)
697 {
698 ScreenSetCursor (-1, -1);
699 cursor_cleared = 1;
700 }
701}
702
703/* Emacs calls cursor-movement functions a lot when it updates the
704 display (probably a legacy of old terminals where you cannot
705 update a screen line without first moving the cursor there).
706 However, cursor movement is expensive on MSDOS (it calls a slow
707 BIOS function and requires 2 mode switches), while actual screen
708 updates access the video memory directly and don't depend on
709 cursor position. To avoid slowing down the redisplay, we cheat:
710 all functions that move the cursor only set internal variables
711 which record the cursor position, whereas the cursor is only
712 moved to its final position whenever screen update is complete.
713
714 `IT_cmgoto' is called from the keyboard reading loop and when the
715 frame update is complete. This means that we are ready for user
716 input, so we update the cursor position to show where the point is,
717 and also make the mouse pointer visible.
718
719 Special treatment is required when the cursor is in the echo area,
720 to put the cursor at the end of the text displayed there. */
721
722static
723IT_cmgoto (f)
724 FRAME_PTR f;
725{
726 /* Only set the cursor to where it should be if the display is
727 already in sync with the window contents. */
728 int update_cursor_pos = MODIFF == unchanged_modified;
729
730 /* If we are in the echo area, put the cursor at the end of text. */
731 if (!update_cursor_pos
732 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
733 {
734 new_pos_X = FRAME_DESIRED_GLYPHS (f)->used[new_pos_Y];
fc171623
KH
735 update_cursor_pos = 1;
736 }
737
738 if (update_cursor_pos
739 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
740 {
741 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
742 if (termscript)
743 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
744 }
745
746 /* Maybe cursor is invisible, so make it visible. */
747 IT_display_cursor (1);
748
749 /* Mouse pointer should be always visible if we are waiting for
750 keyboard input. */
751 if (!mouse_visible)
752 mouse_on ();
753}
754
f32d4091
KS
755static
756IT_reassert_line_highlight (new, vpos)
757 int new, vpos;
758{
759 highlight = new;
760 IT_set_face (0); /* To possibly clear the highlighting. */
761}
762
763static
764IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
1b94449f 765{
f32d4091
KS
766 highlight = new_highlight;
767 IT_set_face (0); /* To possibly clear the highlighting. */
768 IT_cursor_to (vpos, 0);
769 IT_clear_end_of_line (first_unused_hpos);
770}
771
772static
773IT_update_begin ()
774{
775 highlight = 0;
776 IT_set_face (0); /* To possibly clear the highlighting. */
777 screen_face = -1;
778}
779
780static
781IT_update_end ()
782{
783}
1b94449f 784
3bb1f22f
RS
785/* This was more or less copied from xterm.c
786
787 Nowadays, the corresponding function under X is `x_set_menu_bar_lines_1'
788 on xfns.c */
48ffe371 789
f32d4091
KS
790static void
791IT_set_menu_bar_lines (window, n)
48ffe371
RS
792 Lisp_Object window;
793 int n;
f32d4091
KS
794{
795 struct window *w = XWINDOW (window);
796
9a166e40 797 XSETFASTINT (w->last_modified, 0);
3280297a 798 XSETFASTINT (w->last_overlay_modified, 0);
f32d4091
KS
799 XSETFASTINT (w->top, XFASTINT (w->top) + n);
800 XSETFASTINT (w->height, XFASTINT (w->height) - n);
801
802 /* Handle just the top child in a vertical split. */
803 if (!NILP (w->vchild))
804 IT_set_menu_bar_lines (w->vchild, n);
805
806 /* Adjust all children in a horizontal split. */
807 for (window = w->hchild; !NILP (window); window = w->next)
1b94449f 808 {
f32d4091
KS
809 w = XWINDOW (window);
810 IT_set_menu_bar_lines (window, n);
aee81730 811 }
f32d4091
KS
812}
813
3bb1f22f
RS
814/* This was copied from xfns.c */
815
e9fbf17c
RS
816Lisp_Object Qbackground_color;
817Lisp_Object Qforeground_color;
818
3bb1f22f
RS
819void
820x_set_menu_bar_lines (f, value, oldval)
821 struct frame *f;
822 Lisp_Object value, oldval;
823{
824 int nlines;
825 int olines = FRAME_MENU_BAR_LINES (f);
826
827 /* Right now, menu bars don't work properly in minibuf-only frames;
828 most of the commands try to apply themselves to the minibuffer
829 frame itslef, and get an error because you can't switch buffers
830 in or split the minibuffer window. */
831 if (FRAME_MINIBUF_ONLY_P (f))
832 return;
833
834 if (INTEGERP (value))
835 nlines = XINT (value);
836 else
837 nlines = 0;
838
839 FRAME_MENU_BAR_LINES (f) = nlines;
840 IT_set_menu_bar_lines (f->root_window, nlines - olines);
841}
842
48ffe371
RS
843/* IT_set_terminal_modes is called when emacs is started,
844 resumed, and whenever the screen is redrawn! */
f32d4091
KS
845
846static
847IT_set_terminal_modes (void)
848{
aee81730 849 if (termscript)
f32d4091
KS
850 fprintf (termscript, "\n<SET_TERM>");
851 highlight = 0;
852
853 screen_size_X = ScreenCols ();
854 screen_size_Y = ScreenRows ();
855 screen_size = screen_size_X * screen_size_Y;
aee81730 856
f32d4091
KS
857 new_pos_X = new_pos_Y = 0;
858 current_pos_X = current_pos_Y = -1;
859
860 if (term_setup_done)
861 return;
862 term_setup_done = 1;
aee81730 863
f32d4091
KS
864 startup_screen_size_X = screen_size_X;
865 startup_screen_size_Y = screen_size_Y;
c9adab25 866 startup_screen_attrib = ScreenAttrib;
f32d4091
KS
867
868 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
869 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
870
871 if (termscript)
c9adab25
KH
872 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
873 screen_size_X, screen_size_Y);
76ac1508
RS
874
875 bright_bg ();
f32d4091
KS
876}
877
48ffe371
RS
878/* IT_reset_terminal_modes is called when emacs is
879 suspended or killed. */
f32d4091
KS
880
881static
882IT_reset_terminal_modes (void)
883{
c9adab25
KH
884 int display_row_start = (int) ScreenPrimary;
885 int saved_row_len = startup_screen_size_X * 2;
886 int update_row_len = ScreenCols () * 2;
887 int current_rows = ScreenRows ();
888 int to_next_row = update_row_len;
889 unsigned char *saved_row = startup_screen_buffer;
890 int cursor_pos_X = ScreenCols () - 1;
891 int cursor_pos_Y = ScreenRows () - 1;
892
f32d4091 893 if (termscript)
5063b150 894 fprintf (termscript, "\n<RESET_TERM>");
f32d4091
KS
895
896 highlight = 0;
897
898 if (!term_setup_done)
899 return;
900
c9adab25 901 mouse_off ();
b36701cc
RS
902
903 /* Leave the video system in the same state as we found it,
904 as far as the blink/bright-background bit is concerned. */
905 maybe_enable_blinking ();
c9adab25
KH
906
907 /* We have a situation here.
908 We cannot just do ScreenUpdate(startup_screen_buffer) because
909 the luser could have changed screen dimensions inside Emacs
910 and failed (or didn't want) to restore them before killing
911 Emacs. ScreenUpdate() uses the *current* screen dimensions and
912 thus will happily use memory outside what was allocated for
913 `startup_screen_buffer'.
914 Thus we only restore as much as the current screen dimensions
915 can hold, and clear the rest (if the saved screen is smaller than
916 the current) with the color attribute saved at startup. The cursor
917 is also restored within the visible dimensions. */
918
919 ScreenAttrib = startup_screen_attrib;
920 ScreenClear ();
921
922 if (update_row_len > saved_row_len)
923 update_row_len = saved_row_len;
924 if (current_rows > startup_screen_size_Y)
925 current_rows = startup_screen_size_Y;
f32d4091
KS
926
927 if (termscript)
c9adab25
KH
928 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
929 update_row_len / 2, current_rows);
930
931 while (current_rows--)
932 {
933 dosmemput (saved_row, update_row_len, display_row_start);
934 saved_row += saved_row_len;
935 display_row_start += to_next_row;
936 }
937 if (startup_pos_X < cursor_pos_X)
938 cursor_pos_X = startup_pos_X;
939 if (startup_pos_Y < cursor_pos_Y)
940 cursor_pos_Y = startup_pos_Y;
941
942 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
943 xfree (startup_screen_buffer);
f32d4091
KS
944
945 term_setup_done = 0;
946}
947
948static
949IT_set_terminal_window (void)
950{
951}
952
953void
3bb1f22f
RS
954IT_set_frame_parameters (f, alist)
955 FRAME_PTR f;
f32d4091
KS
956 Lisp_Object alist;
957{
958 Lisp_Object tail;
959 int redraw;
960 extern unsigned long load_color ();
f32d4091
KS
961
962 redraw = 0;
963 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
964 {
965 Lisp_Object elt, prop, val;
966
967 elt = Fcar (tail);
968 prop = Fcar (elt);
969 val = Fcdr (elt);
970 CHECK_SYMBOL (prop, 1);
971
972 if (EQ (prop, intern ("foreground-color")))
973 {
974 unsigned long new_color = load_color (f, val);
975 if (new_color != ~0)
976 {
977 FRAME_FOREGROUND_PIXEL (f) = new_color;
978 redraw = 1;
76ac1508 979 if (termscript)
a7cf9151 980 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
f32d4091
KS
981 }
982 }
983 else if (EQ (prop, intern ("background-color")))
984 {
985 unsigned long new_color = load_color (f, val);
986 if (new_color != ~0)
987 {
76ac1508 988 FRAME_BACKGROUND_PIXEL (f) = new_color;
f32d4091 989 redraw = 1;
76ac1508 990 if (termscript)
a7cf9151 991 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
f32d4091
KS
992 }
993 }
994 else if (EQ (prop, intern ("menu-bar-lines")))
3bb1f22f 995 x_set_menu_bar_lines (f, val, 0);
f32d4091
KS
996 }
997
998 if (redraw)
999 {
a7cf9151
EZ
1000 extern void recompute_basic_faces (FRAME_PTR);
1001 extern void redraw_frame (FRAME_PTR);
1002
f32d4091 1003 recompute_basic_faces (f);
3bb1f22f
RS
1004 if (f == selected_frame)
1005 redraw_frame (f);
f32d4091
KS
1006 }
1007}
1008
a7cf9151
EZ
1009extern void init_frame_faces (FRAME_PTR);
1010
f32d4091
KS
1011#endif /* !HAVE_X_WINDOWS */
1012
1013
48ffe371
RS
1014/* Do we need the internal terminal? */
1015
f32d4091
KS
1016void
1017internal_terminal_init ()
1018{
1019 char *term = getenv ("TERM");
1020 char *colors;
1021
1022#ifdef HAVE_X_WINDOWS
1023 if (!inhibit_window_system)
1024 return;
1025#endif
1026
1027 internal_terminal
1028 = (!noninteractive) && term && !strcmp (term, "internal");
1029
1030 if (getenv ("EMACSTEST"))
5063b150 1031 termscript = fopen (getenv ("EMACSTEST"), "wt");
f32d4091
KS
1032
1033#ifndef HAVE_X_WINDOWS
1034 if (!internal_terminal || inhibit_window_system)
1035 {
3bb1f22f 1036 selected_frame->output_method = output_termcap;
f32d4091
KS
1037 return;
1038 }
1039
1040 Vwindow_system = intern ("pc");
1041 Vwindow_system_version = make_number (1);
1042
1043 bzero (&the_only_x_display, sizeof the_only_x_display);
1044 the_only_x_display.background_pixel = 7; /* White */
1045 the_only_x_display.foreground_pixel = 0; /* Black */
76ac1508 1046 bright_bg ();
5063b150 1047 colors = getenv ("EMACSCOLORS");
f32d4091
KS
1048 if (colors && strlen (colors) >= 2)
1049 {
76ac1508
RS
1050 /* The colors use 4 bits each (we enable bright background). */
1051 if (isdigit (colors[0]))
1052 colors[0] -= '0';
1053 else if (isxdigit (colors[0]))
1054 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1bd7b2c7
RS
1055 if (colors[0] >= 0 && colors[0] < 16)
1056 the_only_x_display.foreground_pixel = colors[0];
76ac1508
RS
1057 if (isdigit (colors[1]))
1058 colors[1] -= '0';
1059 else if (isxdigit (colors[1]))
1060 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1061 if (colors[1] >= 0 && colors[1] < 16)
1bd7b2c7 1062 the_only_x_display.background_pixel = colors[1];
f32d4091
KS
1063 }
1064 the_only_x_display.line_height = 1;
64ec6a02 1065 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
f32d4091 1066
3bb1f22f 1067 init_frame_faces (selected_frame);
f32d4091
KS
1068
1069 ring_bell_hook = IT_ring_bell;
1070 write_glyphs_hook = IT_write_glyphs;
1071 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1072 clear_to_end_hook = IT_clear_to_end;
1073 clear_end_of_line_hook = IT_clear_end_of_line;
1074 clear_frame_hook = IT_clear_screen;
1075 change_line_highlight_hook = IT_change_line_highlight;
1076 update_begin_hook = IT_update_begin;
1077 update_end_hook = IT_update_end;
1078 reassert_line_highlight_hook = IT_reassert_line_highlight;
fc171623 1079 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
f32d4091
KS
1080
1081 /* These hooks are called by term.c without being checked. */
1082 set_terminal_modes_hook = IT_set_terminal_modes;
1083 reset_terminal_modes_hook = IT_reset_terminal_modes;
1084 set_terminal_window_hook = IT_set_terminal_window;
1085#endif
1086}
1087
1088dos_get_saved_screen (screen, rows, cols)
1089 char **screen;
1090 int *rows;
1091 int *cols;
1092{
1093#ifndef HAVE_X_WINDOWS
1094 *screen = startup_screen_buffer;
1095 *cols = startup_screen_size_X;
1096 *rows = startup_screen_size_Y;
1097 return 1;
1098#else
1099 return 0;
1100#endif
1101}
3bb1f22f
RS
1102
1103#ifndef HAVE_X_WINDOWS
1104
1105/* We are not X, but we can emulate it well enough for our needs... */
1106void
1107check_x (void)
1108{
1109 if (! FRAME_MSDOS_P (selected_frame))
1110 error ("Not running under a windows system");
1111}
1112
1113#endif
1114
5063b150 1115\f
f32d4091
KS
1116/* ----------------------- Keyboard control ----------------------
1117 *
1118 * Keymaps reflect the following keyboard layout:
1119 *
1120 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1121 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1122 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1123 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1124 * SPACE
1125 */
1126
1127static int extended_kbd; /* 101 (102) keyboard present. */
1128
1129struct dos_keyboard_map
1130{
1131 char *unshifted;
1132 char *shifted;
1133 char *alt_gr;
1134};
1135
1136
1137static struct dos_keyboard_map us_keyboard = {
1138/* 0 1 2 3 4 5 */
1139/* 01234567890123456789012345678901234567890 12345678901234 */
1140 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1141/* 0123456789012345678901234567890123456789 012345678901234 */
1142 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1143 0 /* no Alt-Gr key */
1144};
1145
1146static struct dos_keyboard_map fr_keyboard = {
1147/* 0 1 2 3 4 5 */
1148/* 012 3456789012345678901234567890123456789012345678901234 */
1149