(strout, printchar): Handle minibuffer_auto_raise.
[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
816void
817x_set_menu_bar_lines (f, value, oldval)
818 struct frame *f;
819 Lisp_Object value, oldval;
820{
821 int nlines;
822 int olines = FRAME_MENU_BAR_LINES (f);
823
824 /* Right now, menu bars don't work properly in minibuf-only frames;
825 most of the commands try to apply themselves to the minibuffer
826 frame itslef, and get an error because you can't switch buffers
827 in or split the minibuffer window. */
828 if (FRAME_MINIBUF_ONLY_P (f))
829 return;
830
831 if (INTEGERP (value))
832 nlines = XINT (value);
833 else
834 nlines = 0;
835
836 FRAME_MENU_BAR_LINES (f) = nlines;
837 IT_set_menu_bar_lines (f->root_window, nlines - olines);
838}
839
48ffe371
RS
840/* IT_set_terminal_modes is called when emacs is started,
841 resumed, and whenever the screen is redrawn! */
f32d4091
KS
842
843static
844IT_set_terminal_modes (void)
845{
aee81730 846 if (termscript)
f32d4091
KS
847 fprintf (termscript, "\n<SET_TERM>");
848 highlight = 0;
849
850 screen_size_X = ScreenCols ();
851 screen_size_Y = ScreenRows ();
852 screen_size = screen_size_X * screen_size_Y;
aee81730 853
f32d4091
KS
854 new_pos_X = new_pos_Y = 0;
855 current_pos_X = current_pos_Y = -1;
856
857 if (term_setup_done)
858 return;
859 term_setup_done = 1;
aee81730 860
f32d4091
KS
861 startup_screen_size_X = screen_size_X;
862 startup_screen_size_Y = screen_size_Y;
c9adab25 863 startup_screen_attrib = ScreenAttrib;
f32d4091
KS
864
865 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
866 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
867
868 if (termscript)
c9adab25
KH
869 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
870 screen_size_X, screen_size_Y);
76ac1508
RS
871
872 bright_bg ();
f32d4091
KS
873}
874
48ffe371
RS
875/* IT_reset_terminal_modes is called when emacs is
876 suspended or killed. */
f32d4091
KS
877
878static
879IT_reset_terminal_modes (void)
880{
c9adab25
KH
881 int display_row_start = (int) ScreenPrimary;
882 int saved_row_len = startup_screen_size_X * 2;
883 int update_row_len = ScreenCols () * 2;
884 int current_rows = ScreenRows ();
885 int to_next_row = update_row_len;
886 unsigned char *saved_row = startup_screen_buffer;
887 int cursor_pos_X = ScreenCols () - 1;
888 int cursor_pos_Y = ScreenRows () - 1;
889
f32d4091 890 if (termscript)
5063b150 891 fprintf (termscript, "\n<RESET_TERM>");
f32d4091
KS
892
893 highlight = 0;
894
895 if (!term_setup_done)
896 return;
897
c9adab25 898 mouse_off ();
b36701cc
RS
899
900 /* Leave the video system in the same state as we found it,
901 as far as the blink/bright-background bit is concerned. */
902 maybe_enable_blinking ();
c9adab25
KH
903
904 /* We have a situation here.
905 We cannot just do ScreenUpdate(startup_screen_buffer) because
906 the luser could have changed screen dimensions inside Emacs
907 and failed (or didn't want) to restore them before killing
908 Emacs. ScreenUpdate() uses the *current* screen dimensions and
909 thus will happily use memory outside what was allocated for
910 `startup_screen_buffer'.
911 Thus we only restore as much as the current screen dimensions
912 can hold, and clear the rest (if the saved screen is smaller than
913 the current) with the color attribute saved at startup. The cursor
914 is also restored within the visible dimensions. */
915
916 ScreenAttrib = startup_screen_attrib;
917 ScreenClear ();
918
919 if (update_row_len > saved_row_len)
920 update_row_len = saved_row_len;
921 if (current_rows > startup_screen_size_Y)
922 current_rows = startup_screen_size_Y;
f32d4091
KS
923
924 if (termscript)
c9adab25
KH
925 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
926 update_row_len / 2, current_rows);
927
928 while (current_rows--)
929 {
930 dosmemput (saved_row, update_row_len, display_row_start);
931 saved_row += saved_row_len;
932 display_row_start += to_next_row;
933 }
934 if (startup_pos_X < cursor_pos_X)
935 cursor_pos_X = startup_pos_X;
936 if (startup_pos_Y < cursor_pos_Y)
937 cursor_pos_Y = startup_pos_Y;
938
939 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
940 xfree (startup_screen_buffer);
f32d4091
KS
941
942 term_setup_done = 0;
943}
944
945static
946IT_set_terminal_window (void)
947{
948}
949
950void
3bb1f22f
RS
951IT_set_frame_parameters (f, alist)
952 FRAME_PTR f;
f32d4091
KS
953 Lisp_Object alist;
954{
955 Lisp_Object tail;
956 int redraw;
957 extern unsigned long load_color ();
f32d4091
KS
958
959 redraw = 0;
960 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
961 {
962 Lisp_Object elt, prop, val;
963
964 elt = Fcar (tail);
965 prop = Fcar (elt);
966 val = Fcdr (elt);
967 CHECK_SYMBOL (prop, 1);
968
969 if (EQ (prop, intern ("foreground-color")))
970 {
971 unsigned long new_color = load_color (f, val);
972 if (new_color != ~0)
973 {
974 FRAME_FOREGROUND_PIXEL (f) = new_color;
975 redraw = 1;
76ac1508 976 if (termscript)
a7cf9151 977 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
f32d4091
KS
978 }
979 }
980 else if (EQ (prop, intern ("background-color")))
981 {
982 unsigned long new_color = load_color (f, val);
983 if (new_color != ~0)
984 {
76ac1508 985 FRAME_BACKGROUND_PIXEL (f) = new_color;
f32d4091 986 redraw = 1;
76ac1508 987 if (termscript)
a7cf9151 988 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
f32d4091
KS
989 }
990 }
991 else if (EQ (prop, intern ("menu-bar-lines")))
3bb1f22f 992 x_set_menu_bar_lines (f, val, 0);
f32d4091
KS
993 }
994
995 if (redraw)
996 {
a7cf9151
EZ
997 extern void recompute_basic_faces (FRAME_PTR);
998 extern void redraw_frame (FRAME_PTR);
999
f32d4091 1000 recompute_basic_faces (f);
3bb1f22f
RS
1001 if (f == selected_frame)
1002 redraw_frame (f);
f32d4091
KS
1003 }
1004}
1005
a7cf9151
EZ
1006extern void init_frame_faces (FRAME_PTR);
1007
f32d4091
KS
1008#endif /* !HAVE_X_WINDOWS */
1009
1010
48ffe371
RS
1011/* Do we need the internal terminal? */
1012
f32d4091
KS
1013void
1014internal_terminal_init ()
1015{
1016 char *term = getenv ("TERM");
1017 char *colors;
1018
1019#ifdef HAVE_X_WINDOWS
1020 if (!inhibit_window_system)
1021 return;
1022#endif
1023
1024 internal_terminal
1025 = (!noninteractive) && term && !strcmp (term, "internal");
1026
1027 if (getenv ("EMACSTEST"))
5063b150 1028 termscript = fopen (getenv ("EMACSTEST"), "wt");
f32d4091
KS
1029
1030#ifndef HAVE_X_WINDOWS
1031 if (!internal_terminal || inhibit_window_system)
1032 {
3bb1f22f 1033 selected_frame->output_method = output_termcap;
f32d4091
KS
1034 return;
1035 }
1036
1037 Vwindow_system = intern ("pc");
1038 Vwindow_system_version = make_number (1);
1039
1040 bzero (&the_only_x_display, sizeof the_only_x_display);
1041 the_only_x_display.background_pixel = 7; /* White */
1042 the_only_x_display.foreground_pixel = 0; /* Black */
76ac1508 1043 bright_bg ();
5063b150 1044 colors = getenv ("EMACSCOLORS");
f32d4091
KS
1045 if (colors && strlen (colors) >= 2)
1046 {
76ac1508
RS
1047 /* The colors use 4 bits each (we enable bright background). */
1048 if (isdigit (colors[0]))
1049 colors[0] -= '0';
1050 else if (isxdigit (colors[0]))
1051 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1bd7b2c7
RS
1052 if (colors[0] >= 0 && colors[0] < 16)
1053 the_only_x_display.foreground_pixel = colors[0];
76ac1508
RS
1054 if (isdigit (colors[1]))
1055 colors[1] -= '0';
1056 else if (isxdigit (colors[1]))
1057 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1058 if (colors[1] >= 0 && colors[1] < 16)
1bd7b2c7 1059 the_only_x_display.background_pixel = colors[1];
f32d4091
KS
1060 }
1061 the_only_x_display.line_height = 1;
64ec6a02 1062 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
f32d4091 1063
3bb1f22f 1064 init_frame_faces (selected_frame);
f32d4091
KS
1065
1066 ring_bell_hook = IT_ring_bell;
1067 write_glyphs_hook = IT_write_glyphs;
1068 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1069 clear_to_end_hook = IT_clear_to_end;
1070 clear_end_of_line_hook = IT_clear_end_of_line;
1071 clear_frame_hook = IT_clear_screen;
1072 change_line_highlight_hook = IT_change_line_highlight;
1073 update_begin_hook = IT_update_begin;
1074 update_end_hook = IT_update_end;
1075 reassert_line_highlight_hook = IT_reassert_line_highlight;
fc171623 1076 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
f32d4091
KS
1077
1078 /* These hooks are called by term.c without being checked. */
1079 set_terminal_modes_hook = IT_set_terminal_modes;
1080 reset_terminal_modes_hook = IT_reset_terminal_modes;
1081 set_terminal_window_hook = IT_set_terminal_window;
1082#endif
1083}
1084
1085dos_get_saved_screen (screen, rows, cols)
1086 char **screen;
1087 int *rows;
1088 int *cols;
1089{
1090#ifndef HAVE_X_WINDOWS
1091 *screen = startup_screen_buffer;
1092 *cols = startup_screen_size_X;
1093 *rows = startup_screen_size_Y;
1094 return 1;
1095#else
1096 return 0;
1097#endif
1098}
3bb1f22f
RS
1099
1100#ifndef HAVE_X_WINDOWS
1101
1102/* We are not X, but we can emulate it well enough for our needs... */
1103void
1104check_x (void)
1105{
1106 if (! FRAME_MSDOS_P (selected_frame))
1107 error ("Not running under a windows system");
1108}
1109
1110#endif
1111
5063b150 1112\f
f32d4091
KS
1113/* ----------------------- Keyboard control ----------------------
1114 *
1115 * Keymaps reflect the following keyboard layout:
1116 *
1117 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1118 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1119 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1120 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1121 * SPACE
1122 */
1123
1124static int extended_kbd; /* 101 (102) keyboard present. */
1125
1126struct dos_keyboard_map
1127{
1128 char *unshifted;
1129 char *shifted;
1130 char *alt_gr;
1131};
1132
1133
1134static struct dos_keyboard_map us_keyboard = {
1135/* 0 1 2 3 4 5 */
1136/* 01234567890123456789012345678901234567890 12345678901234 */
1137 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1138/* 0123456789012345678901234567890123456789 012345678901234 */
1139 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1140 0 /* no Alt-Gr key */
1141};
1142
1143static struct dos_keyboard_map fr_keyboard = {
1144/* 0 1 2 3 4 5 */
1145/* 012 3456789012345678901234567890123456789012345678901234 */
1146