(setup-latin1-environment): Set code 222 in special-microsoft-code-table.
[bpt/emacs.git] / src / msdos.c
... / ...
CommitLineData
1/* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
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
8the Free Software Foundation; either version 2, or (at your option)
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
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21/* Contributed by Morten Welinder */
22/* New display, keyboard, and mouse control by Kim F. Storm */
23
24/* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
25
26#include <config.h>
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>
35#include <errno.h>
36#include <string.h> /* for bzero and string functions */
37#include <sys/stat.h> /* for _fixpath */
38#include <unistd.h> /* for chdir, dup, dup2, etc. */
39#if __DJGPP__ >= 2
40#include <fcntl.h>
41#include <io.h> /* for setmode */
42#include <dpmi.h> /* for __dpmi_xxx stuff */
43#include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
44#include <libc/dosio.h> /* for _USE_LFN */
45#include <conio.h> /* for cputs */
46#endif
47
48#include "dosfns.h"
49#include "msdos.h"
50#include "systime.h"
51#include "termhooks.h"
52#include "dispextern.h"
53#include "termopts.h"
54#include "frame.h"
55#include "window.h"
56#include "buffer.h"
57#include "commands.h"
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
65#ifndef _USE_LFN
66#define _USE_LFN 0
67#endif
68
69#ifndef _dos_ds
70#define _dos_ds _go32_info_block.selector_for_linear_memory
71#endif
72
73#if __DJGPP__ > 1
74
75#include <signal.h>
76#include "syssignal.h"
77
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 */
97
98static unsigned long
99event_timestamp ()
100{
101 struct time t;
102 unsigned long s;
103
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;
110
111 return s;
112}
113
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 */
120
121int have_mouse; /* 0: no, 1: enabled, -1: disabled */
122static int mouse_visible;
123
124static int mouse_last_x;
125static int mouse_last_y;
126
127static int mouse_button_translate[NUM_MOUSE_BUTTONS];
128static int mouse_button_count;
129
130void
131mouse_on ()
132{
133 union REGS regs;
134
135 if (have_mouse > 0 && !mouse_visible)
136 {
137 if (termscript)
138 fprintf (termscript, "<M_ON>");
139 regs.x.ax = 0x0001;
140 int86 (0x33, &regs, &regs);
141 mouse_visible = 1;
142 }
143}
144
145void
146mouse_off ()
147{
148 union REGS regs;
149
150 if (have_mouse > 0 && mouse_visible)
151 {
152 if (termscript)
153 fprintf (termscript, "<M_OFF>");
154 regs.x.ax = 0x0002;
155 int86 (0x33, &regs, &regs);
156 mouse_visible = 0;
157 }
158}
159
160void
161mouse_moveto (x, y)
162 int x, y;
163{
164 union REGS regs;
165
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);
172}
173
174static int
175mouse_pressed (b, xp, yp)
176 int b, *xp, *yp;
177{
178 union REGS regs;
179
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);
188}
189
190static int
191mouse_released (b, xp, yp)
192 int b, *xp, *yp;
193{
194 union REGS regs;
195
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);
204}
205
206static void
207mouse_get_xy (int *x, int *y)
208{
209 union REGS regs;
210
211 regs.x.ax = 0x0003;
212 int86 (0x33, &regs, &regs);
213 *x = regs.x.cx / 8;
214 *y = regs.x.dx / 8;
215}
216
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}
238
239static void
240mouse_check_moved ()
241{
242 int x, y;
243
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}
249
250void
251mouse_init ()
252{
253 union REGS regs;
254
255 if (termscript)
256 fprintf (termscript, "<M_INIT>");
257
258 regs.x.ax = 0x0021;
259 int86 (0x33, &regs, &regs);
260
261 regs.x.ax = 0x0007;
262 regs.x.cx = 0;
263 regs.x.dx = 8 * (ScreenCols () - 1);
264 int86 (0x33, &regs, &regs);
265
266 regs.x.ax = 0x0008;
267 regs.x.cx = 0;
268 regs.x.dx = 8 * (ScreenRows () - 1);
269 int86 (0x33, &regs, &regs);
270
271 mouse_moveto (0, 0);
272 mouse_visible = 0;
273}
274\f
275/* ------------------------- Screen control ----------------------
276 *
277 */
278
279static int internal_terminal = 0;
280
281#ifndef HAVE_X_WINDOWS
282extern unsigned char ScreenAttrib;
283static int screen_face;
284static int highlight;
285
286static int screen_size_X;
287static int screen_size_Y;
288static int screen_size;
289
290static int current_pos_X;
291static int current_pos_Y;
292static int new_pos_X;
293static int new_pos_Y;
294
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;
300static unsigned char startup_screen_attrib;
301
302static int term_setup_done;
303
304/* Similar to the_only_frame. */
305struct x_output the_only_x_display;
306
307/* This is never dereferenced. */
308Display *x_current_display;
309
310static
311dos_direct_output (y, x, buf, len)
312 int y;
313 int x;
314 char *buf;
315 int len;
316{
317 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
318
319#if (__DJGPP__ < 2)
320 while (--len >= 0) {
321 dosmemput (buf++, 1, t);
322 t += 2;
323 }
324#else
325 /* This is faster. */
326 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
327 _farnspokeb (t, *buf);
328#endif
329}
330#endif
331
332/* Flash the screen as a substitute for BEEPs. */
333
334#if (__DJGPP__ < 2)
335static void
336do_visible_bell (xorattr)
337 unsigned char xorattr;
338{
339 asm volatile
340 (" movb $1,%%dl
341visible_bell_0:
342 movl _ScreenPrimary,%%eax
343 call dosmemsetup
344 movl %%eax,%%ebx
345 movl %1,%%ecx
346 movb %0,%%al
347 incl %%ebx
348visible_bell_1:
349 xorb %%al,%%gs:(%%ebx)
350 addl $2,%%ebx
351 decl %%ecx
352 jne visible_bell_1
353 decb %%dl
354 jne visible_bell_3
355visible_bell_2:
356 movzwl %%ax,%%eax
357 movzwl %%ax,%%eax
358 movzwl %%ax,%%eax
359 movzwl %%ax,%%eax
360 decw %%cx
361 jne visible_bell_2
362 jmp visible_bell_0
363visible_bell_3:"
364 : /* no output */
365 : "m" (xorattr), "g" (screen_size)
366 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
367}
368
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
382static int blink_bit = -1; /* the state of the blink bit at startup */
383
384/* Enable bright background colors. */
385static void
386bright_bg (void)
387{
388 union REGS regs;
389
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
395 regs.h.bl = 0;
396 regs.x.ax = 0x1003;
397 int86 (0x10, &regs, &regs);
398}
399
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
415/* Set the screen dimensions so that it can show no less than
416 ROWS x COLS frame. */
417
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
440 /* If the user specified a special video mode for these dimensions,
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);
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 }
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)
489 _set_screen_lines (std_dimension[i].rows);
490 break;
491 }
492 i++;
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 {
534 mouse_init ();
535 mouse_on ();
536 }
537
538 /* Tell the caller what dimensions have been REALLY set. */
539 *rows = ScreenRows ();
540 *cols = ScreenCols ();
541
542 /* Enable bright background colors. */
543 bright_bg ();
544}
545
546/* If we write a character in the position where the mouse is,
547 the mouse cursor may need to be refreshed. */
548
549static void
550mouse_off_maybe ()
551{
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)
568 {
569 mouse_off ();
570 ScreenVisualBell ();
571 }
572 else
573 {
574 union REGS inregs, outregs;
575 inregs.h.ah = 2;
576 inregs.h.dl = 7;
577 intdos (&inregs, &outregs);
578 }
579}
580
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;
605
606 if (len == 0) return;
607
608 buf = bp = alloca (len * 2);
609
610 while (--l >= 0)
611 {
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++;
622 }
623
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}
629
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);
641
642 while (--j >= 0)
643 {
644 *sp++ = ' ';
645 *sp++ = ScreenAttrib;
646 }
647
648 mouse_off_maybe ();
649 dosmemput (spaces, i,
650 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
651}
652
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
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];
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
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)
765{
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}
784
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 */
789
790static void
791IT_set_menu_bar_lines (window, n)
792 Lisp_Object window;
793 int n;
794{
795 struct window *w = XWINDOW (window);
796
797 XSETFASTINT (w->last_modified, 0);
798 XSETFASTINT (w->last_overlay_modified, 0);
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)
808 {
809 w = XWINDOW (window);
810 IT_set_menu_bar_lines (window, n);
811 }
812}
813
814/* This was copied from xfns.c */
815
816Lisp_Object Qbackground_color;
817Lisp_Object Qforeground_color;
818
819void
820x_set_menu_bar_lines (f, value, oldval)
821 struct frame *f;
822 Lisp_Object value, oldval;
823{
824 int nlines;
825 int olines = FRAME_MENU_BAR_LINES (f);
826
827 /* Right now, menu bars don't work properly in minibuf-only frames;
828 most of the commands try to apply themselves to the minibuffer
829 frame itslef, and get an error because you can't switch buffers
830 in or split the minibuffer window. */
831 if (FRAME_MINIBUF_ONLY_P (f))
832 return;
833
834 if (INTEGERP (value))
835 nlines = XINT (value);
836 else
837 nlines = 0;
838
839 FRAME_MENU_BAR_LINES (f) = nlines;
840 IT_set_menu_bar_lines (f->root_window, nlines - olines);
841}
842
843/* IT_set_terminal_modes is called when emacs is started,
844 resumed, and whenever the screen is redrawn! */
845
846static
847IT_set_terminal_modes (void)
848{
849 if (termscript)
850 fprintf (termscript, "\n<SET_TERM>");
851 highlight = 0;
852
853 screen_size_X = ScreenCols ();
854 screen_size_Y = ScreenRows ();
855 screen_size = screen_size_X * screen_size_Y;
856
857 new_pos_X = new_pos_Y = 0;
858 current_pos_X = current_pos_Y = -1;
859
860 if (term_setup_done)
861 return;
862 term_setup_done = 1;
863
864 startup_screen_size_X = screen_size_X;
865 startup_screen_size_Y = screen_size_Y;
866 startup_screen_attrib = ScreenAttrib;
867
868 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
869 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
870
871 if (termscript)
872 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
873 screen_size_X, screen_size_Y);
874
875 bright_bg ();
876}
877
878/* IT_reset_terminal_modes is called when emacs is
879 suspended or killed. */
880
881static
882IT_reset_terminal_modes (void)
883{
884 int display_row_start = (int) ScreenPrimary;
885 int saved_row_len = startup_screen_size_X * 2;
886 int update_row_len = ScreenCols () * 2;
887 int current_rows = ScreenRows ();
888 int to_next_row = update_row_len;
889 unsigned char *saved_row = startup_screen_buffer;
890 int cursor_pos_X = ScreenCols () - 1;
891 int cursor_pos_Y = ScreenRows () - 1;
892
893 if (termscript)
894 fprintf (termscript, "\n<RESET_TERM>");
895
896 highlight = 0;
897
898 if (!term_setup_done)
899 return;
900
901 mouse_off ();
902
903 /* Leave the video system in the same state as we found it,
904 as far as the blink/bright-background bit is concerned. */
905 maybe_enable_blinking ();
906
907 /* We have a situation here.
908 We cannot just do ScreenUpdate(startup_screen_buffer) because
909 the luser could have changed screen dimensions inside Emacs
910 and failed (or didn't want) to restore them before killing
911 Emacs. ScreenUpdate() uses the *current* screen dimensions and
912 thus will happily use memory outside what was allocated for
913 `startup_screen_buffer'.
914 Thus we only restore as much as the current screen dimensions
915 can hold, and clear the rest (if the saved screen is smaller than
916 the current) with the color attribute saved at startup. The cursor
917 is also restored within the visible dimensions. */
918
919 ScreenAttrib = startup_screen_attrib;
920 ScreenClear ();
921
922 if (update_row_len > saved_row_len)
923 update_row_len = saved_row_len;
924 if (current_rows > startup_screen_size_Y)
925 current_rows = startup_screen_size_Y;
926
927 if (termscript)
928 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
929 update_row_len / 2, current_rows);
930
931 while (current_rows--)
932 {
933 dosmemput (saved_row, update_row_len, display_row_start);
934 saved_row += saved_row_len;
935 display_row_start += to_next_row;
936 }
937 if (startup_pos_X < cursor_pos_X)
938 cursor_pos_X = startup_pos_X;
939 if (startup_pos_Y < cursor_pos_Y)
940 cursor_pos_Y = startup_pos_Y;
941
942 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
943 xfree (startup_screen_buffer);
944
945 term_setup_done = 0;
946}
947
948static
949IT_set_terminal_window (void)
950{
951}
952
953void
954IT_set_frame_parameters (f, alist)
955 FRAME_PTR f;
956 Lisp_Object alist;
957{
958 Lisp_Object tail;
959 int redraw;
960 extern unsigned long load_color ();
961
962 redraw = 0;
963 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
964 {
965 Lisp_Object elt, prop, val;
966
967 elt = Fcar (tail);
968 prop = Fcar (elt);
969 val = Fcdr (elt);
970 CHECK_SYMBOL (prop, 1);
971
972 if (EQ (prop, intern ("foreground-color")))
973 {
974 unsigned long new_color = load_color (f, val);
975 if (new_color != ~0)
976 {
977 FRAME_FOREGROUND_PIXEL (f) = new_color;
978 redraw = 1;
979 if (termscript)
980 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
981 }
982 }
983 else if (EQ (prop, intern ("background-color")))
984 {
985 unsigned long new_color = load_color (f, val);
986 if (new_color != ~0)
987 {
988 FRAME_BACKGROUND_PIXEL (f) = new_color;
989 redraw = 1;
990 if (termscript)
991 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
992 }
993 }
994 else if (EQ (prop, intern ("menu-bar-lines")))
995 x_set_menu_bar_lines (f, val, 0);
996 }
997
998 if (redraw)
999 {
1000 extern void recompute_basic_faces (FRAME_PTR);
1001 extern void redraw_frame (FRAME_PTR);
1002
1003 recompute_basic_faces (f);
1004 if (f == selected_frame)
1005 redraw_frame (f);
1006 }
1007}
1008
1009extern void init_frame_faces (FRAME_PTR);
1010
1011#endif /* !HAVE_X_WINDOWS */
1012
1013
1014/* Do we need the internal terminal? */
1015
1016void
1017internal_terminal_init ()
1018{
1019 char *term = getenv ("TERM");
1020 char *colors;
1021
1022#ifdef HAVE_X_WINDOWS
1023 if (!inhibit_window_system)
1024 return;
1025#endif
1026
1027 internal_terminal
1028 = (!noninteractive) && term && !strcmp (term, "internal");
1029
1030 if (getenv ("EMACSTEST"))
1031 termscript = fopen (getenv ("EMACSTEST"), "wt");
1032
1033#ifndef HAVE_X_WINDOWS
1034 if (!internal_terminal || inhibit_window_system)
1035 {
1036 selected_frame->output_method = output_termcap;
1037 return;
1038 }
1039
1040 Vwindow_system = intern ("pc");
1041 Vwindow_system_version = make_number (1);
1042
1043 bzero (&the_only_x_display, sizeof the_only_x_display);
1044 the_only_x_display.background_pixel = 7; /* White */
1045 the_only_x_display.foreground_pixel = 0; /* Black */
1046 bright_bg ();
1047 colors = getenv ("EMACSCOLORS");
1048 if (colors && strlen (colors) >= 2)
1049 {
1050 /* The colors use 4 bits each (we enable bright background). */
1051 if (isdigit (colors[0]))
1052 colors[0] -= '0';
1053 else if (isxdigit (colors[0]))
1054 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1055 if (colors[0] >= 0 && colors[0] < 16)
1056 the_only_x_display.foreground_pixel = colors[0];
1057 if (isdigit (colors[1]))
1058 colors[1] -= '0';
1059 else if (isxdigit (colors[1]))
1060 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1061 if (colors[1] >= 0 && colors[1] < 16)
1062 the_only_x_display.background_pixel = colors[1];
1063 }
1064 the_only_x_display.line_height = 1;
1065 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
1066
1067 init_frame_faces (selected_frame);
1068
1069 ring_bell_hook = IT_ring_bell;
1070 write_glyphs_hook = IT_write_glyphs;
1071 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1072 clear_to_end_hook = IT_clear_to_end;
1073 clear_end_of_line_hook = IT_clear_end_of_line;
1074 clear_frame_hook = IT_clear_screen;
1075 change_line_highlight_hook = IT_change_line_highlight;
1076 update_begin_hook = IT_update_begin;
1077 update_end_hook = IT_update_end;
1078 reassert_line_highlight_hook = IT_reassert_line_highlight;
1079 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
1080
1081 /* These hooks are called by term.c without being checked. */
1082 set_terminal_modes_hook = IT_set_terminal_modes;
1083 reset_terminal_modes_hook = IT_reset_terminal_modes;
1084 set_terminal_window_hook = IT_set_terminal_window;
1085#endif
1086}
1087
1088dos_get_saved_screen (screen, rows, cols)
1089 char **screen;
1090 int *rows;
1091 int *cols;
1092{
1093#ifndef HAVE_X_WINDOWS
1094 *screen = startup_screen_buffer;
1095 *cols = startup_screen_size_X;
1096 *rows = startup_screen_size_Y;
1097 return 1;
1098#else
1099 return 0;
1100#endif
1101}
1102
1103#ifndef HAVE_X_WINDOWS
1104
1105/* We are not X, but we can emulate it well enough for our needs... */
1106void
1107check_x (void)
1108{
1109 if (! FRAME_MSDOS_P (selected_frame))
1110 error ("Not running under a windows system");
1111}
1112
1113#endif
1114
1115\f
1116/* ----------------------- Keyboard control ----------------------
1117 *
1118 * Keymaps reflect the following keyboard layout:
1119 *
1120 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1121 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1122 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1123 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1124 * SPACE
1125 */
1126
1127static int extended_kbd; /* 101 (102) keyboard present. */
1128
1129struct dos_keyboard_map
1130{
1131 char *unshifted;
1132 char *shifted;
1133 char *alt_gr;
1134};
1135
1136
1137static struct dos_keyboard_map us_keyboard = {
1138/* 0 1 2 3 4 5 */
1139/* 01234567890123456789012345678901234567890 12345678901234 */
1140 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1141/* 0123456789012345678901234567890123456789 012345678901234 */
1142 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1143 0 /* no Alt-Gr key */
1144};
1145
1146static struct dos_keyboard_map fr_keyboard = {
1147/* 0 1 2 3 4 5 */
1148/* 012 3456789012345678901234567890123456789012345678901234 */
1149