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