new version
[bpt/emacs.git] / src / msdos.c
CommitLineData
0e5c5ac0 1/* MS-DOS specific C utilities. -*- coding: emacs-mule -*-
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
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)
5d7e8345
RS
594 fprintf (termscript, "<FACE %d: %d/%d>",
595 face, FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
f32d4091
KS
596 screen_face = face;
597 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
598}
599
600static
601IT_write_glyphs (GLYPH *str, int len)
602{
603 int newface;
604 int ch, l = len;
605 unsigned char *buf, *bp;
87485d6f 606
f32d4091 607 if (len == 0) return;
aee81730 608
f32d4091 609 buf = bp = alloca (len * 2);
aee81730 610
f32d4091 611 while (--l >= 0)
aee81730 612 {
f32d4091
KS
613 newface = FAST_GLYPH_FACE (*str);
614 if (newface != screen_face)
615 IT_set_face (newface);
616 ch = FAST_GLYPH_CHAR (*str);
617 *bp++ = (unsigned char)ch;
618 *bp++ = ScreenAttrib;
619
620 if (termscript)
621 fputc (ch, termscript);
622 str++;
aee81730
RS
623 }
624
f32d4091
KS
625 mouse_off_maybe ();
626 dosmemput (buf, 2 * len,
627 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
628 new_pos_X += len;
629}
aee81730 630
f32d4091
KS
631static
632IT_clear_end_of_line (first_unused)
633{
634 char *spaces, *sp;
635 int i, j;
636
637 IT_set_face (0);
638 if (termscript)
639 fprintf (termscript, "<CLR:EOL>");
640 i = (j = screen_size_X - new_pos_X) * 2;
641 spaces = sp = alloca (i);
aee81730 642
f32d4091 643 while (--j >= 0)
aee81730 644 {
f32d4091
KS
645 *sp++ = ' ';
646 *sp++ = ScreenAttrib;
aee81730
RS
647 }
648
f32d4091
KS
649 mouse_off_maybe ();
650 dosmemput (spaces, i,
651 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
aee81730
RS
652}
653
f32d4091
KS
654static
655IT_clear_screen (void)
656{
657 if (termscript)
658 fprintf (termscript, "<CLR:SCR>");
659 IT_set_face (0);
660 mouse_off ();
661 ScreenClear ();
662 new_pos_X = new_pos_Y = 0;
663}
664
665static
666IT_clear_to_end (void)
667{
668 if (termscript)
669 fprintf (termscript, "<CLR:EOS>");
670
671 while (new_pos_Y < screen_size_Y) {
672 new_pos_X = 0;
673 IT_clear_end_of_line (0);
674 new_pos_Y++;
675 }
676}
677
678static
679IT_cursor_to (int y, int x)
680{
681 if (termscript)
682 fprintf (termscript, "\n<XY=%dx%d>", x, y);
683 new_pos_X = x;
684 new_pos_Y = y;
685}
686
fc171623
KH
687static int cursor_cleared;
688
689static
690IT_display_cursor (int on)
691{
692 if (on && cursor_cleared)
693 {
694 ScreenSetCursor (current_pos_Y, current_pos_X);
695 cursor_cleared = 0;
696 }
697 else if (!on && !cursor_cleared)
698 {
699 ScreenSetCursor (-1, -1);
700 cursor_cleared = 1;
701 }
702}
703
704/* Emacs calls cursor-movement functions a lot when it updates the
705 display (probably a legacy of old terminals where you cannot
706 update a screen line without first moving the cursor there).
707 However, cursor movement is expensive on MSDOS (it calls a slow
708 BIOS function and requires 2 mode switches), while actual screen
709 updates access the video memory directly and don't depend on
710 cursor position. To avoid slowing down the redisplay, we cheat:
711 all functions that move the cursor only set internal variables
712 which record the cursor position, whereas the cursor is only
713 moved to its final position whenever screen update is complete.
714
715 `IT_cmgoto' is called from the keyboard reading loop and when the
716 frame update is complete. This means that we are ready for user
717 input, so we update the cursor position to show where the point is,
718 and also make the mouse pointer visible.
719
720 Special treatment is required when the cursor is in the echo area,
721 to put the cursor at the end of the text displayed there. */
722
723static
724IT_cmgoto (f)
725 FRAME_PTR f;
726{
727 /* Only set the cursor to where it should be if the display is
728 already in sync with the window contents. */
729 int update_cursor_pos = MODIFF == unchanged_modified;
730
731 /* If we are in the echo area, put the cursor at the end of text. */
732 if (!update_cursor_pos
733 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
734 {
735 new_pos_X = FRAME_DESIRED_GLYPHS (f)->used[new_pos_Y];
fc171623
KH
736 update_cursor_pos = 1;
737 }
738
739 if (update_cursor_pos
740 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
741 {
742 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
743 if (termscript)
744 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
745 }
746
747 /* Maybe cursor is invisible, so make it visible. */
748 IT_display_cursor (1);
749
750 /* Mouse pointer should be always visible if we are waiting for
751 keyboard input. */
752 if (!mouse_visible)
753 mouse_on ();
754}
755
f32d4091
KS
756static
757IT_reassert_line_highlight (new, vpos)
758 int new, vpos;
759{
760 highlight = new;
761 IT_set_face (0); /* To possibly clear the highlighting. */
762}
763
764static
765IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
1b94449f 766{
f32d4091
KS
767 highlight = new_highlight;
768 IT_set_face (0); /* To possibly clear the highlighting. */
769 IT_cursor_to (vpos, 0);
770 IT_clear_end_of_line (first_unused_hpos);
771}
772
773static
774IT_update_begin ()
775{
776 highlight = 0;
777 IT_set_face (0); /* To possibly clear the highlighting. */
778 screen_face = -1;
779}
780
781static
782IT_update_end ()
783{
784}
1b94449f 785
3bb1f22f
RS
786/* This was more or less copied from xterm.c
787
788 Nowadays, the corresponding function under X is `x_set_menu_bar_lines_1'
789 on xfns.c */
48ffe371 790
f32d4091
KS
791static void
792IT_set_menu_bar_lines (window, n)
48ffe371
RS
793 Lisp_Object window;
794 int n;
f32d4091
KS
795{
796 struct window *w = XWINDOW (window);
797
9a166e40 798 XSETFASTINT (w->last_modified, 0);
3280297a 799 XSETFASTINT (w->last_overlay_modified, 0);
f32d4091
KS
800 XSETFASTINT (w->top, XFASTINT (w->top) + n);
801 XSETFASTINT (w->height, XFASTINT (w->height) - n);
802
803 /* Handle just the top child in a vertical split. */
804 if (!NILP (w->vchild))
805 IT_set_menu_bar_lines (w->vchild, n);
806
807 /* Adjust all children in a horizontal split. */
808 for (window = w->hchild; !NILP (window); window = w->next)
1b94449f 809 {
f32d4091
KS
810 w = XWINDOW (window);
811 IT_set_menu_bar_lines (window, n);
aee81730 812 }
f32d4091
KS
813}
814
3bb1f22f
RS
815/* This was copied from xfns.c */
816
e9fbf17c
RS
817Lisp_Object Qbackground_color;
818Lisp_Object Qforeground_color;
819
3bb1f22f
RS
820void
821x_set_menu_bar_lines (f, value, oldval)
822 struct frame *f;
823 Lisp_Object value, oldval;
824{
825 int nlines;
826 int olines = FRAME_MENU_BAR_LINES (f);
827
828 /* Right now, menu bars don't work properly in minibuf-only frames;
829 most of the commands try to apply themselves to the minibuffer
830 frame itslef, and get an error because you can't switch buffers
831 in or split the minibuffer window. */
832 if (FRAME_MINIBUF_ONLY_P (f))
833 return;
834
835 if (INTEGERP (value))
836 nlines = XINT (value);
837 else
838 nlines = 0;
839
840 FRAME_MENU_BAR_LINES (f) = nlines;
841 IT_set_menu_bar_lines (f->root_window, nlines - olines);
842}
843
48ffe371
RS
844/* IT_set_terminal_modes is called when emacs is started,
845 resumed, and whenever the screen is redrawn! */
f32d4091
KS
846
847static
848IT_set_terminal_modes (void)
849{
aee81730 850 if (termscript)
f32d4091
KS
851 fprintf (termscript, "\n<SET_TERM>");
852 highlight = 0;
853
854 screen_size_X = ScreenCols ();
855 screen_size_Y = ScreenRows ();
856 screen_size = screen_size_X * screen_size_Y;
aee81730 857
f32d4091
KS
858 new_pos_X = new_pos_Y = 0;
859 current_pos_X = current_pos_Y = -1;
860
861 if (term_setup_done)
862 return;
863 term_setup_done = 1;
aee81730 864
f32d4091
KS
865 startup_screen_size_X = screen_size_X;
866 startup_screen_size_Y = screen_size_Y;
c9adab25 867 startup_screen_attrib = ScreenAttrib;
f32d4091
KS
868
869 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
870 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
871
872 if (termscript)
c9adab25
KH
873 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
874 screen_size_X, screen_size_Y);
76ac1508
RS
875
876 bright_bg ();
f32d4091
KS
877}
878
48ffe371
RS
879/* IT_reset_terminal_modes is called when emacs is
880 suspended or killed. */
f32d4091
KS
881
882static
883IT_reset_terminal_modes (void)
884{
c9adab25
KH
885 int display_row_start = (int) ScreenPrimary;
886 int saved_row_len = startup_screen_size_X * 2;
887 int update_row_len = ScreenCols () * 2;
888 int current_rows = ScreenRows ();
889 int to_next_row = update_row_len;
890 unsigned char *saved_row = startup_screen_buffer;
891 int cursor_pos_X = ScreenCols () - 1;
892 int cursor_pos_Y = ScreenRows () - 1;
893
f32d4091 894 if (termscript)
5063b150 895 fprintf (termscript, "\n<RESET_TERM>");
f32d4091
KS
896
897 highlight = 0;
898
899 if (!term_setup_done)
900 return;
901
c9adab25 902 mouse_off ();
b36701cc
RS
903
904 /* Leave the video system in the same state as we found it,
905 as far as the blink/bright-background bit is concerned. */
906 maybe_enable_blinking ();
c9adab25
KH
907
908 /* We have a situation here.
909 We cannot just do ScreenUpdate(startup_screen_buffer) because
910 the luser could have changed screen dimensions inside Emacs
911 and failed (or didn't want) to restore them before killing
912 Emacs. ScreenUpdate() uses the *current* screen dimensions and
913 thus will happily use memory outside what was allocated for
914 `startup_screen_buffer'.
915 Thus we only restore as much as the current screen dimensions
916 can hold, and clear the rest (if the saved screen is smaller than
917 the current) with the color attribute saved at startup. The cursor
918 is also restored within the visible dimensions. */
919
920 ScreenAttrib = startup_screen_attrib;
921 ScreenClear ();
922
923 if (update_row_len > saved_row_len)
924 update_row_len = saved_row_len;
925 if (current_rows > startup_screen_size_Y)
926 current_rows = startup_screen_size_Y;
f32d4091
KS
927
928 if (termscript)
c9adab25
KH
929 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
930 update_row_len / 2, current_rows);
931
932 while (current_rows--)
933 {
934 dosmemput (saved_row, update_row_len, display_row_start);
935 saved_row += saved_row_len;
936 display_row_start += to_next_row;
937 }
938 if (startup_pos_X < cursor_pos_X)
939 cursor_pos_X = startup_pos_X;
940 if (startup_pos_Y < cursor_pos_Y)
941 cursor_pos_Y = startup_pos_Y;
942
943 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
944 xfree (startup_screen_buffer);
f32d4091
KS
945
946 term_setup_done = 0;
947}
948
949static
950IT_set_terminal_window (void)
951{
952}
953
954void
3bb1f22f
RS
955IT_set_frame_parameters (f, alist)
956 FRAME_PTR f;
f32d4091
KS
957 Lisp_Object alist;
958{
959 Lisp_Object tail;
db722735
RS
960 int length = XINT (Flength (alist));
961 int i;
962 Lisp_Object *parms
963 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
964 Lisp_Object *values
965 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
f32d4091
KS
966 int redraw;
967 extern unsigned long load_color ();
f32d4091
KS
968
969 redraw = 0;
db722735
RS
970
971 /* Extract parm names and values into those vectors. */
972 i = 0;
f32d4091
KS
973 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
974 {
db722735 975 Lisp_Object elt;
f32d4091
KS
976
977 elt = Fcar (tail);
db722735
RS
978 parms[i] = Fcar (elt);
979 CHECK_SYMBOL (parms[i], 1);
980 values[i] = Fcdr (elt);
981 i++;
982 }
983
984
985 /* Now process them in reverse of specified order. */
986 for (i--; i >= 0; i--)
987 {
988 Lisp_Object prop = parms[i];
989 Lisp_Object val = values[i];
f32d4091 990
4e825084 991 if (EQ (prop, Qforeground_color))
f32d4091
KS
992 {
993 unsigned long new_color = load_color (f, val);
994 if (new_color != ~0)
995 {
996 FRAME_FOREGROUND_PIXEL (f) = new_color;
997 redraw = 1;
76ac1508 998 if (termscript)
a7cf9151 999 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
f32d4091
KS
1000 }
1001 }
4e825084 1002 else if (EQ (prop, Qbackground_color))
f32d4091
KS
1003 {
1004 unsigned long new_color = load_color (f, val);
1005 if (new_color != ~0)
1006 {
76ac1508 1007 FRAME_BACKGROUND_PIXEL (f) = new_color;
f32d4091 1008 redraw = 1;
76ac1508 1009 if (termscript)
a7cf9151 1010 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
f32d4091
KS
1011 }
1012 }
1013 else if (EQ (prop, intern ("menu-bar-lines")))
3bb1f22f 1014 x_set_menu_bar_lines (f, val, 0);
db722735
RS
1015
1016 store_frame_param (f, prop, val);
1017
f32d4091
KS
1018 }
1019
1020 if (redraw)
1021 {
a7cf9151
EZ
1022 extern void recompute_basic_faces (FRAME_PTR);
1023 extern void redraw_frame (FRAME_PTR);
1024
f32d4091 1025 recompute_basic_faces (f);
3bb1f22f
RS
1026 if (f == selected_frame)
1027 redraw_frame (f);
f32d4091
KS
1028 }
1029}
1030
a7cf9151
EZ
1031extern void init_frame_faces (FRAME_PTR);
1032
f32d4091
KS
1033#endif /* !HAVE_X_WINDOWS */
1034
1035
48ffe371
RS
1036/* Do we need the internal terminal? */
1037
f32d4091
KS
1038void
1039internal_terminal_init ()
1040{
1041 char *term = getenv ("TERM");
1042 char *colors;
1043
1044#ifdef HAVE_X_WINDOWS
1045 if (!inhibit_window_system)
1046 return;
1047#endif
1048
1049 internal_terminal
1050 = (!noninteractive) && term && !strcmp (term, "internal");
1051
1052 if (getenv ("EMACSTEST"))
5063b150 1053 termscript = fopen (getenv ("EMACSTEST"), "wt");
f32d4091
KS
1054
1055#ifndef HAVE_X_WINDOWS
1056 if (!internal_terminal || inhibit_window_system)
1057 {
3bb1f22f 1058 selected_frame->output_method = output_termcap;
f32d4091
KS
1059 return;
1060 }
1061
1062 Vwindow_system = intern ("pc");
1063 Vwindow_system_version = make_number (1);
1064
1065 bzero (&the_only_x_display, sizeof the_only_x_display);
1066 the_only_x_display.background_pixel = 7; /* White */
1067 the_only_x_display.foreground_pixel = 0; /* Black */
76ac1508 1068 bright_bg ();
5063b150 1069 colors = getenv ("EMACSCOLORS");
f32d4091
KS
1070 if (colors && strlen (colors) >= 2)
1071 {
76ac1508
RS
1072 /* The colors use 4 bits each (we enable bright background). */
1073 if (isdigit (colors[0]))
1074 colors[0] -= '0';
1075 else if (isxdigit (colors[0]))
1076 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1bd7b2c7
RS
1077 if (colors[0] >= 0 && colors[0] < 16)
1078 the_only_x_display.foreground_pixel = colors[0];
76ac1508
RS
1079 if (isdigit (colors[1]))
1080 colors[1] -= '0';
1081 else if (isxdigit (colors[1]))
1082 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1083 if (colors[1] >= 0 && colors[1] < 16)
1bd7b2c7 1084 the_only_x_display.background_pixel = colors[1];
f32d4091
KS
1085 }
1086 the_only_x_display.line_height = 1;
64ec6a02 1087 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
f32d4091 1088
3bb1f22f 1089 init_frame_faces (selected_frame);
f32d4091
KS
1090
1091 ring_bell_hook = IT_ring_bell;
1092 write_glyphs_hook = IT_write_glyphs;
1093 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1094 clear_to_end_hook = IT_clear_to_end;
1095 clear_end_of_line_hook = IT_clear_end_of_line;
1096 clear_frame_hook = IT_clear_screen;
1097 change_line_highlight_hook = IT_change_line_highlight;
1098 update_begin_hook = IT_update_begin;
1099 update_end_hook = IT_update_end;
1100 reassert_line_highlight_hook = IT_reassert_line_highlight;
fc171623 1101 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
f32d4091
KS
1102
1103 /* These hooks are called by term.c without being checked. */
1104 set_terminal_modes_hook = IT_set_terminal_modes;
1105 reset_terminal_modes_hook = IT_reset_terminal_modes;
1106 set_terminal_window_hook = IT_set_terminal_window;
1107#endif
1108}
1109
1110dos_get_saved_screen (screen, rows, cols)
1111 char **screen;
1112 int *rows;
1113 int *cols;
1114{
1115#ifndef HAVE_X_WINDOWS
1116 *screen = startup_screen_buffer;
1117 *cols = startup_screen_size_X;
1118 *rows = startup_screen_size_Y;
1119 return 1;
1120#else
1121 return 0;
1122#endif
1123}
3bb1f22f
RS
1124
1125#ifndef HAVE_X_WINDOWS
1126
1127/* We are not X, but we can emulate it well enough for our needs... */
1128void
1129check_x (void)
1130{
1131 if (! FRAME_MSDOS_P (selected_frame))
1132 error ("Not running under a windows system");
1133}
1134
1135#endif
1136
5063b150 1137\f
f32d4091
KS
1138/* ----------------------- Keyboard control ----------------------
1139 *
1140 * Keymaps reflect the following keyboard layout:
1141 *
1142 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1143 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1144 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1145 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1146 * SPACE
1147 */
1148
1149static int extended_kbd; /* 101 (102) keyboard present. */
1150
1151struct dos_keyboard_map
1152{
1153 char *unshifted;
1154 char *shifted;
1155 char *alt_gr;
1156};
1157
1158
1159static struct dos_keyboard_map us_keyboard = {
1160/* 0 1 2 3 4 5 */
1161/* 01234567890123456789012345678901234567890 12345678901234 */
1162 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1163/* 0123456789012345678901234567890123456789 012345678901234 */
1164 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1165 0 /* no Alt-Gr key */
1166};
1167
1168static struct dos_keyboard_map fr_keyboard = {
1169/* 0 1 2 3 4 5 */
1170/* 012 3456789012345678901234567890123456789012345678901234 */
1171