(fix_submap_inheritance, get_keyelt, store_in_keymap,
[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>
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
211c7152
EZ
160static void
161mouse_get_xy (int *x, int *y)
162{
163 union REGS regs;
164
165 regs.x.ax = 0x0003;
166 int86 (0x33, &regs, &regs);
167 *x = regs.x.cx / 8;
168 *y = regs.x.dx / 8;
169}
170
f32d4091
KS
171void
172mouse_moveto (x, y)
173 int x, y;
1b94449f 174{
f32d4091 175 union REGS regs;
1b94449f 176
f32d4091
KS
177 if (termscript)
178 fprintf (termscript, "<M_XY=%dx%d>", x, y);
179 regs.x.ax = 0x0004;
180 mouse_last_x = regs.x.cx = x * 8;
181 mouse_last_y = regs.x.dx = y * 8;
182 int86 (0x33, &regs, &regs);
1b94449f
RS
183}
184
f32d4091
KS
185static int
186mouse_pressed (b, xp, yp)
187 int b, *xp, *yp;
1b94449f 188{
f32d4091 189 union REGS regs;
1b94449f 190
f32d4091
KS
191 if (b >= mouse_button_count)
192 return 0;
193 regs.x.ax = 0x0005;
194 regs.x.bx = mouse_button_translate[b];
195 int86 (0x33, &regs, &regs);
196 if (regs.x.bx)
197 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
198 return (regs.x.bx != 0);
1b94449f
RS
199}
200
f32d4091
KS
201static int
202mouse_released (b, xp, yp)
203 int b, *xp, *yp;
1b94449f
RS
204{
205 union REGS regs;
206
f32d4091
KS
207 if (b >= mouse_button_count)
208 return 0;
209 regs.x.ax = 0x0006;
210 regs.x.bx = mouse_button_translate[b];
211 int86 (0x33, &regs, &regs);
212 if (regs.x.bx)
213 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
214 return (regs.x.bx != 0);
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;
211c7152
EZ
226 Lisp_Object frame, tail;
227
228 /* Clear the mouse-moved flag for every frame on this display. */
229 FOR_EACH_FRAME (tail, frame)
230 XFRAME (frame)->mouse_moved = 0;
f32d4091 231
f32d4091
KS
232 *f = selected_frame;
233 *bar_window = Qnil;
234 mouse_get_xy (&ix, &iy);
f32d4091 235 *time = event_timestamp ();
211c7152
EZ
236 *x = make_number (mouse_last_x = ix);
237 *y = make_number (mouse_last_y = iy);
f32d4091 238}
1b94449f 239
f32d4091
KS
240static void
241mouse_check_moved ()
1b94449f 242{
aee81730 243 int x, y;
1b94449f 244
f32d4091
KS
245 mouse_get_xy (&x, &y);
246 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
247 mouse_last_x = x;
248 mouse_last_y = y;
249}
1b94449f 250
f32d4091
KS
251void
252mouse_init ()
253{
254 union REGS regs;
647c32eb 255
f32d4091
KS
256 if (termscript)
257 fprintf (termscript, "<M_INIT>");
1b94449f 258
f32d4091
KS
259 regs.x.ax = 0x0021;
260 int86 (0x33, &regs, &regs);
091d0bdf 261
f32d4091
KS
262 regs.x.ax = 0x0007;
263 regs.x.cx = 0;
264 regs.x.dx = 8 * (ScreenCols () - 1);
265 int86 (0x33, &regs, &regs);
1b94449f 266
f32d4091
KS
267 regs.x.ax = 0x0008;
268 regs.x.cx = 0;
269 regs.x.dx = 8 * (ScreenRows () - 1);
270 int86 (0x33, &regs, &regs);
1b94449f 271
f32d4091
KS
272 mouse_moveto (0, 0);
273 mouse_visible = 0;
274}
3eb1dbb6 275\f
f32d4091
KS
276/* ------------------------- Screen control ----------------------
277 *
278 */
aee81730 279
f32d4091 280static int internal_terminal = 0;
aee81730 281
f32d4091
KS
282#ifndef HAVE_X_WINDOWS
283extern unsigned char ScreenAttrib;
284static int screen_face;
285static int highlight;
aee81730 286
f32d4091
KS
287static int screen_size_X;
288static int screen_size_Y;
289static int screen_size;
1b94449f 290
f32d4091
KS
291static int current_pos_X;
292static int current_pos_Y;
293static int new_pos_X;
294static int new_pos_Y;
1b94449f 295
f32d4091
KS
296static void *startup_screen_buffer;
297static int startup_screen_size_X;
298static int startup_screen_size_Y;
299static int startup_pos_X;
300static int startup_pos_Y;
c9adab25 301static unsigned char startup_screen_attrib;
1b94449f 302
f32d4091 303static int term_setup_done;
1b94449f 304
f32d4091 305/* Similar to the_only_frame. */
f6816f88 306struct x_output the_only_x_display;
1b94449f 307
f32d4091
KS
308/* This is never dereferenced. */
309Display *x_current_display;
1b94449f 310
039274cf
EZ
311/* Support for DOS/V (allows Japanese characters to be displayed on
312 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
313
314/* Holds the address of the text-mode screen buffer. */
315static unsigned long screen_old_address = 0;
316/* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
317static unsigned short screen_virtual_segment = 0;
318static unsigned short screen_virtual_offset = 0;
319
320#if __DJGPP__ > 1
321/* Update the screen from a part of relocated DOS/V screen buffer which
322 begins at OFFSET and includes COUNT characters. */
323static void
324dosv_refresh_virtual_screen (int offset, int count)
325{
326 __dpmi_regs regs;
327
328 regs.h.ah = 0xff; /* update relocated screen */
329 regs.x.es = screen_virtual_segment;
330 regs.x.di = screen_virtual_offset + offset;
331 regs.x.cx = count;
332 __dpmi_int (0x10, &regs);
333}
334#endif
335
f32d4091
KS
336static
337dos_direct_output (y, x, buf, len)
338 int y;
339 int x;
340 char *buf;
341 int len;
1b94449f 342{
f32d4091 343 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
039274cf
EZ
344 int t0 = t;
345 int l0 = len;
fc171623
KH
346
347#if (__DJGPP__ < 2)
f32d4091
KS
348 while (--len >= 0) {
349 dosmemput (buf++, 1, t);
350 t += 2;
351 }
fc171623
KH
352#else
353 /* This is faster. */
354 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
355 _farnspokeb (t, *buf);
039274cf
EZ
356
357 if (screen_virtual_segment)
358 dosv_refresh_virtual_screen (t0, l0);
fc171623 359#endif
1b94449f 360}
aee81730 361#endif
1b94449f 362
1b94449f
RS
363/* Flash the screen as a substitute for BEEPs. */
364
f32d4091 365#if (__DJGPP__ < 2)
49a09c76 366static void
fcea9cd4 367do_visible_bell (xorattr)
1b94449f
RS
368 unsigned char xorattr;
369{
49a09c76 370 asm volatile
ca986694 371 (" movb $1,%%dl
1b94449f 372visible_bell_0:
ca986694 373 movl _ScreenPrimary,%%eax
49a09c76 374 call dosmemsetup
ca986694
RS
375 movl %%eax,%%ebx
376 movl %1,%%ecx
377 movb %0,%%al
378 incl %%ebx
1b94449f 379visible_bell_1:
ca986694
RS
380 xorb %%al,%%gs:(%%ebx)
381 addl $2,%%ebx
382 decl %%ecx
49a09c76 383 jne visible_bell_1
ca986694 384 decb %%dl
49a09c76 385 jne visible_bell_3
1b94449f 386visible_bell_2:
ca986694
RS
387 movzwl %%ax,%%eax
388 movzwl %%ax,%%eax
389 movzwl %%ax,%%eax
390 movzwl %%ax,%%eax
391 decw %%cx
49a09c76
RS
392 jne visible_bell_2
393 jmp visible_bell_0
ca986694
RS
394visible_bell_3:"
395 : /* no output */
f32d4091 396 : "m" (xorattr), "g" (screen_size)
ca986694 397 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
1b94449f
RS
398}
399
f32d4091
KS
400static void
401ScreenVisualBell (void)
402{
403 /* This creates an xor-mask that will swap the default fore- and
404 background colors. */
405 do_visible_bell (((the_only_x_display.foreground_pixel
406 ^ the_only_x_display.background_pixel)
407 * 0x11) & 0x7f);
408}
409#endif
410
411#ifndef HAVE_X_WINDOWS
412
b36701cc
RS
413static int blink_bit = -1; /* the state of the blink bit at startup */
414
76ac1508
RS
415/* Enable bright background colors. */
416static void
417bright_bg (void)
418{
419 union REGS regs;
420
b36701cc
RS
421 /* Remember the original state of the blink/bright-background bit.
422 It is stored at 0040:0065h in the BIOS data area. */
423 if (blink_bit == -1)
424 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
425
76ac1508
RS
426 regs.h.bl = 0;
427 regs.x.ax = 0x1003;
428 int86 (0x10, &regs, &regs);
429}
430
b36701cc
RS
431/* Disable bright background colors (and enable blinking) if we found
432 the video system in that state at startup. */
433static void
434maybe_enable_blinking (void)
435{
436 if (blink_bit == 1)
437 {
438 union REGS regs;
439
440 regs.h.bl = 1;
441 regs.x.ax = 0x1003;
442 int86 (0x10, &regs, &regs);
443 }
444}
445
4a96d4d2
KH
446/* Set the screen dimensions so that it can show no less than
447 ROWS x COLS frame. */
48ffe371 448
4a96d4d2
KH
449void
450dos_set_window_size (rows, cols)
451 int *rows, *cols;
452{
453 char video_name[30];
454 Lisp_Object video_mode;
455 int video_mode_value;
456 int have_vga = 0;
457 union REGS regs;
458 int current_rows = ScreenRows (), current_cols = ScreenCols ();
459
460 if (*rows == current_rows && *cols == current_cols)
461 return;
462
463 /* Do we have a VGA? */
464 regs.x.ax = 0x1a00;
465 int86 (0x10, &regs, &regs);
466 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
467 have_vga = 1;
468
469 mouse_off ();
470
48ffe371 471 /* If the user specified a special video mode for these dimensions,
4a96d4d2
KH
472 use that mode. */
473 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
474 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
475 Qnil))-> value;
476
477 if (INTEGERP (video_mode)
478 && (video_mode_value = XINT (video_mode)) > 0)
479 {
480 regs.x.ax = video_mode_value;
481 int86 (0x10, &regs, &regs);
48ffe371
RS
482
483 if (have_mouse)
484 {
485 /* Must hardware-reset the mouse, or else it won't update
486 its notion of screen dimensions for some non-standard
487 video modes. This is *painfully* slow... */
488 regs.x.ax = 0;
489 int86 (0x33, &regs, &regs);
490 }
4a96d4d2
KH
491 }
492
493 /* Find one of the dimensions supported by standard EGA/VGA
494 which gives us at least the required dimensions. */
495
496#if __DJGPP__ > 1
497
498 else
499 {
500 static struct {
501 int rows;
502 int need_vga;
503 } std_dimension[] = {
504 {25, 0},
505 {28, 1},
506 {35, 0},
507 {40, 1},
508 {43, 0},
509 {50, 1}
510 };
511 int i = 0;
512
513 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
514 {
515 if (std_dimension[i].need_vga <= have_vga
516 && std_dimension[i].rows >= *rows)
517 {
518 if (std_dimension[i].rows != current_rows
519 || *cols != current_cols)
48ffe371 520 _set_screen_lines (std_dimension[i].rows);
4a96d4d2
KH
521 break;
522 }
48ffe371 523 i++;
4a96d4d2
KH
524 }
525 }
526
527#else /* not __DJGPP__ > 1 */
528
529 else if (*rows <= 25)
530 {
531 if (current_rows != 25 || current_cols != 80)
532 {
533 regs.x.ax = 3;
534 int86 (0x10, &regs, &regs);
535 regs.x.ax = 0x1101;
536 regs.h.bl = 0;
537 int86 (0x10, &regs, &regs);
538 regs.x.ax = 0x1200;
539 regs.h.bl = 32;
540 int86 (0x10, &regs, &regs);
541 regs.x.ax = 3;
542 int86 (0x10, &regs, &regs);
543 }
544 }
545 else if (*rows <= 50)
546 if (have_vga && (current_rows != 50 || current_cols != 80)
547 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
548 {
549 regs.x.ax = 3;
550 int86 (0x10, &regs, &regs);
551 regs.x.ax = 0x1112;
552 regs.h.bl = 0;
553 int86 (0x10, &regs, &regs);
554 regs.x.ax = 0x1200;
555 regs.h.bl = 32;
556 int86 (0x10, &regs, &regs);
557 regs.x.ax = 0x0100;
558 regs.x.cx = 7;
559 int86 (0x10, &regs, &regs);
560 }
561#endif /* not __DJGPP__ > 1 */
562
563 if (have_mouse)
564 {
4a96d4d2
KH
565 mouse_init ();
566 mouse_on ();
567 }
568
569 /* Tell the caller what dimensions have been REALLY set. */
570 *rows = ScreenRows ();
571 *cols = ScreenCols ();
76ac1508
RS
572
573 /* Enable bright background colors. */
574 bright_bg ();
039274cf
EZ
575
576 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
577 be defensive anyway. */
578 if (screen_virtual_segment)
579 dosv_refresh_virtual_screen (0, *cols * *rows);
4a96d4d2
KH
580}
581
48ffe371
RS
582/* If we write a character in the position where the mouse is,
583 the mouse cursor may need to be refreshed. */
09e2ac30
RS
584
585static void
f32d4091 586mouse_off_maybe ()
09e2ac30 587{
f32d4091
KS
588 int x, y;
589
590 if (!mouse_visible)
591 return;
592
593 mouse_get_xy (&x, &y);
594 if (y != new_pos_Y || x < new_pos_X)
595 return;
596
597 mouse_off ();
598}
599
600static
601IT_ring_bell ()
602{
603 if (visible_bell)
aee81730 604 {
f32d4091
KS
605 mouse_off ();
606 ScreenVisualBell ();
aee81730 607 }
f32d4091 608 else
3635be47
RS
609 {
610 union REGS inregs, outregs;
611 inregs.h.ah = 2;
612 inregs.h.dl = 7;
613 intdos (&inregs, &outregs);
614 }
09e2ac30
RS
615}
616
f32d4091
KS
617static void
618IT_set_face (int face)
619{
620 struct face *fp;
621 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
622
623 if (face == 1 || (face == 0 && highlight))
624 fp = FRAME_MODE_LINE_FACE (foo);
625 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
626 fp = FRAME_DEFAULT_FACE (foo);
627 else
628 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
629 if (termscript)
5d7e8345
RS
630 fprintf (termscript, "<FACE %d: %d/%d>",
631 face, FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
f32d4091
KS
632 screen_face = face;
633 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
634}
635
636static
637IT_write_glyphs (GLYPH *str, int len)
638{
639 int newface;
640 int ch, l = len;
641 unsigned char *buf, *bp;
039274cf 642 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
87485d6f 643
f32d4091 644 if (len == 0) return;
aee81730 645
f32d4091 646 buf = bp = alloca (len * 2);
aee81730 647
f32d4091 648 while (--l >= 0)
aee81730 649 {
f32d4091
KS
650 newface = FAST_GLYPH_FACE (*str);
651 if (newface != screen_face)
652 IT_set_face (newface);
653 ch = FAST_GLYPH_CHAR (*str);
654 *bp++ = (unsigned char)ch;
655 *bp++ = ScreenAttrib;
656
657 if (termscript)
658 fputc (ch, termscript);
659 str++;
aee81730
RS
660 }
661
f32d4091 662 mouse_off_maybe ();
039274cf
EZ
663 dosmemput (buf, 2 * len, (int)ScreenPrimary + offset);
664 if (screen_virtual_segment)
665 dosv_refresh_virtual_screen (offset, len);
f32d4091
KS
666 new_pos_X += len;
667}
aee81730 668
f32d4091
KS
669static
670IT_clear_end_of_line (first_unused)
671{
672 char *spaces, *sp;
673 int i, j;
039274cf 674 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
f32d4091
KS
675
676 IT_set_face (0);
677 if (termscript)
678 fprintf (termscript, "<CLR:EOL>");
679 i = (j = screen_size_X - new_pos_X) * 2;
680 spaces = sp = alloca (i);
aee81730 681
f32d4091 682 while (--j >= 0)
aee81730 683 {
f32d4091
KS
684 *sp++ = ' ';
685 *sp++ = ScreenAttrib;
aee81730
RS
686 }
687
f32d4091 688 mouse_off_maybe ();
039274cf
EZ
689 dosmemput (spaces, i, (int)ScreenPrimary + offset);
690 if (screen_virtual_segment)
691 dosv_refresh_virtual_screen (offset, i / 2);
aee81730
RS
692}
693
f32d4091
KS
694static
695IT_clear_screen (void)
696{
697 if (termscript)
698 fprintf (termscript, "<CLR:SCR>");
699 IT_set_face (0);
700 mouse_off ();
701 ScreenClear ();
039274cf
EZ
702 if (screen_virtual_segment)
703 dosv_refresh_virtual_screen (0, screen_size);
f32d4091
KS
704 new_pos_X = new_pos_Y = 0;
705}
706
707static
708IT_clear_to_end (void)
709{
710 if (termscript)
711 fprintf (termscript, "<CLR:EOS>");
712
713 while (new_pos_Y < screen_size_Y) {
714 new_pos_X = 0;
715 IT_clear_end_of_line (0);
716 new_pos_Y++;
717 }
718}
719
720static
721IT_cursor_to (int y, int x)
722{
723 if (termscript)
724 fprintf (termscript, "\n<XY=%dx%d>", x, y);
725 new_pos_X = x;
726 new_pos_Y = y;
727}
728
fc171623
KH
729static int cursor_cleared;
730
731static
732IT_display_cursor (int on)
733{
734 if (on && cursor_cleared)
735 {
736 ScreenSetCursor (current_pos_Y, current_pos_X);
737 cursor_cleared = 0;
738 }
739 else if (!on && !cursor_cleared)
740 {
741 ScreenSetCursor (-1, -1);
742 cursor_cleared = 1;
743 }
039274cf
EZ
744 if (screen_virtual_segment)
745 dosv_refresh_virtual_screen (2 * (current_pos_X + screen_size_X * current_pos_Y), 1);
fc171623
KH
746}
747
748/* Emacs calls cursor-movement functions a lot when it updates the
749 display (probably a legacy of old terminals where you cannot
750 update a screen line without first moving the cursor there).
751 However, cursor movement is expensive on MSDOS (it calls a slow
752 BIOS function and requires 2 mode switches), while actual screen
753 updates access the video memory directly and don't depend on
754 cursor position. To avoid slowing down the redisplay, we cheat:
755 all functions that move the cursor only set internal variables
756 which record the cursor position, whereas the cursor is only
757 moved to its final position whenever screen update is complete.
758
759 `IT_cmgoto' is called from the keyboard reading loop and when the
760 frame update is complete. This means that we are ready for user
761 input, so we update the cursor position to show where the point is,
762 and also make the mouse pointer visible.
763
764 Special treatment is required when the cursor is in the echo area,
765 to put the cursor at the end of the text displayed there. */
766
767static
768IT_cmgoto (f)
769 FRAME_PTR f;
770{
771 /* Only set the cursor to where it should be if the display is
772 already in sync with the window contents. */
773 int update_cursor_pos = MODIFF == unchanged_modified;
774
775 /* If we are in the echo area, put the cursor at the end of text. */
776 if (!update_cursor_pos
777 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
778 {
779 new_pos_X = FRAME_DESIRED_GLYPHS (f)->used[new_pos_Y];
fc171623
KH
780 update_cursor_pos = 1;
781 }
782
783 if (update_cursor_pos
784 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
785 {
786 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
787 if (termscript)
788 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
789 }
790
791 /* Maybe cursor is invisible, so make it visible. */
792 IT_display_cursor (1);
793
794 /* Mouse pointer should be always visible if we are waiting for
795 keyboard input. */
796 if (!mouse_visible)
797 mouse_on ();
798}
799
f32d4091
KS
800static
801IT_reassert_line_highlight (new, vpos)
802 int new, vpos;
803{
804 highlight = new;
805 IT_set_face (0); /* To possibly clear the highlighting. */
806}
807
808static
809IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
1b94449f 810{
f32d4091
KS
811 highlight = new_highlight;
812 IT_set_face (0); /* To possibly clear the highlighting. */
813 IT_cursor_to (vpos, 0);
814 IT_clear_end_of_line (first_unused_hpos);
815}
816
817static
818IT_update_begin ()
819{
820 highlight = 0;
821 IT_set_face (0); /* To possibly clear the highlighting. */
822 screen_face = -1;
823}
824
825static
826IT_update_end ()
827{
828}
1b94449f 829
211c7152 830/* set-window-configuration on window.c needs this. */
3bb1f22f
RS
831void
832x_set_menu_bar_lines (f, value, oldval)
833 struct frame *f;
834 Lisp_Object value, oldval;
835{
211c7152
EZ
836 set_menu_bar_lines (f, value, oldval);
837}
3bb1f22f 838
211c7152 839/* This was copied from xfns.c */
3bb1f22f 840
211c7152
EZ
841Lisp_Object Qbackground_color;
842Lisp_Object Qforeground_color;
843extern Lisp_Object Qtitle;
3bb1f22f 844
48ffe371
RS
845/* IT_set_terminal_modes is called when emacs is started,
846 resumed, and whenever the screen is redrawn! */
f32d4091
KS
847
848static
849IT_set_terminal_modes (void)
850{
aee81730 851 if (termscript)
f32d4091
KS
852 fprintf (termscript, "\n<SET_TERM>");
853 highlight = 0;
854
855 screen_size_X = ScreenCols ();
856 screen_size_Y = ScreenRows ();
857 screen_size = screen_size_X * screen_size_Y;
aee81730 858
f32d4091
KS
859 new_pos_X = new_pos_Y = 0;
860 current_pos_X = current_pos_Y = -1;
861
862 if (term_setup_done)
863 return;
864 term_setup_done = 1;
aee81730 865
f32d4091
KS
866 startup_screen_size_X = screen_size_X;
867 startup_screen_size_Y = screen_size_Y;
c9adab25 868 startup_screen_attrib = ScreenAttrib;
f32d4091 869
039274cf
EZ
870#if __DJGPP__ > 1
871 /* Is DOS/V (or any other RSIS software which relocates
872 the screen) installed? */
873 {
874 unsigned short es_value;
875 __dpmi_regs regs;
876
877 regs.h.ah = 0xfe; /* get relocated screen address */
878 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
879 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
880 else if (screen_old_address) /* already switched to Japanese mode once */
881 regs.x.es = (screen_old_address >> 4) & 0xffff;
882 else
883 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
884 regs.x.di = 0;
885 es_value = regs.x.es;
886 __dpmi_int (0x10, &regs);
887
888 if (regs.x.es != es_value && regs.x.es != (ScreenPrimary >> 4) & 0xffff)
889 {
890 screen_old_address = ScreenPrimary;
891 screen_virtual_segment = regs.x.es;
892 screen_virtual_offset = regs.x.di;
893 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
894 }
895 }
896#endif /* __DJGPP__ > 1 */
897
f32d4091
KS
898 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
899 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
900
901 if (termscript)
c9adab25 902 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
039274cf 903 screen_size_X, screen_size_Y);
76ac1508
RS
904
905 bright_bg ();
f32d4091
KS
906}
907
48ffe371
RS
908/* IT_reset_terminal_modes is called when emacs is
909 suspended or killed. */
f32d4091
KS
910
911static
912IT_reset_terminal_modes (void)
913{
c9adab25
KH
914 int display_row_start = (int) ScreenPrimary;
915 int saved_row_len = startup_screen_size_X * 2;
916 int update_row_len = ScreenCols () * 2;
917 int current_rows = ScreenRows ();
918 int to_next_row = update_row_len;
919 unsigned char *saved_row = startup_screen_buffer;
920 int cursor_pos_X = ScreenCols () - 1;
921 int cursor_pos_Y = ScreenRows () - 1;
922
f32d4091 923 if (termscript)
5063b150 924 fprintf (termscript, "\n<RESET_TERM>");
f32d4091
KS
925
926 highlight = 0;
927
928 if (!term_setup_done)
929 return;
930
c9adab25 931 mouse_off ();
b36701cc
RS
932
933 /* Leave the video system in the same state as we found it,
934 as far as the blink/bright-background bit is concerned. */
935 maybe_enable_blinking ();
c9adab25
KH
936
937 /* We have a situation here.
938 We cannot just do ScreenUpdate(startup_screen_buffer) because
939 the luser could have changed screen dimensions inside Emacs
940 and failed (or didn't want) to restore them before killing
941 Emacs. ScreenUpdate() uses the *current* screen dimensions and
942 thus will happily use memory outside what was allocated for
943 `startup_screen_buffer'.
944 Thus we only restore as much as the current screen dimensions
945 can hold, and clear the rest (if the saved screen is smaller than
946 the current) with the color attribute saved at startup. The cursor
947 is also restored within the visible dimensions. */
948
949 ScreenAttrib = startup_screen_attrib;
950 ScreenClear ();
039274cf
EZ
951 if (screen_virtual_segment)
952 dosv_refresh_virtual_screen (0, screen_size);
c9adab25
KH
953
954 if (update_row_len > saved_row_len)
955 update_row_len = saved_row_len;
956 if (current_rows > startup_screen_size_Y)
957 current_rows = startup_screen_size_Y;
f32d4091
KS
958
959 if (termscript)
c9adab25
KH
960 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
961 update_row_len / 2, current_rows);
962
963 while (current_rows--)
964 {
965 dosmemput (saved_row, update_row_len, display_row_start);
039274cf
EZ
966 if (screen_virtual_segment)
967 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
968 update_row_len / 2);
c9adab25
KH
969 saved_row += saved_row_len;
970 display_row_start += to_next_row;
971 }
972 if (startup_pos_X < cursor_pos_X)
973 cursor_pos_X = startup_pos_X;
974 if (startup_pos_Y < cursor_pos_Y)
975 cursor_pos_Y = startup_pos_Y;
976
977 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
039274cf
EZ
978 if (screen_virtual_segment)
979 dosv_refresh_virtual_screen (2*(cursor_pos_X+cursor_pos_Y*screen_size_X),
980 1);
c9adab25 981 xfree (startup_screen_buffer);
f32d4091
KS
982
983 term_setup_done = 0;
984}
985
986static
987IT_set_terminal_window (void)
988{
989}
990
991void
3bb1f22f
RS
992IT_set_frame_parameters (f, alist)
993 FRAME_PTR f;
f32d4091
KS
994 Lisp_Object alist;
995{
996 Lisp_Object tail;
db722735
RS
997 int length = XINT (Flength (alist));
998 int i;
999 Lisp_Object *parms
1000 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1001 Lisp_Object *values
1002 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
f32d4091
KS
1003 int redraw;
1004 extern unsigned long load_color ();
f32d4091
KS
1005
1006 redraw = 0;
db722735
RS
1007
1008 /* Extract parm names and values into those vectors. */
1009 i = 0;
f32d4091
KS
1010 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1011 {
db722735 1012 Lisp_Object elt;
f32d4091
KS
1013
1014 elt = Fcar (tail);
db722735
RS
1015 parms[i] = Fcar (elt);
1016 CHECK_SYMBOL (parms[i], 1);
1017 values[i] = Fcdr (elt);
1018 i++;
1019 }
1020
1021
1022 /* Now process them in reverse of specified order. */
1023 for (i--; i >= 0; i--)
1024 {
1025 Lisp_Object prop = parms[i];
1026 Lisp_Object val = values[i];
f32d4091 1027
4e825084 1028 if (EQ (prop, Qforeground_color))
f32d4091
KS
1029 {
1030 unsigned long new_color = load_color (f, val);
1031 if (new_color != ~0)
1032 {
1033 FRAME_FOREGROUND_PIXEL (f) = new_color;
1034 redraw = 1;
76ac1508 1035 if (termscript)
a7cf9151 1036 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
f32d4091
KS
1037 }
1038 }
4e825084 1039 else if (EQ (prop, Qbackground_color))
f32d4091
KS
1040 {
1041 unsigned long new_color = load_color (f, val);
1042 if (new_color != ~0)
1043 {
76ac1508 1044 FRAME_BACKGROUND_PIXEL (f) = new_color;
f32d4091 1045 redraw = 1;
76ac1508 1046 if (termscript)
a7cf9151 1047 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
f32d4091
KS
1048 }
1049 }
211c7152
EZ
1050 else if (EQ (prop, Qtitle))
1051 {
1052 x_set_title (f, val);
1053 if (termscript)
1054 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
1055 }
1056 else if (EQ (prop, intern ("reverse")) && EQ (val, Qt))
1057 {
1058 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
db722735 1059
211c7152
EZ
1060 FRAME_FOREGROUND_PIXEL (f) = FRAME_BACKGROUND_PIXEL (f);
1061 FRAME_BACKGROUND_PIXEL (f) = fg;
1062 if (termscript)
1063 fprintf (termscript, "<INVERSE-VIDEO>\n");
1064 }
db722735
RS
1065 store_frame_param (f, prop, val);
1066
f32d4091
KS
1067 }
1068
1069 if (redraw)
1070 {
a7cf9151
EZ
1071 extern void recompute_basic_faces (FRAME_PTR);
1072 extern void redraw_frame (FRAME_PTR);
1073
f32d4091 1074 recompute_basic_faces (f);
3bb1f22f
RS
1075 if (f == selected_frame)
1076 redraw_frame (f);
f32d4091
KS
1077 }
1078}
1079
a7cf9151
EZ
1080extern void init_frame_faces (FRAME_PTR);
1081
f32d4091
KS
1082#endif /* !HAVE_X_WINDOWS */
1083
1084
48ffe371
RS
1085/* Do we need the internal terminal? */
1086
f32d4091
KS
1087void
1088internal_terminal_init ()
1089{
1090 char *term = getenv ("TERM");
1091 char *colors;
1092
1093#ifdef HAVE_X_WINDOWS
1094 if (!inhibit_window_system)
1095 return;
1096#endif
1097
1098 internal_terminal
1099 = (!noninteractive) && term && !strcmp (term, "internal");
1100
1101 if (getenv ("EMACSTEST"))
5063b150 1102 termscript = fopen (getenv ("EMACSTEST"), "wt");
f32d4091
KS
1103
1104#ifndef HAVE_X_WINDOWS
1105 if (!internal_terminal || inhibit_window_system)
1106 {
3bb1f22f 1107 selected_frame->output_method = output_termcap;
f32d4091
KS
1108 return;
1109 }
1110
1111 Vwindow_system = intern ("pc");
1112 Vwindow_system_version = make_number (1);
039274cf
EZ
1113
1114 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1115 screen_old_address = 0;
1116
f32d4091
KS
1117 bzero (&the_only_x_display, sizeof the_only_x_display);
1118 the_only_x_display.background_pixel = 7; /* White */
1119 the_only_x_display.foreground_pixel = 0; /* Black */
76ac1508 1120 bright_bg ();
5063b150 1121 colors = getenv ("EMACSCOLORS");
f32d4091
KS
1122 if (colors && strlen (colors) >= 2)
1123 {
76ac1508
RS
1124 /* The colors use 4 bits each (we enable bright background). */
1125 if (isdigit (colors[0]))
1126 colors[0] -= '0';
1127 else if (isxdigit (colors[0]))
1128 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1bd7b2c7
RS
1129 if (colors[0] >= 0 && colors[0] < 16)
1130 the_only_x_display.foreground_pixel = colors[0];
76ac1508
RS
1131 if (isdigit (colors[1]))
1132 colors[1] -= '0';
1133 else if (isxdigit (colors[1]))
1134 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1135 if (colors[1] >= 0 && colors[1] < 16)
1bd7b2c7 1136 the_only_x_display.background_pixel = colors[1];
f32d4091
KS
1137 }
1138 the_only_x_display.line_height = 1;
64ec6a02 1139 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
f32d4091 1140
3bb1f22f 1141 init_frame_faces (selected_frame);
f32d4091
KS
1142
1143 ring_bell_hook = IT_ring_bell;
1144 write_glyphs_hook = IT_write_glyphs;
1145 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1146 clear_to_end_hook = IT_clear_to_end;
1147 clear_end_of_line_hook = IT_clear_end_of_line;
1148 clear_frame_hook = IT_clear_screen;
1149 change_line_highlight_hook = IT_change_line_highlight;
1150 update_begin_hook = IT_update_begin;
1151 update_end_hook = IT_update_end;
1152 reassert_line_highlight_hook = IT_reassert_line_highlight;
fc171623 1153 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
f32d4091
KS
1154
1155 /* These hooks are called by term.c without being checked. */
1156 set_terminal_modes_hook = IT_set_terminal_modes;
1157 reset_terminal_modes_hook = IT_reset_terminal_modes;
1158 set_terminal_window_hook = IT_set_terminal_window;
1159#endif
1160}
1161
1162dos_get_saved_screen (screen, rows, cols)
1163 char **screen;
1164 int *rows;
1165 int *cols;
1166{
1167#ifndef HAVE_X_WINDOWS
1168 *screen = startup_screen_buffer;
1169 *cols = startup_screen_size_X;
1170 *rows = startup_screen_size_Y;
039274cf 1171 return *screen != (char *)0;
f32d4091
KS
1172#else
1173 return 0;
1174#endif
1175}
3bb1f22f
RS
1176
1177#ifndef HAVE_X_WINDOWS
1178
1179/* We are not X, but we can emulate it well enough for our needs... */
1180void
1181check_x (void)
1182{
1183 if (! FRAME_MSDOS_P (selected_frame))
1184 error ("Not running under a windows system");
1185}
1186
1187#endif
1188
5063b150 1189\f
f32d4091
KS
1190/* ----------------------- Keyboard control ----------------------
1191 *
1192 * Keymaps reflect the following keyboard layout:
1193 *
1194 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1195 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1196 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1197 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1198 * SPACE
1199 */
1200
1201static int extended_kbd; /* 101 (102) keyboard present. */
1202
1203struct dos_keyboard_map
1204{
1205 char *unshifted;
1206 char *shifted;
1207 char *alt_gr;
1208};
1209
1210
1211static struct dos_keyboard_map us_keyboard = {
1212/* 0 1 2 3 4 5 */
1213/* 01234567890123456789012345678901234567890 12345678901234 */
1214 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1215/* 0123456789012345678901234567890123456789 012345678901234 */
1216 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1217 0 /* no Alt-Gr key */
1218};
1219
1220static struct dos_keyboard_map fr_keyboard = {
1221/* 0 1 2 3 4 5 */
1222/* 012 3456789012345678901234567890123456789012345678901234 */
1223