Changes for separate unspecified foreground and background colors
[bpt/emacs.git] / src / msdos.c
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 94, 95, 96, 97, 1999 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, 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 <time.h>
33 #include <sys/param.h>
34 #include <sys/time.h>
35 #include <dos.h>
36 #include <errno.h>
37 #include <string.h> /* for bzero and string functions */
38 #include <sys/stat.h> /* for _fixpath */
39 #include <unistd.h> /* for chdir, dup, dup2, etc. */
40 #if __DJGPP__ >= 2
41 #include <fcntl.h>
42 #include <io.h> /* for setmode */
43 #include <dpmi.h> /* for __dpmi_xxx stuff */
44 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
45 #include <libc/dosio.h> /* for _USE_LFN */
46 #include <conio.h> /* for cputs */
47 #endif
48
49 #include "msdos.h"
50 #include "systime.h"
51 #include "termhooks.h"
52 #include "termchar.h"
53 #include "dispextern.h"
54 #include "dosfns.h"
55 #include "termopts.h"
56 #include "charset.h"
57 #include "coding.h"
58 #include "disptab.h"
59 #include "frame.h"
60 #include "window.h"
61 #include "buffer.h"
62 #include "commands.h"
63 #include <go32.h>
64 #include <pc.h>
65 #include <ctype.h>
66 /* #include <process.h> */
67 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
68 #define P_WAIT 1
69
70 #ifndef _USE_LFN
71 #define _USE_LFN 0
72 #endif
73
74 #ifndef _dos_ds
75 #define _dos_ds _go32_info_block.selector_for_linear_memory
76 #endif
77
78 #if __DJGPP__ > 1
79
80 #include <signal.h>
81 #include "syssignal.h"
82
83 #ifndef SYSTEM_MALLOC
84
85 #ifdef GNU_MALLOC
86
87 /* If other `malloc' than ours is used, force our `sbrk' behave like
88 Unix programs expect (resize memory blocks to keep them contiguous).
89 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
90 because that's what `gmalloc' expects to get. */
91 #include <crt0.h>
92
93 #ifdef REL_ALLOC
94 int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
95 #else /* not REL_ALLOC */
96 int _crt0_startup_flags = (_CRT0_FLAG_UNIX_SBRK | _CRT0_FLAG_FILL_SBRK_MEMORY);
97 #endif /* not REL_ALLOC */
98 #endif /* GNU_MALLOC */
99
100 #endif /* not SYSTEM_MALLOC */
101 #endif /* __DJGPP__ > 1 */
102
103 static unsigned long
104 event_timestamp ()
105 {
106 struct time t;
107 unsigned long s;
108
109 gettime (&t);
110 s = t.ti_min;
111 s *= 60;
112 s += t.ti_sec;
113 s *= 1000;
114 s += t.ti_hund * 10;
115
116 return s;
117 }
118
119 \f
120 /* ------------------------ Mouse control ---------------------------
121 *
122 * Coordinates are in screen positions and zero based.
123 * Mouse buttons are numbered from left to right and also zero based.
124 */
125
126 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
127 static int mouse_visible;
128
129 static int mouse_last_x;
130 static int mouse_last_y;
131
132 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
133 static int mouse_button_count;
134
135 void
136 mouse_on ()
137 {
138 union REGS regs;
139
140 if (have_mouse > 0 && !mouse_visible)
141 {
142 if (termscript)
143 fprintf (termscript, "<M_ON>");
144 regs.x.ax = 0x0001;
145 int86 (0x33, &regs, &regs);
146 mouse_visible = 1;
147 }
148 }
149
150 void
151 mouse_off ()
152 {
153 union REGS regs;
154
155 if (have_mouse > 0 && mouse_visible)
156 {
157 if (termscript)
158 fprintf (termscript, "<M_OFF>");
159 regs.x.ax = 0x0002;
160 int86 (0x33, &regs, &regs);
161 mouse_visible = 0;
162 }
163 }
164
165 static void
166 mouse_get_xy (int *x, int *y)
167 {
168 union REGS regs;
169
170 regs.x.ax = 0x0003;
171 int86 (0x33, &regs, &regs);
172 *x = regs.x.cx / 8;
173 *y = regs.x.dx / 8;
174 }
175
176 void
177 mouse_moveto (x, y)
178 int x, y;
179 {
180 union REGS regs;
181
182 if (termscript)
183 fprintf (termscript, "<M_XY=%dx%d>", x, y);
184 regs.x.ax = 0x0004;
185 mouse_last_x = regs.x.cx = x * 8;
186 mouse_last_y = regs.x.dx = y * 8;
187 int86 (0x33, &regs, &regs);
188 }
189
190 static int
191 mouse_pressed (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 = 0x0005;
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
206 static int
207 mouse_released (b, xp, yp)
208 int b, *xp, *yp;
209 {
210 union REGS regs;
211
212 if (b >= mouse_button_count)
213 return 0;
214 regs.x.ax = 0x0006;
215 regs.x.bx = mouse_button_translate[b];
216 int86 (0x33, &regs, &regs);
217 if (regs.x.bx)
218 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
219 return (regs.x.bx != 0);
220 }
221
222 static int
223 mouse_button_depressed (b, xp, yp)
224 int b, *xp, *yp;
225 {
226 union REGS regs;
227
228 if (b >= mouse_button_count)
229 return 0;
230 regs.x.ax = 0x0003;
231 int86 (0x33, &regs, &regs);
232 if ((regs.x.bx & (1 << mouse_button_translate[b])) != 0)
233 {
234 *xp = regs.x.cx / 8;
235 *yp = regs.x.dx / 8;
236 return 1;
237 }
238 return 0;
239 }
240
241 void
242 mouse_get_pos (f, insist, bar_window, part, x, y, time)
243 FRAME_PTR *f;
244 int insist;
245 Lisp_Object *bar_window, *x, *y;
246 enum scroll_bar_part *part;
247 unsigned long *time;
248 {
249 int ix, iy;
250 Lisp_Object frame, tail;
251
252 /* Clear the mouse-moved flag for every frame on this display. */
253 FOR_EACH_FRAME (tail, frame)
254 XFRAME (frame)->mouse_moved = 0;
255
256 *f = SELECTED_FRAME();
257 *bar_window = Qnil;
258 mouse_get_xy (&ix, &iy);
259 *time = event_timestamp ();
260 *x = make_number (mouse_last_x = ix);
261 *y = make_number (mouse_last_y = iy);
262 }
263
264 static void
265 mouse_check_moved ()
266 {
267 int x, y;
268
269 mouse_get_xy (&x, &y);
270 SELECTED_FRAME()->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
271 mouse_last_x = x;
272 mouse_last_y = y;
273 }
274
275 void
276 mouse_init ()
277 {
278 union REGS regs;
279 int b;
280
281 if (termscript)
282 fprintf (termscript, "<M_INIT>");
283
284 regs.x.ax = 0x0021;
285 int86 (0x33, &regs, &regs);
286
287 /* Reset the mouse last press/release info. It seems that Windows
288 doesn't do that automatically when function 21h is called, which
289 causes Emacs to ``remember'' the click that switched focus to the
290 window just before Emacs was started from that window. */
291 for (b = 0; b < mouse_button_count; b++)
292 {
293 int dummy_x, dummy_y;
294
295 (void) mouse_pressed (b, &dummy_x, &dummy_y);
296 (void) mouse_released (b, &dummy_x, &dummy_y);
297 }
298
299 regs.x.ax = 0x0007;
300 regs.x.cx = 0;
301 regs.x.dx = 8 * (ScreenCols () - 1);
302 int86 (0x33, &regs, &regs);
303
304 regs.x.ax = 0x0008;
305 regs.x.cx = 0;
306 regs.x.dx = 8 * (ScreenRows () - 1);
307 int86 (0x33, &regs, &regs);
308
309 mouse_moveto (0, 0);
310 mouse_visible = 0;
311 }
312 \f
313 /* ------------------------- Screen control ----------------------
314 *
315 */
316
317 static int internal_terminal = 0;
318
319 #ifndef HAVE_X_WINDOWS
320 extern unsigned char ScreenAttrib;
321 static int screen_face;
322 static int highlight;
323
324 static int screen_size_X;
325 static int screen_size_Y;
326 static int screen_size;
327
328 static int current_pos_X;
329 static int current_pos_Y;
330 static int new_pos_X;
331 static int new_pos_Y;
332
333 static void *startup_screen_buffer;
334 static int startup_screen_size_X;
335 static int startup_screen_size_Y;
336 static int startup_pos_X;
337 static int startup_pos_Y;
338 static unsigned char startup_screen_attrib;
339
340 static clock_t startup_time;
341
342 static int term_setup_done;
343
344 /* Similar to the_only_frame. */
345 struct x_output the_only_x_display;
346
347 /* Support for DOS/V (allows Japanese characters to be displayed on
348 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
349
350 /* Holds the address of the text-mode screen buffer. */
351 static unsigned long screen_old_address = 0;
352 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
353 static unsigned short screen_virtual_segment = 0;
354 static unsigned short screen_virtual_offset = 0;
355 /* A flag to control how to display unibyte 8-bit characters. */
356 extern int unibyte_display_via_language_environment;
357
358 #if __DJGPP__ > 1
359 /* Update the screen from a part of relocated DOS/V screen buffer which
360 begins at OFFSET and includes COUNT characters. */
361 static void
362 dosv_refresh_virtual_screen (int offset, int count)
363 {
364 __dpmi_regs regs;
365
366 if (offset < 0 || count < 0) /* paranoia; illegal values crash DOS/V */
367 return;
368
369 regs.h.ah = 0xff; /* update relocated screen */
370 regs.x.es = screen_virtual_segment;
371 regs.x.di = screen_virtual_offset + offset;
372 regs.x.cx = count;
373 __dpmi_int (0x10, &regs);
374 }
375 #endif
376
377 static void
378 dos_direct_output (y, x, buf, len)
379 int y;
380 int x;
381 char *buf;
382 int len;
383 {
384 int t0 = 2 * (x + y * screen_size_X);
385 int t = t0 + (int) ScreenPrimary;
386 int l0 = len;
387
388 #if (__DJGPP__ < 2)
389 while (--len >= 0) {
390 dosmemput (buf++, 1, t);
391 t += 2;
392 }
393 #else
394 /* This is faster. */
395 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
396 _farnspokeb (t, *buf);
397
398 if (screen_virtual_segment)
399 dosv_refresh_virtual_screen (t0, l0);
400 #endif
401 }
402 #endif
403
404 /* Flash the screen as a substitute for BEEPs. */
405
406 #if (__DJGPP__ < 2)
407 static void
408 do_visible_bell (xorattr)
409 unsigned char xorattr;
410 {
411 asm volatile
412 (" movb $1,%%dl
413 visible_bell_0:
414 movl _ScreenPrimary,%%eax
415 call dosmemsetup
416 movl %%eax,%%ebx
417 movl %1,%%ecx
418 movb %0,%%al
419 incl %%ebx
420 visible_bell_1:
421 xorb %%al,%%gs:(%%ebx)
422 addl $2,%%ebx
423 decl %%ecx
424 jne visible_bell_1
425 decb %%dl
426 jne visible_bell_3
427 visible_bell_2:
428 movzwl %%ax,%%eax
429 movzwl %%ax,%%eax
430 movzwl %%ax,%%eax
431 movzwl %%ax,%%eax
432 decw %%cx
433 jne visible_bell_2
434 jmp visible_bell_0
435 visible_bell_3:"
436 : /* no output */
437 : "m" (xorattr), "g" (screen_size)
438 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
439 }
440
441 static void
442 ScreenVisualBell (void)
443 {
444 /* This creates an xor-mask that will swap the default fore- and
445 background colors. */
446 do_visible_bell (((the_only_x_display.foreground_pixel
447 ^ the_only_x_display.background_pixel)
448 * 0x11) & 0x7f);
449 }
450 #endif
451
452 #ifndef HAVE_X_WINDOWS
453
454 static int blink_bit = -1; /* the state of the blink bit at startup */
455
456 /* Enable bright background colors. */
457 static void
458 bright_bg (void)
459 {
460 union REGS regs;
461
462 /* Remember the original state of the blink/bright-background bit.
463 It is stored at 0040:0065h in the BIOS data area. */
464 if (blink_bit == -1)
465 blink_bit = (_farpeekb (_dos_ds, 0x465) & 0x20) == 0x20;
466
467 regs.h.bl = 0;
468 regs.x.ax = 0x1003;
469 int86 (0x10, &regs, &regs);
470 }
471
472 /* Disable bright background colors (and enable blinking) if we found
473 the video system in that state at startup. */
474 static void
475 maybe_enable_blinking (void)
476 {
477 if (blink_bit == 1)
478 {
479 union REGS regs;
480
481 regs.h.bl = 1;
482 regs.x.ax = 0x1003;
483 int86 (0x10, &regs, &regs);
484 }
485 }
486
487 /* Set the screen dimensions so that it can show no less than
488 ROWS x COLS frame. */
489
490 void
491 dos_set_window_size (rows, cols)
492 int *rows, *cols;
493 {
494 char video_name[30];
495 Lisp_Object video_mode;
496 int video_mode_value;
497 int have_vga = 0;
498 union REGS regs;
499 int current_rows = ScreenRows (), current_cols = ScreenCols ();
500
501 if (*rows == current_rows && *cols == current_cols)
502 return;
503
504 /* Do we have a VGA? */
505 regs.x.ax = 0x1a00;
506 int86 (0x10, &regs, &regs);
507 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
508 have_vga = 1;
509
510 mouse_off ();
511
512 /* If the user specified a special video mode for these dimensions,
513 use that mode. */
514 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
515 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
516 Qnil))-> value;
517
518 if (INTEGERP (video_mode)
519 && (video_mode_value = XINT (video_mode)) > 0)
520 {
521 regs.x.ax = video_mode_value;
522 int86 (0x10, &regs, &regs);
523
524 if (have_mouse)
525 {
526 /* Must hardware-reset the mouse, or else it won't update
527 its notion of screen dimensions for some non-standard
528 video modes. This is *painfully* slow... */
529 regs.x.ax = 0;
530 int86 (0x33, &regs, &regs);
531 }
532 }
533
534 /* Find one of the dimensions supported by standard EGA/VGA
535 which gives us at least the required dimensions. */
536
537 #if __DJGPP__ > 1
538
539 else
540 {
541 static struct {
542 int rows;
543 int need_vga;
544 } std_dimension[] = {
545 {25, 0},
546 {28, 1},
547 {35, 0},
548 {40, 1},
549 {43, 0},
550 {50, 1}
551 };
552 int i = 0;
553
554 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
555 {
556 if (std_dimension[i].need_vga <= have_vga
557 && std_dimension[i].rows >= *rows)
558 {
559 if (std_dimension[i].rows != current_rows
560 || *cols != current_cols)
561 _set_screen_lines (std_dimension[i].rows);
562 break;
563 }
564 i++;
565 }
566 }
567
568 #else /* not __DJGPP__ > 1 */
569
570 else if (*rows <= 25)
571 {
572 if (current_rows != 25 || current_cols != 80)
573 {
574 regs.x.ax = 3;
575 int86 (0x10, &regs, &regs);
576 regs.x.ax = 0x1101;
577 regs.h.bl = 0;
578 int86 (0x10, &regs, &regs);
579 regs.x.ax = 0x1200;
580 regs.h.bl = 32;
581 int86 (0x10, &regs, &regs);
582 regs.x.ax = 3;
583 int86 (0x10, &regs, &regs);
584 }
585 }
586 else if (*rows <= 50)
587 if (have_vga && (current_rows != 50 || current_cols != 80)
588 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
589 {
590 regs.x.ax = 3;
591 int86 (0x10, &regs, &regs);
592 regs.x.ax = 0x1112;
593 regs.h.bl = 0;
594 int86 (0x10, &regs, &regs);
595 regs.x.ax = 0x1200;
596 regs.h.bl = 32;
597 int86 (0x10, &regs, &regs);
598 regs.x.ax = 0x0100;
599 regs.x.cx = 7;
600 int86 (0x10, &regs, &regs);
601 }
602 #endif /* not __DJGPP__ > 1 */
603
604 if (have_mouse)
605 {
606 mouse_init ();
607 mouse_on ();
608 }
609
610 /* Tell the caller what dimensions have been REALLY set. */
611 *rows = ScreenRows ();
612 *cols = ScreenCols ();
613
614 /* Enable bright background colors. */
615 bright_bg ();
616
617 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
618 be defensive anyway. */
619 if (screen_virtual_segment)
620 dosv_refresh_virtual_screen (0, *cols * *rows);
621 }
622
623 /* If we write a character in the position where the mouse is,
624 the mouse cursor may need to be refreshed. */
625
626 static void
627 mouse_off_maybe ()
628 {
629 int x, y;
630
631 if (!mouse_visible)
632 return;
633
634 mouse_get_xy (&x, &y);
635 if (y != new_pos_Y || x < new_pos_X)
636 return;
637
638 mouse_off ();
639 }
640
641 static void
642 IT_ring_bell (void)
643 {
644 if (visible_bell)
645 {
646 mouse_off ();
647 ScreenVisualBell ();
648 }
649 else
650 {
651 union REGS inregs, outregs;
652 inregs.h.ah = 2;
653 inregs.h.dl = 7;
654 intdos (&inregs, &outregs);
655 }
656 }
657
658 /* Given a face id FACE, extract the face parameters to be used for
659 display until the face changes. The face parameters (actually, its
660 color) are used to construct the video attribute byte for each
661 glyph during the construction of the buffer that is then blitted to
662 the video RAM. */
663 static void
664 IT_set_face (int face)
665 {
666 struct frame *sf = SELECTED_FRAME();
667 struct face *fp = FACE_FROM_ID (sf, face);
668 unsigned long fg, bg;
669
670 if (!fp)
671 {
672 fp = FACE_FROM_ID (sf, DEFAULT_FACE_ID);
673 /* The default face for the frame should always be realized and
674 cached. */
675 if (!fp)
676 abort ();
677 }
678 screen_face = face;
679 fg = fp->foreground;
680 bg = fp->background;
681
682 /* Don't use invalid colors. In particular, a color of -1 means use
683 the colors of the default face, except that if highlight is on,
684 invert the foreground and the background. Note that we assume
685 all 16 colors to be available for the background, since Emacs
686 switches on this mode (and loses the blinking attribute) at
687 startup. */
688 if (fg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_FG_COLOR)
689 fg = highlight || fp->tty_reverse_p ? FRAME_BACKGROUND_PIXEL (sf)
690 : FRAME_FOREGROUND_PIXEL (sf);
691 else if (fg == FACE_TTY_DEFAULT_BG_COLOR)
692 fg = highlight ? FRAME_FOREGROUND_PIXEL (sf) : FRAME_BACKGROUND_PIXEL (sf);
693 if (bg == FACE_TTY_DEFAULT_COLOR || fg == FACE_TTY_DEFAULT_BG_COLOR)
694 bg = highlight || fp->tty_reverse_p ? FRAME_FOREGROUND_PIXEL (sf)
695 : FRAME_BACKGROUND_PIXEL (sf);
696 else if (bg == FACE_TTY_DEFAULT_FG_COLOR)
697 fg = highlight ? FRAME_BACKGROUND_PIXEL (sf) : FRAME_FOREGROUND_PIXEL (sf);
698 if (termscript)
699 fprintf (termscript, "<FACE %d%s: %d/%d>",
700 face, highlight ? "H" : "", fp->foreground, fp->background);
701 if (fg >= 0 && fg < 16)
702 {
703 ScreenAttrib &= 0xf0;
704 ScreenAttrib |= fg;
705 }
706 if (bg >= 0 && bg < 16)
707 {
708 ScreenAttrib &= 0x0f;
709 ScreenAttrib |= ((bg & 0x0f) << 4);
710 }
711 }
712
713 Lisp_Object Vdos_unsupported_char_glyph;
714
715 static void
716 IT_write_glyphs (struct glyph *str, int str_len)
717 {
718 unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
719 int unsupported_face = FAST_GLYPH_FACE (Vdos_unsupported_char_glyph);
720 unsigned unsupported_char= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph);
721 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
722 register int sl = str_len;
723 register int tlen = GLYPH_TABLE_LENGTH;
724 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
725
726 struct coding_system *coding = (CODING_REQUIRE_ENCODING (&terminal_coding)
727 ? &terminal_coding
728 : &safe_terminal_coding);
729 struct frame *sf;
730
731 /* Do we need to consider conversion of unibyte characters to
732 multibyte? */
733 int convert_unibyte_characters
734 = (NILP (current_buffer->enable_multibyte_characters)
735 && unibyte_display_via_language_environment);
736
737 if (str_len == 0) return;
738
739 screen_buf = screen_bp = alloca (str_len * 2);
740 screen_buf_end = screen_buf + str_len * 2;
741 sf = SELECTED_FRAME();
742
743 /* Since faces get cached and uncached behind our back, we can't
744 rely on their indices in the cache being consistent across
745 invocations. So always reset the screen face to the default
746 face of the frame, before writing glyphs, and let the glyphs
747 set the right face if it's different from the default. */
748 IT_set_face (DEFAULT_FACE_ID);
749
750 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
751 the tail. */
752 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
753 while (sl)
754 {
755 int cf, chlen, enclen;
756 unsigned char workbuf[4], *buf;
757 unsigned ch;
758 register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
759
760 /* Find the actual glyph to display by traversing the entire
761 aliases chain for this glyph. */
762 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
763
764 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
765 only for the redisplay code to know how many columns does
766 this character occupy on the screen. Skip padding glyphs. */
767 if (CHAR_GLYPH_PADDING_P (*str))
768 {
769 str++;
770 sl--;
771 }
772 else
773 {
774 /* Convert the character code to multibyte, if they
775 requested display via language environment. */
776 ch = FAST_GLYPH_CHAR (g);
777 /* We only want to convert unibyte characters to multibyte
778 in unibyte buffers! Otherwise, the 8-bit code might come
779 from the display table set up to display foreign characters. */
780 if (SINGLE_BYTE_CHAR_P (ch) && convert_unibyte_characters
781 && (ch >= 0240
782 || (ch >= 0200 && !NILP (Vnonascii_translation_table))))
783 ch = unibyte_char_to_multibyte (ch);
784
785 /* Invalid characters are displayed with a special glyph. */
786 if (! GLYPH_CHAR_VALID_P (ch))
787 {
788 g = !NILP (Vdos_unsupported_char_glyph)
789 ? Vdos_unsupported_char_glyph
790 : MAKE_GLYPH (sf, '\177', GLYPH_FACE (sf, g));
791 ch = FAST_GLYPH_CHAR (g);
792 }
793 if (COMPOSITE_CHAR_P (ch))
794 {
795 /* If CH is a composite character, we can display
796 only the first component. */
797 g = cmpchar_table[COMPOSITE_CHAR_ID (ch)]->glyph[0],
798 ch = GLYPH_CHAR (sf, g);
799 cf = FAST_GLYPH_FACE (g);
800 }
801
802 /* If the face of this glyph is different from the current
803 screen face, update the screen attribute byte. */
804 cf = FAST_GLYPH_FACE (g);
805 if (cf != screen_face)
806 IT_set_face (cf); /* handles invalid faces gracefully */
807
808 if (GLYPH_SIMPLE_P (tbase, tlen, g))
809 /* We generate the multi-byte form of CH in BUF. */
810 chlen = CHAR_STRING (ch, workbuf, buf);
811 else
812 {
813 /* We have a string in Vglyph_table. */
814 chlen = GLYPH_LENGTH (tbase, g);
815 buf = GLYPH_STRING (tbase, g);
816 }
817
818 /* If the character is not multibyte, don't bother converting it. */
819 if (chlen == 1)
820 {
821 *conversion_buffer = (unsigned char)ch;
822 chlen = 0;
823 enclen = 1;
824 }
825 else
826 {
827 encode_coding (coding, buf, conversion_buffer, chlen,
828 conversion_buffer_size);
829 chlen -= coding->consumed;
830 enclen = coding->produced;
831
832 /* Replace glyph codes that cannot be converted by
833 terminal_coding with Vdos_unsupported_char_glyph. */
834 if (*conversion_buffer == '?')
835 {
836 char *cbp = conversion_buffer;
837
838 while (cbp < conversion_buffer + enclen && *cbp == '?')
839 *cbp++ = unsupported_char;
840 if (unsupported_face != screen_face)
841 IT_set_face (unsupported_face);
842 }
843 }
844
845 if (enclen + chlen > screen_buf_end - screen_bp)
846 {
847 /* The allocated buffer for screen writes is too small.
848 Flush it and loop again without incrementing STR, so
849 that the next loop will begin with the same glyph. */
850 int nbytes = screen_bp - screen_buf;
851
852 mouse_off_maybe ();
853 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
854 if (screen_virtual_segment)
855 dosv_refresh_virtual_screen (offset, nbytes / 2);
856 new_pos_X += nbytes / 2;
857 offset += nbytes;
858
859 /* Prepare to reuse the same buffer again. */
860 screen_bp = screen_buf;
861 }
862 else
863 {
864 /* There's enough place in the allocated buffer to add
865 the encoding of this glyph. */
866
867 /* First, copy the encoded bytes. */
868 for (bp = conversion_buffer; enclen--; bp++)
869 {
870 *screen_bp++ = (unsigned char)*bp;
871 *screen_bp++ = ScreenAttrib;
872 if (termscript)
873 fputc (*bp, termscript);
874 }
875
876 /* Now copy the bytes not consumed by the encoding. */
877 if (chlen > 0)
878 {
879 buf += coding->consumed;
880 while (chlen--)
881 {
882 if (termscript)
883 fputc (*buf, termscript);
884 *screen_bp++ = (unsigned char)*buf++;
885 *screen_bp++ = ScreenAttrib;
886 }
887 }
888
889 /* Update STR and its remaining length. */
890 str++;
891 sl--;
892 }
893 }
894 }
895
896 /* Dump whatever is left in the screen buffer. */
897 mouse_off_maybe ();
898 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
899 if (screen_virtual_segment)
900 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
901 new_pos_X += (screen_bp - screen_buf) / 2;
902
903 /* We may have to output some codes to terminate the writing. */
904 if (CODING_REQUIRE_FLUSHING (coding))
905 {
906 coding->mode |= CODING_MODE_LAST_BLOCK;
907 encode_coding (coding, "", conversion_buffer, 0, conversion_buffer_size);
908 if (coding->produced > 0)
909 {
910 for (screen_bp = screen_buf, bp = conversion_buffer;
911 coding->produced--; bp++)
912 {
913 *screen_bp++ = (unsigned char)*bp;
914 *screen_bp++ = ScreenAttrib;
915 if (termscript)
916 fputc (*bp, termscript);
917 }
918 offset += screen_bp - screen_buf;
919 mouse_off_maybe ();
920 dosmemput (screen_buf, screen_bp - screen_buf,
921 (int)ScreenPrimary + offset);
922 if (screen_virtual_segment)
923 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
924 new_pos_X += (screen_bp - screen_buf) / 2;
925 }
926 }
927 }
928
929 static void
930 IT_clear_end_of_line (int first_unused)
931 {
932 char *spaces, *sp;
933 int i, j;
934 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
935 extern int fatal_error_in_progress;
936
937 if (new_pos_X >= first_unused || fatal_error_in_progress)
938 return;
939
940 IT_set_face (0);
941 if (termscript)
942 fprintf (termscript, "<CLR:EOL>");
943 i = (j = first_unused - new_pos_X) * 2;
944 spaces = sp = alloca (i);
945
946 while (--j >= 0)
947 {
948 *sp++ = ' ';
949 *sp++ = ScreenAttrib;
950 }
951
952 mouse_off_maybe ();
953 dosmemput (spaces, i, (int)ScreenPrimary + offset);
954 if (screen_virtual_segment)
955 dosv_refresh_virtual_screen (offset, i / 2);
956
957 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
958 Let's follow their lead, in case someone relies on this. */
959 new_pos_X = first_unused;
960 }
961
962 static void
963 IT_clear_screen (void)
964 {
965 if (termscript)
966 fprintf (termscript, "<CLR:SCR>");
967 IT_set_face (0);
968 mouse_off ();
969 ScreenClear ();
970 if (screen_virtual_segment)
971 dosv_refresh_virtual_screen (0, screen_size);
972 new_pos_X = new_pos_Y = 0;
973 }
974
975 static void
976 IT_clear_to_end (void)
977 {
978 if (termscript)
979 fprintf (termscript, "<CLR:EOS>");
980
981 while (new_pos_Y < screen_size_Y) {
982 new_pos_X = 0;
983 IT_clear_end_of_line (0);
984 new_pos_Y++;
985 }
986 }
987
988 static void
989 IT_cursor_to (int y, int x)
990 {
991 if (termscript)
992 fprintf (termscript, "\n<XY=%dx%d>", x, y);
993 new_pos_X = x;
994 new_pos_Y = y;
995 }
996
997 static int cursor_cleared;
998
999 static void
1000 IT_display_cursor (int on)
1001 {
1002 if (on && cursor_cleared)
1003 {
1004 ScreenSetCursor (current_pos_Y, current_pos_X);
1005 cursor_cleared = 0;
1006 }
1007 else if (!on && !cursor_cleared)
1008 {
1009 ScreenSetCursor (-1, -1);
1010 cursor_cleared = 1;
1011 }
1012 }
1013
1014 /* Emacs calls cursor-movement functions a lot when it updates the
1015 display (probably a legacy of old terminals where you cannot
1016 update a screen line without first moving the cursor there).
1017 However, cursor movement is expensive on MSDOS (it calls a slow
1018 BIOS function and requires 2 mode switches), while actual screen
1019 updates access the video memory directly and don't depend on
1020 cursor position. To avoid slowing down the redisplay, we cheat:
1021 all functions that move the cursor only set internal variables
1022 which record the cursor position, whereas the cursor is only
1023 moved to its final position whenever screen update is complete.
1024
1025 `IT_cmgoto' is called from the keyboard reading loop and when the
1026 frame update is complete. This means that we are ready for user
1027 input, so we update the cursor position to show where the point is,
1028 and also make the mouse pointer visible.
1029
1030 Special treatment is required when the cursor is in the echo area,
1031 to put the cursor at the end of the text displayed there. */
1032
1033 static void
1034 IT_cmgoto (FRAME_PTR f)
1035 {
1036 /* Only set the cursor to where it should be if the display is
1037 already in sync with the window contents. */
1038 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1039
1040 /* FIXME: This needs to be rewritten for the new redisplay, or
1041 removed. */
1042 #if 0
1043 static int previous_pos_X = -1;
1044
1045 update_cursor_pos = 1; /* temporary!!! */
1046
1047 /* If the display is in sync, forget any previous knowledge about
1048 cursor position. This is primarily for unexpected events like
1049 C-g in the minibuffer. */
1050 if (update_cursor_pos && previous_pos_X >= 0)
1051 previous_pos_X = -1;
1052 /* If we are in the echo area, put the cursor at the
1053 end of the echo area message. */
1054 if (!update_cursor_pos
1055 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
1056 {
1057 int tem_X = current_pos_X, dummy;
1058
1059 if (echo_area_glyphs)
1060 {
1061 tem_X = echo_area_glyphs_length;
1062 /* Save current cursor position, to be restored after the
1063 echo area message is erased. Only remember one level
1064 of previous cursor position. */
1065 if (previous_pos_X == -1)
1066 ScreenGetCursor (&dummy, &previous_pos_X);
1067 }
1068 else if (previous_pos_X >= 0)
1069 {
1070 /* We wind up here after the echo area message is erased.
1071 Restore the cursor position we remembered above. */
1072 tem_X = previous_pos_X;
1073 previous_pos_X = -1;
1074 }
1075
1076 if (current_pos_X != tem_X)
1077 {
1078 new_pos_X = tem_X;
1079 update_cursor_pos = 1;
1080 }
1081 }
1082 #endif
1083
1084 if (update_cursor_pos
1085 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1086 {
1087 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1088 if (termscript)
1089 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1090 }
1091
1092 /* Maybe cursor is invisible, so make it visible. */
1093 IT_display_cursor (1);
1094
1095 /* Mouse pointer should be always visible if we are waiting for
1096 keyboard input. */
1097 if (!mouse_visible)
1098 mouse_on ();
1099 }
1100
1101 static void
1102 IT_reassert_line_highlight (int new, int vpos)
1103 {
1104 highlight = new;
1105 }
1106
1107 static void
1108 IT_change_line_highlight (int new_highlight, int y, int vpos, int first_unused_hpos)
1109 {
1110 highlight = new_highlight;
1111 IT_cursor_to (vpos, 0);
1112 IT_clear_end_of_line (first_unused_hpos);
1113 }
1114
1115 static void
1116 IT_update_begin (struct frame *foo)
1117 {
1118 highlight = 0;
1119 }
1120
1121 static void
1122 IT_update_end (struct frame *foo)
1123 {
1124 }
1125
1126 /* Copy LEN glyphs displayed on a single line whose vertical position
1127 is YPOS, beginning at horizontal position XFROM to horizontal
1128 position XTO, by moving blocks in the video memory. Used by
1129 functions that insert and delete glyphs. */
1130 static void
1131 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1132 {
1133 /* The offsets of source and destination relative to the
1134 conventional memorty selector. */
1135 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1136 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1137
1138 if (from == to || len <= 0)
1139 return;
1140
1141 _farsetsel (_dos_ds);
1142
1143 /* The source and destination might overlap, so we need to move
1144 glyphs non-destructively. */
1145 if (from > to)
1146 {
1147 for ( ; len; from += 2, to += 2, len--)
1148 _farnspokew (to, _farnspeekw (from));
1149 }
1150 else
1151 {
1152 from += (len - 1) * 2;
1153 to += (len - 1) * 2;
1154 for ( ; len; from -= 2, to -= 2, len--)
1155 _farnspokew (to, _farnspeekw (from));
1156 }
1157 if (screen_virtual_segment)
1158 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1159 }
1160
1161 /* Insert and delete glyphs. */
1162 static void
1163 IT_insert_glyphs (start, len)
1164 register struct glyph *start;
1165 register int len;
1166 {
1167 int shift_by_width = screen_size_X - (new_pos_X + len);
1168
1169 /* Shift right the glyphs from the nominal cursor position to the
1170 end of this line. */
1171 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1172
1173 /* Now write the glyphs to be inserted. */
1174 IT_write_glyphs (start, len);
1175 }
1176
1177 static void
1178 IT_delete_glyphs (n)
1179 register int n;
1180 {
1181 abort ();
1182 }
1183
1184 /* set-window-configuration on window.c needs this. */
1185 void
1186 x_set_menu_bar_lines (f, value, oldval)
1187 struct frame *f;
1188 Lisp_Object value, oldval;
1189 {
1190 set_menu_bar_lines (f, value, oldval);
1191 }
1192
1193 /* This was copied from xfns.c */
1194
1195 Lisp_Object Qbackground_color;
1196 Lisp_Object Qforeground_color;
1197 extern Lisp_Object Qtitle;
1198
1199 /* IT_set_terminal_modes is called when emacs is started,
1200 resumed, and whenever the screen is redrawn! */
1201
1202 static void
1203 IT_set_terminal_modes (void)
1204 {
1205 if (termscript)
1206 fprintf (termscript, "\n<SET_TERM>");
1207 highlight = 0;
1208
1209 screen_size_X = ScreenCols ();
1210 screen_size_Y = ScreenRows ();
1211 screen_size = screen_size_X * screen_size_Y;
1212
1213 new_pos_X = new_pos_Y = 0;
1214 current_pos_X = current_pos_Y = -1;
1215
1216 if (term_setup_done)
1217 return;
1218 term_setup_done = 1;
1219
1220 startup_screen_size_X = screen_size_X;
1221 startup_screen_size_Y = screen_size_Y;
1222 startup_screen_attrib = ScreenAttrib;
1223
1224 #if __DJGPP__ > 1
1225 /* Is DOS/V (or any other RSIS software which relocates
1226 the screen) installed? */
1227 {
1228 unsigned short es_value;
1229 __dpmi_regs regs;
1230
1231 regs.h.ah = 0xfe; /* get relocated screen address */
1232 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1233 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1234 else if (screen_old_address) /* already switched to Japanese mode once */
1235 regs.x.es = (screen_old_address >> 4) & 0xffff;
1236 else
1237 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1238 regs.x.di = 0;
1239 es_value = regs.x.es;
1240 __dpmi_int (0x10, &regs);
1241
1242 if (regs.x.es != es_value)
1243 {
1244 /* screen_old_address is only set if ScreenPrimary does NOT
1245 already point to the relocated buffer address returned by
1246 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1247 ScreenPrimary to that address at startup under DOS/V. */
1248 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
1249 screen_old_address = ScreenPrimary;
1250 screen_virtual_segment = regs.x.es;
1251 screen_virtual_offset = regs.x.di;
1252 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1253 }
1254 }
1255 #endif /* __DJGPP__ > 1 */
1256
1257 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1258 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1259
1260 if (termscript)
1261 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1262 screen_size_X, screen_size_Y);
1263
1264 bright_bg ();
1265 }
1266
1267 /* IT_reset_terminal_modes is called when emacs is
1268 suspended or killed. */
1269
1270 static void
1271 IT_reset_terminal_modes (void)
1272 {
1273 int display_row_start = (int) ScreenPrimary;
1274 int saved_row_len = startup_screen_size_X * 2;
1275 int update_row_len = ScreenCols () * 2;
1276 int current_rows = ScreenRows ();
1277 int to_next_row = update_row_len;
1278 unsigned char *saved_row = startup_screen_buffer;
1279 int cursor_pos_X = ScreenCols () - 1;
1280 int cursor_pos_Y = ScreenRows () - 1;
1281
1282 if (termscript)
1283 fprintf (termscript, "\n<RESET_TERM>");
1284
1285 highlight = 0;
1286
1287 if (!term_setup_done)
1288 return;
1289
1290 mouse_off ();
1291
1292 /* Leave the video system in the same state as we found it,
1293 as far as the blink/bright-background bit is concerned. */
1294 maybe_enable_blinking ();
1295
1296 /* We have a situation here.
1297 We cannot just do ScreenUpdate(startup_screen_buffer) because
1298 the luser could have changed screen dimensions inside Emacs
1299 and failed (or didn't want) to restore them before killing
1300 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1301 thus will happily use memory outside what was allocated for
1302 `startup_screen_buffer'.
1303 Thus we only restore as much as the current screen dimensions
1304 can hold, and clear the rest (if the saved screen is smaller than
1305 the current) with the color attribute saved at startup. The cursor
1306 is also restored within the visible dimensions. */
1307
1308 ScreenAttrib = startup_screen_attrib;
1309
1310 /* Don't restore the screen if we are exiting less than 2 seconds
1311 after startup: we might be crashing, and the screen might show
1312 some vital clues to what's wrong. */
1313 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
1314 {
1315 ScreenClear ();
1316 if (screen_virtual_segment)
1317 dosv_refresh_virtual_screen (0, screen_size);
1318
1319 if (update_row_len > saved_row_len)
1320 update_row_len = saved_row_len;
1321 if (current_rows > startup_screen_size_Y)
1322 current_rows = startup_screen_size_Y;
1323
1324 if (termscript)
1325 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1326 update_row_len / 2, current_rows);
1327
1328 while (current_rows--)
1329 {
1330 dosmemput (saved_row, update_row_len, display_row_start);
1331 if (screen_virtual_segment)
1332 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
1333 update_row_len / 2);
1334 saved_row += saved_row_len;
1335 display_row_start += to_next_row;
1336 }
1337 }
1338 if (startup_pos_X < cursor_pos_X)
1339 cursor_pos_X = startup_pos_X;
1340 if (startup_pos_Y < cursor_pos_Y)
1341 cursor_pos_Y = startup_pos_Y;
1342
1343 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
1344 xfree (startup_screen_buffer);
1345
1346 term_setup_done = 0;
1347 }
1348
1349 static void
1350 IT_set_terminal_window (int foo)
1351 {
1352 }
1353
1354 /* Remember the screen colors of the curent frame, to serve as the
1355 default colors for newly-created frames. */
1356
1357 static int initial_screen_colors[2];
1358
1359 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
1360 Smsdos_remember_default_colors, 1, 1, 0,
1361 "Remember the screen colors of the current frame.")
1362 (frame)
1363 Lisp_Object frame;
1364 {
1365 int reverse;
1366 struct frame *f;
1367
1368 CHECK_FRAME (frame, 0);
1369 f= XFRAME (frame);
1370 reverse = EQ (Fcdr (Fassq (intern ("reverse"), f->param_alist)), Qt);
1371
1372 initial_screen_colors[0]
1373 = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
1374 initial_screen_colors[1]
1375 = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
1376 }
1377
1378 void
1379 IT_set_frame_parameters (f, alist)
1380 struct frame *f;
1381 Lisp_Object alist;
1382 {
1383 Lisp_Object tail;
1384 int length = XINT (Flength (alist));
1385 int i, j;
1386 Lisp_Object *parms
1387 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1388 Lisp_Object *values
1389 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1390 Lisp_Object qreverse = intern ("reverse");
1391 /* Do we have to reverse the foreground and background colors? */
1392 int reverse = EQ (Fcdr (Fassq (qreverse, f->param_alist)), Qt);
1393 int was_reverse = reverse;
1394 int redraw = 0, fg_set = 0, bg_set = 0;
1395 unsigned long orig_fg;
1396 unsigned long orig_bg;
1397
1398 /* If we are creating a new frame, begin with the original screen colors
1399 used for the initial frame. */
1400 if (alist == Vdefault_frame_alist
1401 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
1402 {
1403 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
1404 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
1405 }
1406 orig_fg = FRAME_FOREGROUND_PIXEL (f);
1407 orig_bg = FRAME_BACKGROUND_PIXEL (f);
1408
1409 /* Extract parm names and values into those vectors. */
1410 i = 0;
1411 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1412 {
1413 Lisp_Object elt;
1414
1415 elt = Fcar (tail);
1416 parms[i] = Fcar (elt);
1417 CHECK_SYMBOL (parms[i], 1);
1418 values[i] = Fcdr (elt);
1419 i++;
1420 }
1421
1422 j = i;
1423
1424 for (i = 0; i < j; i++)
1425 {
1426 Lisp_Object prop = parms[i];
1427 Lisp_Object val = values[i];
1428
1429 if (EQ (prop, qreverse))
1430 reverse = EQ (val, Qt);
1431 }
1432
1433 if (termscript && reverse && !was_reverse)
1434 fprintf (termscript, "<INVERSE-VIDEO>\n");
1435
1436 /* Now process the alist elements in reverse of specified order. */
1437 for (i--; i >= 0; i--)
1438 {
1439 Lisp_Object prop = parms[i];
1440 Lisp_Object val = values[i];
1441
1442 if (EQ (prop, Qforeground_color))
1443 {
1444 unsigned long new_color = load_color (f, NULL, val, reverse
1445 ? LFACE_BACKGROUND_INDEX
1446 : LFACE_FOREGROUND_INDEX);
1447 if (new_color != ~0)
1448 {
1449 if (reverse)
1450 /* FIXME: should the fore-/background of the default
1451 face change here as well? */
1452 FRAME_BACKGROUND_PIXEL (f) = new_color;
1453 else
1454 FRAME_FOREGROUND_PIXEL (f) = new_color;
1455 redraw = 1;
1456 fg_set = 1;
1457 if (termscript)
1458 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
1459 }
1460 }
1461 else if (EQ (prop, Qbackground_color))
1462 {
1463 unsigned long new_color = load_color (f, NULL, val, reverse
1464 ? LFACE_FOREGROUND_INDEX
1465 : LFACE_BACKGROUND_INDEX);
1466 if (new_color != ~0)
1467 {
1468 if (reverse)
1469 FRAME_FOREGROUND_PIXEL (f) = new_color;
1470 else
1471 FRAME_BACKGROUND_PIXEL (f) = new_color;
1472 redraw = 1;
1473 bg_set = 1;
1474 if (termscript)
1475 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
1476 }
1477 }
1478 else if (EQ (prop, Qtitle))
1479 {
1480 x_set_title (f, val);
1481 if (termscript)
1482 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
1483 }
1484 store_frame_param (f, prop, val);
1485 }
1486
1487 /* If they specified "reverse", but not the colors, we need to swap
1488 the current frame colors. */
1489 if (reverse && !was_reverse)
1490 {
1491 if (!fg_set)
1492 {
1493 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
1494 redraw = 1;
1495 }
1496 if (!bg_set)
1497 {
1498 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
1499 redraw = 1;
1500 }
1501 }
1502
1503 if (redraw)
1504 {
1505 face_change_count++; /* forces xdisp.c to recompute basic faces */
1506 if (f == SELECTED_FRAME())
1507 redraw_frame (f);
1508 }
1509 }
1510
1511 extern void init_frame_faces (FRAME_PTR);
1512
1513 #endif /* !HAVE_X_WINDOWS */
1514
1515
1516 /* Do we need the internal terminal? */
1517
1518 void
1519 internal_terminal_init ()
1520 {
1521 char *term = getenv ("TERM");
1522 char *colors;
1523 struct frame *sf = SELECTED_FRAME();
1524
1525 #ifdef HAVE_X_WINDOWS
1526 if (!inhibit_window_system)
1527 return;
1528 #endif
1529
1530 internal_terminal
1531 = (!noninteractive) && term && !strcmp (term, "internal");
1532
1533 if (getenv ("EMACSTEST"))
1534 termscript = fopen (getenv ("EMACSTEST"), "wt");
1535
1536 #ifndef HAVE_X_WINDOWS
1537 if (!internal_terminal || inhibit_window_system)
1538 {
1539 sf->output_method = output_termcap;
1540 return;
1541 }
1542
1543 Vwindow_system = intern ("pc");
1544 Vwindow_system_version = make_number (1);
1545 sf->output_method = output_msdos_raw;
1546
1547 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1548 screen_old_address = 0;
1549
1550 /* Forget the stale screen colors as well. */
1551 initial_screen_colors[0] = initial_screen_colors[1] = -1;
1552
1553 bzero (&the_only_x_display, sizeof the_only_x_display);
1554 the_only_x_display.background_pixel = 7; /* White */
1555 the_only_x_display.foreground_pixel = 0; /* Black */
1556 bright_bg ();
1557 colors = getenv ("EMACSCOLORS");
1558 if (colors && strlen (colors) >= 2)
1559 {
1560 /* The colors use 4 bits each (we enable bright background). */
1561 if (isdigit (colors[0]))
1562 colors[0] -= '0';
1563 else if (isxdigit (colors[0]))
1564 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1565 if (colors[0] >= 0 && colors[0] < 16)
1566 the_only_x_display.foreground_pixel = colors[0];
1567 if (isdigit (colors[1]))
1568 colors[1] -= '0';
1569 else if (isxdigit (colors[1]))
1570 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1571 if (colors[1] >= 0 && colors[1] < 16)
1572 the_only_x_display.background_pixel = colors[1];
1573 }
1574 the_only_x_display.line_height = 1;
1575 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
1576
1577 init_frame_faces (sf);
1578
1579 ring_bell_hook = IT_ring_bell;
1580 insert_glyphs_hook = IT_insert_glyphs;
1581 delete_glyphs_hook = IT_delete_glyphs;
1582 write_glyphs_hook = IT_write_glyphs;
1583 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1584 clear_to_end_hook = IT_clear_to_end;
1585 clear_end_of_line_hook = IT_clear_end_of_line;
1586 clear_frame_hook = IT_clear_screen;
1587 change_line_highlight_hook = IT_change_line_highlight;
1588 update_begin_hook = IT_update_begin;
1589 update_end_hook = IT_update_end;
1590 reassert_line_highlight_hook = IT_reassert_line_highlight;
1591 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
1592
1593 /* These hooks are called by term.c without being checked. */
1594 set_terminal_modes_hook = IT_set_terminal_modes;
1595 reset_terminal_modes_hook = IT_reset_terminal_modes;
1596 set_terminal_window_hook = IT_set_terminal_window;
1597 char_ins_del_ok = 0;
1598 #endif
1599 }
1600
1601 dos_get_saved_screen (screen, rows, cols)
1602 char **screen;
1603 int *rows;
1604 int *cols;
1605 {
1606 #ifndef HAVE_X_WINDOWS
1607 *screen = startup_screen_buffer;
1608 *cols = startup_screen_size_X;
1609 *rows = startup_screen_size_Y;
1610 return *screen != (char *)0;
1611 #else
1612 return 0;
1613 #endif
1614 }
1615
1616 #ifndef HAVE_X_WINDOWS
1617
1618 /* We are not X, but we can emulate it well enough for our needs... */
1619 void
1620 check_x (void)
1621 {
1622 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
1623 error ("Not running under a window system");
1624 }
1625
1626 #endif
1627
1628 \f
1629 /* ----------------------- Keyboard control ----------------------
1630 *
1631 * Keymaps reflect the following keyboard layout:
1632 *
1633 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1634 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1635 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1636 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1637 * SPACE
1638 */
1639
1640 #define Ignore 0x0000
1641 #define Normal 0x0000 /* normal key - alt changes scan-code */
1642 #define FctKey 0x1000 /* func key if c == 0, else c */
1643 #define Special 0x2000 /* func key even if c != 0 */
1644 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1645 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1646 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1647 #define Grey 0x6000 /* Grey keypad key */
1648
1649 #define Alt 0x0100 /* alt scan-code */
1650 #define Ctrl 0x0200 /* ctrl scan-code */
1651 #define Shift 0x0400 /* shift scan-code */
1652
1653 static int extended_kbd; /* 101 (102) keyboard present. */
1654
1655 struct kbd_translate {
1656 unsigned char sc;
1657 unsigned char ch;
1658 unsigned short code;
1659 };
1660
1661 struct dos_keyboard_map
1662 {
1663 char *unshifted;
1664 char *shifted;
1665 char *alt_gr;
1666 struct kbd_translate *translate_table;
1667 };
1668
1669
1670 static struct dos_keyboard_map us_keyboard = {
1671 /* 0 1 2 3 4 5 */
1672 /* 01234567890123456789012345678901234567890 12345678901234 */
1673 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1674 /* 0123456789012345678901234567890123456789 012345678901234 */
1675 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1676 0, /* no Alt-Gr key */
1677 0 /* no translate table */
1678 };
1679
1680 static struct dos_keyboard_map fr_keyboard = {
1681 /* 0 1 2 3 4 5 */
1682 /* 012 3456789012345678901234567890123456789012345678901234 */
1683 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1684 /* 0123456789012345678901234567890123456789012345678901234 */
1685 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1686 /* 01234567 89012345678901234567890123456789012345678901234 */
1687 " ~#{[|`\\^@]} Ï ",
1688 0 /* no translate table */
1689 };
1690
1691 /*
1692 * Italian keyboard support, country code 39.
1693 * '<' 56:3c*0000
1694 * '>' 56:3e*0000
1695 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1696 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1697 */
1698
1699 static struct kbd_translate it_kbd_translate_table[] = {
1700 { 0x56, 0x3c, Normal | 13 },
1701 { 0x56, 0x3e, Normal | 27 },
1702 { 0, 0, 0 }
1703 };
1704 static struct dos_keyboard_map it_keyboard = {
1705 /* 0 1 2 3 4 5 */
1706 /* 0 123456789012345678901234567890123456789012345678901234 */
1707 "\\1234567890'\8d< qwertyuiop\8a+> asdfghjkl\95\85\97 zxcvbnm,.- ",
1708 /* 01 23456789012345678901234567890123456789012345678901234 */
1709 "|!\"\9c$%&/()=?^> QWERTYUIOP\82* ASDFGHJKL\87øõ ZXCVBNM;:_ ",
1710 /* 0123456789012345678901234567890123456789012345678901234 */
1711 " {}~` [] @# ",
1712 it_kbd_translate_table
1713 };
1714
1715 static struct dos_keyboard_map dk_keyboard = {
1716 /* 0 1 2 3 4 5 */
1717 /* 0123456789012345678901234567890123456789012345678901234 */
1718 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
1719 /* 01 23456789012345678901234567890123456789012345678901234 */
1720 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
1721 /* 0123456789012345678901234567890123456789012345678901234 */
1722 " @\9c$ {[]} | ",
1723 0 /* no translate table */
1724 };
1725
1726 static struct kbd_translate jp_kbd_translate_table[] = {
1727 { 0x73, 0x5c, Normal | 0 },
1728 { 0x73, 0x5f, Normal | 0 },
1729 { 0x73, 0x1c, Map | 0 },
1730 { 0x7d, 0x5c, Normal | 13 },
1731 { 0x7d, 0x7c, Normal | 13 },
1732 { 0x7d, 0x1c, Map | 13 },
1733 { 0, 0, 0 }
1734 };
1735 static struct dos_keyboard_map jp_keyboard = {
1736 /* 0 1 2 3 4 5 */
1737 /* 0123456789012 345678901234567890123456789012345678901234 */
1738 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
1739 /* 01 23456789012345678901234567890123456789012345678901234 */
1740 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
1741 0, /* no Alt-Gr key */
1742 jp_kbd_translate_table
1743 };
1744
1745 static struct keyboard_layout_list
1746 {
1747 int country_code;
1748 struct dos_keyboard_map *keyboard_map;
1749 } keyboard_layout_list[] =
1750 {
1751 1, &us_keyboard,
1752 33, &fr_keyboard,
1753 39, &it_keyboard,
1754 45, &dk_keyboard,
1755 81, &jp_keyboard
1756 };
1757
1758 static struct dos_keyboard_map *keyboard;
1759 static int keyboard_map_all;
1760 static int international_keyboard;
1761
1762 int
1763 dos_set_keyboard (code, always)
1764 int code;
1765 int always;
1766 {
1767 int i;
1768 _go32_dpmi_registers regs;
1769
1770 /* See if Keyb.Com is installed (for international keyboard support).
1771 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
1772 of Windows 9X! So don't do that! */
1773 regs.x.ax = 0xad80;
1774 regs.x.ss = regs.x.sp = regs.x.flags = 0;
1775 _go32_dpmi_simulate_int (0x2f, &regs);
1776 if (regs.h.al == 0xff)
1777 international_keyboard = 1;
1778
1779 /* Initialize to US settings, for countries that don't have their own. */
1780 keyboard = keyboard_layout_list[0].keyboard_map;
1781 keyboard_map_all = always;
1782 dos_keyboard_layout = 1;
1783
1784 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
1785 if (code == keyboard_layout_list[i].country_code)
1786 {
1787 keyboard = keyboard_layout_list[i].keyboard_map;
1788 keyboard_map_all = always;
1789 dos_keyboard_layout = code;
1790 return 1;
1791 }
1792 return 0;
1793 }
1794 \f
1795 static struct
1796 {
1797 unsigned char char_code; /* normal code */
1798 unsigned char meta_code; /* M- code */
1799 unsigned char keypad_code; /* keypad code */
1800 unsigned char editkey_code; /* edit key */
1801 } keypad_translate_map[] = {
1802 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1803 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1804 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1805 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1806 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1807 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1808 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1809 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1810 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1811 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1812 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1813 };
1814
1815 static struct
1816 {
1817 unsigned char char_code; /* normal code */
1818 unsigned char keypad_code; /* keypad code */
1819 } grey_key_translate_map[] = {
1820 '/', 0xaf, /* kp-decimal */
1821 '*', 0xaa, /* kp-multiply */
1822 '-', 0xad, /* kp-subtract */
1823 '+', 0xab, /* kp-add */
1824 '\r', 0x8d /* kp-enter */
1825 };
1826
1827 static unsigned short
1828 ibmpc_translate_map[] =
1829 {
1830 /* --------------- 00 to 0f --------------- */
1831 Normal | 0xff, /* Ctrl Break + Alt-NNN */
1832 Alt | ModFct | 0x1b, /* Escape */
1833 Normal | 1, /* '1' */
1834 Normal | 2, /* '2' */
1835 Normal | 3, /* '3' */
1836 Normal | 4, /* '4' */
1837 Normal | 5, /* '5' */
1838 Normal | 6, /* '6' */
1839 Normal | 7, /* '7' */
1840 Normal | 8, /* '8' */
1841 Normal | 9, /* '9' */
1842 Normal | 10, /* '0' */
1843 Normal | 11, /* '-' */
1844 Normal | 12, /* '=' */
1845 Special | 0x08, /* Backspace */
1846 ModFct | 0x74, /* Tab/Backtab */
1847
1848 /* --------------- 10 to 1f --------------- */
1849 Map | 15, /* 'q' */
1850 Map | 16, /* 'w' */
1851 Map | 17, /* 'e' */
1852 Map | 18, /* 'r' */
1853 Map | 19, /* 't' */
1854 Map | 20, /* 'y' */
1855 Map | 21, /* 'u' */
1856 Map | 22, /* 'i' */
1857 Map | 23, /* 'o' */
1858 Map | 24, /* 'p' */
1859 Map | 25, /* '[' */
1860 Map | 26, /* ']' */
1861 ModFct | 0x0d, /* Return */
1862 Ignore, /* Ctrl */
1863 Map | 30, /* 'a' */
1864 Map | 31, /* 's' */
1865
1866 /* --------------- 20 to 2f --------------- */
1867 Map | 32, /* 'd' */
1868 Map | 33, /* 'f' */
1869 Map | 34, /* 'g' */
1870 Map | 35, /* 'h' */
1871 Map | 36, /* 'j' */
1872 Map | 37, /* 'k' */
1873 Map | 38, /* 'l' */
1874 Map | 39, /* ';' */
1875 Map | 40, /* '\'' */
1876 Map | 0, /* '`' */
1877 Ignore, /* Left shift */
1878 Map | 41, /* '\\' */
1879 Map | 45, /* 'z' */
1880 Map | 46, /* 'x' */
1881 Map | 47, /* 'c' */
1882 Map | 48, /* 'v' */
1883
1884 /* --------------- 30 to 3f --------------- */
1885 Map | 49, /* 'b' */
1886 Map | 50, /* 'n' */
1887 Map | 51, /* 'm' */
1888 Map | 52, /* ',' */
1889 Map | 53, /* '.' */
1890 Map | 54, /* '/' */
1891 Ignore, /* Right shift */
1892 Grey | 1, /* Grey * */
1893 Ignore, /* Alt */
1894 Normal | 55, /* ' ' */
1895 Ignore, /* Caps Lock */
1896 FctKey | 0xbe, /* F1 */
1897 FctKey | 0xbf, /* F2 */
1898 FctKey | 0xc0, /* F3 */
1899 FctKey | 0xc1, /* F4 */
1900 FctKey | 0xc2, /* F5 */
1901
1902 /* --------------- 40 to 4f --------------- */
1903 FctKey | 0xc3, /* F6 */
1904 FctKey | 0xc4, /* F7 */
1905 FctKey | 0xc5, /* F8 */
1906 FctKey | 0xc6, /* F9 */
1907 FctKey | 0xc7, /* F10 */
1908 Ignore, /* Num Lock */
1909 Ignore, /* Scroll Lock */
1910 KeyPad | 7, /* Home */
1911 KeyPad | 8, /* Up */
1912 KeyPad | 9, /* Page Up */
1913 Grey | 2, /* Grey - */
1914 KeyPad | 4, /* Left */
1915 KeyPad | 5, /* Keypad 5 */
1916 KeyPad | 6, /* Right */
1917 Grey | 3, /* Grey + */
1918 KeyPad | 1, /* End */
1919
1920 /* --------------- 50 to 5f --------------- */
1921 KeyPad | 2, /* Down */
1922 KeyPad | 3, /* Page Down */
1923 KeyPad | 0, /* Insert */
1924 KeyPad | 10, /* Delete */
1925 Shift | FctKey | 0xbe, /* (Shift) F1 */
1926 Shift | FctKey | 0xbf, /* (Shift) F2 */
1927 Shift | FctKey | 0xc0, /* (Shift) F3 */
1928 Shift | FctKey | 0xc1, /* (Shift) F4 */
1929 Shift | FctKey | 0xc2, /* (Shift) F5 */
1930 Shift | FctKey | 0xc3, /* (Shift) F6 */
1931 Shift | FctKey | 0xc4, /* (Shift) F7 */
1932 Shift | FctKey | 0xc5, /* (Shift) F8 */
1933 Shift | FctKey | 0xc6, /* (Shift) F9 */
1934 Shift | FctKey | 0xc7, /* (Shift) F10 */
1935 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1936 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1937
1938 /* --------------- 60 to 6f --------------- */
1939 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1940 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1941 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1942 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1943 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1944 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1945 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1946 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1947 Alt | FctKey | 0xbe, /* (Alt) F1 */
1948 Alt | FctKey | 0xbf, /* (Alt) F2 */
1949 Alt | FctKey | 0xc0, /* (Alt) F3 */
1950 Alt | FctKey | 0xc1, /* (Alt) F4 */
1951 Alt | FctKey | 0xc2, /* (Alt) F5 */
1952 Alt | FctKey | 0xc3, /* (Alt) F6 */
1953 Alt | FctKey | 0xc4, /* (Alt) F7 */
1954 Alt | FctKey | 0xc5, /* (Alt) F8 */
1955
1956 /* --------------- 70 to 7f --------------- */
1957 Alt | FctKey | 0xc6, /* (Alt) F9 */
1958 Alt | FctKey | 0xc7, /* (Alt) F10 */
1959 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1960 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1961 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1962 Ctrl | KeyPad | 1, /* (Ctrl) End */
1963 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1964 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1965 Alt | Map | 1, /* '1' */
1966 Alt | Map | 2, /* '2' */
1967 Alt | Map | 3, /* '3' */
1968 Alt | Map | 4, /* '4' */
1969 Alt | Map | 5, /* '5' */
1970 Alt | Map | 6, /* '6' */
1971 Alt | Map | 7, /* '7' */
1972 Alt | Map | 8, /* '8' */
1973
1974 /* --------------- 80 to 8f --------------- */
1975 Alt | Map | 9, /* '9' */
1976 Alt | Map | 10, /* '0' */
1977 Alt | Map | 11, /* '-' */
1978 Alt | Map | 12, /* '=' */
1979 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1980 FctKey | 0xc8, /* F11 */
1981 FctKey | 0xc9, /* F12 */
1982 Shift | FctKey | 0xc8, /* (Shift) F11 */
1983 Shift | FctKey | 0xc9, /* (Shift) F12 */
1984 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1985 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1986 Alt | FctKey | 0xc8, /* (Alt) F11 */
1987 Alt | FctKey | 0xc9, /* (Alt) F12 */
1988 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1989 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1990 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1991
1992 /* --------------- 90 to 9f --------------- */
1993 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1994 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1995 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1996 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1997 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1998 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1999 Ctrl | Grey | 1, /* (Ctrl) Grey * */
2000 Alt | FctKey | 0x50, /* (Alt) Home */
2001 Alt | FctKey | 0x52, /* (Alt) Up */
2002 Alt | FctKey | 0x55, /* (Alt) Page Up */
2003 Ignore, /* NO KEY */
2004 Alt | FctKey | 0x51, /* (Alt) Left */
2005 Ignore, /* NO KEY */
2006 Alt | FctKey | 0x53, /* (Alt) Right */
2007 Ignore, /* NO KEY */
2008 Alt | FctKey | 0x57, /* (Alt) End */
2009
2010 /* --------------- a0 to af --------------- */
2011 Alt | KeyPad | 2, /* (Alt) Down */
2012 Alt | KeyPad | 3, /* (Alt) Page Down */
2013 Alt | KeyPad | 0, /* (Alt) Insert */
2014 Alt | KeyPad | 10, /* (Alt) Delete */
2015 Alt | Grey | 0, /* (Alt) Grey / */
2016 Alt | FctKey | 0x09, /* (Alt) Tab */
2017 Alt | Grey | 4 /* (Alt) Keypad Enter */
2018 };
2019 \f
2020 /* These bit-positions corresponds to values returned by BIOS */
2021 #define SHIFT_P 0x0003 /* two bits! */
2022 #define CTRL_P 0x0004
2023 #define ALT_P 0x0008
2024 #define SCRLOCK_P 0x0010
2025 #define NUMLOCK_P 0x0020
2026 #define CAPSLOCK_P 0x0040
2027 #define ALT_GR_P 0x0800
2028 #define SUPER_P 0x4000 /* pseudo */
2029 #define HYPER_P 0x8000 /* pseudo */
2030
2031 static int
2032 dos_get_modifiers (keymask)
2033 int *keymask;
2034 {
2035 union REGS regs;
2036 int mask;
2037 int modifiers = 0;
2038
2039 /* Calculate modifier bits */
2040 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2041 int86 (0x16, &regs, &regs);
2042
2043 if (!extended_kbd)
2044 {
2045 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2046 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2047 }
2048 else
2049 {
2050 mask = regs.h.al & (SHIFT_P |
2051 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2052
2053 /* Do not break international keyboard support. */
2054 /* When Keyb.Com is loaded, the right Alt key is */
2055 /* used for accessing characters like { and } */
2056 if (regs.h.ah & 2) /* Left ALT pressed ? */
2057 mask |= ALT_P;
2058
2059 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2060 {
2061 mask |= ALT_GR_P;
2062 if (dos_hyper_key == 1)
2063 {
2064 mask |= HYPER_P;
2065 modifiers |= hyper_modifier;
2066 }
2067 else if (dos_super_key == 1)
2068 {
2069 mask |= SUPER_P;
2070 modifiers |= super_modifier;
2071 }
2072 else if (!international_keyboard)
2073 {
2074 /* If Keyb.Com is NOT installed, let Right Alt behave
2075 like the Left Alt. */
2076 mask &= ~ALT_GR_P;
2077 mask |= ALT_P;
2078 }
2079 }
2080
2081 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2082 mask |= CTRL_P;
2083
2084 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2085 {
2086 if (dos_hyper_key == 2)
2087 {
2088 mask |= HYPER_P;
2089 modifiers |= hyper_modifier;
2090 }
2091 else if (dos_super_key == 2)
2092 {
2093 mask |= SUPER_P;
2094 modifiers |= super_modifier;
2095 }
2096 else
2097 mask |= CTRL_P;
2098 }
2099 }
2100
2101 if (mask & SHIFT_P)
2102 modifiers |= shift_modifier;
2103 if (mask & CTRL_P)
2104 modifiers |= ctrl_modifier;
2105 if (mask & ALT_P)
2106 modifiers |= meta_modifier;
2107
2108 if (keymask)
2109 *keymask = mask;
2110 return modifiers;
2111 }
2112
2113 #define NUM_RECENT_DOSKEYS (100)
2114 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2115 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2116 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2117
2118 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2119 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
2120 Each input key receives two values in this vector: first the ASCII code,\n\
2121 and then the scan code.")
2122 ()
2123 {
2124 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
2125 Lisp_Object val;
2126
2127 if (total_doskeys < NUM_RECENT_DOSKEYS)
2128 return Fvector (total_doskeys, keys);
2129 else
2130 {
2131 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2132 bcopy (keys + recent_doskeys_index,
2133 XVECTOR (val)->contents,
2134 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
2135 bcopy (keys,
2136 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
2137 recent_doskeys_index * sizeof (Lisp_Object));
2138 return val;
2139 }
2140 }
2141
2142 /* Get a char from keyboard. Function keys are put into the event queue. */
2143
2144 extern void kbd_buffer_store_event (struct input_event *);
2145 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
2146
2147 static int
2148 dos_rawgetc ()
2149 {
2150 struct input_event event;
2151 union REGS regs;
2152
2153 #ifndef HAVE_X_WINDOWS
2154 /* Maybe put the cursor where it should be. */
2155 IT_cmgoto (SELECTED_FRAME());
2156 #endif
2157
2158 /* The following condition is equivalent to `kbhit ()', except that
2159 it uses the bios to do its job. This pleases DESQview/X. */
2160 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2161 int86 (0x16, &regs, &regs),
2162 (regs.x.flags & 0x40) == 0)
2163 {
2164 union REGS regs;
2165 register unsigned char c;
2166 int sc, code = -1, mask, kp_mode;
2167 int modifiers;
2168
2169 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2170 int86 (0x16, &regs, &regs);
2171 c = regs.h.al;
2172 sc = regs.h.ah;
2173
2174 total_doskeys += 2;
2175 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2176 = make_number (c);
2177 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2178 recent_doskeys_index = 0;
2179 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2180 = make_number (sc);
2181 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2182 recent_doskeys_index = 0;
2183
2184 modifiers = dos_get_modifiers (&mask);
2185
2186 #ifndef HAVE_X_WINDOWS
2187 if (!NILP (Vdos_display_scancodes))
2188 {
2189 char buf[11];
2190 sprintf (buf, "%02x:%02x*%04x",
2191 (unsigned) (sc&0xff), (unsigned) c, mask);
2192 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2193 }
2194 #endif
2195
2196 if (sc == 0xe0)
2197 {
2198 switch (c)
2199 {
2200 case 10: /* Ctrl Grey Enter */
2201 code = Ctrl | Grey | 4;
2202 break;
2203 case 13: /* Grey Enter */
2204 code = Grey | 4;
2205 break;
2206 case '/': /* Grey / */
2207 code = Grey | 0;
2208 break;
2209 default:
2210 continue;
2211 };
2212 c = 0;
2213 }
2214 else
2215 {
2216 /* Try the keyboard-private translation table first. */
2217 if (keyboard->translate_table)
2218 {
2219 struct kbd_translate *p = keyboard->translate_table;
2220
2221 while (p->sc)
2222 {
2223 if (p->sc == sc && p->ch == c)
2224 {
2225 code = p->code;
2226 break;
2227 }
2228 p++;
2229 }
2230 }
2231 /* If the private table didn't translate it, use the general
2232 one. */
2233 if (code == -1)
2234 {
2235 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
2236 continue;
2237 if ((code = ibmpc_translate_map[sc]) == Ignore)
2238 continue;
2239 }
2240 }
2241
2242 if (c == 0)
2243 {
2244 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2245 Emacs is ready to read a key. Therefore, if they press
2246 `Alt-x' when Emacs is busy, by the time we get to
2247 `dos_get_modifiers', they might have already released the
2248 Alt key, and Emacs gets just `x', which is BAD.
2249 However, for keys with the `Map' property set, the ASCII
2250 code returns zero iff Alt is pressed. So, when we DON'T
2251 have to support international_keyboard, we don't have to
2252 distinguish between the left and right Alt keys, and we
2253 can set the META modifier for any keys with the `Map'
2254 property if they return zero ASCII code (c = 0). */
2255 if ( (code & Alt)
2256 || ( (code & 0xf000) == Map && !international_keyboard))
2257 modifiers |= meta_modifier;
2258 if (code & Ctrl)
2259 modifiers |= ctrl_modifier;
2260 if (code & Shift)
2261 modifiers |= shift_modifier;
2262 }
2263
2264 switch (code & 0xf000)
2265 {
2266 case ModFct:
2267 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
2268 return c;
2269 c = 0; /* Special */
2270
2271 case FctKey:
2272 if (c != 0)
2273 return c;
2274
2275 case Special:
2276 code |= 0xff00;
2277 break;
2278
2279 case Normal:
2280 if (sc == 0)
2281 {
2282 if (c == 0) /* ctrl-break */
2283 continue;
2284 return c; /* ALT-nnn */
2285 }
2286 if (!keyboard_map_all)
2287 {
2288 if (c != ' ')
2289 return c;
2290 code = c;
2291 break;
2292 }
2293
2294 case Map:
2295 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
2296 if (!keyboard_map_all)
2297 return c;
2298
2299 code &= 0xff;
2300 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
2301 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
2302
2303 if (mask & SHIFT_P)
2304 {
2305 code = keyboard->shifted[code];
2306 mask -= SHIFT_P;
2307 modifiers &= ~shift_modifier;
2308 }
2309 else
2310 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
2311 code = keyboard->alt_gr[code];
2312 else
2313 code = keyboard->unshifted[code];
2314 break;
2315
2316 case KeyPad:
2317 code &= 0xff;
2318 if (c == 0xe0) /* edit key */
2319 kp_mode = 3;
2320 else
2321 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
2322 kp_mode = dos_keypad_mode & 0x03;
2323 else
2324 kp_mode = (dos_keypad_mode >> 4) & 0x03;
2325
2326 switch (kp_mode)
2327 {
2328 case 0:
2329 if (code == 10 && dos_decimal_point)
2330 return dos_decimal_point;
2331 return keypad_translate_map[code].char_code;
2332
2333 case 1:
2334 code = 0xff00 | keypad_translate_map[code].keypad_code;
2335 break;
2336
2337 case 2:
2338 code = keypad_translate_map[code].meta_code;
2339 modifiers = meta_modifier;
2340 break;
2341
2342 case 3:
2343 code = 0xff00 | keypad_translate_map[code].editkey_code;
2344 break;
2345 }
2346 break;
2347
2348 case Grey:
2349 code &= 0xff;
2350 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
2351 if (dos_keypad_mode & kp_mode)
2352 code = 0xff00 | grey_key_translate_map[code].keypad_code;
2353 else
2354 code = grey_key_translate_map[code].char_code;
2355 break;
2356 }
2357
2358 make_event:
2359 if (code == 0)
2360 continue;
2361
2362 if (code >= 0x100)
2363 event.kind = non_ascii_keystroke;
2364 else
2365 event.kind = ascii_keystroke;
2366 event.code = code;
2367 event.modifiers = modifiers;
2368 event.frame_or_window = selected_frame;
2369 event.timestamp = event_timestamp ();
2370 kbd_buffer_store_event (&event);
2371 }
2372
2373 if (have_mouse > 0 && !mouse_preempted)
2374 {
2375 int but, press, x, y, ok;
2376
2377 /* Check for mouse movement *before* buttons. */
2378 mouse_check_moved ();
2379
2380 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
2381 for (press = 0; press < 2; press++)
2382 {
2383 int button_num = but;
2384
2385 if (press)
2386 ok = mouse_pressed (but, &x, &y);
2387 else
2388 ok = mouse_released (but, &x, &y);
2389 if (ok)
2390 {
2391 /* Allow a simultaneous press/release of Mouse-1 and
2392 Mouse-2 to simulate Mouse-3 on two-button mice. */
2393 if (mouse_button_count == 2 && but < 2)
2394 {
2395 int x2, y2; /* don't clobber original coordinates */
2396
2397 /* If only one button is pressed, wait 100 msec and
2398 check again. This way, Speedy Gonzales isn't
2399 punished, while the slow get their chance. */
2400 if (press && mouse_pressed (1-but, &x2, &y2)
2401 || !press && mouse_released (1-but, &x2, &y2))
2402 button_num = 2;
2403 else
2404 {
2405 delay (100);
2406 if (press && mouse_pressed (1-but, &x2, &y2)
2407 || !press && mouse_released (1-but, &x2, &y2))
2408 button_num = 2;
2409 }
2410 }
2411
2412 event.kind = mouse_click;
2413 event.code = button_num;
2414 event.modifiers = dos_get_modifiers (0)
2415 | (press ? down_modifier : up_modifier);
2416 event.x = x;
2417 event.y = y;
2418 event.frame_or_window = selected_frame;
2419 event.timestamp = event_timestamp ();
2420 kbd_buffer_store_event (&event);
2421 }
2422 }
2423 }
2424
2425 return -1;
2426 }
2427
2428 static int prev_get_char = -1;
2429
2430 /* Return 1 if a key is ready to be read without suspending execution. */
2431
2432 dos_keysns ()
2433 {
2434 if (prev_get_char != -1)
2435 return 1;
2436 else
2437 return ((prev_get_char = dos_rawgetc ()) != -1);
2438 }
2439
2440 /* Read a key. Return -1 if no key is ready. */
2441
2442 dos_keyread ()
2443 {
2444 if (prev_get_char != -1)
2445 {
2446 int c = prev_get_char;
2447 prev_get_char = -1;
2448 return c;
2449 }
2450 else
2451 return dos_rawgetc ();
2452 }
2453 \f
2454 #ifndef HAVE_X_WINDOWS
2455 /* See xterm.c for more info. */
2456 void
2457 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
2458 FRAME_PTR f;
2459 register int pix_x, pix_y;
2460 register int *x, *y;
2461 XRectangle *bounds;
2462 int noclip;
2463 {
2464 if (bounds) abort ();
2465
2466 /* Ignore clipping. */
2467
2468 *x = pix_x;
2469 *y = pix_y;
2470 }
2471
2472 void
2473 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
2474 FRAME_PTR f;
2475 register int x, y;
2476 register int *pix_x, *pix_y;
2477 {
2478 *pix_x = x;
2479 *pix_y = y;
2480 }
2481 \f
2482 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2483 for now.
2484
2485 Actually, I don't know the meaning of all the parameters of the functions
2486 here -- I only know how they are called by xmenu.c. I could of course
2487 grab the nearest Xlib manual (down the hall, second-to-last door on the
2488 left), but I don't think it's worth the effort. */
2489
2490 static XMenu *
2491 IT_menu_create ()
2492 {
2493 XMenu *menu;
2494
2495 menu = (XMenu *) xmalloc (sizeof (XMenu));
2496 menu->allocated = menu->count = menu->panecount = menu->width = 0;
2497 return menu;
2498 }
2499
2500 /* Allocate some (more) memory for MENU ensuring that there is room for one
2501 for item. */
2502
2503 static void
2504 IT_menu_make_room (XMenu *menu)
2505 {
2506 if (menu->allocated == 0)
2507 {
2508 int count = menu->allocated = 10;
2509 menu->text = (char **) xmalloc (count * sizeof (char *));
2510 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
2511 menu->panenumber = (int *) xmalloc (count * sizeof (int));
2512 }
2513 else if (menu->allocated == menu->count)
2514 {
2515 int count = menu->allocated = menu->allocated + 10;
2516 menu->text
2517 = (char **) xrealloc (menu->text, count * sizeof (char *));
2518 menu->submenu
2519 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
2520 menu->panenumber
2521 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
2522 }
2523 }
2524
2525 /* Search the given menu structure for a given pane number. */
2526
2527 static XMenu *
2528 IT_menu_search_pane (XMenu *menu, int pane)
2529 {
2530 int i;
2531 XMenu *try;
2532
2533 for (i = 0; i < menu->count; i++)
2534 if (menu->submenu[i])
2535 {
2536 if (pane == menu->panenumber[i])
2537 return menu->submenu[i];
2538 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
2539 return try;
2540 }
2541 return (XMenu *) 0;
2542 }
2543
2544 /* Determine how much screen space a given menu needs. */
2545
2546 static void
2547 IT_menu_calc_size (XMenu *menu, int *width, int *height)
2548 {
2549 int i, h2, w2, maxsubwidth, maxheight;
2550
2551 maxsubwidth = 0;
2552 maxheight = menu->count;
2553 for (i = 0; i < menu->count; i++)
2554 {
2555 if (menu->submenu[i])
2556 {
2557 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
2558 if (w2 > maxsubwidth) maxsubwidth = w2;
2559 if (i + h2 > maxheight) maxheight = i + h2;
2560 }
2561 }
2562 *width = menu->width + maxsubwidth;
2563 *height = maxheight;
2564 }
2565
2566 /* Display MENU at (X,Y) using FACES. */
2567
2568 static void
2569 IT_menu_display (XMenu *menu, int y, int x, int *faces)
2570 {
2571 int i, j, face, width;
2572 struct glyph *text, *p;
2573 char *q;
2574 int mx, my;
2575 int enabled, mousehere;
2576 int row, col;
2577 struct frame *sf = SELECTED_FRAME();
2578
2579 width = menu->width;
2580 text = (struct glyph *) xmalloc ((width + 2) * sizeof (struct glyph));
2581 ScreenGetCursor (&row, &col);
2582 mouse_get_xy (&mx, &my);
2583 IT_update_begin (sf);
2584 for (i = 0; i < menu->count; i++)
2585 {
2586 IT_cursor_to (y + i, x);
2587 enabled
2588 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2589 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
2590 face = faces[enabled + mousehere * 2];
2591 p = text;
2592 SET_CHAR_GLYPH (*p, ' ', face, 0);
2593 p++;
2594 for (j = 0, q = menu->text[i]; *q; j++)
2595 {
2596 if (*q > 26)
2597 {
2598 SET_CHAR_GLYPH (*p, *q++, face, 0);
2599 p++;
2600 }
2601 else /* make '^x' */
2602 {
2603 SET_CHAR_GLYPH (*p, '^', face, 0);
2604 p++;
2605 j++;
2606 SET_CHAR_GLYPH (*p, *q++ + 64, face, 0);
2607 p++;
2608 }
2609 }
2610
2611 for (; j < width; j++, p++)
2612 SET_CHAR_GLYPH (*p, ' ', face, 0);
2613
2614 SET_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
2615 p++;
2616 IT_write_glyphs (text, width + 2);
2617 }
2618 IT_update_end (sf);
2619 IT_cursor_to (row, col);
2620 xfree (text);
2621 }
2622 \f
2623 /* --------------------------- X Menu emulation ---------------------- */
2624
2625 /* Report availability of menus. */
2626
2627 int
2628 have_menus_p ()
2629 {
2630 return 1;
2631 }
2632
2633 /* Create a brand new menu structure. */
2634
2635 XMenu *
2636 XMenuCreate (Display *foo1, Window foo2, char *foo3)
2637 {
2638 return IT_menu_create ();
2639 }
2640
2641 /* Create a new pane and place it on the outer-most level. It is not
2642 clear that it should be placed out there, but I don't know what else
2643 to do. */
2644
2645 int
2646 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
2647 {
2648 int len;
2649 char *p;
2650
2651 if (!enable)
2652 abort ();
2653
2654 IT_menu_make_room (menu);
2655 menu->submenu[menu->count] = IT_menu_create ();
2656 menu->text[menu->count] = txt;
2657 menu->panenumber[menu->count] = ++menu->panecount;
2658 menu->count++;
2659
2660 /* Adjust length for possible control characters (which will
2661 be written as ^x). */
2662 for (len = strlen (txt), p = txt; *p; p++)
2663 if (*p < 27)
2664 len++;
2665
2666 if (len > menu->width)
2667 menu->width = len;
2668
2669 return menu->panecount;
2670 }
2671
2672 /* Create a new item in a menu pane. */
2673
2674 int
2675 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
2676 int foo, char *txt, int enable)
2677 {
2678 int len;
2679 char *p;
2680
2681 if (pane)
2682 if (!(menu = IT_menu_search_pane (menu, pane)))
2683 return XM_FAILURE;
2684 IT_menu_make_room (menu);
2685 menu->submenu[menu->count] = (XMenu *) 0;
2686 menu->text[menu->count] = txt;
2687 menu->panenumber[menu->count] = enable;
2688 menu->count++;
2689
2690 /* Adjust length for possible control characters (which will
2691 be written as ^x). */
2692 for (len = strlen (txt), p = txt; *p; p++)
2693 if (*p < 27)
2694 len++;
2695
2696 if (len > menu->width)
2697 menu->width = len;
2698
2699 return XM_SUCCESS;
2700 }
2701
2702 /* Decide where the menu would be placed if requested at (X,Y). */
2703
2704 void
2705 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
2706 int *ulx, int *uly, int *width, int *height)
2707 {
2708 IT_menu_calc_size (menu, width, height);
2709 *ulx = x + 1;
2710 *uly = y;
2711 *width += 2;
2712 }
2713
2714 struct IT_menu_state
2715 {
2716 void *screen_behind;
2717 XMenu *menu;
2718 int pane;
2719 int x, y;
2720 };
2721
2722
2723 /* Display menu, wait for user's response, and return that response. */
2724
2725 int
2726 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
2727 int x0, int y0, unsigned ButtonMask, char **txt)
2728 {
2729 struct IT_menu_state *state;
2730 int statecount;
2731 int x, y, i, b;
2732 int screensize;
2733 int faces[4];
2734 Lisp_Object selectface;
2735 int leave, result, onepane;
2736 int title_faces[4]; /* face to display the menu title */
2737 int buffers_num_deleted = 0;
2738 struct frame *sf = SELECTED_FRAME();
2739
2740 /* Just in case we got here without a mouse present... */
2741 if (have_mouse <= 0)
2742 return XM_IA_SELECT;
2743 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2744 around the display. */
2745 if (x0 <= 0)
2746 x0 = 1;
2747 if (y0 <= 0)
2748 y0 = 1;
2749
2750 /* We will process all the mouse events directly, so we had
2751 better prevented dos_rawgetc from stealing them from us. */
2752 mouse_preempted++;
2753
2754 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
2755 screensize = screen_size * 2;
2756 faces[0]
2757 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
2758 CHARSET_ASCII, DEFAULT_FACE_ID);
2759 faces[1]
2760 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
2761 CHARSET_ASCII, DEFAULT_FACE_ID);
2762 selectface = intern ("msdos-menu-select-face");
2763 faces[2] = lookup_derived_face (sf, selectface,
2764 CHARSET_ASCII, faces[0]);
2765 faces[3] = lookup_derived_face (sf, selectface,
2766 CHARSET_ASCII, faces[1]);
2767
2768 /* Make sure the menu title is always displayed with
2769 `msdos-menu-active-face', no matter where the mouse pointer is. */
2770 for (i = 0; i < 4; i++)
2771 title_faces[i] = faces[3];
2772
2773 statecount = 1;
2774
2775 /* Don't let the title for the "Buffers" popup menu include a
2776 digit (which is ugly).
2777
2778 This is a terrible kludge, but I think the "Buffers" case is
2779 the only one where the title includes a number, so it doesn't
2780 seem to be necessary to make this more general. */
2781 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
2782 {
2783 menu->text[0][7] = '\0';
2784 buffers_num_deleted = 1;
2785 }
2786 state[0].menu = menu;
2787 mouse_off ();
2788 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
2789
2790 /* Turn off the cursor. Otherwise it shows through the menu
2791 panes, which is ugly. */
2792 IT_display_cursor (0);
2793
2794 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
2795 if (buffers_num_deleted)
2796 menu->text[0][7] = ' ';
2797 if ((onepane = menu->count == 1 && menu->submenu[0]))
2798 {
2799 menu->width = menu->submenu[0]->width;
2800 state[0].menu = menu->submenu[0];
2801 }
2802 else
2803 {
2804 state[0].menu = menu;
2805 }
2806 state[0].x = x0 - 1;
2807 state[0].y = y0;
2808 state[0].pane = onepane;
2809
2810 mouse_last_x = -1; /* A hack that forces display. */
2811 leave = 0;
2812 while (!leave)
2813 {
2814 if (!mouse_visible) mouse_on ();
2815 mouse_check_moved ();
2816 if (sf->mouse_moved)
2817 {
2818 sf->mouse_moved = 0;
2819 result = XM_IA_SELECT;
2820 mouse_get_xy (&x, &y);
2821 for (i = 0; i < statecount; i++)
2822 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
2823 {
2824 int dy = y - state[i].y;
2825 if (0 <= dy && dy < state[i].menu->count)
2826 {
2827 if (!state[i].menu->submenu[dy])
2828 if (state[i].menu->panenumber[dy])
2829 result = XM_SUCCESS;
2830 else
2831 result = XM_IA_SELECT;
2832 *pane = state[i].pane - 1;
2833 *selidx = dy;
2834 /* We hit some part of a menu, so drop extra menus that
2835 have been opened. That does not include an open and
2836 active submenu. */
2837 if (i != statecount - 2
2838 || state[i].menu->submenu[dy] != state[i+1].menu)
2839 while (i != statecount - 1)
2840 {
2841 statecount--;
2842 mouse_off ();
2843 ScreenUpdate (state[statecount].screen_behind);
2844 if (screen_virtual_segment)
2845 dosv_refresh_virtual_screen (0, screen_size);
2846 xfree (state[statecount].screen_behind);
2847 }
2848 if (i == statecount - 1 && state[i].menu->submenu[dy])
2849 {
2850 IT_menu_display (state[i].menu,
2851 state[i].y,
2852 state[i].x,
2853 faces);
2854 state[statecount].menu = state[i].menu->submenu[dy];
2855 state[statecount].pane = state[i].menu->panenumber[dy];
2856 mouse_off ();
2857 ScreenRetrieve (state[statecount].screen_behind
2858 = xmalloc (screensize));
2859 state[statecount].x
2860 = state[i].x + state[i].menu->width + 2;
2861 state[statecount].y = y;
2862 statecount++;
2863 }
2864 }
2865 }
2866 IT_menu_display (state[statecount - 1].menu,
2867 state[statecount - 1].y,
2868 state[statecount - 1].x,
2869 faces);
2870 }
2871 else
2872 /* We are busy-waiting for the mouse to move, so let's be nice
2873 to other Windows applications by releasing our time slice. */
2874 __dpmi_yield ();
2875 for (b = 0; b < mouse_button_count && !leave; b++)
2876 {
2877 /* Only leave if user both pressed and released the mouse, and in
2878 that order. This avoids popping down the menu pane unless
2879 the user is really done with it. */
2880 if (mouse_pressed (b, &x, &y))
2881 {
2882 while (mouse_button_depressed (b, &x, &y))
2883 __dpmi_yield ();
2884 leave = 1;
2885 }
2886 (void) mouse_released (b, &x, &y);
2887 }
2888 }
2889
2890 mouse_off ();
2891 ScreenUpdate (state[0].screen_behind);
2892 if (screen_virtual_segment)
2893 dosv_refresh_virtual_screen (0, screen_size);
2894 while (statecount--)
2895 xfree (state[statecount].screen_behind);
2896 IT_display_cursor (1); /* turn cursor back on */
2897 /* Clean up any mouse events that are waiting inside Emacs event queue.
2898 These events are likely to be generated before the menu was even
2899 displayed, probably because the user pressed and released the button
2900 (which invoked the menu) too quickly. If we don't remove these events,
2901 Emacs will process them after we return and surprise the user. */
2902 discard_mouse_events ();
2903 /* Allow mouse events generation by dos_rawgetc. */
2904 mouse_preempted--;
2905 return result;
2906 }
2907
2908 /* Dispose of a menu. */
2909
2910 void
2911 XMenuDestroy (Display *foo, XMenu *menu)
2912 {
2913 int i;
2914 if (menu->allocated)
2915 {
2916 for (i = 0; i < menu->count; i++)
2917 if (menu->submenu[i])
2918 XMenuDestroy (foo, menu->submenu[i]);
2919 xfree (menu->text);
2920 xfree (menu->submenu);
2921 xfree (menu->panenumber);
2922 }
2923 xfree (menu);
2924 }
2925
2926 int
2927 x_pixel_width (struct frame *f)
2928 {
2929 return FRAME_WIDTH (f);
2930 }
2931
2932 int
2933 x_pixel_height (struct frame *f)
2934 {
2935 return FRAME_HEIGHT (f);
2936 }
2937 #endif /* !HAVE_X_WINDOWS */
2938 \f
2939 /* ----------------------- DOS / UNIX conversion --------------------- */
2940
2941 void msdos_downcase_filename (unsigned char *);
2942
2943 /* Destructively turn backslashes into slashes. */
2944
2945 void
2946 dostounix_filename (p)
2947 register char *p;
2948 {
2949 msdos_downcase_filename (p);
2950
2951 while (*p)
2952 {
2953 if (*p == '\\')
2954 *p = '/';
2955 p++;
2956 }
2957 }
2958
2959 /* Destructively turn slashes into backslashes. */
2960
2961 void
2962 unixtodos_filename (p)
2963 register char *p;
2964 {
2965 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2966 {
2967 *p += 'a' - 'A';
2968 p += 2;
2969 }
2970
2971 while (*p)
2972 {
2973 if (*p == '/')
2974 *p = '\\';
2975 p++;
2976 }
2977 }
2978
2979 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2980
2981 int
2982 getdefdir (drive, dst)
2983 int drive;
2984 char *dst;
2985 {
2986 char in_path[4], *p = in_path;
2987 int e = errno;
2988
2989 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2990 if (drive != 0)
2991 {
2992 *p++ = drive + 'A' - 1;
2993 *p++ = ':';
2994 }
2995
2996 *p++ = '.';
2997 *p = '\0';
2998 errno = 0;
2999 _fixpath (in_path, dst);
3000 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3001 it queries the LFN support, so ignore that error. */
3002 if ((errno && errno != ENOSYS) || *dst == '\0')
3003 return 0;
3004
3005 msdos_downcase_filename (dst);
3006
3007 errno = e;
3008 return 1;
3009 }
3010
3011 /* Remove all CR's that are followed by a LF. */
3012
3013 int
3014 crlf_to_lf (n, buf)
3015 register int n;
3016 register unsigned char *buf;
3017 {
3018 unsigned char *np = buf;
3019 unsigned char *startp = buf;
3020 unsigned char *endp = buf + n;
3021
3022 if (n == 0)
3023 return n;
3024 while (buf < endp - 1)
3025 {
3026 if (*buf == 0x0d)
3027 {
3028 if (*(++buf) != 0x0a)
3029 *np++ = 0x0d;
3030 }
3031 else
3032 *np++ = *buf++;
3033 }
3034 if (buf < endp)
3035 *np++ = *buf++;
3036 return np - startp;
3037 }
3038
3039 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
3040
3041 /* In DJGPP v2.0, library `write' can call `malloc', which might
3042 cause relocation of the buffer whose address we get in ADDR.
3043 Here is a version of `write' that avoids calling `malloc',
3044 to serve us until such time as the library is fixed.
3045 Actually, what we define here is called `__write', because
3046 `write' is a stub that just jmp's to `__write' (to be
3047 POSIXLY-correct with respect to the global name-space). */
3048
3049 #include <io.h> /* for _write */
3050 #include <libc/dosio.h> /* for __file_handle_modes[] */
3051
3052 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
3053
3054 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
3055
3056 int
3057 __write (int handle, const void *buffer, size_t count)
3058 {
3059 if (count == 0)
3060 return 0;
3061
3062 if(__file_handle_modes[handle] & O_BINARY)
3063 return _write (handle, buffer, count);
3064 else
3065 {
3066 char *xbp = xbuf;
3067 const char *bp = buffer;
3068 int total_written = 0;
3069 int nmoved = 0, ncr = 0;
3070
3071 while (count)
3072 {
3073 /* The next test makes sure there's space for at least 2 more
3074 characters in xbuf[], so both CR and LF can be put there. */
3075 if (xbp < XBUF_END)
3076 {
3077 if (*bp == '\n')
3078 {
3079 ncr++;
3080 *xbp++ = '\r';
3081 }
3082 *xbp++ = *bp++;
3083 nmoved++;
3084 count--;
3085 }
3086 if (xbp >= XBUF_END || !count)
3087 {
3088 size_t to_write = nmoved + ncr;
3089 int written = _write (handle, xbuf, to_write);
3090
3091 if (written == -1)
3092 return -1;
3093 else
3094 total_written += nmoved; /* CRs aren't counted in ret value */
3095
3096 /* If some, but not all were written (disk full?), return
3097 an estimate of the total written bytes not counting CRs. */
3098 if (written < to_write)
3099 return total_written - (to_write - written) * nmoved/to_write;
3100
3101 nmoved = 0;
3102 ncr = 0;
3103 xbp = xbuf;
3104 }
3105 }
3106 return total_written;
3107 }
3108 }
3109
3110 /* A low-level file-renaming function which works around Windows 95 bug.
3111 This is pulled directly out of DJGPP v2.01 library sources, and only
3112 used when you compile with DJGPP v2.0. */
3113
3114 #include <io.h>
3115
3116 int _rename(const char *old, const char *new)
3117 {
3118 __dpmi_regs r;
3119 int olen = strlen(old) + 1;
3120 int i;
3121 int use_lfn = _USE_LFN;
3122 char tempfile[FILENAME_MAX];
3123 const char *orig = old;
3124 int lfn_fd = -1;
3125
3126 r.x.dx = __tb_offset;
3127 r.x.di = __tb_offset + olen;
3128 r.x.ds = r.x.es = __tb_segment;
3129
3130 if (use_lfn)
3131 {
3132 /* Windows 95 bug: for some filenames, when you rename
3133 file -> file~ (as in Emacs, to leave a backup), the
3134 short 8+3 alias doesn't change, which effectively
3135 makes OLD and NEW the same file. We must rename
3136 through a temporary file to work around this. */
3137
3138 char *pbase = 0, *p;
3139 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
3140 int idx = sizeof(try_char) - 1;
3141
3142 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
3143 might point to another drive, which will fail the DOS call. */
3144 strcpy(tempfile, old);
3145 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
3146 if (*p == '/' || *p == '\\' || *p == ':')
3147 pbase = p;
3148 if (pbase)
3149 pbase++;
3150 else
3151 pbase = tempfile;
3152 strcpy(pbase, "X$$djren$$.$$temp$$");
3153
3154 do
3155 {
3156 if (idx <= 0)
3157 return -1;
3158 *pbase = try_char[--idx];
3159 } while (_chmod(tempfile, 0) != -1);
3160
3161 r.x.ax = 0x7156;
3162 _put_path2(tempfile, olen);
3163 _put_path(old);
3164 __dpmi_int(0x21, &r);
3165 if (r.x.flags & 1)
3166 {
3167 errno = __doserr_to_errno(r.x.ax);
3168 return -1;
3169 }
3170
3171 /* Now create a file with the original name. This will
3172 ensure that NEW will always have a 8+3 alias
3173 different from that of OLD. (Seems to be required
3174 when NameNumericTail in the Registry is set to 0.) */
3175 lfn_fd = _creat(old, 0);
3176
3177 olen = strlen(tempfile) + 1;
3178 old = tempfile;
3179 r.x.di = __tb_offset + olen;
3180 }
3181
3182 for (i=0; i<2; i++)
3183 {
3184 if(use_lfn)
3185 r.x.ax = 0x7156;
3186 else
3187 r.h.ah = 0x56;
3188 _put_path2(new, olen);
3189 _put_path(old);
3190 __dpmi_int(0x21, &r);
3191 if(r.x.flags & 1)
3192 {
3193 if (r.x.ax == 5 && i == 0) /* access denied */
3194 remove(new); /* and try again */
3195 else
3196 {
3197 errno = __doserr_to_errno(r.x.ax);
3198
3199 /* Restore to original name if we renamed it to temporary. */
3200 if (use_lfn)
3201 {
3202 if (lfn_fd != -1)
3203 {
3204 _close (lfn_fd);
3205 remove (orig);
3206 }
3207 _put_path2(orig, olen);
3208 _put_path(tempfile);
3209 r.x.ax = 0x7156;
3210 __dpmi_int(0x21, &r);
3211 }
3212 return -1;
3213 }
3214 }
3215 else
3216 break;
3217 }
3218
3219 /* Success. Delete the file possibly created to work
3220 around the Windows 95 bug. */
3221 if (lfn_fd != -1)
3222 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
3223 return 0;
3224 }
3225
3226 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
3227
3228 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3229 0, 0, 0,
3230 "Return non-nil if long file names are supported on MSDOS.")
3231 ()
3232 {
3233 return (_USE_LFN ? Qt : Qnil);
3234 }
3235
3236 /* Convert alphabetic characters in a filename to lower-case. */
3237
3238 void
3239 msdos_downcase_filename (p)
3240 register unsigned char *p;
3241 {
3242 /* Always lower-case drive letters a-z, even if the filesystem
3243 preserves case in filenames.
3244 This is so MSDOS filenames could be compared by string comparison
3245 functions that are case-sensitive. Even case-preserving filesystems
3246 do not distinguish case in drive letters. */
3247 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3248 {
3249 *p += 'a' - 'A';
3250 p += 2;
3251 }
3252
3253 /* Under LFN we expect to get pathnames in their true case. */
3254 if (NILP (Fmsdos_long_file_names ()))
3255 for ( ; *p; p++)
3256 if (*p >= 'A' && *p <= 'Z')
3257 *p += 'a' - 'A';
3258 }
3259
3260 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3261 1, 1, 0,
3262 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
3263 When long filenames are supported, doesn't change FILENAME.\n\
3264 If FILENAME is not a string, returns nil.\n\
3265 The argument object is never altered--the value is a copy.")
3266 (filename)
3267 Lisp_Object filename;
3268 {
3269 Lisp_Object tem;
3270
3271 if (! STRINGP (filename))
3272 return Qnil;
3273
3274 tem = Fcopy_sequence (filename);
3275 msdos_downcase_filename (XSTRING (tem)->data);
3276 return tem;
3277 }
3278 \f
3279 /* The Emacs root directory as determined by init_environment. */
3280
3281 static char emacsroot[MAXPATHLEN];
3282
3283 char *
3284 rootrelativepath (rel)
3285 char *rel;
3286 {
3287 static char result[MAXPATHLEN + 10];
3288
3289 strcpy (result, emacsroot);
3290 strcat (result, "/");
3291 strcat (result, rel);
3292 return result;
3293 }
3294
3295 /* Define a lot of environment variables if not already defined. Don't
3296 remove anything unless you know what you're doing -- lots of code will
3297 break if one or more of these are missing. */
3298
3299 void
3300 init_environment (argc, argv, skip_args)
3301 int argc;
3302 char **argv;
3303 int skip_args;
3304 {
3305 char *s, *t, *root;
3306 int len;
3307 static const char * const tempdirs[] = {
3308 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3309 };
3310 int i;
3311 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
3312
3313 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3314 temporary files and assume "/tmp" if $TMPDIR is unset, which
3315 will break on DOS/Windows. Refuse to work if we cannot find
3316 a directory, not even "c:/", usable for that purpose. */
3317 for (i = 0; i < imax ; i++)
3318 {
3319 const char *tmp = tempdirs[i];
3320
3321 if (*tmp == '$')
3322 tmp = getenv (tmp + 1);
3323 /* Note that `access' can lie to us if the directory resides on a
3324 read-only filesystem, like CD-ROM or a write-protected floppy.
3325 The only way to be really sure is to actually create a file and
3326 see if it succeeds. But I think that's too much to ask. */
3327 if (tmp && access (tmp, D_OK) == 0)
3328 {
3329 setenv ("TMPDIR", tmp, 1);
3330 break;
3331 }
3332 }
3333 if (i >= imax)
3334 cmd_error_internal
3335 (Fcons (Qerror,
3336 Fcons (build_string ("no usable temporary directories found!!"),
3337 Qnil)),
3338 "While setting TMPDIR: ");
3339
3340 /* Note the startup time, so we know not to clear the screen if we
3341 exit immediately; see IT_reset_terminal_modes.
3342 (Yes, I know `clock' returns zero the first time it's called, but
3343 I do this anyway, in case some wiseguy changes that at some point.) */
3344 startup_time = clock ();
3345
3346 /* Find our root from argv[0]. Assuming argv[0] is, say,
3347 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3348 root = alloca (MAXPATHLEN + 20);
3349 _fixpath (argv[0], root);
3350 msdos_downcase_filename (root);
3351 len = strlen (root);
3352 while (len > 0 && root[len] != '/' && root[len] != ':')
3353 len--;
3354 root[len] = '\0';
3355 if (len > 4
3356 && (strcmp (root + len - 4, "/bin") == 0
3357 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
3358 root[len - 4] = '\0';
3359 else
3360 strcpy (root, "c:/emacs"); /* let's be defensive */
3361 len = strlen (root);
3362 strcpy (emacsroot, root);
3363
3364 /* We default HOME to our root. */
3365 setenv ("HOME", root, 0);
3366
3367 /* We default EMACSPATH to root + "/bin". */
3368 strcpy (root + len, "/bin");
3369 setenv ("EMACSPATH", root, 0);
3370
3371 /* I don't expect anybody to ever use other terminals so the internal
3372 terminal is the default. */
3373 setenv ("TERM", "internal", 0);
3374
3375 #ifdef HAVE_X_WINDOWS
3376 /* Emacs expects DISPLAY to be set. */
3377 setenv ("DISPLAY", "unix:0.0", 0);
3378 #endif
3379
3380 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3381 downcase it and mirror the backslashes. */
3382 s = getenv ("COMSPEC");
3383 if (!s) s = "c:/command.com";
3384 t = alloca (strlen (s) + 1);
3385 strcpy (t, s);
3386 dostounix_filename (t);
3387 setenv ("SHELL", t, 0);
3388
3389 /* PATH is also downcased and backslashes mirrored. */
3390 s = getenv ("PATH");
3391 if (!s) s = "";
3392 t = alloca (strlen (s) + 3);
3393 /* Current directory is always considered part of MsDos's path but it is
3394 not normally mentioned. Now it is. */
3395 strcat (strcpy (t, ".;"), s);
3396 dostounix_filename (t); /* Not a single file name, but this should work. */
3397 setenv ("PATH", t, 1);
3398
3399 /* In some sense all dos users have root privileges, so... */
3400 setenv ("USER", "root", 0);
3401 setenv ("NAME", getenv ("USER"), 0);
3402
3403 /* Time zone determined from country code. To make this possible, the
3404 country code may not span more than one time zone. In other words,
3405 in the USA, you lose. */
3406 if (!getenv ("TZ"))
3407 switch (dos_country_code)
3408 {
3409 case 31: /* Belgium */
3410 case 32: /* The Netherlands */
3411 case 33: /* France */
3412 case 34: /* Spain */
3413 case 36: /* Hungary */
3414 case 38: /* Yugoslavia (or what's left of it?) */
3415 case 39: /* Italy */
3416 case 41: /* Switzerland */
3417 case 42: /* Tjekia */
3418 case 45: /* Denmark */
3419 case 46: /* Sweden */
3420 case 47: /* Norway */
3421 case 48: /* Poland */
3422 case 49: /* Germany */
3423 /* Daylight saving from last Sunday in March to last Sunday in
3424 September, both at 2AM. */
3425 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3426 break;
3427 case 44: /* United Kingdom */
3428 case 351: /* Portugal */
3429 case 354: /* Iceland */
3430 setenv ("TZ", "GMT+00", 0);
3431 break;
3432 case 81: /* Japan */
3433 case 82: /* Korea */
3434 setenv ("TZ", "JST-09", 0);
3435 break;
3436 case 90: /* Turkey */
3437 case 358: /* Finland */
3438 setenv ("TZ", "EET-02", 0);
3439 break;
3440 case 972: /* Israel */
3441 /* This is an approximation. (For exact rules, use the
3442 `zoneinfo/israel' file which comes with DJGPP, but you need
3443 to install it in `/usr/share/zoneinfo/' directory first.) */
3444 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3445 break;
3446 }
3447 tzset ();
3448 }
3449
3450 \f
3451
3452 static int break_stat; /* BREAK check mode status. */
3453 static int stdin_stat; /* stdin IOCTL status. */
3454
3455 #if __DJGPP__ < 2
3456
3457 /* These must be global. */
3458 static _go32_dpmi_seginfo ctrl_break_vector;
3459 static _go32_dpmi_registers ctrl_break_regs;
3460 static int ctrlbreakinstalled = 0;
3461
3462 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
3463
3464 void
3465 ctrl_break_func (regs)
3466 _go32_dpmi_registers *regs;
3467 {
3468 Vquit_flag = Qt;
3469 }
3470
3471 void
3472 install_ctrl_break_check ()
3473 {
3474 if (!ctrlbreakinstalled)
3475 {
3476 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
3477 was compiler with Djgpp 1.11 maintenance level 5 or later! */
3478 ctrlbreakinstalled = 1;
3479 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
3480 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
3481 &ctrl_break_regs);
3482 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
3483 }
3484 }
3485
3486 #endif /* __DJGPP__ < 2 */
3487
3488 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3489 control chars by DOS. Determine the keyboard type. */
3490
3491 int
3492 dos_ttraw ()
3493 {
3494 union REGS inregs, outregs;
3495 static int first_time = 1;
3496
3497 break_stat = getcbrk ();
3498 setcbrk (0);
3499 #if __DJGPP__ < 2
3500 install_ctrl_break_check ();
3501 #endif
3502
3503 if (first_time)
3504 {
3505 inregs.h.ah = 0xc0;
3506 int86 (0x15, &inregs, &outregs);
3507 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
3508
3509 have_mouse = 0;
3510
3511 if (internal_terminal
3512 #ifdef HAVE_X_WINDOWS
3513 && inhibit_window_system
3514 #endif
3515 )
3516 {
3517 inregs.x.ax = 0x0021;
3518 int86 (0x33, &inregs, &outregs);
3519 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3520 if (!have_mouse)
3521 {
3522 /* Reportedly, the above doesn't work for some mouse drivers. There
3523 is an additional detection method that should work, but might be
3524 a little slower. Use that as an alternative. */
3525 inregs.x.ax = 0x0000;
3526 int86 (0x33, &inregs, &outregs);
3527 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3528 }
3529
3530 if (have_mouse)
3531 {
3532 have_mouse = 1; /* enable mouse */
3533 mouse_visible = 0;
3534
3535 if (outregs.x.bx == 3)
3536 {
3537 mouse_button_count = 3;
3538 mouse_button_translate[0] = 0; /* Left */
3539 mouse_button_translate[1] = 2; /* Middle */
3540 mouse_button_translate[2] = 1; /* Right */
3541 }
3542 else
3543 {
3544 mouse_button_count = 2;
3545 mouse_button_translate[0] = 0;
3546 mouse_button_translate[1] = 1;
3547 }
3548 mouse_position_hook = &mouse_get_pos;
3549 mouse_init ();
3550 }
3551 }
3552
3553 first_time = 0;
3554
3555 #if __DJGPP__ >= 2
3556
3557 stdin_stat = setmode (fileno (stdin), O_BINARY);
3558 return (stdin_stat != -1);
3559 }
3560 else
3561 return (setmode (fileno (stdin), O_BINARY) != -1);
3562
3563 #else /* __DJGPP__ < 2 */
3564
3565 }
3566
3567 /* I think it is wrong to overwrite `stdin_stat' every time
3568 but the first one this function is called, but I don't
3569 want to change the way it used to work in v1.x.--EZ */
3570
3571 inregs.x.ax = 0x4400; /* Get IOCTL status. */
3572 inregs.x.bx = 0x00; /* 0 = stdin. */
3573 intdos (&inregs, &outregs);
3574 stdin_stat = outregs.h.dl;
3575
3576 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
3577 inregs.x.ax = 0x4401; /* Set IOCTL status */
3578 intdos (&inregs, &outregs);
3579 return !outregs.x.cflag;
3580
3581 #endif /* __DJGPP__ < 2 */
3582 }
3583
3584 /* Restore status of standard input and Ctrl-C checking. */
3585
3586 int
3587 dos_ttcooked ()
3588 {
3589 union REGS inregs, outregs;
3590
3591 setcbrk (break_stat);
3592 mouse_off ();
3593
3594 #if __DJGPP__ >= 2
3595
3596 return (setmode (fileno (stdin), stdin_stat) != -1);
3597
3598 #else /* not __DJGPP__ >= 2 */
3599
3600 inregs.x.ax = 0x4401; /* Set IOCTL status. */
3601 inregs.x.bx = 0x00; /* 0 = stdin. */
3602 inregs.x.dx = stdin_stat;
3603 intdos (&inregs, &outregs);
3604 return !outregs.x.cflag;
3605
3606 #endif /* not __DJGPP__ >= 2 */
3607 }
3608
3609 \f
3610 /* Run command as specified by ARGV in directory DIR.
3611 The command is run with input from TEMPIN, output to
3612 file TEMPOUT and stderr to TEMPERR. */
3613
3614 int
3615 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
3616 unsigned char **argv;
3617 const char *working_dir;
3618 int tempin, tempout, temperr;
3619 char **envv;
3620 {
3621 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
3622 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3623 int msshell, result = -1;
3624 int inbak, outbak, errbak;
3625 int x, y;
3626 Lisp_Object cmd;
3627
3628 /* Get current directory as MSDOS cwd is not per-process. */
3629 getwd (oldwd);
3630
3631 /* If argv[0] is the shell, it might come in any lettercase.
3632 Since `Fmember' is case-sensitive, we need to downcase
3633 argv[0], even if we are on case-preserving filesystems. */
3634 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
3635 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
3636 {
3637 *pl = *pa++;
3638 if (*pl >= 'A' && *pl <= 'Z')
3639 *pl += 'a' - 'A';
3640 }
3641 *pl = '\0';
3642
3643 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
3644 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
3645 && !strcmp ("-c", argv[1]);
3646 if (msshell)
3647 {
3648 saveargv1 = argv[1];
3649 saveargv2 = argv[2];
3650 argv[1] = "/c";
3651 if (argv[2])
3652 {
3653 char *p = alloca (strlen (argv[2]) + 1);
3654
3655 strcpy (argv[2] = p, saveargv2);
3656 while (*p && isspace (*p))
3657 p++;
3658 while (*p && !isspace (*p))
3659 if (*p == '/')
3660 *p++ = '\\';
3661 else
3662 p++;
3663 }
3664 }
3665
3666 chdir (working_dir);
3667 inbak = dup (0);
3668 outbak = dup (1);
3669 errbak = dup (2);
3670 if (inbak < 0 || outbak < 0 || errbak < 0)
3671 goto done; /* Allocation might fail due to lack of descriptors. */
3672
3673 if (have_mouse > 0)
3674 mouse_get_xy (&x, &y);
3675
3676 dos_ttcooked (); /* do it here while 0 = stdin */
3677
3678 dup2 (tempin, 0);
3679 dup2 (tempout, 1);
3680 dup2 (temperr, 2);
3681
3682 #if __DJGPP__ > 1
3683
3684 if (msshell && !argv[3])
3685 {
3686 /* MS-DOS native shells are too restrictive. For starters, they
3687 cannot grok commands longer than 126 characters. In DJGPP v2
3688 and later, `system' is much smarter, so we'll call it instead. */
3689
3690 const char *cmnd;
3691
3692 /* A shell gets a single argument--its full command
3693 line--whose original was saved in `saveargv2'. */
3694
3695 /* Don't let them pass empty command lines to `system', since
3696 with some shells it will try to invoke an interactive shell,
3697 which will hang Emacs. */
3698 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
3699 ;
3700 if (*cmnd)
3701 {
3702 extern char **environ;
3703 int save_system_flags = __system_flags;
3704
3705 /* Request the most powerful version of `system'. We need
3706 all the help we can get to avoid calling stock DOS shells. */
3707 __system_flags = (__system_redirect
3708 | __system_use_shell
3709 | __system_allow_multiple_cmds
3710 | __system_allow_long_cmds
3711 | __system_handle_null_commands
3712 | __system_emulate_chdir);
3713
3714 environ = envv;
3715 result = system (cmnd);
3716 __system_flags = save_system_flags;
3717 }
3718 else
3719 result = 0; /* emulate Unixy shell behavior with empty cmd line */
3720 }
3721 else
3722
3723 #endif /* __DJGPP__ > 1 */
3724
3725 result = spawnve (P_WAIT, argv[0], argv, envv);
3726
3727 dup2 (inbak, 0);
3728 dup2 (outbak, 1);
3729 dup2 (errbak, 2);
3730 emacs_close (inbak);
3731 emacs_close (outbak);
3732 emacs_close (errbak);
3733
3734 dos_ttraw ();
3735 if (have_mouse > 0)
3736 {
3737 mouse_init ();
3738 mouse_moveto (x, y);
3739 }
3740
3741 /* Some programs might change the meaning of the highest bit of the
3742 text attribute byte, so we get blinking characters instead of the
3743 bright background colors. Restore that. */
3744 bright_bg ();
3745
3746 done:
3747 chdir (oldwd);
3748 if (msshell)
3749 {
3750 argv[1] = saveargv1;
3751 argv[2] = saveargv2;
3752 }
3753 return result;
3754 }
3755
3756 croak (badfunc)
3757 char *badfunc;
3758 {
3759 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
3760 reset_sys_modes ();
3761 exit (1);
3762 }
3763 \f
3764 #if __DJGPP__ < 2
3765
3766 /* ------------------------- Compatibility functions -------------------
3767 * gethostname
3768 * gettimeofday
3769 */
3770
3771 /* Hostnames for a pc are not really funny,
3772 but they are used in change log so we emulate the best we can. */
3773
3774 gethostname (p, size)
3775 char *p;
3776 int size;
3777 {
3778 char *q = egetenv ("HOSTNAME");
3779
3780 if (!q) q = "pc";
3781 strcpy (p, q);
3782 return 0;
3783 }
3784
3785 /* When time zones are set from Ms-Dos too many C-libraries are playing
3786 tricks with time values. We solve this by defining our own version
3787 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3788 once and after each call to `tzset' with TZ changed. That is
3789 accomplished by aliasing tzset to init_gettimeofday. */
3790
3791 static struct tm time_rec;
3792
3793 int
3794 gettimeofday (struct timeval *tp, struct timezone *tzp)
3795 {
3796 if (tp)
3797 {
3798 struct time t;
3799 struct tm tm;
3800
3801 gettime (&t);
3802 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
3803 {
3804 struct date d;
3805 getdate (&d);
3806 time_rec.tm_year = d.da_year - 1900;
3807 time_rec.tm_mon = d.da_mon - 1;
3808 time_rec.tm_mday = d.da_day;
3809 }
3810
3811 time_rec.tm_hour = t.ti_hour;
3812 time_rec.tm_min = t.ti_min;
3813 time_rec.tm_sec = t.ti_sec;
3814
3815 tm = time_rec;
3816 tm.tm_gmtoff = dos_timezone_offset;
3817
3818 tp->tv_sec = mktime (&tm); /* may modify tm */
3819 tp->tv_usec = t.ti_hund * (1000000 / 100);
3820 }
3821 /* Ignore tzp; it's obsolescent. */
3822 return 0;
3823 }
3824
3825 #endif /* __DJGPP__ < 2 */
3826
3827 /*
3828 * A list of unimplemented functions that we silently ignore.
3829 */
3830
3831 #if __DJGPP__ < 2
3832 unsigned alarm (s) unsigned s; {}
3833 fork () { return 0; }
3834 int kill (x, y) int x, y; { return -1; }
3835 nice (p) int p; {}
3836 void volatile pause () {}
3837 sigsetmask (x) int x; { return 0; }
3838 sigblock (mask) int mask; { return 0; }
3839 #endif
3840
3841 void request_sigio (void) {}
3842 setpgrp () {return 0; }
3843 setpriority (x,y,z) int x,y,z; { return 0; }
3844 void unrequest_sigio (void) {}
3845
3846 #if __DJGPP__ > 1
3847
3848 #ifdef POSIX_SIGNALS
3849
3850 /* Augment DJGPP library POSIX signal functions. This is needed
3851 as of DJGPP v2.01, but might be in the library in later releases. */
3852
3853 #include <libc/bss.h>
3854
3855 /* A counter to know when to re-initialize the static sets. */
3856 static int sigprocmask_count = -1;
3857
3858 /* Which signals are currently blocked (initially none). */
3859 static sigset_t current_mask;
3860
3861 /* Which signals are pending (initially none). */
3862 static sigset_t pending_signals;
3863
3864 /* Previous handlers to restore when the blocked signals are unblocked. */
3865 typedef void (*sighandler_t)(int);
3866 static sighandler_t prev_handlers[320];
3867
3868 /* A signal handler which just records that a signal occured
3869 (it will be raised later, if and when the signal is unblocked). */
3870 static void
3871 sig_suspender (signo)
3872 int signo;
3873 {
3874 sigaddset (&pending_signals, signo);
3875 }
3876
3877 int
3878 sigprocmask (how, new_set, old_set)
3879 int how;
3880 const sigset_t *new_set;
3881 sigset_t *old_set;
3882 {
3883 int signo;
3884 sigset_t new_mask;
3885
3886 /* If called for the first time, initialize. */
3887 if (sigprocmask_count != __bss_count)
3888 {
3889 sigprocmask_count = __bss_count;
3890 sigemptyset (&pending_signals);
3891 sigemptyset (&current_mask);
3892 for (signo = 0; signo < 320; signo++)
3893 prev_handlers[signo] = SIG_ERR;
3894 }
3895
3896 if (old_set)
3897 *old_set = current_mask;
3898
3899 if (new_set == 0)
3900 return 0;
3901
3902 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
3903 {
3904 errno = EINVAL;
3905 return -1;
3906 }
3907
3908 sigemptyset (&new_mask);
3909
3910 /* DJGPP supports upto 320 signals. */
3911 for (signo = 0; signo < 320; signo++)
3912 {
3913 if (sigismember (&current_mask, signo))
3914 sigaddset (&new_mask, signo);
3915 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
3916 {
3917 sigaddset (&new_mask, signo);
3918
3919 /* SIGKILL is silently ignored, as on other platforms. */
3920 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
3921 prev_handlers[signo] = signal (signo, sig_suspender);
3922 }
3923 if (( how == SIG_UNBLOCK
3924 && sigismember (&new_mask, signo)
3925 && sigismember (new_set, signo))
3926 || (how == SIG_SETMASK
3927 && sigismember (&new_mask, signo)
3928 && !sigismember (new_set, signo)))
3929 {
3930 sigdelset (&new_mask, signo);
3931 if (prev_handlers[signo] != SIG_ERR)
3932 {
3933 signal (signo, prev_handlers[signo]);
3934 prev_handlers[signo] = SIG_ERR;
3935 }
3936 if (sigismember (&pending_signals, signo))
3937 {
3938 sigdelset (&pending_signals, signo);
3939 raise (signo);
3940 }
3941 }
3942 }
3943 current_mask = new_mask;
3944 return 0;
3945 }
3946
3947 #else /* not POSIX_SIGNALS */
3948
3949 sigsetmask (x) int x; { return 0; }
3950 sigblock (mask) int mask; { return 0; }
3951
3952 #endif /* not POSIX_SIGNALS */
3953 #endif /* __DJGPP__ > 1 */
3954
3955 #ifndef HAVE_SELECT
3956 #include "sysselect.h"
3957
3958 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3959 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3960 ((long)(time).tv_sec < 0 \
3961 || ((time).tv_sec == 0 \
3962 && (long)(time).tv_usec <= 0))
3963 #endif
3964
3965 /* This yields the rest of the current time slice to the task manager.
3966 It should be called by any code which knows that it has nothing
3967 useful to do except idle.
3968
3969 I don't use __dpmi_yield here, since versions of library before 2.02
3970 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
3971 on some versions of Windows 9X. */
3972
3973 void
3974 dos_yield_time_slice (void)
3975 {
3976 _go32_dpmi_registers r;
3977
3978 r.x.ax = 0x1680;
3979 r.x.ss = r.x.sp = r.x.flags = 0;
3980 _go32_dpmi_simulate_int (0x2f, &r);
3981 if (r.h.al == 0x80)
3982 errno = ENOSYS;
3983 }
3984
3985 /* Only event queue is checked. */
3986 /* We don't have to call timer_check here
3987 because wait_reading_process_input takes care of that. */
3988 int
3989 sys_select (nfds, rfds, wfds, efds, timeout)
3990 int nfds;
3991 SELECT_TYPE *rfds, *wfds, *efds;
3992 EMACS_TIME *timeout;
3993 {
3994 int check_input;
3995 struct time t;
3996
3997 check_input = 0;
3998 if (rfds)
3999 {
4000 check_input = FD_ISSET (0, rfds);
4001 FD_ZERO (rfds);
4002 }
4003 if (wfds)
4004 FD_ZERO (wfds);
4005 if (efds)
4006 FD_ZERO (efds);
4007
4008 if (nfds != 1)
4009 abort ();
4010
4011 /* If we are looking only for the terminal, with no timeout,
4012 just read it and wait -- that's more efficient. */
4013 if (!timeout)
4014 {
4015 while (!detect_input_pending ())
4016 {
4017 dos_yield_time_slice ();
4018 }
4019 }
4020 else
4021 {
4022 EMACS_TIME clnow, cllast, cldiff;
4023
4024 gettime (&t);
4025 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
4026
4027 while (!check_input || !detect_input_pending ())
4028 {
4029 gettime (&t);
4030 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
4031 EMACS_SUB_TIME (cldiff, clnow, cllast);
4032
4033 /* When seconds wrap around, we assume that no more than
4034 1 minute passed since last `gettime'. */
4035 if (EMACS_TIME_NEG_P (cldiff))
4036 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
4037 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
4038
4039 /* Stop when timeout value crosses zero. */
4040 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
4041 return 0;
4042 cllast = clnow;
4043 dos_yield_time_slice ();
4044 }
4045 }
4046
4047 FD_SET (0, rfds);
4048 return 1;
4049 }
4050 #endif
4051
4052 /*
4053 * Define overlaid functions:
4054 *
4055 * chdir -> sys_chdir
4056 * tzset -> init_gettimeofday
4057 * abort -> dos_abort
4058 */
4059
4060 #ifdef chdir
4061 #undef chdir
4062 extern int chdir ();
4063
4064 int
4065 sys_chdir (path)
4066 const char* path;
4067 {
4068 int len = strlen (path);
4069 char *tmp = (char *)path;
4070
4071 if (*tmp && tmp[1] == ':')
4072 {
4073 if (getdisk () != tolower (tmp[0]) - 'a')
4074 setdisk (tolower (tmp[0]) - 'a');
4075 tmp += 2; /* strip drive: KFS 1995-07-06 */
4076 len -= 2;
4077 }
4078
4079 if (len > 1 && (tmp[len - 1] == '/'))
4080 {
4081 char *tmp1 = (char *) alloca (len + 1);
4082 strcpy (tmp1, tmp);
4083 tmp1[len - 1] = 0;
4084 tmp = tmp1;
4085 }
4086 return chdir (tmp);
4087 }
4088 #endif
4089
4090 #ifdef tzset
4091 #undef tzset
4092 extern void tzset (void);
4093
4094 void
4095 init_gettimeofday ()
4096 {
4097 time_t ltm, gtm;
4098 struct tm *lstm;
4099
4100 tzset ();
4101 ltm = gtm = time (NULL);
4102 ltm = mktime (lstm = localtime (&ltm));
4103 gtm = mktime (gmtime (&gtm));
4104 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4105 time_rec.tm_isdst = lstm->tm_isdst;
4106 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4107 }
4108 #endif
4109
4110 #ifdef abort
4111 #undef abort
4112 void
4113 dos_abort (file, line)
4114 char *file;
4115 int line;
4116 {
4117 char buffer1[200], buffer2[400];
4118 int i, j;
4119
4120 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
4121 for (i = j = 0; buffer1[i]; i++) {
4122 buffer2[j++] = buffer1[i];
4123 buffer2[j++] = 0x70;
4124 }
4125 dosmemput (buffer2, j, (int)ScreenPrimary);
4126 ScreenSetCursor (2, 0);
4127 abort ();
4128 }
4129 #else
4130 void
4131 abort ()
4132 {
4133 dos_ttcooked ();
4134 ScreenSetCursor (10, 0);
4135 cputs ("\r\n\nEmacs aborted!\r\n");
4136 #if __DJGPP__ > 1
4137 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4138 if (screen_virtual_segment)
4139 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4140 /* Generate traceback, so we could tell whodunit. */
4141 signal (SIGINT, SIG_DFL);
4142 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4143 #else /* __DJGPP_MINOR__ >= 2 */
4144 raise (SIGABRT);
4145 #endif /* __DJGPP_MINOR__ >= 2 */
4146 #endif
4147 exit (2);
4148 }
4149 #endif
4150
4151 /* The following variables are required so that cus-start.el won't
4152 complain about unbound variables. */
4153 #ifndef HAVE_X_WINDOWS
4154 /* Search path for bitmap files (xfns.c). */
4155 Lisp_Object Vx_bitmap_file_path;
4156 int x_stretch_cursor_p;
4157 #endif
4158 #ifndef subprocesses
4159 /* Nonzero means delete a process right away if it exits (process.c). */
4160 static int delete_exited_processes;
4161 #endif
4162
4163 syms_of_msdos ()
4164 {
4165 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4166 staticpro (&recent_doskeys);
4167 #ifndef HAVE_X_WINDOWS
4168 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
4169 "List of directories to search for bitmap files for X.");
4170 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
4171
4172 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
4173 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
4174 For example, if a block cursor is over a tab, it will be drawn as\n\
4175 wide as that tab on the display. (No effect on MS-DOS.)");
4176 x_stretch_cursor_p = 0;
4177
4178 /* The following three are from xfns.c: */
4179 Qbackground_color = intern ("background-color");
4180 staticpro (&Qbackground_color);
4181 Qforeground_color = intern ("foreground-color");
4182 staticpro (&Qforeground_color);
4183
4184 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
4185 "*Glyph to display instead of chars not supported by current codepage.\n\
4186
4187 This variable is used only by MSDOS terminals.");
4188 Vdos_unsupported_char_glyph = '\177';
4189 #endif
4190 #ifndef subprocesses
4191 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
4192 "*Non-nil means delete processes immediately when they exit.\n\
4193 nil means don't delete them until `list-processes' is run.");
4194 delete_exited_processes = 0;
4195 #endif
4196
4197 defsubr (&Srecent_doskeys);
4198 defsubr (&Smsdos_long_file_names);
4199 defsubr (&Smsdos_downcase_filename);
4200 defsubr (&Smsdos_remember_default_colors);
4201 }
4202
4203 #endif /* MSDOS */
4204