* keyboard.c (Qratio): New symbol.
[emacs.git] / src / msdos.c
blob450d1273c02570084c56fcadf8ccadf97e277dad
1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 94, 95, 96, 97, 1999 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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.
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.
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. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
26 #include <config.h>
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
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
70 #ifndef _USE_LFN
71 #define _USE_LFN 0
72 #endif
74 #ifndef _dos_ds
75 #define _dos_ds _go32_info_block.selector_for_linear_memory
76 #endif
78 #if __DJGPP__ > 1
80 #include <signal.h>
81 #include "syssignal.h"
83 #ifndef SYSTEM_MALLOC
85 #ifdef GNU_MALLOC
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>
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 */
100 #endif /* not SYSTEM_MALLOC */
101 #endif /* __DJGPP__ > 1 */
103 static unsigned long
104 event_timestamp ()
106 struct time t;
107 unsigned long s;
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;
116 return s;
120 /* ------------------------ Mouse control ---------------------------
122 * Coordinates are in screen positions and zero based.
123 * Mouse buttons are numbered from left to right and also zero based.
126 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
127 static int mouse_visible;
129 static int mouse_last_x;
130 static int mouse_last_y;
132 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
133 static int mouse_button_count;
135 void
136 mouse_on ()
138 union REGS regs;
140 if (have_mouse > 0 && !mouse_visible)
142 if (termscript)
143 fprintf (termscript, "<M_ON>");
144 regs.x.ax = 0x0001;
145 int86 (0x33, &regs, &regs);
146 mouse_visible = 1;
150 void
151 mouse_off ()
153 union REGS regs;
155 if (have_mouse > 0 && mouse_visible)
157 if (termscript)
158 fprintf (termscript, "<M_OFF>");
159 regs.x.ax = 0x0002;
160 int86 (0x33, &regs, &regs);
161 mouse_visible = 0;
165 static void
166 mouse_get_xy (int *x, int *y)
168 union REGS regs;
170 regs.x.ax = 0x0003;
171 int86 (0x33, &regs, &regs);
172 *x = regs.x.cx / 8;
173 *y = regs.x.dx / 8;
176 void
177 mouse_moveto (x, y)
178 int x, y;
180 union REGS regs;
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);
190 static int
191 mouse_pressed (b, xp, yp)
192 int b, *xp, *yp;
194 union REGS regs;
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);
206 static int
207 mouse_released (b, xp, yp)
208 int b, *xp, *yp;
210 union REGS regs;
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);
222 static int
223 mouse_button_depressed (b, xp, yp)
224 int b, *xp, *yp;
226 union REGS regs;
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)
234 *xp = regs.x.cx / 8;
235 *yp = regs.x.dx / 8;
236 return 1;
238 return 0;
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;
249 int ix, iy;
250 Lisp_Object frame, tail;
252 /* Clear the mouse-moved flag for every frame on this display. */
253 FOR_EACH_FRAME (tail, frame)
254 XFRAME (frame)->mouse_moved = 0;
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);
264 static void
265 mouse_check_moved ()
267 int x, y;
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;
275 void
276 mouse_init ()
278 union REGS regs;
279 int b;
281 if (termscript)
282 fprintf (termscript, "<M_INIT>");
284 regs.x.ax = 0x0021;
285 int86 (0x33, &regs, &regs);
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++)
293 int dummy_x, dummy_y;
295 (void) mouse_pressed (b, &dummy_x, &dummy_y);
296 (void) mouse_released (b, &dummy_x, &dummy_y);
299 regs.x.ax = 0x0007;
300 regs.x.cx = 0;
301 regs.x.dx = 8 * (ScreenCols () - 1);
302 int86 (0x33, &regs, &regs);
304 regs.x.ax = 0x0008;
305 regs.x.cx = 0;
306 regs.x.dx = 8 * (ScreenRows () - 1);
307 int86 (0x33, &regs, &regs);
309 mouse_moveto (0, 0);
310 mouse_visible = 0;
313 /* ------------------------- Screen control ----------------------
317 static int internal_terminal = 0;
319 #ifndef HAVE_X_WINDOWS
320 extern unsigned char ScreenAttrib;
321 static int screen_face;
322 static int highlight;
324 static int screen_size_X;
325 static int screen_size_Y;
326 static int screen_size;
328 static int current_pos_X;
329 static int current_pos_Y;
330 static int new_pos_X;
331 static int new_pos_Y;
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;
340 static clock_t startup_time;
342 static int term_setup_done;
344 /* Similar to the_only_frame. */
345 struct x_output the_only_x_display;
347 /* Support for DOS/V (allows Japanese characters to be displayed on
348 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
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;
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)
364 __dpmi_regs regs;
366 if (offset < 0 || count < 0) /* paranoia; illegal values crash DOS/V */
367 return;
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);
375 #endif
377 static void
378 dos_direct_output (y, x, buf, len)
379 int y;
380 int x;
381 char *buf;
382 int len;
384 int t0 = 2 * (x + y * screen_size_X);
385 int t = t0 + (int) ScreenPrimary;
386 int l0 = len;
388 #if (__DJGPP__ < 2)
389 while (--len >= 0) {
390 dosmemput (buf++, 1, t);
391 t += 2;
393 #else
394 /* This is faster. */
395 for (_farsetsel (_dos_ds); --len >= 0; t += 2, buf++)
396 _farnspokeb (t, *buf);
398 if (screen_virtual_segment)
399 dosv_refresh_virtual_screen (t0, l0);
400 #endif
402 #endif
404 /* Flash the screen as a substitute for BEEPs. */
406 #if (__DJGPP__ < 2)
407 static void
408 do_visible_bell (xorattr)
409 unsigned char xorattr;
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");
441 static void
442 ScreenVisualBell (void)
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);
450 #endif
452 #ifndef HAVE_X_WINDOWS
454 static int blink_bit = -1; /* the state of the blink bit at startup */
456 /* Enable bright background colors. */
457 static void
458 bright_bg (void)
460 union REGS regs;
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;
467 regs.h.bl = 0;
468 regs.x.ax = 0x1003;
469 int86 (0x10, &regs, &regs);
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)
477 if (blink_bit == 1)
479 union REGS regs;
481 regs.h.bl = 1;
482 regs.x.ax = 0x1003;
483 int86 (0x10, &regs, &regs);
487 /* Set the screen dimensions so that it can show no less than
488 ROWS x COLS frame. */
490 void
491 dos_set_window_size (rows, cols)
492 int *rows, *cols;
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 ();
501 if (*rows == current_rows && *cols == current_cols)
502 return;
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;
510 mouse_off ();
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;
518 if (INTEGERP (video_mode)
519 && (video_mode_value = XINT (video_mode)) > 0)
521 regs.x.ax = video_mode_value;
522 int86 (0x10, &regs, &regs);
524 if (have_mouse)
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);
534 /* Find one of the dimensions supported by standard EGA/VGA
535 which gives us at least the required dimensions. */
537 #if __DJGPP__ > 1
539 else
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}
552 int i = 0;
554 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
556 if (std_dimension[i].need_vga <= have_vga
557 && std_dimension[i].rows >= *rows)
559 if (std_dimension[i].rows != current_rows
560 || *cols != current_cols)
561 _set_screen_lines (std_dimension[i].rows);
562 break;
564 i++;
568 #else /* not __DJGPP__ > 1 */
570 else if (*rows <= 25)
572 if (current_rows != 25 || current_cols != 80)
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);
586 else if (*rows <= 50)
587 if (have_vga && (current_rows != 50 || current_cols != 80)
588 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
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);
602 #endif /* not __DJGPP__ > 1 */
604 if (have_mouse)
606 mouse_init ();
607 mouse_on ();
610 /* Tell the caller what dimensions have been REALLY set. */
611 *rows = ScreenRows ();
612 *cols = ScreenCols ();
614 /* Enable bright background colors. */
615 bright_bg ();
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);
623 /* If we write a character in the position where the mouse is,
624 the mouse cursor may need to be refreshed. */
626 static void
627 mouse_off_maybe ()
629 int x, y;
631 if (!mouse_visible)
632 return;
634 mouse_get_xy (&x, &y);
635 if (y != new_pos_Y || x < new_pos_X)
636 return;
638 mouse_off ();
641 static void
642 IT_ring_bell (void)
644 if (visible_bell)
646 mouse_off ();
647 ScreenVisualBell ();
649 else
651 union REGS inregs, outregs;
652 inregs.h.ah = 2;
653 inregs.h.dl = 7;
654 intdos (&inregs, &outregs);
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)
666 struct frame *sf = SELECTED_FRAME();
667 struct face *fp = FACE_FROM_ID (sf, face);
668 unsigned long fg, bg;
670 if (!fp)
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 ();
678 screen_face = face;
679 fg = fp->foreground;
680 bg = fp->background;
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 == (unsigned long)-1)
689 fg = highlight || fp->tty_reverse_p ? FRAME_BACKGROUND_PIXEL (sf)
690 : FRAME_FOREGROUND_PIXEL (sf);
691 if (bg == (unsigned long)-1)
692 bg = highlight || fp->tty_reverse_p ? FRAME_FOREGROUND_PIXEL (sf)
693 : FRAME_BACKGROUND_PIXEL (sf);
694 if (termscript)
695 fprintf (termscript, "<FACE %d%s: %d/%d>",
696 face, highlight ? "H" : "", fp->foreground, fp->background);
697 if (fg >= 0 && fg < 16)
699 ScreenAttrib &= 0xf0;
700 ScreenAttrib |= fg;
702 if (bg >= 0 && bg < 16)
704 ScreenAttrib &= 0x0f;
705 ScreenAttrib |= ((bg & 0x0f) << 4);
709 Lisp_Object Vdos_unsupported_char_glyph;
711 static void
712 IT_write_glyphs (struct glyph *str, int str_len)
714 unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
715 int unsupported_face = FAST_GLYPH_FACE (Vdos_unsupported_char_glyph);
716 unsigned unsupported_char= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph);
717 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
718 register int sl = str_len;
719 register int tlen = GLYPH_TABLE_LENGTH;
720 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
722 struct coding_system *coding = (CODING_REQUIRE_ENCODING (&terminal_coding)
723 ? &terminal_coding
724 : &safe_terminal_coding);
725 struct frame *sf;
727 /* Do we need to consider conversion of unibyte characters to
728 multibyte? */
729 int convert_unibyte_characters
730 = (NILP (current_buffer->enable_multibyte_characters)
731 && unibyte_display_via_language_environment);
733 if (str_len == 0) return;
735 screen_buf = screen_bp = alloca (str_len * 2);
736 screen_buf_end = screen_buf + str_len * 2;
737 sf = SELECTED_FRAME();
739 /* Since faces get cached and uncached behind our back, we can't
740 rely on their indices in the cache being consistent across
741 invocations. So always reset the screen face to the default
742 face of the frame, before writing glyphs, and let the glyphs
743 set the right face if it's different from the default. */
744 IT_set_face (DEFAULT_FACE_ID);
746 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
747 the tail. */
748 terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
749 while (sl)
751 int cf, chlen, enclen;
752 unsigned char workbuf[4], *buf;
753 unsigned ch;
754 register GLYPH g = GLYPH_FROM_CHAR_GLYPH (*str);
756 /* Find the actual glyph to display by traversing the entire
757 aliases chain for this glyph. */
758 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
760 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
761 only for the redisplay code to know how many columns does
762 this character occupy on the screen. Skip padding glyphs. */
763 if (CHAR_GLYPH_PADDING_P (*str))
765 str++;
766 sl--;
768 else
770 /* Convert the character code to multibyte, if they
771 requested display via language environment. */
772 ch = FAST_GLYPH_CHAR (g);
773 /* We only want to convert unibyte characters to multibyte
774 in unibyte buffers! Otherwise, the 8-bit code might come
775 from the display table set up to display foreign characters. */
776 if (SINGLE_BYTE_CHAR_P (ch) && convert_unibyte_characters
777 && (ch >= 0240
778 || (ch >= 0200 && !NILP (Vnonascii_translation_table))))
779 ch = unibyte_char_to_multibyte (ch);
781 /* Invalid characters are displayed with a special glyph. */
782 if (! GLYPH_CHAR_VALID_P (ch))
784 g = !NILP (Vdos_unsupported_char_glyph)
785 ? Vdos_unsupported_char_glyph
786 : MAKE_GLYPH (sf, '\177', GLYPH_FACE (sf, g));
787 ch = FAST_GLYPH_CHAR (g);
789 if (COMPOSITE_CHAR_P (ch))
791 /* If CH is a composite character, we can display
792 only the first component. */
793 g = cmpchar_table[COMPOSITE_CHAR_ID (ch)]->glyph[0],
794 ch = GLYPH_CHAR (sf, g);
795 cf = FAST_GLYPH_FACE (g);
798 /* If the face of this glyph is different from the current
799 screen face, update the screen attribute byte. */
800 cf = FAST_GLYPH_FACE (g);
801 if (cf != screen_face)
802 IT_set_face (cf); /* handles invalid faces gracefully */
804 if (GLYPH_SIMPLE_P (tbase, tlen, g))
805 /* We generate the multi-byte form of CH in BUF. */
806 chlen = CHAR_STRING (ch, workbuf, buf);
807 else
809 /* We have a string in Vglyph_table. */
810 chlen = GLYPH_LENGTH (tbase, g);
811 buf = GLYPH_STRING (tbase, g);
814 /* If the character is not multibyte, don't bother converting it. */
815 if (chlen == 1)
817 *conversion_buffer = (unsigned char)ch;
818 chlen = 0;
819 enclen = 1;
821 else
823 encode_coding (coding, buf, conversion_buffer, chlen,
824 conversion_buffer_size);
825 chlen -= coding->consumed;
826 enclen = coding->produced;
828 /* Replace glyph codes that cannot be converted by
829 terminal_coding with Vdos_unsupported_char_glyph. */
830 if (*conversion_buffer == '?')
832 char *cbp = conversion_buffer;
834 while (cbp < conversion_buffer + enclen && *cbp == '?')
835 *cbp++ = unsupported_char;
836 if (unsupported_face != screen_face)
837 IT_set_face (unsupported_face);
841 if (enclen + chlen > screen_buf_end - screen_bp)
843 /* The allocated buffer for screen writes is too small.
844 Flush it and loop again without incrementing STR, so
845 that the next loop will begin with the same glyph. */
846 int nbytes = screen_bp - screen_buf;
848 mouse_off_maybe ();
849 dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
850 if (screen_virtual_segment)
851 dosv_refresh_virtual_screen (offset, nbytes / 2);
852 new_pos_X += nbytes / 2;
853 offset += nbytes;
855 /* Prepare to reuse the same buffer again. */
856 screen_bp = screen_buf;
858 else
860 /* There's enough place in the allocated buffer to add
861 the encoding of this glyph. */
863 /* First, copy the encoded bytes. */
864 for (bp = conversion_buffer; enclen--; bp++)
866 *screen_bp++ = (unsigned char)*bp;
867 *screen_bp++ = ScreenAttrib;
868 if (termscript)
869 fputc (*bp, termscript);
872 /* Now copy the bytes not consumed by the encoding. */
873 if (chlen > 0)
875 buf += coding->consumed;
876 while (chlen--)
878 if (termscript)
879 fputc (*buf, termscript);
880 *screen_bp++ = (unsigned char)*buf++;
881 *screen_bp++ = ScreenAttrib;
885 /* Update STR and its remaining length. */
886 str++;
887 sl--;
892 /* Dump whatever is left in the screen buffer. */
893 mouse_off_maybe ();
894 dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
895 if (screen_virtual_segment)
896 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
897 new_pos_X += (screen_bp - screen_buf) / 2;
899 /* We may have to output some codes to terminate the writing. */
900 if (CODING_REQUIRE_FLUSHING (coding))
902 coding->mode |= CODING_MODE_LAST_BLOCK;
903 encode_coding (coding, "", conversion_buffer, 0, conversion_buffer_size);
904 if (coding->produced > 0)
906 for (screen_bp = screen_buf, bp = conversion_buffer;
907 coding->produced--; bp++)
909 *screen_bp++ = (unsigned char)*bp;
910 *screen_bp++ = ScreenAttrib;
911 if (termscript)
912 fputc (*bp, termscript);
914 offset += screen_bp - screen_buf;
915 mouse_off_maybe ();
916 dosmemput (screen_buf, screen_bp - screen_buf,
917 (int)ScreenPrimary + offset);
918 if (screen_virtual_segment)
919 dosv_refresh_virtual_screen (offset, (screen_bp - screen_buf) / 2);
920 new_pos_X += (screen_bp - screen_buf) / 2;
925 static void
926 IT_clear_end_of_line (int first_unused)
928 char *spaces, *sp;
929 int i, j;
930 int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
931 extern int fatal_error_in_progress;
933 if (new_pos_X >= first_unused || fatal_error_in_progress)
934 return;
936 IT_set_face (0);
937 if (termscript)
938 fprintf (termscript, "<CLR:EOL>");
939 i = (j = first_unused - new_pos_X) * 2;
940 spaces = sp = alloca (i);
942 while (--j >= 0)
944 *sp++ = ' ';
945 *sp++ = ScreenAttrib;
948 mouse_off_maybe ();
949 dosmemput (spaces, i, (int)ScreenPrimary + offset);
950 if (screen_virtual_segment)
951 dosv_refresh_virtual_screen (offset, i / 2);
953 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
954 Let's follow their lead, in case someone relies on this. */
955 new_pos_X = first_unused;
958 static void
959 IT_clear_screen (void)
961 if (termscript)
962 fprintf (termscript, "<CLR:SCR>");
963 IT_set_face (0);
964 mouse_off ();
965 ScreenClear ();
966 if (screen_virtual_segment)
967 dosv_refresh_virtual_screen (0, screen_size);
968 new_pos_X = new_pos_Y = 0;
971 static void
972 IT_clear_to_end (void)
974 if (termscript)
975 fprintf (termscript, "<CLR:EOS>");
977 while (new_pos_Y < screen_size_Y) {
978 new_pos_X = 0;
979 IT_clear_end_of_line (0);
980 new_pos_Y++;
984 static void
985 IT_cursor_to (int y, int x)
987 if (termscript)
988 fprintf (termscript, "\n<XY=%dx%d>", x, y);
989 new_pos_X = x;
990 new_pos_Y = y;
993 static int cursor_cleared;
995 static void
996 IT_display_cursor (int on)
998 if (on && cursor_cleared)
1000 ScreenSetCursor (current_pos_Y, current_pos_X);
1001 cursor_cleared = 0;
1003 else if (!on && !cursor_cleared)
1005 ScreenSetCursor (-1, -1);
1006 cursor_cleared = 1;
1010 /* Emacs calls cursor-movement functions a lot when it updates the
1011 display (probably a legacy of old terminals where you cannot
1012 update a screen line without first moving the cursor there).
1013 However, cursor movement is expensive on MSDOS (it calls a slow
1014 BIOS function and requires 2 mode switches), while actual screen
1015 updates access the video memory directly and don't depend on
1016 cursor position. To avoid slowing down the redisplay, we cheat:
1017 all functions that move the cursor only set internal variables
1018 which record the cursor position, whereas the cursor is only
1019 moved to its final position whenever screen update is complete.
1021 `IT_cmgoto' is called from the keyboard reading loop and when the
1022 frame update is complete. This means that we are ready for user
1023 input, so we update the cursor position to show where the point is,
1024 and also make the mouse pointer visible.
1026 Special treatment is required when the cursor is in the echo area,
1027 to put the cursor at the end of the text displayed there. */
1029 static void
1030 IT_cmgoto (FRAME_PTR f)
1032 /* Only set the cursor to where it should be if the display is
1033 already in sync with the window contents. */
1034 int update_cursor_pos = 1; /* MODIFF == unchanged_modified; */
1036 /* FIXME: This needs to be rewritten for the new redisplay, or
1037 removed. */
1038 #if 0
1039 static int previous_pos_X = -1;
1041 update_cursor_pos = 1; /* temporary!!! */
1043 /* If the display is in sync, forget any previous knowledge about
1044 cursor position. This is primarily for unexpected events like
1045 C-g in the minibuffer. */
1046 if (update_cursor_pos && previous_pos_X >= 0)
1047 previous_pos_X = -1;
1048 /* If we are in the echo area, put the cursor at the
1049 end of the echo area message. */
1050 if (!update_cursor_pos
1051 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top) <= new_pos_Y)
1053 int tem_X = current_pos_X, dummy;
1055 if (echo_area_glyphs)
1057 tem_X = echo_area_glyphs_length;
1058 /* Save current cursor position, to be restored after the
1059 echo area message is erased. Only remember one level
1060 of previous cursor position. */
1061 if (previous_pos_X == -1)
1062 ScreenGetCursor (&dummy, &previous_pos_X);
1064 else if (previous_pos_X >= 0)
1066 /* We wind up here after the echo area message is erased.
1067 Restore the cursor position we remembered above. */
1068 tem_X = previous_pos_X;
1069 previous_pos_X = -1;
1072 if (current_pos_X != tem_X)
1074 new_pos_X = tem_X;
1075 update_cursor_pos = 1;
1078 #endif
1080 if (update_cursor_pos
1081 && (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y))
1083 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X);
1084 if (termscript)
1085 fprintf (termscript, "\n<CURSOR:%dx%d>", current_pos_X, current_pos_Y);
1088 /* Maybe cursor is invisible, so make it visible. */
1089 IT_display_cursor (1);
1091 /* Mouse pointer should be always visible if we are waiting for
1092 keyboard input. */
1093 if (!mouse_visible)
1094 mouse_on ();
1097 static void
1098 IT_reassert_line_highlight (int new, int vpos)
1100 highlight = new;
1103 static void
1104 IT_change_line_highlight (int new_highlight, int y, int vpos, int first_unused_hpos)
1106 highlight = new_highlight;
1107 IT_cursor_to (vpos, 0);
1108 IT_clear_end_of_line (first_unused_hpos);
1111 static void
1112 IT_update_begin (struct frame *foo)
1114 highlight = 0;
1117 static void
1118 IT_update_end (struct frame *foo)
1122 /* Copy LEN glyphs displayed on a single line whose vertical position
1123 is YPOS, beginning at horizontal position XFROM to horizontal
1124 position XTO, by moving blocks in the video memory. Used by
1125 functions that insert and delete glyphs. */
1126 static void
1127 IT_copy_glyphs (int xfrom, int xto, size_t len, int ypos)
1129 /* The offsets of source and destination relative to the
1130 conventional memorty selector. */
1131 int from = 2 * (xfrom + screen_size_X * ypos) + ScreenPrimary;
1132 int to = 2 * (xto + screen_size_X * ypos) + ScreenPrimary;
1134 if (from == to || len <= 0)
1135 return;
1137 _farsetsel (_dos_ds);
1139 /* The source and destination might overlap, so we need to move
1140 glyphs non-destructively. */
1141 if (from > to)
1143 for ( ; len; from += 2, to += 2, len--)
1144 _farnspokew (to, _farnspeekw (from));
1146 else
1148 from += (len - 1) * 2;
1149 to += (len - 1) * 2;
1150 for ( ; len; from -= 2, to -= 2, len--)
1151 _farnspokew (to, _farnspeekw (from));
1153 if (screen_virtual_segment)
1154 dosv_refresh_virtual_screen (ypos * screen_size_X * 2, screen_size_X);
1157 /* Insert and delete glyphs. */
1158 static void
1159 IT_insert_glyphs (start, len)
1160 register struct glyph *start;
1161 register int len;
1163 int shift_by_width = screen_size_X - (new_pos_X + len);
1165 /* Shift right the glyphs from the nominal cursor position to the
1166 end of this line. */
1167 IT_copy_glyphs (new_pos_X, new_pos_X + len, shift_by_width, new_pos_Y);
1169 /* Now write the glyphs to be inserted. */
1170 IT_write_glyphs (start, len);
1173 static void
1174 IT_delete_glyphs (n)
1175 register int n;
1177 abort ();
1180 /* set-window-configuration on window.c needs this. */
1181 void
1182 x_set_menu_bar_lines (f, value, oldval)
1183 struct frame *f;
1184 Lisp_Object value, oldval;
1186 set_menu_bar_lines (f, value, oldval);
1189 /* This was copied from xfns.c */
1191 Lisp_Object Qbackground_color;
1192 Lisp_Object Qforeground_color;
1193 extern Lisp_Object Qtitle;
1195 /* IT_set_terminal_modes is called when emacs is started,
1196 resumed, and whenever the screen is redrawn! */
1198 static void
1199 IT_set_terminal_modes (void)
1201 if (termscript)
1202 fprintf (termscript, "\n<SET_TERM>");
1203 highlight = 0;
1205 screen_size_X = ScreenCols ();
1206 screen_size_Y = ScreenRows ();
1207 screen_size = screen_size_X * screen_size_Y;
1209 new_pos_X = new_pos_Y = 0;
1210 current_pos_X = current_pos_Y = -1;
1212 if (term_setup_done)
1213 return;
1214 term_setup_done = 1;
1216 startup_screen_size_X = screen_size_X;
1217 startup_screen_size_Y = screen_size_Y;
1218 startup_screen_attrib = ScreenAttrib;
1220 #if __DJGPP__ > 1
1221 /* Is DOS/V (or any other RSIS software which relocates
1222 the screen) installed? */
1224 unsigned short es_value;
1225 __dpmi_regs regs;
1227 regs.h.ah = 0xfe; /* get relocated screen address */
1228 if (ScreenPrimary == 0xb0000UL || ScreenPrimary == 0xb8000UL)
1229 regs.x.es = (ScreenPrimary >> 4) & 0xffff;
1230 else if (screen_old_address) /* already switched to Japanese mode once */
1231 regs.x.es = (screen_old_address >> 4) & 0xffff;
1232 else
1233 regs.x.es = ScreenMode () == 7 ? 0xb000 : 0xb800;
1234 regs.x.di = 0;
1235 es_value = regs.x.es;
1236 __dpmi_int (0x10, &regs);
1238 if (regs.x.es != es_value)
1240 /* screen_old_address is only set if ScreenPrimary does NOT
1241 already point to the relocated buffer address returned by
1242 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1243 ScreenPrimary to that address at startup under DOS/V. */
1244 if (regs.x.es != (ScreenPrimary >> 4) & 0xffff)
1245 screen_old_address = ScreenPrimary;
1246 screen_virtual_segment = regs.x.es;
1247 screen_virtual_offset = regs.x.di;
1248 ScreenPrimary = (screen_virtual_segment << 4) + screen_virtual_offset;
1251 #endif /* __DJGPP__ > 1 */
1253 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
1254 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
1256 if (termscript)
1257 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1258 screen_size_X, screen_size_Y);
1260 bright_bg ();
1263 /* IT_reset_terminal_modes is called when emacs is
1264 suspended or killed. */
1266 static void
1267 IT_reset_terminal_modes (void)
1269 int display_row_start = (int) ScreenPrimary;
1270 int saved_row_len = startup_screen_size_X * 2;
1271 int update_row_len = ScreenCols () * 2;
1272 int current_rows = ScreenRows ();
1273 int to_next_row = update_row_len;
1274 unsigned char *saved_row = startup_screen_buffer;
1275 int cursor_pos_X = ScreenCols () - 1;
1276 int cursor_pos_Y = ScreenRows () - 1;
1278 if (termscript)
1279 fprintf (termscript, "\n<RESET_TERM>");
1281 highlight = 0;
1283 if (!term_setup_done)
1284 return;
1286 mouse_off ();
1288 /* Leave the video system in the same state as we found it,
1289 as far as the blink/bright-background bit is concerned. */
1290 maybe_enable_blinking ();
1292 /* We have a situation here.
1293 We cannot just do ScreenUpdate(startup_screen_buffer) because
1294 the luser could have changed screen dimensions inside Emacs
1295 and failed (or didn't want) to restore them before killing
1296 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1297 thus will happily use memory outside what was allocated for
1298 `startup_screen_buffer'.
1299 Thus we only restore as much as the current screen dimensions
1300 can hold, and clear the rest (if the saved screen is smaller than
1301 the current) with the color attribute saved at startup. The cursor
1302 is also restored within the visible dimensions. */
1304 ScreenAttrib = startup_screen_attrib;
1306 /* Don't restore the screen if we are exiting less than 2 seconds
1307 after startup: we might be crashing, and the screen might show
1308 some vital clues to what's wrong. */
1309 if (clock () - startup_time >= 2*CLOCKS_PER_SEC)
1311 ScreenClear ();
1312 if (screen_virtual_segment)
1313 dosv_refresh_virtual_screen (0, screen_size);
1315 if (update_row_len > saved_row_len)
1316 update_row_len = saved_row_len;
1317 if (current_rows > startup_screen_size_Y)
1318 current_rows = startup_screen_size_Y;
1320 if (termscript)
1321 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1322 update_row_len / 2, current_rows);
1324 while (current_rows--)
1326 dosmemput (saved_row, update_row_len, display_row_start);
1327 if (screen_virtual_segment)
1328 dosv_refresh_virtual_screen (display_row_start - ScreenPrimary,
1329 update_row_len / 2);
1330 saved_row += saved_row_len;
1331 display_row_start += to_next_row;
1334 if (startup_pos_X < cursor_pos_X)
1335 cursor_pos_X = startup_pos_X;
1336 if (startup_pos_Y < cursor_pos_Y)
1337 cursor_pos_Y = startup_pos_Y;
1339 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
1340 xfree (startup_screen_buffer);
1342 term_setup_done = 0;
1345 static void
1346 IT_set_terminal_window (int foo)
1350 /* Remember the screen colors of the curent frame, to serve as the
1351 default colors for newly-created frames. */
1353 static int initial_screen_colors[2];
1355 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors,
1356 Smsdos_remember_default_colors, 1, 1, 0,
1357 "Remember the screen colors of the current frame.")
1358 (frame)
1359 Lisp_Object frame;
1361 int reverse;
1362 struct frame *f;
1364 CHECK_FRAME (frame, 0);
1365 f= XFRAME (frame);
1366 reverse = EQ (Fcdr (Fassq (intern ("reverse"), f->param_alist)), Qt);
1368 initial_screen_colors[0]
1369 = reverse ? FRAME_BACKGROUND_PIXEL (f) : FRAME_FOREGROUND_PIXEL (f);
1370 initial_screen_colors[1]
1371 = reverse ? FRAME_FOREGROUND_PIXEL (f) : FRAME_BACKGROUND_PIXEL (f);
1374 void
1375 IT_set_frame_parameters (f, alist)
1376 struct frame *f;
1377 Lisp_Object alist;
1379 Lisp_Object tail;
1380 int length = XINT (Flength (alist));
1381 int i, j;
1382 Lisp_Object *parms
1383 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1384 Lisp_Object *values
1385 = (Lisp_Object *) alloca (length * sizeof (Lisp_Object));
1386 Lisp_Object qreverse = intern ("reverse");
1387 /* Do we have to reverse the foreground and background colors? */
1388 int reverse = EQ (Fcdr (Fassq (qreverse, f->param_alist)), Qt);
1389 int was_reverse = reverse;
1390 int redraw = 0, fg_set = 0, bg_set = 0;
1391 unsigned long orig_fg;
1392 unsigned long orig_bg;
1394 /* If we are creating a new frame, begin with the original screen colors
1395 used for the initial frame. */
1396 if (alist == Vdefault_frame_alist
1397 && initial_screen_colors[0] != -1 && initial_screen_colors[1] != -1)
1399 FRAME_FOREGROUND_PIXEL (f) = initial_screen_colors[0];
1400 FRAME_BACKGROUND_PIXEL (f) = initial_screen_colors[1];
1402 orig_fg = FRAME_FOREGROUND_PIXEL (f);
1403 orig_bg = FRAME_BACKGROUND_PIXEL (f);
1405 /* Extract parm names and values into those vectors. */
1406 i = 0;
1407 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
1409 Lisp_Object elt;
1411 elt = Fcar (tail);
1412 parms[i] = Fcar (elt);
1413 CHECK_SYMBOL (parms[i], 1);
1414 values[i] = Fcdr (elt);
1415 i++;
1418 j = i;
1420 for (i = 0; i < j; i++)
1422 Lisp_Object prop = parms[i];
1423 Lisp_Object val = values[i];
1425 if (EQ (prop, qreverse))
1426 reverse = EQ (val, Qt);
1429 if (termscript && reverse && !was_reverse)
1430 fprintf (termscript, "<INVERSE-VIDEO>\n");
1432 /* Now process the alist elements in reverse of specified order. */
1433 for (i--; i >= 0; i--)
1435 Lisp_Object prop = parms[i];
1436 Lisp_Object val = values[i];
1438 if (EQ (prop, Qforeground_color))
1440 unsigned long new_color = load_color (f, NULL, val, reverse
1441 ? LFACE_BACKGROUND_INDEX
1442 : LFACE_FOREGROUND_INDEX);
1443 if (new_color != ~0)
1445 if (reverse)
1446 /* FIXME: should the fore-/background of the default
1447 face change here as well? */
1448 FRAME_BACKGROUND_PIXEL (f) = new_color;
1449 else
1450 FRAME_FOREGROUND_PIXEL (f) = new_color;
1451 redraw = 1;
1452 fg_set = 1;
1453 if (termscript)
1454 fprintf (termscript, "<FGCOLOR %lu>\n", new_color);
1457 else if (EQ (prop, Qbackground_color))
1459 unsigned long new_color = load_color (f, NULL, val, reverse
1460 ? LFACE_FOREGROUND_INDEX
1461 : LFACE_BACKGROUND_INDEX);
1462 if (new_color != ~0)
1464 if (reverse)
1465 FRAME_FOREGROUND_PIXEL (f) = new_color;
1466 else
1467 FRAME_BACKGROUND_PIXEL (f) = new_color;
1468 redraw = 1;
1469 bg_set = 1;
1470 if (termscript)
1471 fprintf (termscript, "<BGCOLOR %lu>\n", new_color);
1474 else if (EQ (prop, Qtitle))
1476 x_set_title (f, val);
1477 if (termscript)
1478 fprintf (termscript, "<TITLE: %s>\n", XSTRING (val)->data);
1480 store_frame_param (f, prop, val);
1483 /* If they specified "reverse", but not the colors, we need to swap
1484 the current frame colors. */
1485 if (reverse && !was_reverse)
1487 if (!fg_set)
1489 FRAME_BACKGROUND_PIXEL (f) = orig_fg;
1490 redraw = 1;
1492 if (!bg_set)
1494 FRAME_FOREGROUND_PIXEL (f) = orig_bg;
1495 redraw = 1;
1499 if (redraw)
1501 face_change_count++; /* forces xdisp.c to recompute basic faces */
1502 if (f == SELECTED_FRAME())
1503 redraw_frame (f);
1507 extern void init_frame_faces (FRAME_PTR);
1509 #endif /* !HAVE_X_WINDOWS */
1512 /* Do we need the internal terminal? */
1514 void
1515 internal_terminal_init ()
1517 char *term = getenv ("TERM");
1518 char *colors;
1519 struct frame *sf = SELECTED_FRAME();
1521 #ifdef HAVE_X_WINDOWS
1522 if (!inhibit_window_system)
1523 return;
1524 #endif
1526 internal_terminal
1527 = (!noninteractive) && term && !strcmp (term, "internal");
1529 if (getenv ("EMACSTEST"))
1530 termscript = fopen (getenv ("EMACSTEST"), "wt");
1532 #ifndef HAVE_X_WINDOWS
1533 if (!internal_terminal || inhibit_window_system)
1535 sf->output_method = output_termcap;
1536 return;
1539 Vwindow_system = intern ("pc");
1540 Vwindow_system_version = make_number (1);
1541 sf->output_method = output_msdos_raw;
1543 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1544 screen_old_address = 0;
1546 /* Forget the stale screen colors as well. */
1547 initial_screen_colors[0] = initial_screen_colors[1] = -1;
1549 bzero (&the_only_x_display, sizeof the_only_x_display);
1550 the_only_x_display.background_pixel = 7; /* White */
1551 the_only_x_display.foreground_pixel = 0; /* Black */
1552 bright_bg ();
1553 colors = getenv ("EMACSCOLORS");
1554 if (colors && strlen (colors) >= 2)
1556 /* The colors use 4 bits each (we enable bright background). */
1557 if (isdigit (colors[0]))
1558 colors[0] -= '0';
1559 else if (isxdigit (colors[0]))
1560 colors[0] -= (isupper (colors[0]) ? 'A' : 'a') - 10;
1561 if (colors[0] >= 0 && colors[0] < 16)
1562 the_only_x_display.foreground_pixel = colors[0];
1563 if (isdigit (colors[1]))
1564 colors[1] -= '0';
1565 else if (isxdigit (colors[1]))
1566 colors[1] -= (isupper (colors[1]) ? 'A' : 'a') - 10;
1567 if (colors[1] >= 0 && colors[1] < 16)
1568 the_only_x_display.background_pixel = colors[1];
1570 the_only_x_display.line_height = 1;
1571 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
1573 init_frame_faces (sf);
1575 ring_bell_hook = IT_ring_bell;
1576 insert_glyphs_hook = IT_insert_glyphs;
1577 delete_glyphs_hook = IT_delete_glyphs;
1578 write_glyphs_hook = IT_write_glyphs;
1579 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
1580 clear_to_end_hook = IT_clear_to_end;
1581 clear_end_of_line_hook = IT_clear_end_of_line;
1582 clear_frame_hook = IT_clear_screen;
1583 change_line_highlight_hook = IT_change_line_highlight;
1584 update_begin_hook = IT_update_begin;
1585 update_end_hook = IT_update_end;
1586 reassert_line_highlight_hook = IT_reassert_line_highlight;
1587 frame_up_to_date_hook = IT_cmgoto; /* position cursor when update is done */
1589 /* These hooks are called by term.c without being checked. */
1590 set_terminal_modes_hook = IT_set_terminal_modes;
1591 reset_terminal_modes_hook = IT_reset_terminal_modes;
1592 set_terminal_window_hook = IT_set_terminal_window;
1593 char_ins_del_ok = 0;
1594 #endif
1597 dos_get_saved_screen (screen, rows, cols)
1598 char **screen;
1599 int *rows;
1600 int *cols;
1602 #ifndef HAVE_X_WINDOWS
1603 *screen = startup_screen_buffer;
1604 *cols = startup_screen_size_X;
1605 *rows = startup_screen_size_Y;
1606 return *screen != (char *)0;
1607 #else
1608 return 0;
1609 #endif
1612 #ifndef HAVE_X_WINDOWS
1614 /* We are not X, but we can emulate it well enough for our needs... */
1615 void
1616 check_x (void)
1618 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
1619 error ("Not running under a window system");
1622 #endif
1625 /* ----------------------- Keyboard control ----------------------
1627 * Keymaps reflect the following keyboard layout:
1629 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1630 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1631 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1632 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1633 * SPACE
1636 #define Ignore 0x0000
1637 #define Normal 0x0000 /* normal key - alt changes scan-code */
1638 #define FctKey 0x1000 /* func key if c == 0, else c */
1639 #define Special 0x2000 /* func key even if c != 0 */
1640 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1641 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1642 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1643 #define Grey 0x6000 /* Grey keypad key */
1645 #define Alt 0x0100 /* alt scan-code */
1646 #define Ctrl 0x0200 /* ctrl scan-code */
1647 #define Shift 0x0400 /* shift scan-code */
1649 static int extended_kbd; /* 101 (102) keyboard present. */
1651 struct kbd_translate {
1652 unsigned char sc;
1653 unsigned char ch;
1654 unsigned short code;
1657 struct dos_keyboard_map
1659 char *unshifted;
1660 char *shifted;
1661 char *alt_gr;
1662 struct kbd_translate *translate_table;
1666 static struct dos_keyboard_map us_keyboard = {
1667 /* 0 1 2 3 4 5 */
1668 /* 01234567890123456789012345678901234567890 12345678901234 */
1669 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1670 /* 0123456789012345678901234567890123456789 012345678901234 */
1671 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1672 0, /* no Alt-Gr key */
1673 0 /* no translate table */
1676 static struct dos_keyboard_map fr_keyboard = {
1677 /* 0 1 2 3 4 5 */
1678 /* 012 3456789012345678901234567890123456789012345678901234 */
1679 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1680 /* 0123456789012345678901234567890123456789012345678901234 */
1681 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1682 /* 01234567 89012345678901234567890123456789012345678901234 */
1683 " ~#{[|`\\^@]} Ï ",
1684 0 /* no translate table */
1688 * Italian keyboard support, country code 39.
1689 * '<' 56:3c*0000
1690 * '>' 56:3e*0000
1691 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1692 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1695 static struct kbd_translate it_kbd_translate_table[] = {
1696 { 0x56, 0x3c, Normal | 13 },
1697 { 0x56, 0x3e, Normal | 27 },
1698 { 0, 0, 0 }
1700 static struct dos_keyboard_map it_keyboard = {
1701 /* 0 1 2 3 4 5 */
1702 /* 0 123456789012345678901234567890123456789012345678901234 */
1703 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
1704 /* 01 23456789012345678901234567890123456789012345678901234 */
1705 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
1706 /* 0123456789012345678901234567890123456789012345678901234 */
1707 " {}~` [] @# ",
1708 it_kbd_translate_table
1711 static struct dos_keyboard_map dk_keyboard = {
1712 /* 0 1 2 3 4 5 */
1713 /* 0123456789012345678901234567890123456789012345678901234 */
1714 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
1715 /* 01 23456789012345678901234567890123456789012345678901234 */
1716 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
1717 /* 0123456789012345678901234567890123456789012345678901234 */
1718 " @œ$ {[]} | ",
1719 0 /* no translate table */
1722 static struct kbd_translate jp_kbd_translate_table[] = {
1723 { 0x73, 0x5c, Normal | 0 },
1724 { 0x73, 0x5f, Normal | 0 },
1725 { 0x73, 0x1c, Map | 0 },
1726 { 0x7d, 0x5c, Normal | 13 },
1727 { 0x7d, 0x7c, Normal | 13 },
1728 { 0x7d, 0x1c, Map | 13 },
1729 { 0, 0, 0 }
1731 static struct dos_keyboard_map jp_keyboard = {
1732 /* 0 1 2 3 4 5 */
1733 /* 0123456789012 345678901234567890123456789012345678901234 */
1734 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
1735 /* 01 23456789012345678901234567890123456789012345678901234 */
1736 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
1737 0, /* no Alt-Gr key */
1738 jp_kbd_translate_table
1741 static struct keyboard_layout_list
1743 int country_code;
1744 struct dos_keyboard_map *keyboard_map;
1745 } keyboard_layout_list[] =
1747 1, &us_keyboard,
1748 33, &fr_keyboard,
1749 39, &it_keyboard,
1750 45, &dk_keyboard,
1751 81, &jp_keyboard
1754 static struct dos_keyboard_map *keyboard;
1755 static int keyboard_map_all;
1756 static int international_keyboard;
1759 dos_set_keyboard (code, always)
1760 int code;
1761 int always;
1763 int i;
1764 _go32_dpmi_registers regs;
1766 /* See if Keyb.Com is installed (for international keyboard support).
1767 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
1768 of Windows 9X! So don't do that! */
1769 regs.x.ax = 0xad80;
1770 regs.x.ss = regs.x.sp = regs.x.flags = 0;
1771 _go32_dpmi_simulate_int (0x2f, &regs);
1772 if (regs.h.al == 0xff)
1773 international_keyboard = 1;
1775 /* Initialize to US settings, for countries that don't have their own. */
1776 keyboard = keyboard_layout_list[0].keyboard_map;
1777 keyboard_map_all = always;
1778 dos_keyboard_layout = 1;
1780 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
1781 if (code == keyboard_layout_list[i].country_code)
1783 keyboard = keyboard_layout_list[i].keyboard_map;
1784 keyboard_map_all = always;
1785 dos_keyboard_layout = code;
1786 return 1;
1788 return 0;
1791 static struct
1793 unsigned char char_code; /* normal code */
1794 unsigned char meta_code; /* M- code */
1795 unsigned char keypad_code; /* keypad code */
1796 unsigned char editkey_code; /* edit key */
1797 } keypad_translate_map[] = {
1798 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1799 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1800 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1801 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1802 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1803 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1804 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1805 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1806 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1807 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1808 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1811 static struct
1813 unsigned char char_code; /* normal code */
1814 unsigned char keypad_code; /* keypad code */
1815 } grey_key_translate_map[] = {
1816 '/', 0xaf, /* kp-decimal */
1817 '*', 0xaa, /* kp-multiply */
1818 '-', 0xad, /* kp-subtract */
1819 '+', 0xab, /* kp-add */
1820 '\r', 0x8d /* kp-enter */
1823 static unsigned short
1824 ibmpc_translate_map[] =
1826 /* --------------- 00 to 0f --------------- */
1827 Normal | 0xff, /* Ctrl Break + Alt-NNN */
1828 Alt | ModFct | 0x1b, /* Escape */
1829 Normal | 1, /* '1' */
1830 Normal | 2, /* '2' */
1831 Normal | 3, /* '3' */
1832 Normal | 4, /* '4' */
1833 Normal | 5, /* '5' */
1834 Normal | 6, /* '6' */
1835 Normal | 7, /* '7' */
1836 Normal | 8, /* '8' */
1837 Normal | 9, /* '9' */
1838 Normal | 10, /* '0' */
1839 Normal | 11, /* '-' */
1840 Normal | 12, /* '=' */
1841 Special | 0x08, /* Backspace */
1842 ModFct | 0x74, /* Tab/Backtab */
1844 /* --------------- 10 to 1f --------------- */
1845 Map | 15, /* 'q' */
1846 Map | 16, /* 'w' */
1847 Map | 17, /* 'e' */
1848 Map | 18, /* 'r' */
1849 Map | 19, /* 't' */
1850 Map | 20, /* 'y' */
1851 Map | 21, /* 'u' */
1852 Map | 22, /* 'i' */
1853 Map | 23, /* 'o' */
1854 Map | 24, /* 'p' */
1855 Map | 25, /* '[' */
1856 Map | 26, /* ']' */
1857 ModFct | 0x0d, /* Return */
1858 Ignore, /* Ctrl */
1859 Map | 30, /* 'a' */
1860 Map | 31, /* 's' */
1862 /* --------------- 20 to 2f --------------- */
1863 Map | 32, /* 'd' */
1864 Map | 33, /* 'f' */
1865 Map | 34, /* 'g' */
1866 Map | 35, /* 'h' */
1867 Map | 36, /* 'j' */
1868 Map | 37, /* 'k' */
1869 Map | 38, /* 'l' */
1870 Map | 39, /* ';' */
1871 Map | 40, /* '\'' */
1872 Map | 0, /* '`' */
1873 Ignore, /* Left shift */
1874 Map | 41, /* '\\' */
1875 Map | 45, /* 'z' */
1876 Map | 46, /* 'x' */
1877 Map | 47, /* 'c' */
1878 Map | 48, /* 'v' */
1880 /* --------------- 30 to 3f --------------- */
1881 Map | 49, /* 'b' */
1882 Map | 50, /* 'n' */
1883 Map | 51, /* 'm' */
1884 Map | 52, /* ',' */
1885 Map | 53, /* '.' */
1886 Map | 54, /* '/' */
1887 Ignore, /* Right shift */
1888 Grey | 1, /* Grey * */
1889 Ignore, /* Alt */
1890 Normal | 55, /* ' ' */
1891 Ignore, /* Caps Lock */
1892 FctKey | 0xbe, /* F1 */
1893 FctKey | 0xbf, /* F2 */
1894 FctKey | 0xc0, /* F3 */
1895 FctKey | 0xc1, /* F4 */
1896 FctKey | 0xc2, /* F5 */
1898 /* --------------- 40 to 4f --------------- */
1899 FctKey | 0xc3, /* F6 */
1900 FctKey | 0xc4, /* F7 */
1901 FctKey | 0xc5, /* F8 */
1902 FctKey | 0xc6, /* F9 */
1903 FctKey | 0xc7, /* F10 */
1904 Ignore, /* Num Lock */
1905 Ignore, /* Scroll Lock */
1906 KeyPad | 7, /* Home */
1907 KeyPad | 8, /* Up */
1908 KeyPad | 9, /* Page Up */
1909 Grey | 2, /* Grey - */
1910 KeyPad | 4, /* Left */
1911 KeyPad | 5, /* Keypad 5 */
1912 KeyPad | 6, /* Right */
1913 Grey | 3, /* Grey + */
1914 KeyPad | 1, /* End */
1916 /* --------------- 50 to 5f --------------- */
1917 KeyPad | 2, /* Down */
1918 KeyPad | 3, /* Page Down */
1919 KeyPad | 0, /* Insert */
1920 KeyPad | 10, /* Delete */
1921 Shift | FctKey | 0xbe, /* (Shift) F1 */
1922 Shift | FctKey | 0xbf, /* (Shift) F2 */
1923 Shift | FctKey | 0xc0, /* (Shift) F3 */
1924 Shift | FctKey | 0xc1, /* (Shift) F4 */
1925 Shift | FctKey | 0xc2, /* (Shift) F5 */
1926 Shift | FctKey | 0xc3, /* (Shift) F6 */
1927 Shift | FctKey | 0xc4, /* (Shift) F7 */
1928 Shift | FctKey | 0xc5, /* (Shift) F8 */
1929 Shift | FctKey | 0xc6, /* (Shift) F9 */
1930 Shift | FctKey | 0xc7, /* (Shift) F10 */
1931 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1932 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1934 /* --------------- 60 to 6f --------------- */
1935 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1936 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1937 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1938 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1939 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1940 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1941 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1942 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1943 Alt | FctKey | 0xbe, /* (Alt) F1 */
1944 Alt | FctKey | 0xbf, /* (Alt) F2 */
1945 Alt | FctKey | 0xc0, /* (Alt) F3 */
1946 Alt | FctKey | 0xc1, /* (Alt) F4 */
1947 Alt | FctKey | 0xc2, /* (Alt) F5 */
1948 Alt | FctKey | 0xc3, /* (Alt) F6 */
1949 Alt | FctKey | 0xc4, /* (Alt) F7 */
1950 Alt | FctKey | 0xc5, /* (Alt) F8 */
1952 /* --------------- 70 to 7f --------------- */
1953 Alt | FctKey | 0xc6, /* (Alt) F9 */
1954 Alt | FctKey | 0xc7, /* (Alt) F10 */
1955 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1956 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1957 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1958 Ctrl | KeyPad | 1, /* (Ctrl) End */
1959 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1960 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1961 Alt | Map | 1, /* '1' */
1962 Alt | Map | 2, /* '2' */
1963 Alt | Map | 3, /* '3' */
1964 Alt | Map | 4, /* '4' */
1965 Alt | Map | 5, /* '5' */
1966 Alt | Map | 6, /* '6' */
1967 Alt | Map | 7, /* '7' */
1968 Alt | Map | 8, /* '8' */
1970 /* --------------- 80 to 8f --------------- */
1971 Alt | Map | 9, /* '9' */
1972 Alt | Map | 10, /* '0' */
1973 Alt | Map | 11, /* '-' */
1974 Alt | Map | 12, /* '=' */
1975 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1976 FctKey | 0xc8, /* F11 */
1977 FctKey | 0xc9, /* F12 */
1978 Shift | FctKey | 0xc8, /* (Shift) F11 */
1979 Shift | FctKey | 0xc9, /* (Shift) F12 */
1980 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1981 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1982 Alt | FctKey | 0xc8, /* (Alt) F11 */
1983 Alt | FctKey | 0xc9, /* (Alt) F12 */
1984 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1985 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1986 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1988 /* --------------- 90 to 9f --------------- */
1989 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1990 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1991 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1992 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1993 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1994 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1995 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1996 Alt | FctKey | 0x50, /* (Alt) Home */
1997 Alt | FctKey | 0x52, /* (Alt) Up */
1998 Alt | FctKey | 0x55, /* (Alt) Page Up */
1999 Ignore, /* NO KEY */
2000 Alt | FctKey | 0x51, /* (Alt) Left */
2001 Ignore, /* NO KEY */
2002 Alt | FctKey | 0x53, /* (Alt) Right */
2003 Ignore, /* NO KEY */
2004 Alt | FctKey | 0x57, /* (Alt) End */
2006 /* --------------- a0 to af --------------- */
2007 Alt | KeyPad | 2, /* (Alt) Down */
2008 Alt | KeyPad | 3, /* (Alt) Page Down */
2009 Alt | KeyPad | 0, /* (Alt) Insert */
2010 Alt | KeyPad | 10, /* (Alt) Delete */
2011 Alt | Grey | 0, /* (Alt) Grey / */
2012 Alt | FctKey | 0x09, /* (Alt) Tab */
2013 Alt | Grey | 4 /* (Alt) Keypad Enter */
2016 /* These bit-positions corresponds to values returned by BIOS */
2017 #define SHIFT_P 0x0003 /* two bits! */
2018 #define CTRL_P 0x0004
2019 #define ALT_P 0x0008
2020 #define SCRLOCK_P 0x0010
2021 #define NUMLOCK_P 0x0020
2022 #define CAPSLOCK_P 0x0040
2023 #define ALT_GR_P 0x0800
2024 #define SUPER_P 0x4000 /* pseudo */
2025 #define HYPER_P 0x8000 /* pseudo */
2027 static int
2028 dos_get_modifiers (keymask)
2029 int *keymask;
2031 union REGS regs;
2032 int mask;
2033 int modifiers = 0;
2035 /* Calculate modifier bits */
2036 regs.h.ah = extended_kbd ? 0x12 : 0x02;
2037 int86 (0x16, &regs, &regs);
2039 if (!extended_kbd)
2041 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
2042 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2044 else
2046 mask = regs.h.al & (SHIFT_P |
2047 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
2049 /* Do not break international keyboard support. */
2050 /* When Keyb.Com is loaded, the right Alt key is */
2051 /* used for accessing characters like { and } */
2052 if (regs.h.ah & 2) /* Left ALT pressed ? */
2053 mask |= ALT_P;
2055 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
2057 mask |= ALT_GR_P;
2058 if (dos_hyper_key == 1)
2060 mask |= HYPER_P;
2061 modifiers |= hyper_modifier;
2063 else if (dos_super_key == 1)
2065 mask |= SUPER_P;
2066 modifiers |= super_modifier;
2068 else if (!international_keyboard)
2070 /* If Keyb.Com is NOT installed, let Right Alt behave
2071 like the Left Alt. */
2072 mask &= ~ALT_GR_P;
2073 mask |= ALT_P;
2077 if (regs.h.ah & 1) /* Left CTRL pressed ? */
2078 mask |= CTRL_P;
2080 if (regs.h.ah & 4) /* Right CTRL pressed ? */
2082 if (dos_hyper_key == 2)
2084 mask |= HYPER_P;
2085 modifiers |= hyper_modifier;
2087 else if (dos_super_key == 2)
2089 mask |= SUPER_P;
2090 modifiers |= super_modifier;
2092 else
2093 mask |= CTRL_P;
2097 if (mask & SHIFT_P)
2098 modifiers |= shift_modifier;
2099 if (mask & CTRL_P)
2100 modifiers |= ctrl_modifier;
2101 if (mask & ALT_P)
2102 modifiers |= meta_modifier;
2104 if (keymask)
2105 *keymask = mask;
2106 return modifiers;
2109 #define NUM_RECENT_DOSKEYS (100)
2110 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
2111 int total_doskeys; /* Total number of elements stored into recent_doskeys */
2112 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
2114 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
2115 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
2116 Each input key receives two values in this vector: first the ASCII code,\n\
2117 and then the scan code.")
2120 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
2121 Lisp_Object val;
2123 if (total_doskeys < NUM_RECENT_DOSKEYS)
2124 return Fvector (total_doskeys, keys);
2125 else
2127 val = Fvector (NUM_RECENT_DOSKEYS, keys);
2128 bcopy (keys + recent_doskeys_index,
2129 XVECTOR (val)->contents,
2130 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
2131 bcopy (keys,
2132 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
2133 recent_doskeys_index * sizeof (Lisp_Object));
2134 return val;
2138 /* Get a char from keyboard. Function keys are put into the event queue. */
2140 extern void kbd_buffer_store_event (struct input_event *);
2141 static int mouse_preempted = 0; /* non-zero when XMenu gobbles mouse events */
2143 static int
2144 dos_rawgetc ()
2146 struct input_event event;
2147 union REGS regs;
2149 #ifndef HAVE_X_WINDOWS
2150 /* Maybe put the cursor where it should be. */
2151 IT_cmgoto (SELECTED_FRAME());
2152 #endif
2154 /* The following condition is equivalent to `kbhit ()', except that
2155 it uses the bios to do its job. This pleases DESQview/X. */
2156 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
2157 int86 (0x16, &regs, &regs),
2158 (regs.x.flags & 0x40) == 0)
2160 union REGS regs;
2161 register unsigned char c;
2162 int sc, code = -1, mask, kp_mode;
2163 int modifiers;
2165 regs.h.ah = extended_kbd ? 0x10 : 0x00;
2166 int86 (0x16, &regs, &regs);
2167 c = regs.h.al;
2168 sc = regs.h.ah;
2170 total_doskeys += 2;
2171 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2172 = make_number (c);
2173 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2174 recent_doskeys_index = 0;
2175 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
2176 = make_number (sc);
2177 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
2178 recent_doskeys_index = 0;
2180 modifiers = dos_get_modifiers (&mask);
2182 #ifndef HAVE_X_WINDOWS
2183 if (!NILP (Vdos_display_scancodes))
2185 char buf[11];
2186 sprintf (buf, "%02x:%02x*%04x",
2187 (unsigned) (sc&0xff), (unsigned) c, mask);
2188 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
2190 #endif
2192 if (sc == 0xe0)
2194 switch (c)
2196 case 10: /* Ctrl Grey Enter */
2197 code = Ctrl | Grey | 4;
2198 break;
2199 case 13: /* Grey Enter */
2200 code = Grey | 4;
2201 break;
2202 case '/': /* Grey / */
2203 code = Grey | 0;
2204 break;
2205 default:
2206 continue;
2208 c = 0;
2210 else
2212 /* Try the keyboard-private translation table first. */
2213 if (keyboard->translate_table)
2215 struct kbd_translate *p = keyboard->translate_table;
2217 while (p->sc)
2219 if (p->sc == sc && p->ch == c)
2221 code = p->code;
2222 break;
2224 p++;
2227 /* If the private table didn't translate it, use the general
2228 one. */
2229 if (code == -1)
2231 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
2232 continue;
2233 if ((code = ibmpc_translate_map[sc]) == Ignore)
2234 continue;
2238 if (c == 0)
2240 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2241 Emacs is ready to read a key. Therefore, if they press
2242 `Alt-x' when Emacs is busy, by the time we get to
2243 `dos_get_modifiers', they might have already released the
2244 Alt key, and Emacs gets just `x', which is BAD.
2245 However, for keys with the `Map' property set, the ASCII
2246 code returns zero iff Alt is pressed. So, when we DON'T
2247 have to support international_keyboard, we don't have to
2248 distinguish between the left and right Alt keys, and we
2249 can set the META modifier for any keys with the `Map'
2250 property if they return zero ASCII code (c = 0). */
2251 if ( (code & Alt)
2252 || ( (code & 0xf000) == Map && !international_keyboard))
2253 modifiers |= meta_modifier;
2254 if (code & Ctrl)
2255 modifiers |= ctrl_modifier;
2256 if (code & Shift)
2257 modifiers |= shift_modifier;
2260 switch (code & 0xf000)
2262 case ModFct:
2263 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
2264 return c;
2265 c = 0; /* Special */
2267 case FctKey:
2268 if (c != 0)
2269 return c;
2271 case Special:
2272 code |= 0xff00;
2273 break;
2275 case Normal:
2276 if (sc == 0)
2278 if (c == 0) /* ctrl-break */
2279 continue;
2280 return c; /* ALT-nnn */
2282 if (!keyboard_map_all)
2284 if (c != ' ')
2285 return c;
2286 code = c;
2287 break;
2290 case Map:
2291 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
2292 if (!keyboard_map_all)
2293 return c;
2295 code &= 0xff;
2296 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
2297 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
2299 if (mask & SHIFT_P)
2301 code = keyboard->shifted[code];
2302 mask -= SHIFT_P;
2303 modifiers &= ~shift_modifier;
2305 else
2306 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
2307 code = keyboard->alt_gr[code];
2308 else
2309 code = keyboard->unshifted[code];
2310 break;
2312 case KeyPad:
2313 code &= 0xff;
2314 if (c == 0xe0) /* edit key */
2315 kp_mode = 3;
2316 else
2317 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
2318 kp_mode = dos_keypad_mode & 0x03;
2319 else
2320 kp_mode = (dos_keypad_mode >> 4) & 0x03;
2322 switch (kp_mode)
2324 case 0:
2325 if (code == 10 && dos_decimal_point)
2326 return dos_decimal_point;
2327 return keypad_translate_map[code].char_code;
2329 case 1:
2330 code = 0xff00 | keypad_translate_map[code].keypad_code;
2331 break;
2333 case 2:
2334 code = keypad_translate_map[code].meta_code;
2335 modifiers = meta_modifier;
2336 break;
2338 case 3:
2339 code = 0xff00 | keypad_translate_map[code].editkey_code;
2340 break;
2342 break;
2344 case Grey:
2345 code &= 0xff;
2346 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
2347 if (dos_keypad_mode & kp_mode)
2348 code = 0xff00 | grey_key_translate_map[code].keypad_code;
2349 else
2350 code = grey_key_translate_map[code].char_code;
2351 break;
2354 make_event:
2355 if (code == 0)
2356 continue;
2358 if (code >= 0x100)
2359 event.kind = non_ascii_keystroke;
2360 else
2361 event.kind = ascii_keystroke;
2362 event.code = code;
2363 event.modifiers = modifiers;
2364 event.frame_or_window = selected_frame;
2365 event.timestamp = event_timestamp ();
2366 kbd_buffer_store_event (&event);
2369 if (have_mouse > 0 && !mouse_preempted)
2371 int but, press, x, y, ok;
2373 /* Check for mouse movement *before* buttons. */
2374 mouse_check_moved ();
2376 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
2377 for (press = 0; press < 2; press++)
2379 int button_num = but;
2381 if (press)
2382 ok = mouse_pressed (but, &x, &y);
2383 else
2384 ok = mouse_released (but, &x, &y);
2385 if (ok)
2387 /* Allow a simultaneous press/release of Mouse-1 and
2388 Mouse-2 to simulate Mouse-3 on two-button mice. */
2389 if (mouse_button_count == 2 && but < 2)
2391 int x2, y2; /* don't clobber original coordinates */
2393 /* If only one button is pressed, wait 100 msec and
2394 check again. This way, Speedy Gonzales isn't
2395 punished, while the slow get their chance. */
2396 if (press && mouse_pressed (1-but, &x2, &y2)
2397 || !press && mouse_released (1-but, &x2, &y2))
2398 button_num = 2;
2399 else
2401 delay (100);
2402 if (press && mouse_pressed (1-but, &x2, &y2)
2403 || !press && mouse_released (1-but, &x2, &y2))
2404 button_num = 2;
2408 event.kind = mouse_click;
2409 event.code = button_num;
2410 event.modifiers = dos_get_modifiers (0)
2411 | (press ? down_modifier : up_modifier);
2412 event.x = x;
2413 event.y = y;
2414 event.frame_or_window = selected_frame;
2415 event.timestamp = event_timestamp ();
2416 kbd_buffer_store_event (&event);
2421 return -1;
2424 static int prev_get_char = -1;
2426 /* Return 1 if a key is ready to be read without suspending execution. */
2428 dos_keysns ()
2430 if (prev_get_char != -1)
2431 return 1;
2432 else
2433 return ((prev_get_char = dos_rawgetc ()) != -1);
2436 /* Read a key. Return -1 if no key is ready. */
2438 dos_keyread ()
2440 if (prev_get_char != -1)
2442 int c = prev_get_char;
2443 prev_get_char = -1;
2444 return c;
2446 else
2447 return dos_rawgetc ();
2450 #ifndef HAVE_X_WINDOWS
2451 /* See xterm.c for more info. */
2452 void
2453 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
2454 FRAME_PTR f;
2455 register int pix_x, pix_y;
2456 register int *x, *y;
2457 XRectangle *bounds;
2458 int noclip;
2460 if (bounds) abort ();
2462 /* Ignore clipping. */
2464 *x = pix_x;
2465 *y = pix_y;
2468 void
2469 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
2470 FRAME_PTR f;
2471 register int x, y;
2472 register int *pix_x, *pix_y;
2474 *pix_x = x;
2475 *pix_y = y;
2478 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2479 for now.
2481 Actually, I don't know the meaning of all the parameters of the functions
2482 here -- I only know how they are called by xmenu.c. I could of course
2483 grab the nearest Xlib manual (down the hall, second-to-last door on the
2484 left), but I don't think it's worth the effort. */
2486 static XMenu *
2487 IT_menu_create ()
2489 XMenu *menu;
2491 menu = (XMenu *) xmalloc (sizeof (XMenu));
2492 menu->allocated = menu->count = menu->panecount = menu->width = 0;
2493 return menu;
2496 /* Allocate some (more) memory for MENU ensuring that there is room for one
2497 for item. */
2499 static void
2500 IT_menu_make_room (XMenu *menu)
2502 if (menu->allocated == 0)
2504 int count = menu->allocated = 10;
2505 menu->text = (char **) xmalloc (count * sizeof (char *));
2506 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
2507 menu->panenumber = (int *) xmalloc (count * sizeof (int));
2509 else if (menu->allocated == menu->count)
2511 int count = menu->allocated = menu->allocated + 10;
2512 menu->text
2513 = (char **) xrealloc (menu->text, count * sizeof (char *));
2514 menu->submenu
2515 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
2516 menu->panenumber
2517 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
2521 /* Search the given menu structure for a given pane number. */
2523 static XMenu *
2524 IT_menu_search_pane (XMenu *menu, int pane)
2526 int i;
2527 XMenu *try;
2529 for (i = 0; i < menu->count; i++)
2530 if (menu->submenu[i])
2532 if (pane == menu->panenumber[i])
2533 return menu->submenu[i];
2534 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
2535 return try;
2537 return (XMenu *) 0;
2540 /* Determine how much screen space a given menu needs. */
2542 static void
2543 IT_menu_calc_size (XMenu *menu, int *width, int *height)
2545 int i, h2, w2, maxsubwidth, maxheight;
2547 maxsubwidth = 0;
2548 maxheight = menu->count;
2549 for (i = 0; i < menu->count; i++)
2551 if (menu->submenu[i])
2553 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
2554 if (w2 > maxsubwidth) maxsubwidth = w2;
2555 if (i + h2 > maxheight) maxheight = i + h2;
2558 *width = menu->width + maxsubwidth;
2559 *height = maxheight;
2562 /* Display MENU at (X,Y) using FACES. */
2564 static void
2565 IT_menu_display (XMenu *menu, int y, int x, int *faces)
2567 int i, j, face, width;
2568 struct glyph *text, *p;
2569 char *q;
2570 int mx, my;
2571 int enabled, mousehere;
2572 int row, col;
2573 struct frame *sf = SELECTED_FRAME();
2575 width = menu->width;
2576 text = (struct glyph *) xmalloc ((width + 2) * sizeof (struct glyph));
2577 ScreenGetCursor (&row, &col);
2578 mouse_get_xy (&mx, &my);
2579 IT_update_begin (sf);
2580 for (i = 0; i < menu->count; i++)
2582 IT_cursor_to (y + i, x);
2583 enabled
2584 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
2585 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
2586 face = faces[enabled + mousehere * 2];
2587 p = text;
2588 SET_CHAR_GLYPH (*p, ' ', face, 0);
2589 p++;
2590 for (j = 0, q = menu->text[i]; *q; j++)
2592 if (*q > 26)
2594 SET_CHAR_GLYPH (*p, *q++, face, 0);
2595 p++;
2597 else /* make '^x' */
2599 SET_CHAR_GLYPH (*p, '^', face, 0);
2600 p++;
2601 j++;
2602 SET_CHAR_GLYPH (*p, *q++ + 64, face, 0);
2603 p++;
2607 for (; j < width; j++, p++)
2608 SET_CHAR_GLYPH (*p, ' ', face, 0);
2610 SET_CHAR_GLYPH (*p, menu->submenu[i] ? 16 : ' ', face, 0);
2611 p++;
2612 IT_write_glyphs (text, width + 2);
2614 IT_update_end (sf);
2615 IT_cursor_to (row, col);
2616 xfree (text);
2619 /* --------------------------- X Menu emulation ---------------------- */
2621 /* Report availability of menus. */
2624 have_menus_p ()
2626 return 1;
2629 /* Create a brand new menu structure. */
2631 XMenu *
2632 XMenuCreate (Display *foo1, Window foo2, char *foo3)
2634 return IT_menu_create ();
2637 /* Create a new pane and place it on the outer-most level. It is not
2638 clear that it should be placed out there, but I don't know what else
2639 to do. */
2642 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
2644 int len;
2645 char *p;
2647 if (!enable)
2648 abort ();
2650 IT_menu_make_room (menu);
2651 menu->submenu[menu->count] = IT_menu_create ();
2652 menu->text[menu->count] = txt;
2653 menu->panenumber[menu->count] = ++menu->panecount;
2654 menu->count++;
2656 /* Adjust length for possible control characters (which will
2657 be written as ^x). */
2658 for (len = strlen (txt), p = txt; *p; p++)
2659 if (*p < 27)
2660 len++;
2662 if (len > menu->width)
2663 menu->width = len;
2665 return menu->panecount;
2668 /* Create a new item in a menu pane. */
2671 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
2672 int foo, char *txt, int enable)
2674 int len;
2675 char *p;
2677 if (pane)
2678 if (!(menu = IT_menu_search_pane (menu, pane)))
2679 return XM_FAILURE;
2680 IT_menu_make_room (menu);
2681 menu->submenu[menu->count] = (XMenu *) 0;
2682 menu->text[menu->count] = txt;
2683 menu->panenumber[menu->count] = enable;
2684 menu->count++;
2686 /* Adjust length for possible control characters (which will
2687 be written as ^x). */
2688 for (len = strlen (txt), p = txt; *p; p++)
2689 if (*p < 27)
2690 len++;
2692 if (len > menu->width)
2693 menu->width = len;
2695 return XM_SUCCESS;
2698 /* Decide where the menu would be placed if requested at (X,Y). */
2700 void
2701 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
2702 int *ulx, int *uly, int *width, int *height)
2704 IT_menu_calc_size (menu, width, height);
2705 *ulx = x + 1;
2706 *uly = y;
2707 *width += 2;
2710 struct IT_menu_state
2712 void *screen_behind;
2713 XMenu *menu;
2714 int pane;
2715 int x, y;
2719 /* Display menu, wait for user's response, and return that response. */
2722 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
2723 int x0, int y0, unsigned ButtonMask, char **txt)
2725 struct IT_menu_state *state;
2726 int statecount;
2727 int x, y, i, b;
2728 int screensize;
2729 int faces[4];
2730 Lisp_Object selectface;
2731 int leave, result, onepane;
2732 int title_faces[4]; /* face to display the menu title */
2733 int buffers_num_deleted = 0;
2734 struct frame *sf = SELECTED_FRAME();
2736 /* Just in case we got here without a mouse present... */
2737 if (have_mouse <= 0)
2738 return XM_IA_SELECT;
2739 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2740 around the display. */
2741 if (x0 <= 0)
2742 x0 = 1;
2743 if (y0 <= 0)
2744 y0 = 1;
2746 /* We will process all the mouse events directly, so we had
2747 better prevented dos_rawgetc from stealing them from us. */
2748 mouse_preempted++;
2750 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
2751 screensize = screen_size * 2;
2752 faces[0]
2753 = lookup_derived_face (sf, intern ("msdos-menu-passive-face"),
2754 CHARSET_ASCII, DEFAULT_FACE_ID);
2755 faces[1]
2756 = lookup_derived_face (sf, intern ("msdos-menu-active-face"),
2757 CHARSET_ASCII, DEFAULT_FACE_ID);
2758 selectface = intern ("msdos-menu-select-face");
2759 faces[2] = lookup_derived_face (sf, selectface,
2760 CHARSET_ASCII, faces[0]);
2761 faces[3] = lookup_derived_face (sf, selectface,
2762 CHARSET_ASCII, faces[1]);
2764 /* Make sure the menu title is always displayed with
2765 `msdos-menu-active-face', no matter where the mouse pointer is. */
2766 for (i = 0; i < 4; i++)
2767 title_faces[i] = faces[3];
2769 statecount = 1;
2771 /* Don't let the title for the "Buffers" popup menu include a
2772 digit (which is ugly).
2774 This is a terrible kludge, but I think the "Buffers" case is
2775 the only one where the title includes a number, so it doesn't
2776 seem to be necessary to make this more general. */
2777 if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
2779 menu->text[0][7] = '\0';
2780 buffers_num_deleted = 1;
2782 state[0].menu = menu;
2783 mouse_off ();
2784 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
2786 /* Turn off the cursor. Otherwise it shows through the menu
2787 panes, which is ugly. */
2788 IT_display_cursor (0);
2790 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
2791 if (buffers_num_deleted)
2792 menu->text[0][7] = ' ';
2793 if ((onepane = menu->count == 1 && menu->submenu[0]))
2795 menu->width = menu->submenu[0]->width;
2796 state[0].menu = menu->submenu[0];
2798 else
2800 state[0].menu = menu;
2802 state[0].x = x0 - 1;
2803 state[0].y = y0;
2804 state[0].pane = onepane;
2806 mouse_last_x = -1; /* A hack that forces display. */
2807 leave = 0;
2808 while (!leave)
2810 if (!mouse_visible) mouse_on ();
2811 mouse_check_moved ();
2812 if (sf->mouse_moved)
2814 sf->mouse_moved = 0;
2815 result = XM_IA_SELECT;
2816 mouse_get_xy (&x, &y);
2817 for (i = 0; i < statecount; i++)
2818 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
2820 int dy = y - state[i].y;
2821 if (0 <= dy && dy < state[i].menu->count)
2823 if (!state[i].menu->submenu[dy])
2824 if (state[i].menu->panenumber[dy])
2825 result = XM_SUCCESS;
2826 else
2827 result = XM_IA_SELECT;
2828 *pane = state[i].pane - 1;
2829 *selidx = dy;
2830 /* We hit some part of a menu, so drop extra menus that
2831 have been opened. That does not include an open and
2832 active submenu. */
2833 if (i != statecount - 2
2834 || state[i].menu->submenu[dy] != state[i+1].menu)
2835 while (i != statecount - 1)
2837 statecount--;
2838 mouse_off ();
2839 ScreenUpdate (state[statecount].screen_behind);
2840 if (screen_virtual_segment)
2841 dosv_refresh_virtual_screen (0, screen_size);
2842 xfree (state[statecount].screen_behind);
2844 if (i == statecount - 1 && state[i].menu->submenu[dy])
2846 IT_menu_display (state[i].menu,
2847 state[i].y,
2848 state[i].x,
2849 faces);
2850 state[statecount].menu = state[i].menu->submenu[dy];
2851 state[statecount].pane = state[i].menu->panenumber[dy];
2852 mouse_off ();
2853 ScreenRetrieve (state[statecount].screen_behind
2854 = xmalloc (screensize));
2855 state[statecount].x
2856 = state[i].x + state[i].menu->width + 2;
2857 state[statecount].y = y;
2858 statecount++;
2862 IT_menu_display (state[statecount - 1].menu,
2863 state[statecount - 1].y,
2864 state[statecount - 1].x,
2865 faces);
2867 else
2868 /* We are busy-waiting for the mouse to move, so let's be nice
2869 to other Windows applications by releasing our time slice. */
2870 __dpmi_yield ();
2871 for (b = 0; b < mouse_button_count && !leave; b++)
2873 /* Only leave if user both pressed and released the mouse, and in
2874 that order. This avoids popping down the menu pane unless
2875 the user is really done with it. */
2876 if (mouse_pressed (b, &x, &y))
2878 while (mouse_button_depressed (b, &x, &y))
2879 __dpmi_yield ();
2880 leave = 1;
2882 (void) mouse_released (b, &x, &y);
2886 mouse_off ();
2887 ScreenUpdate (state[0].screen_behind);
2888 if (screen_virtual_segment)
2889 dosv_refresh_virtual_screen (0, screen_size);
2890 while (statecount--)
2891 xfree (state[statecount].screen_behind);
2892 IT_display_cursor (1); /* turn cursor back on */
2893 /* Clean up any mouse events that are waiting inside Emacs event queue.
2894 These events are likely to be generated before the menu was even
2895 displayed, probably because the user pressed and released the button
2896 (which invoked the menu) too quickly. If we don't remove these events,
2897 Emacs will process them after we return and surprise the user. */
2898 discard_mouse_events ();
2899 /* Allow mouse events generation by dos_rawgetc. */
2900 mouse_preempted--;
2901 return result;
2904 /* Dispose of a menu. */
2906 void
2907 XMenuDestroy (Display *foo, XMenu *menu)
2909 int i;
2910 if (menu->allocated)
2912 for (i = 0; i < menu->count; i++)
2913 if (menu->submenu[i])
2914 XMenuDestroy (foo, menu->submenu[i]);
2915 xfree (menu->text);
2916 xfree (menu->submenu);
2917 xfree (menu->panenumber);
2919 xfree (menu);
2923 x_pixel_width (struct frame *f)
2925 return FRAME_WIDTH (f);
2929 x_pixel_height (struct frame *f)
2931 return FRAME_HEIGHT (f);
2933 #endif /* !HAVE_X_WINDOWS */
2935 /* ----------------------- DOS / UNIX conversion --------------------- */
2937 void msdos_downcase_filename (unsigned char *);
2939 /* Destructively turn backslashes into slashes. */
2941 void
2942 dostounix_filename (p)
2943 register char *p;
2945 msdos_downcase_filename (p);
2947 while (*p)
2949 if (*p == '\\')
2950 *p = '/';
2951 p++;
2955 /* Destructively turn slashes into backslashes. */
2957 void
2958 unixtodos_filename (p)
2959 register char *p;
2961 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
2963 *p += 'a' - 'A';
2964 p += 2;
2967 while (*p)
2969 if (*p == '/')
2970 *p = '\\';
2971 p++;
2975 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2978 getdefdir (drive, dst)
2979 int drive;
2980 char *dst;
2982 char in_path[4], *p = in_path;
2983 int e = errno;
2985 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2986 if (drive != 0)
2988 *p++ = drive + 'A' - 1;
2989 *p++ = ':';
2992 *p++ = '.';
2993 *p = '\0';
2994 errno = 0;
2995 _fixpath (in_path, dst);
2996 /* _fixpath can set errno to ENOSYS on non-LFN systems because
2997 it queries the LFN support, so ignore that error. */
2998 if ((errno && errno != ENOSYS) || *dst == '\0')
2999 return 0;
3001 msdos_downcase_filename (dst);
3003 errno = e;
3004 return 1;
3007 /* Remove all CR's that are followed by a LF. */
3010 crlf_to_lf (n, buf)
3011 register int n;
3012 register unsigned char *buf;
3014 unsigned char *np = buf;
3015 unsigned char *startp = buf;
3016 unsigned char *endp = buf + n;
3018 if (n == 0)
3019 return n;
3020 while (buf < endp - 1)
3022 if (*buf == 0x0d)
3024 if (*(++buf) != 0x0a)
3025 *np++ = 0x0d;
3027 else
3028 *np++ = *buf++;
3030 if (buf < endp)
3031 *np++ = *buf++;
3032 return np - startp;
3035 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
3037 /* In DJGPP v2.0, library `write' can call `malloc', which might
3038 cause relocation of the buffer whose address we get in ADDR.
3039 Here is a version of `write' that avoids calling `malloc',
3040 to serve us until such time as the library is fixed.
3041 Actually, what we define here is called `__write', because
3042 `write' is a stub that just jmp's to `__write' (to be
3043 POSIXLY-correct with respect to the global name-space). */
3045 #include <io.h> /* for _write */
3046 #include <libc/dosio.h> /* for __file_handle_modes[] */
3048 static char xbuf[64 * 1024]; /* DOS cannot write more in one chunk */
3050 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
3053 __write (int handle, const void *buffer, size_t count)
3055 if (count == 0)
3056 return 0;
3058 if(__file_handle_modes[handle] & O_BINARY)
3059 return _write (handle, buffer, count);
3060 else
3062 char *xbp = xbuf;
3063 const char *bp = buffer;
3064 int total_written = 0;
3065 int nmoved = 0, ncr = 0;
3067 while (count)
3069 /* The next test makes sure there's space for at least 2 more
3070 characters in xbuf[], so both CR and LF can be put there. */
3071 if (xbp < XBUF_END)
3073 if (*bp == '\n')
3075 ncr++;
3076 *xbp++ = '\r';
3078 *xbp++ = *bp++;
3079 nmoved++;
3080 count--;
3082 if (xbp >= XBUF_END || !count)
3084 size_t to_write = nmoved + ncr;
3085 int written = _write (handle, xbuf, to_write);
3087 if (written == -1)
3088 return -1;
3089 else
3090 total_written += nmoved; /* CRs aren't counted in ret value */
3092 /* If some, but not all were written (disk full?), return
3093 an estimate of the total written bytes not counting CRs. */
3094 if (written < to_write)
3095 return total_written - (to_write - written) * nmoved/to_write;
3097 nmoved = 0;
3098 ncr = 0;
3099 xbp = xbuf;
3102 return total_written;
3106 /* A low-level file-renaming function which works around Windows 95 bug.
3107 This is pulled directly out of DJGPP v2.01 library sources, and only
3108 used when you compile with DJGPP v2.0. */
3110 #include <io.h>
3112 int _rename(const char *old, const char *new)
3114 __dpmi_regs r;
3115 int olen = strlen(old) + 1;
3116 int i;
3117 int use_lfn = _USE_LFN;
3118 char tempfile[FILENAME_MAX];
3119 const char *orig = old;
3120 int lfn_fd = -1;
3122 r.x.dx = __tb_offset;
3123 r.x.di = __tb_offset + olen;
3124 r.x.ds = r.x.es = __tb_segment;
3126 if (use_lfn)
3128 /* Windows 95 bug: for some filenames, when you rename
3129 file -> file~ (as in Emacs, to leave a backup), the
3130 short 8+3 alias doesn't change, which effectively
3131 makes OLD and NEW the same file. We must rename
3132 through a temporary file to work around this. */
3134 char *pbase = 0, *p;
3135 static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
3136 int idx = sizeof(try_char) - 1;
3138 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
3139 might point to another drive, which will fail the DOS call. */
3140 strcpy(tempfile, old);
3141 for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
3142 if (*p == '/' || *p == '\\' || *p == ':')
3143 pbase = p;
3144 if (pbase)
3145 pbase++;
3146 else
3147 pbase = tempfile;
3148 strcpy(pbase, "X$$djren$$.$$temp$$");
3152 if (idx <= 0)
3153 return -1;
3154 *pbase = try_char[--idx];
3155 } while (_chmod(tempfile, 0) != -1);
3157 r.x.ax = 0x7156;
3158 _put_path2(tempfile, olen);
3159 _put_path(old);
3160 __dpmi_int(0x21, &r);
3161 if (r.x.flags & 1)
3163 errno = __doserr_to_errno(r.x.ax);
3164 return -1;
3167 /* Now create a file with the original name. This will
3168 ensure that NEW will always have a 8+3 alias
3169 different from that of OLD. (Seems to be required
3170 when NameNumericTail in the Registry is set to 0.) */
3171 lfn_fd = _creat(old, 0);
3173 olen = strlen(tempfile) + 1;
3174 old = tempfile;
3175 r.x.di = __tb_offset + olen;
3178 for (i=0; i<2; i++)
3180 if(use_lfn)
3181 r.x.ax = 0x7156;
3182 else
3183 r.h.ah = 0x56;
3184 _put_path2(new, olen);
3185 _put_path(old);
3186 __dpmi_int(0x21, &r);
3187 if(r.x.flags & 1)
3189 if (r.x.ax == 5 && i == 0) /* access denied */
3190 remove(new); /* and try again */
3191 else
3193 errno = __doserr_to_errno(r.x.ax);
3195 /* Restore to original name if we renamed it to temporary. */
3196 if (use_lfn)
3198 if (lfn_fd != -1)
3200 _close (lfn_fd);
3201 remove (orig);
3203 _put_path2(orig, olen);
3204 _put_path(tempfile);
3205 r.x.ax = 0x7156;
3206 __dpmi_int(0x21, &r);
3208 return -1;
3211 else
3212 break;
3215 /* Success. Delete the file possibly created to work
3216 around the Windows 95 bug. */
3217 if (lfn_fd != -1)
3218 return (_close (lfn_fd) == 0) ? remove (orig) : -1;
3219 return 0;
3222 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
3224 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,
3225 0, 0, 0,
3226 "Return non-nil if long file names are supported on MSDOS.")
3229 return (_USE_LFN ? Qt : Qnil);
3232 /* Convert alphabetic characters in a filename to lower-case. */
3234 void
3235 msdos_downcase_filename (p)
3236 register unsigned char *p;
3238 /* Always lower-case drive letters a-z, even if the filesystem
3239 preserves case in filenames.
3240 This is so MSDOS filenames could be compared by string comparison
3241 functions that are case-sensitive. Even case-preserving filesystems
3242 do not distinguish case in drive letters. */
3243 if (p[1] == ':' && *p >= 'A' && *p <= 'Z')
3245 *p += 'a' - 'A';
3246 p += 2;
3249 /* Under LFN we expect to get pathnames in their true case. */
3250 if (NILP (Fmsdos_long_file_names ()))
3251 for ( ; *p; p++)
3252 if (*p >= 'A' && *p <= 'Z')
3253 *p += 'a' - 'A';
3256 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename, Smsdos_downcase_filename,
3257 1, 1, 0,
3258 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
3259 When long filenames are supported, doesn't change FILENAME.\n\
3260 If FILENAME is not a string, returns nil.\n\
3261 The argument object is never altered--the value is a copy.")
3262 (filename)
3263 Lisp_Object filename;
3265 Lisp_Object tem;
3267 if (! STRINGP (filename))
3268 return Qnil;
3270 tem = Fcopy_sequence (filename);
3271 msdos_downcase_filename (XSTRING (tem)->data);
3272 return tem;
3275 /* The Emacs root directory as determined by init_environment. */
3277 static char emacsroot[MAXPATHLEN];
3279 char *
3280 rootrelativepath (rel)
3281 char *rel;
3283 static char result[MAXPATHLEN + 10];
3285 strcpy (result, emacsroot);
3286 strcat (result, "/");
3287 strcat (result, rel);
3288 return result;
3291 /* Define a lot of environment variables if not already defined. Don't
3292 remove anything unless you know what you're doing -- lots of code will
3293 break if one or more of these are missing. */
3295 void
3296 init_environment (argc, argv, skip_args)
3297 int argc;
3298 char **argv;
3299 int skip_args;
3301 char *s, *t, *root;
3302 int len;
3303 static const char * const tempdirs[] = {
3304 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3306 int i;
3307 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
3309 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3310 temporary files and assume "/tmp" if $TMPDIR is unset, which
3311 will break on DOS/Windows. Refuse to work if we cannot find
3312 a directory, not even "c:/", usable for that purpose. */
3313 for (i = 0; i < imax ; i++)
3315 const char *tmp = tempdirs[i];
3317 if (*tmp == '$')
3318 tmp = getenv (tmp + 1);
3319 /* Note that `access' can lie to us if the directory resides on a
3320 read-only filesystem, like CD-ROM or a write-protected floppy.
3321 The only way to be really sure is to actually create a file and
3322 see if it succeeds. But I think that's too much to ask. */
3323 if (tmp && access (tmp, D_OK) == 0)
3325 setenv ("TMPDIR", tmp, 1);
3326 break;
3329 if (i >= imax)
3330 cmd_error_internal
3331 (Fcons (Qerror,
3332 Fcons (build_string ("no usable temporary directories found!!"),
3333 Qnil)),
3334 "While setting TMPDIR: ");
3336 /* Note the startup time, so we know not to clear the screen if we
3337 exit immediately; see IT_reset_terminal_modes.
3338 (Yes, I know `clock' returns zero the first time it's called, but
3339 I do this anyway, in case some wiseguy changes that at some point.) */
3340 startup_time = clock ();
3342 /* Find our root from argv[0]. Assuming argv[0] is, say,
3343 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3344 root = alloca (MAXPATHLEN + 20);
3345 _fixpath (argv[0], root);
3346 msdos_downcase_filename (root);
3347 len = strlen (root);
3348 while (len > 0 && root[len] != '/' && root[len] != ':')
3349 len--;
3350 root[len] = '\0';
3351 if (len > 4
3352 && (strcmp (root + len - 4, "/bin") == 0
3353 || strcmp (root + len - 4, "/src") == 0)) /* under a debugger */
3354 root[len - 4] = '\0';
3355 else
3356 strcpy (root, "c:/emacs"); /* let's be defensive */
3357 len = strlen (root);
3358 strcpy (emacsroot, root);
3360 /* We default HOME to our root. */
3361 setenv ("HOME", root, 0);
3363 /* We default EMACSPATH to root + "/bin". */
3364 strcpy (root + len, "/bin");
3365 setenv ("EMACSPATH", root, 0);
3367 /* I don't expect anybody to ever use other terminals so the internal
3368 terminal is the default. */
3369 setenv ("TERM", "internal", 0);
3371 #ifdef HAVE_X_WINDOWS
3372 /* Emacs expects DISPLAY to be set. */
3373 setenv ("DISPLAY", "unix:0.0", 0);
3374 #endif
3376 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3377 downcase it and mirror the backslashes. */
3378 s = getenv ("COMSPEC");
3379 if (!s) s = "c:/command.com";
3380 t = alloca (strlen (s) + 1);
3381 strcpy (t, s);
3382 dostounix_filename (t);
3383 setenv ("SHELL", t, 0);
3385 /* PATH is also downcased and backslashes mirrored. */
3386 s = getenv ("PATH");
3387 if (!s) s = "";
3388 t = alloca (strlen (s) + 3);
3389 /* Current directory is always considered part of MsDos's path but it is
3390 not normally mentioned. Now it is. */
3391 strcat (strcpy (t, ".;"), s);
3392 dostounix_filename (t); /* Not a single file name, but this should work. */
3393 setenv ("PATH", t, 1);
3395 /* In some sense all dos users have root privileges, so... */
3396 setenv ("USER", "root", 0);
3397 setenv ("NAME", getenv ("USER"), 0);
3399 /* Time zone determined from country code. To make this possible, the
3400 country code may not span more than one time zone. In other words,
3401 in the USA, you lose. */
3402 if (!getenv ("TZ"))
3403 switch (dos_country_code)
3405 case 31: /* Belgium */
3406 case 32: /* The Netherlands */
3407 case 33: /* France */
3408 case 34: /* Spain */
3409 case 36: /* Hungary */
3410 case 38: /* Yugoslavia (or what's left of it?) */
3411 case 39: /* Italy */
3412 case 41: /* Switzerland */
3413 case 42: /* Tjekia */
3414 case 45: /* Denmark */
3415 case 46: /* Sweden */
3416 case 47: /* Norway */
3417 case 48: /* Poland */
3418 case 49: /* Germany */
3419 /* Daylight saving from last Sunday in March to last Sunday in
3420 September, both at 2AM. */
3421 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3422 break;
3423 case 44: /* United Kingdom */
3424 case 351: /* Portugal */
3425 case 354: /* Iceland */
3426 setenv ("TZ", "GMT+00", 0);
3427 break;
3428 case 81: /* Japan */
3429 case 82: /* Korea */
3430 setenv ("TZ", "JST-09", 0);
3431 break;
3432 case 90: /* Turkey */
3433 case 358: /* Finland */
3434 setenv ("TZ", "EET-02", 0);
3435 break;
3436 case 972: /* Israel */
3437 /* This is an approximation. (For exact rules, use the
3438 `zoneinfo/israel' file which comes with DJGPP, but you need
3439 to install it in `/usr/share/zoneinfo/' directory first.) */
3440 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3441 break;
3443 tzset ();
3448 static int break_stat; /* BREAK check mode status. */
3449 static int stdin_stat; /* stdin IOCTL status. */
3451 #if __DJGPP__ < 2
3453 /* These must be global. */
3454 static _go32_dpmi_seginfo ctrl_break_vector;
3455 static _go32_dpmi_registers ctrl_break_regs;
3456 static int ctrlbreakinstalled = 0;
3458 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
3460 void
3461 ctrl_break_func (regs)
3462 _go32_dpmi_registers *regs;
3464 Vquit_flag = Qt;
3467 void
3468 install_ctrl_break_check ()
3470 if (!ctrlbreakinstalled)
3472 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
3473 was compiler with Djgpp 1.11 maintenance level 5 or later! */
3474 ctrlbreakinstalled = 1;
3475 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
3476 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
3477 &ctrl_break_regs);
3478 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
3482 #endif /* __DJGPP__ < 2 */
3484 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3485 control chars by DOS. Determine the keyboard type. */
3488 dos_ttraw ()
3490 union REGS inregs, outregs;
3491 static int first_time = 1;
3493 break_stat = getcbrk ();
3494 setcbrk (0);
3495 #if __DJGPP__ < 2
3496 install_ctrl_break_check ();
3497 #endif
3499 if (first_time)
3501 inregs.h.ah = 0xc0;
3502 int86 (0x15, &inregs, &outregs);
3503 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
3505 have_mouse = 0;
3507 if (internal_terminal
3508 #ifdef HAVE_X_WINDOWS
3509 && inhibit_window_system
3510 #endif
3513 inregs.x.ax = 0x0021;
3514 int86 (0x33, &inregs, &outregs);
3515 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3516 if (!have_mouse)
3518 /* Reportedly, the above doesn't work for some mouse drivers. There
3519 is an additional detection method that should work, but might be
3520 a little slower. Use that as an alternative. */
3521 inregs.x.ax = 0x0000;
3522 int86 (0x33, &inregs, &outregs);
3523 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
3526 if (have_mouse)
3528 have_mouse = 1; /* enable mouse */
3529 mouse_visible = 0;
3531 if (outregs.x.bx == 3)
3533 mouse_button_count = 3;
3534 mouse_button_translate[0] = 0; /* Left */
3535 mouse_button_translate[1] = 2; /* Middle */
3536 mouse_button_translate[2] = 1; /* Right */
3538 else
3540 mouse_button_count = 2;
3541 mouse_button_translate[0] = 0;
3542 mouse_button_translate[1] = 1;
3544 mouse_position_hook = &mouse_get_pos;
3545 mouse_init ();
3549 first_time = 0;
3551 #if __DJGPP__ >= 2
3553 stdin_stat = setmode (fileno (stdin), O_BINARY);
3554 return (stdin_stat != -1);
3556 else
3557 return (setmode (fileno (stdin), O_BINARY) != -1);
3559 #else /* __DJGPP__ < 2 */
3563 /* I think it is wrong to overwrite `stdin_stat' every time
3564 but the first one this function is called, but I don't
3565 want to change the way it used to work in v1.x.--EZ */
3567 inregs.x.ax = 0x4400; /* Get IOCTL status. */
3568 inregs.x.bx = 0x00; /* 0 = stdin. */
3569 intdos (&inregs, &outregs);
3570 stdin_stat = outregs.h.dl;
3572 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
3573 inregs.x.ax = 0x4401; /* Set IOCTL status */
3574 intdos (&inregs, &outregs);
3575 return !outregs.x.cflag;
3577 #endif /* __DJGPP__ < 2 */
3580 /* Restore status of standard input and Ctrl-C checking. */
3583 dos_ttcooked ()
3585 union REGS inregs, outregs;
3587 setcbrk (break_stat);
3588 mouse_off ();
3590 #if __DJGPP__ >= 2
3592 return (setmode (fileno (stdin), stdin_stat) != -1);
3594 #else /* not __DJGPP__ >= 2 */
3596 inregs.x.ax = 0x4401; /* Set IOCTL status. */
3597 inregs.x.bx = 0x00; /* 0 = stdin. */
3598 inregs.x.dx = stdin_stat;
3599 intdos (&inregs, &outregs);
3600 return !outregs.x.cflag;
3602 #endif /* not __DJGPP__ >= 2 */
3606 /* Run command as specified by ARGV in directory DIR.
3607 The command is run with input from TEMPIN, output to
3608 file TEMPOUT and stderr to TEMPERR. */
3611 run_msdos_command (argv, working_dir, tempin, tempout, temperr, envv)
3612 unsigned char **argv;
3613 const char *working_dir;
3614 int tempin, tempout, temperr;
3615 char **envv;
3617 char *saveargv1, *saveargv2, *lowcase_argv0, *pa, *pl;
3618 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3619 int msshell, result = -1;
3620 int inbak, outbak, errbak;
3621 int x, y;
3622 Lisp_Object cmd;
3624 /* Get current directory as MSDOS cwd is not per-process. */
3625 getwd (oldwd);
3627 /* If argv[0] is the shell, it might come in any lettercase.
3628 Since `Fmember' is case-sensitive, we need to downcase
3629 argv[0], even if we are on case-preserving filesystems. */
3630 lowcase_argv0 = alloca (strlen (argv[0]) + 1);
3631 for (pa = argv[0], pl = lowcase_argv0; *pa; pl++)
3633 *pl = *pa++;
3634 if (*pl >= 'A' && *pl <= 'Z')
3635 *pl += 'a' - 'A';
3637 *pl = '\0';
3639 cmd = Ffile_name_nondirectory (build_string (lowcase_argv0));
3640 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
3641 && !strcmp ("-c", argv[1]);
3642 if (msshell)
3644 saveargv1 = argv[1];
3645 saveargv2 = argv[2];
3646 argv[1] = "/c";
3647 if (argv[2])
3649 char *p = alloca (strlen (argv[2]) + 1);
3651 strcpy (argv[2] = p, saveargv2);
3652 while (*p && isspace (*p))
3653 p++;
3654 while (*p && !isspace (*p))
3655 if (*p == '/')
3656 *p++ = '\\';
3657 else
3658 p++;
3662 chdir (working_dir);
3663 inbak = dup (0);
3664 outbak = dup (1);
3665 errbak = dup (2);
3666 if (inbak < 0 || outbak < 0 || errbak < 0)
3667 goto done; /* Allocation might fail due to lack of descriptors. */
3669 if (have_mouse > 0)
3670 mouse_get_xy (&x, &y);
3672 dos_ttcooked (); /* do it here while 0 = stdin */
3674 dup2 (tempin, 0);
3675 dup2 (tempout, 1);
3676 dup2 (temperr, 2);
3678 #if __DJGPP__ > 1
3680 if (msshell && !argv[3])
3682 /* MS-DOS native shells are too restrictive. For starters, they
3683 cannot grok commands longer than 126 characters. In DJGPP v2
3684 and later, `system' is much smarter, so we'll call it instead. */
3686 const char *cmnd;
3688 /* A shell gets a single argument--its full command
3689 line--whose original was saved in `saveargv2'. */
3691 /* Don't let them pass empty command lines to `system', since
3692 with some shells it will try to invoke an interactive shell,
3693 which will hang Emacs. */
3694 for (cmnd = saveargv2; *cmnd && isspace (*cmnd); cmnd++)
3696 if (*cmnd)
3698 extern char **environ;
3699 int save_system_flags = __system_flags;
3701 /* Request the most powerful version of `system'. We need
3702 all the help we can get to avoid calling stock DOS shells. */
3703 __system_flags = (__system_redirect
3704 | __system_use_shell
3705 | __system_allow_multiple_cmds
3706 | __system_allow_long_cmds
3707 | __system_handle_null_commands
3708 | __system_emulate_chdir);
3710 environ = envv;
3711 result = system (cmnd);
3712 __system_flags = save_system_flags;
3714 else
3715 result = 0; /* emulate Unixy shell behavior with empty cmd line */
3717 else
3719 #endif /* __DJGPP__ > 1 */
3721 result = spawnve (P_WAIT, argv[0], argv, envv);
3723 dup2 (inbak, 0);
3724 dup2 (outbak, 1);
3725 dup2 (errbak, 2);
3726 emacs_close (inbak);
3727 emacs_close (outbak);
3728 emacs_close (errbak);
3730 dos_ttraw ();
3731 if (have_mouse > 0)
3733 mouse_init ();
3734 mouse_moveto (x, y);
3737 /* Some programs might change the meaning of the highest bit of the
3738 text attribute byte, so we get blinking characters instead of the
3739 bright background colors. Restore that. */
3740 bright_bg ();
3742 done:
3743 chdir (oldwd);
3744 if (msshell)
3746 argv[1] = saveargv1;
3747 argv[2] = saveargv2;
3749 return result;
3752 croak (badfunc)
3753 char *badfunc;
3755 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
3756 reset_sys_modes ();
3757 exit (1);
3760 #if __DJGPP__ < 2
3762 /* ------------------------- Compatibility functions -------------------
3763 * gethostname
3764 * gettimeofday
3767 /* Hostnames for a pc are not really funny,
3768 but they are used in change log so we emulate the best we can. */
3770 gethostname (p, size)
3771 char *p;
3772 int size;
3774 char *q = egetenv ("HOSTNAME");
3776 if (!q) q = "pc";
3777 strcpy (p, q);
3778 return 0;
3781 /* When time zones are set from Ms-Dos too many C-libraries are playing
3782 tricks with time values. We solve this by defining our own version
3783 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3784 once and after each call to `tzset' with TZ changed. That is
3785 accomplished by aliasing tzset to init_gettimeofday. */
3787 static struct tm time_rec;
3790 gettimeofday (struct timeval *tp, struct timezone *tzp)
3792 if (tp)
3794 struct time t;
3795 struct tm tm;
3797 gettime (&t);
3798 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
3800 struct date d;
3801 getdate (&d);
3802 time_rec.tm_year = d.da_year - 1900;
3803 time_rec.tm_mon = d.da_mon - 1;
3804 time_rec.tm_mday = d.da_day;
3807 time_rec.tm_hour = t.ti_hour;
3808 time_rec.tm_min = t.ti_min;
3809 time_rec.tm_sec = t.ti_sec;
3811 tm = time_rec;
3812 tm.tm_gmtoff = dos_timezone_offset;
3814 tp->tv_sec = mktime (&tm); /* may modify tm */
3815 tp->tv_usec = t.ti_hund * (1000000 / 100);
3817 /* Ignore tzp; it's obsolescent. */
3818 return 0;
3821 #endif /* __DJGPP__ < 2 */
3824 * A list of unimplemented functions that we silently ignore.
3827 #if __DJGPP__ < 2
3828 unsigned alarm (s) unsigned s; {}
3829 fork () { return 0; }
3830 int kill (x, y) int x, y; { return -1; }
3831 nice (p) int p; {}
3832 void volatile pause () {}
3833 sigsetmask (x) int x; { return 0; }
3834 sigblock (mask) int mask; { return 0; }
3835 #endif
3837 void request_sigio (void) {}
3838 setpgrp () {return 0; }
3839 setpriority (x,y,z) int x,y,z; { return 0; }
3840 void unrequest_sigio (void) {}
3842 #if __DJGPP__ > 1
3844 #ifdef POSIX_SIGNALS
3846 /* Augment DJGPP library POSIX signal functions. This is needed
3847 as of DJGPP v2.01, but might be in the library in later releases. */
3849 #include <libc/bss.h>
3851 /* A counter to know when to re-initialize the static sets. */
3852 static int sigprocmask_count = -1;
3854 /* Which signals are currently blocked (initially none). */
3855 static sigset_t current_mask;
3857 /* Which signals are pending (initially none). */
3858 static sigset_t pending_signals;
3860 /* Previous handlers to restore when the blocked signals are unblocked. */
3861 typedef void (*sighandler_t)(int);
3862 static sighandler_t prev_handlers[320];
3864 /* A signal handler which just records that a signal occured
3865 (it will be raised later, if and when the signal is unblocked). */
3866 static void
3867 sig_suspender (signo)
3868 int signo;
3870 sigaddset (&pending_signals, signo);
3874 sigprocmask (how, new_set, old_set)
3875 int how;
3876 const sigset_t *new_set;
3877 sigset_t *old_set;
3879 int signo;
3880 sigset_t new_mask;
3882 /* If called for the first time, initialize. */
3883 if (sigprocmask_count != __bss_count)
3885 sigprocmask_count = __bss_count;
3886 sigemptyset (&pending_signals);
3887 sigemptyset (&current_mask);
3888 for (signo = 0; signo < 320; signo++)
3889 prev_handlers[signo] = SIG_ERR;
3892 if (old_set)
3893 *old_set = current_mask;
3895 if (new_set == 0)
3896 return 0;
3898 if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
3900 errno = EINVAL;
3901 return -1;
3904 sigemptyset (&new_mask);
3906 /* DJGPP supports upto 320 signals. */
3907 for (signo = 0; signo < 320; signo++)
3909 if (sigismember (&current_mask, signo))
3910 sigaddset (&new_mask, signo);
3911 else if (sigismember (new_set, signo) && how != SIG_UNBLOCK)
3913 sigaddset (&new_mask, signo);
3915 /* SIGKILL is silently ignored, as on other platforms. */
3916 if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR)
3917 prev_handlers[signo] = signal (signo, sig_suspender);
3919 if (( how == SIG_UNBLOCK
3920 && sigismember (&new_mask, signo)
3921 && sigismember (new_set, signo))
3922 || (how == SIG_SETMASK
3923 && sigismember (&new_mask, signo)
3924 && !sigismember (new_set, signo)))
3926 sigdelset (&new_mask, signo);
3927 if (prev_handlers[signo] != SIG_ERR)
3929 signal (signo, prev_handlers[signo]);
3930 prev_handlers[signo] = SIG_ERR;
3932 if (sigismember (&pending_signals, signo))
3934 sigdelset (&pending_signals, signo);
3935 raise (signo);
3939 current_mask = new_mask;
3940 return 0;
3943 #else /* not POSIX_SIGNALS */
3945 sigsetmask (x) int x; { return 0; }
3946 sigblock (mask) int mask; { return 0; }
3948 #endif /* not POSIX_SIGNALS */
3949 #endif /* __DJGPP__ > 1 */
3951 #ifndef HAVE_SELECT
3952 #include "sysselect.h"
3954 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3955 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3956 ((long)(time).tv_sec < 0 \
3957 || ((time).tv_sec == 0 \
3958 && (long)(time).tv_usec <= 0))
3959 #endif
3961 /* This yields the rest of the current time slice to the task manager.
3962 It should be called by any code which knows that it has nothing
3963 useful to do except idle.
3965 I don't use __dpmi_yield here, since versions of library before 2.02
3966 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
3967 on some versions of Windows 9X. */
3969 void
3970 dos_yield_time_slice (void)
3972 _go32_dpmi_registers r;
3974 r.x.ax = 0x1680;
3975 r.x.ss = r.x.sp = r.x.flags = 0;
3976 _go32_dpmi_simulate_int (0x2f, &r);
3977 if (r.h.al == 0x80)
3978 errno = ENOSYS;
3981 /* Only event queue is checked. */
3982 /* We don't have to call timer_check here
3983 because wait_reading_process_input takes care of that. */
3985 sys_select (nfds, rfds, wfds, efds, timeout)
3986 int nfds;
3987 SELECT_TYPE *rfds, *wfds, *efds;
3988 EMACS_TIME *timeout;
3990 int check_input;
3991 struct time t;
3993 check_input = 0;
3994 if (rfds)
3996 check_input = FD_ISSET (0, rfds);
3997 FD_ZERO (rfds);
3999 if (wfds)
4000 FD_ZERO (wfds);
4001 if (efds)
4002 FD_ZERO (efds);
4004 if (nfds != 1)
4005 abort ();
4007 /* If we are looking only for the terminal, with no timeout,
4008 just read it and wait -- that's more efficient. */
4009 if (!timeout)
4011 while (!detect_input_pending ())
4013 dos_yield_time_slice ();
4016 else
4018 EMACS_TIME clnow, cllast, cldiff;
4020 gettime (&t);
4021 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
4023 while (!check_input || !detect_input_pending ())
4025 gettime (&t);
4026 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
4027 EMACS_SUB_TIME (cldiff, clnow, cllast);
4029 /* When seconds wrap around, we assume that no more than
4030 1 minute passed since last `gettime'. */
4031 if (EMACS_TIME_NEG_P (cldiff))
4032 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
4033 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
4035 /* Stop when timeout value crosses zero. */
4036 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
4037 return 0;
4038 cllast = clnow;
4039 dos_yield_time_slice ();
4043 FD_SET (0, rfds);
4044 return 1;
4046 #endif
4049 * Define overlaid functions:
4051 * chdir -> sys_chdir
4052 * tzset -> init_gettimeofday
4053 * abort -> dos_abort
4056 #ifdef chdir
4057 #undef chdir
4058 extern int chdir ();
4061 sys_chdir (path)
4062 const char* path;
4064 int len = strlen (path);
4065 char *tmp = (char *)path;
4067 if (*tmp && tmp[1] == ':')
4069 if (getdisk () != tolower (tmp[0]) - 'a')
4070 setdisk (tolower (tmp[0]) - 'a');
4071 tmp += 2; /* strip drive: KFS 1995-07-06 */
4072 len -= 2;
4075 if (len > 1 && (tmp[len - 1] == '/'))
4077 char *tmp1 = (char *) alloca (len + 1);
4078 strcpy (tmp1, tmp);
4079 tmp1[len - 1] = 0;
4080 tmp = tmp1;
4082 return chdir (tmp);
4084 #endif
4086 #ifdef tzset
4087 #undef tzset
4088 extern void tzset (void);
4090 void
4091 init_gettimeofday ()
4093 time_t ltm, gtm;
4094 struct tm *lstm;
4096 tzset ();
4097 ltm = gtm = time (NULL);
4098 ltm = mktime (lstm = localtime (&ltm));
4099 gtm = mktime (gmtime (&gtm));
4100 time_rec.tm_hour = 99; /* force gettimeofday to get date */
4101 time_rec.tm_isdst = lstm->tm_isdst;
4102 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
4104 #endif
4106 #ifdef abort
4107 #undef abort
4108 void
4109 dos_abort (file, line)
4110 char *file;
4111 int line;
4113 char buffer1[200], buffer2[400];
4114 int i, j;
4116 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
4117 for (i = j = 0; buffer1[i]; i++) {
4118 buffer2[j++] = buffer1[i];
4119 buffer2[j++] = 0x70;
4121 dosmemput (buffer2, j, (int)ScreenPrimary);
4122 ScreenSetCursor (2, 0);
4123 abort ();
4125 #else
4126 void
4127 abort ()
4129 dos_ttcooked ();
4130 ScreenSetCursor (10, 0);
4131 cputs ("\r\n\nEmacs aborted!\r\n");
4132 #if __DJGPP__ > 1
4133 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4134 if (screen_virtual_segment)
4135 dosv_refresh_virtual_screen (2 * 10 * screen_size_X, 4 * screen_size_X);
4136 /* Generate traceback, so we could tell whodunit. */
4137 signal (SIGINT, SIG_DFL);
4138 __asm__ __volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4139 #else /* __DJGPP_MINOR__ >= 2 */
4140 raise (SIGABRT);
4141 #endif /* __DJGPP_MINOR__ >= 2 */
4142 #endif
4143 exit (2);
4145 #endif
4147 /* The following variables are required so that cus-start.el won't
4148 complain about unbound variables. */
4149 #ifndef HAVE_X_WINDOWS
4150 /* Search path for bitmap files (xfns.c). */
4151 Lisp_Object Vx_bitmap_file_path;
4152 int x_stretch_cursor_p;
4153 #endif
4154 #ifndef subprocesses
4155 /* Nonzero means delete a process right away if it exits (process.c). */
4156 static int delete_exited_processes;
4157 #endif
4159 syms_of_msdos ()
4161 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
4162 staticpro (&recent_doskeys);
4163 #ifndef HAVE_X_WINDOWS
4164 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
4165 "List of directories to search for bitmap files for X.");
4166 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
4168 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
4169 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
4170 For example, if a block cursor is over a tab, it will be drawn as\n\
4171 wide as that tab on the display. (No effect on MS-DOS.)");
4172 x_stretch_cursor_p = 0;
4174 /* The following three are from xfns.c: */
4175 Qbackground_color = intern ("background-color");
4176 staticpro (&Qbackground_color);
4177 Qforeground_color = intern ("foreground-color");
4178 staticpro (&Qforeground_color);
4180 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph,
4181 "*Glyph to display instead of chars not supported by current codepage.\n\
4183 This variable is used only by MSDOS terminals.");
4184 Vdos_unsupported_char_glyph = '\177';
4185 #endif
4186 #ifndef subprocesses
4187 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
4188 "*Non-nil means delete processes immediately when they exit.\n\
4189 nil means don't delete them until `list-processes' is run.");
4190 delete_exited_processes = 0;
4191 #endif
4193 defsubr (&Srecent_doskeys);
4194 defsubr (&Smsdos_long_file_names);
4195 defsubr (&Smsdos_downcase_filename);
4196 defsubr (&Smsdos_remember_default_colors);
4199 #endif /* MSDOS */