Comment change.
[emacs.git] / src / msdos.c
blob8a52e4968ebca1c431660741472a7956752fc19c
1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* Contributed by Morten Welinder */
21 /* New display, keyboard, and mouse control by Kim F. Storm */
23 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
25 #include <config.h>
27 #ifdef MSDOS
28 #include "lisp.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <sys/param.h>
32 #include <sys/time.h>
33 #include <dos.h>
34 #include "dosfns.h"
35 #include "msdos.h"
36 #include "systime.h"
37 #include "termhooks.h"
38 #include "dispextern.h"
39 #include "termopts.h"
40 #include "frame.h"
41 #include "window.h"
42 #include <go32.h>
43 #include <pc.h>
44 #include <ctype.h>
45 /* #include <process.h> */
46 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
47 #define P_WAIT 1
50 static unsigned long
51 event_timestamp ()
53 struct time t;
54 unsigned long s;
56 gettime (&t);
57 s = t.ti_min;
58 s *= 60;
59 s += t.ti_sec;
60 s *= 1000;
61 s += t.ti_hund * 10;
63 return s;
67 /* ------------------------ Mouse control ---------------------------
69 * Coordinates are in screen positions and zero based.
70 * Mouse buttons are numbered from left to right and also zero based.
73 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
74 static int mouse_visible;
76 static int mouse_last_x;
77 static int mouse_last_y;
79 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
80 static int mouse_button_count;
82 void
83 mouse_on ()
85 union REGS regs;
87 if (have_mouse > 0 && !mouse_visible)
89 if (termscript)
90 fprintf (termscript, "<M_ON>");
91 regs.x.ax = 0x0001;
92 int86 (0x33, &regs, &regs);
93 mouse_visible = 1;
97 void
98 mouse_off ()
100 union REGS regs;
102 if (have_mouse > 0 && mouse_visible)
104 if (termscript)
105 fprintf (termscript, "<M_OFF>");
106 regs.x.ax = 0x0002;
107 int86 (0x33, &regs, &regs);
108 mouse_visible = 0;
112 void
113 mouse_moveto (x, y)
114 int x, y;
116 union REGS regs;
118 if (termscript)
119 fprintf (termscript, "<M_XY=%dx%d>", x, y);
120 regs.x.ax = 0x0004;
121 mouse_last_x = regs.x.cx = x * 8;
122 mouse_last_y = regs.x.dx = y * 8;
123 int86 (0x33, &regs, &regs);
126 static int
127 mouse_pressed (b, xp, yp)
128 int b, *xp, *yp;
130 union REGS regs;
132 if (b >= mouse_button_count)
133 return 0;
134 regs.x.ax = 0x0005;
135 regs.x.bx = mouse_button_translate[b];
136 int86 (0x33, &regs, &regs);
137 if (regs.x.bx)
138 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
139 return (regs.x.bx != 0);
142 static int
143 mouse_released (b, xp, yp)
144 int b, *xp, *yp;
146 union REGS regs;
148 if (b >= mouse_button_count)
149 return 0;
150 regs.x.ax = 0x0006;
151 regs.x.bx = mouse_button_translate[b];
152 int86 (0x33, &regs, &regs);
153 if (regs.x.bx)
154 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
155 return (regs.x.bx != 0);
158 static void
159 mouse_get_xy (int *x, int *y)
161 union REGS regs;
163 regs.x.ax = 0x0003;
164 int86 (0x33, &regs, &regs);
165 *x = regs.x.cx / 8;
166 *y = regs.x.dx / 8;
169 void
170 mouse_get_pos (f, insist, bar_window, part, x, y, time)
171 FRAME_PTR *f;
172 int insist;
173 Lisp_Object *bar_window, *x, *y;
174 enum scroll_bar_part *part;
175 unsigned long *time;
177 int ix, iy;
178 union REGS regs;
180 regs.x.ax = 0x0003;
181 int86 (0x33, &regs, &regs);
182 *f = selected_frame;
183 *bar_window = Qnil;
184 mouse_get_xy (&ix, &iy);
185 selected_frame->mouse_moved = 0;
186 *x = make_number (ix);
187 *y = make_number (iy);
188 *time = event_timestamp ();
191 static void
192 mouse_check_moved ()
194 int x, y;
196 mouse_get_xy (&x, &y);
197 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
198 mouse_last_x = x;
199 mouse_last_y = y;
202 void
203 mouse_init ()
205 union REGS regs;
207 if (termscript)
208 fprintf (termscript, "<M_INIT>");
210 regs.x.ax = 0x0021;
211 int86 (0x33, &regs, &regs);
213 regs.x.ax = 0x0007;
214 regs.x.cx = 0;
215 regs.x.dx = 8 * (ScreenCols () - 1);
216 int86 (0x33, &regs, &regs);
218 regs.x.ax = 0x0008;
219 regs.x.cx = 0;
220 regs.x.dx = 8 * (ScreenRows () - 1);
221 int86 (0x33, &regs, &regs);
223 mouse_moveto (0, 0);
224 mouse_visible = 0;
227 /* ------------------------- Screen control ----------------------
231 static int internal_terminal = 0;
233 #ifndef HAVE_X_WINDOWS
234 extern unsigned char ScreenAttrib;
235 static int screen_face;
236 static int highlight;
238 static int screen_size_X;
239 static int screen_size_Y;
240 static int screen_size;
242 static int current_pos_X;
243 static int current_pos_Y;
244 static int new_pos_X;
245 static int new_pos_Y;
247 static void *startup_screen_buffer;
248 static int startup_screen_size_X;
249 static int startup_screen_size_Y;
250 static int startup_pos_X;
251 static int startup_pos_Y;
253 static int term_setup_done;
255 /* Similar to the_only_frame. */
256 struct x_output the_only_x_display;
258 /* This is never dereferenced. */
259 Display *x_current_display;
262 #define SCREEN_SET_CURSOR() \
263 if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \
264 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
266 static
267 dos_direct_output (y, x, buf, len)
268 int y;
269 int x;
270 char *buf;
271 int len;
273 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
275 while (--len >= 0) {
276 dosmemput (buf++, 1, t);
277 t += 2;
280 #endif
282 /* Flash the screen as a substitute for BEEPs. */
284 #if (__DJGPP__ < 2)
285 static void
286 do_visible_bell (xorattr)
287 unsigned char xorattr;
289 asm volatile
290 (" movb $1,%%dl
291 visible_bell_0:
292 movl _ScreenPrimary,%%eax
293 call dosmemsetup
294 movl %%eax,%%ebx
295 movl %1,%%ecx
296 movb %0,%%al
297 incl %%ebx
298 visible_bell_1:
299 xorb %%al,%%gs:(%%ebx)
300 addl $2,%%ebx
301 decl %%ecx
302 jne visible_bell_1
303 decb %%dl
304 jne visible_bell_3
305 visible_bell_2:
306 movzwl %%ax,%%eax
307 movzwl %%ax,%%eax
308 movzwl %%ax,%%eax
309 movzwl %%ax,%%eax
310 decw %%cx
311 jne visible_bell_2
312 jmp visible_bell_0
313 visible_bell_3:"
314 : /* no output */
315 : "m" (xorattr), "g" (screen_size)
316 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
319 static void
320 ScreenVisualBell (void)
322 /* This creates an xor-mask that will swap the default fore- and
323 background colors. */
324 do_visible_bell (((the_only_x_display.foreground_pixel
325 ^ the_only_x_display.background_pixel)
326 * 0x11) & 0x7f);
328 #endif
330 #ifndef HAVE_X_WINDOWS
333 * If we write a character in the position where the mouse is,
334 * the mouse cursor may need to be refreshed.
337 static void
338 mouse_off_maybe ()
340 int x, y;
342 if (!mouse_visible)
343 return;
345 mouse_get_xy (&x, &y);
346 if (y != new_pos_Y || x < new_pos_X)
347 return;
349 mouse_off ();
352 static
353 IT_ring_bell ()
355 if (visible_bell)
357 mouse_off ();
358 ScreenVisualBell ();
360 else
362 union REGS inregs, outregs;
363 inregs.h.ah = 2;
364 inregs.h.dl = 7;
365 intdos (&inregs, &outregs);
369 static void
370 IT_set_face (int face)
372 struct face *fp;
373 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
375 if (face == 1 || (face == 0 && highlight))
376 fp = FRAME_MODE_LINE_FACE (foo);
377 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
378 fp = FRAME_DEFAULT_FACE (foo);
379 else
380 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
381 if (termscript)
382 fprintf (termscript, "<FACE:%d:%d>", FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
383 screen_face = face;
384 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
387 static
388 IT_write_glyphs (GLYPH *str, int len)
390 int newface;
391 int ch, l = len;
392 unsigned char *buf, *bp;
394 if (len == 0) return;
396 buf = bp = alloca (len * 2);
398 while (--l >= 0)
400 newface = FAST_GLYPH_FACE (*str);
401 if (newface != screen_face)
402 IT_set_face (newface);
403 ch = FAST_GLYPH_CHAR (*str);
404 *bp++ = (unsigned char)ch;
405 *bp++ = ScreenAttrib;
407 if (termscript)
408 fputc (ch, termscript);
409 str++;
412 mouse_off_maybe ();
413 dosmemput (buf, 2 * len,
414 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
415 new_pos_X += len;
418 static
419 IT_clear_end_of_line (first_unused)
421 char *spaces, *sp;
422 int i, j;
424 IT_set_face (0);
425 if (termscript)
426 fprintf (termscript, "<CLR:EOL>");
427 i = (j = screen_size_X - new_pos_X) * 2;
428 spaces = sp = alloca (i);
430 while (--j >= 0)
432 *sp++ = ' ';
433 *sp++ = ScreenAttrib;
436 mouse_off_maybe ();
437 dosmemput (spaces, i,
438 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
441 static
442 IT_clear_screen (void)
444 if (termscript)
445 fprintf (termscript, "<CLR:SCR>");
446 IT_set_face (0);
447 mouse_off ();
448 ScreenClear ();
449 new_pos_X = new_pos_Y = 0;
452 static
453 IT_clear_to_end (void)
455 if (termscript)
456 fprintf (termscript, "<CLR:EOS>");
458 while (new_pos_Y < screen_size_Y) {
459 new_pos_X = 0;
460 IT_clear_end_of_line (0);
461 new_pos_Y++;
465 static
466 IT_cursor_to (int y, int x)
468 if (termscript)
469 fprintf (termscript, "\n<XY=%dx%d>", x, y);
470 new_pos_X = x;
471 new_pos_Y = y;
474 static
475 IT_reassert_line_highlight (new, vpos)
476 int new, vpos;
478 highlight = new;
479 IT_set_face (0); /* To possibly clear the highlighting. */
482 static
483 IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
485 highlight = new_highlight;
486 IT_set_face (0); /* To possibly clear the highlighting. */
487 IT_cursor_to (vpos, 0);
488 IT_clear_end_of_line (first_unused_hpos);
491 static
492 IT_update_begin ()
494 highlight = 0;
495 IT_set_face (0); /* To possibly clear the highlighting. */
496 screen_face = -1;
499 static
500 IT_update_end ()
504 /* This was more or less copied from xterm.c */
505 static void
506 IT_set_menu_bar_lines (window, n)
507 Lisp_Object window;
508 int n;
510 struct window *w = XWINDOW (window);
512 XSETFASTINT (w->top, XFASTINT (w->top) + n);
513 XSETFASTINT (w->height, XFASTINT (w->height) - n);
515 /* Handle just the top child in a vertical split. */
516 if (!NILP (w->vchild))
517 IT_set_menu_bar_lines (w->vchild, n);
519 /* Adjust all children in a horizontal split. */
520 for (window = w->hchild; !NILP (window); window = w->next)
522 w = XWINDOW (window);
523 IT_set_menu_bar_lines (window, n);
528 * IT_set_terminal_modes is called when emacs is started,
529 * resumed, and whenever the screen is redrawn!
532 static
533 IT_set_terminal_modes (void)
535 char *colors;
536 FRAME_PTR f;
537 struct face *fp;
539 if (termscript)
540 fprintf (termscript, "\n<SET_TERM>");
541 highlight = 0;
543 screen_size_X = ScreenCols ();
544 screen_size_Y = ScreenRows ();
545 screen_size = screen_size_X * screen_size_Y;
547 new_pos_X = new_pos_Y = 0;
548 current_pos_X = current_pos_Y = -1;
550 if (term_setup_done)
551 return;
552 term_setup_done = 1;
554 startup_screen_size_X = screen_size_X;
555 startup_screen_size_Y = screen_size_Y;
557 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
558 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
560 if (termscript)
561 fprintf (termscript, "<SCREEN SAVED>\n");
565 * IT_reset_terminal_modes is called when emacs is
566 * suspended or killed.
569 static
570 IT_reset_terminal_modes (void)
572 if (termscript)
573 fprintf (termscript, "\n<RESET_TERM>");
575 highlight = 0;
577 if (!term_setup_done)
578 return;
580 ScreenUpdate (startup_screen_buffer);
581 ScreenSetCursor (startup_pos_Y, startup_pos_X);
582 xfree (startup_screen_buffer);
584 if (termscript)
585 fprintf (termscript, "<SCREEN RESTORED>\n");
587 term_setup_done = 0;
590 static
591 IT_set_terminal_window (void)
595 void
596 IT_set_frame_parameters (frame, alist)
597 FRAME_PTR frame;
598 Lisp_Object alist;
600 Lisp_Object tail;
601 int redraw;
602 extern unsigned long load_color ();
603 FRAME_PTR f = (FRAME_PTR) &the_only_frame;
605 redraw = 0;
606 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
608 Lisp_Object elt, prop, val;
610 elt = Fcar (tail);
611 prop = Fcar (elt);
612 val = Fcdr (elt);
613 CHECK_SYMBOL (prop, 1);
615 if (EQ (prop, intern ("foreground-color")))
617 unsigned long new_color = load_color (f, val);
618 if (new_color != ~0)
620 FRAME_FOREGROUND_PIXEL (f) = new_color;
621 redraw = 1;
624 else if (EQ (prop, intern ("background-color")))
626 unsigned long new_color = load_color (f, val);
627 if (new_color != ~0)
629 FRAME_BACKGROUND_PIXEL (f) = new_color & ~8;
630 redraw = 1;
633 else if (EQ (prop, intern ("menu-bar-lines")))
635 int new;
636 int old = FRAME_MENU_BAR_LINES (the_only_frame);
638 if (INTEGERP (val))
639 new = XINT (val);
640 else
641 new = 0;
642 FRAME_MENU_BAR_LINES (f) = new;
643 IT_set_menu_bar_lines (the_only_frame.root_window, new - old);
647 if (redraw)
649 recompute_basic_faces (f);
650 Fredraw_frame (Fselected_frame ());
654 #endif /* !HAVE_X_WINDOWS */
657 /* Do we need the internal terminal? */
658 void
659 internal_terminal_init ()
661 char *term = getenv ("TERM");
662 char *colors;
664 #ifdef HAVE_X_WINDOWS
665 if (!inhibit_window_system)
666 return;
667 #endif
669 internal_terminal
670 = (!noninteractive) && term && !strcmp (term, "internal");
672 if (getenv ("EMACSTEST"))
673 termscript = fopen (getenv ("EMACSTEST"), "wt");
675 #ifndef HAVE_X_WINDOWS
676 if (!internal_terminal || inhibit_window_system)
678 the_only_frame.output_method = output_termcap;
679 return;
682 Vwindow_system = intern ("pc");
683 Vwindow_system_version = make_number (1);
685 bzero (&the_only_x_display, sizeof the_only_x_display);
686 the_only_x_display.background_pixel = 7; /* White */
687 the_only_x_display.foreground_pixel = 0; /* Black */
688 colors = getenv ("EMACSCOLORS");
689 if (colors && strlen (colors) >= 2)
691 the_only_x_display.foreground_pixel = colors[0] & 0x07;
692 the_only_x_display.background_pixel = colors[1] & 0x07;
694 the_only_x_display.line_height = 1;
695 the_only_frame.output_data.x = &the_only_x_display;
696 the_only_frame.output_method = output_msdos_raw;
697 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
699 init_frame_faces ((FRAME_PTR) &the_only_frame);
701 ring_bell_hook = IT_ring_bell;
702 write_glyphs_hook = IT_write_glyphs;
703 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
704 clear_to_end_hook = IT_clear_to_end;
705 clear_end_of_line_hook = IT_clear_end_of_line;
706 clear_frame_hook = IT_clear_screen;
707 change_line_highlight_hook = IT_change_line_highlight;
708 update_begin_hook = IT_update_begin;
709 update_end_hook = IT_update_end;
710 reassert_line_highlight_hook = IT_reassert_line_highlight;
712 /* These hooks are called by term.c without being checked. */
713 set_terminal_modes_hook = IT_set_terminal_modes;
714 reset_terminal_modes_hook = IT_reset_terminal_modes;
715 set_terminal_window_hook = IT_set_terminal_window;
716 #endif
719 dos_get_saved_screen (screen, rows, cols)
720 char **screen;
721 int *rows;
722 int *cols;
724 #ifndef HAVE_X_WINDOWS
725 *screen = startup_screen_buffer;
726 *cols = startup_screen_size_X;
727 *rows = startup_screen_size_Y;
728 return 1;
729 #else
730 return 0;
731 #endif
736 /* ----------------------- Keyboard control ----------------------
738 * Keymaps reflect the following keyboard layout:
740 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
741 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
742 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
743 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
744 * SPACE
747 static int extended_kbd; /* 101 (102) keyboard present. */
749 struct dos_keyboard_map
751 char *unshifted;
752 char *shifted;
753 char *alt_gr;
757 static struct dos_keyboard_map us_keyboard = {
758 /* 0 1 2 3 4 5 */
759 /* 01234567890123456789012345678901234567890 12345678901234 */
760 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
761 /* 0123456789012345678901234567890123456789 012345678901234 */
762 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
763 0 /* no Alt-Gr key */
766 static struct dos_keyboard_map fr_keyboard = {
767 /* 0 1 2 3 4 5 */
768 /* 012 3456789012345678901234567890123456789012345678901234 */
769 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
770 /* 0123456789012345678901234567890123456789012345678901234 */
771 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
772 /* 01234567 89012345678901234567890123456789012345678901234 */
773 " ~#{[|`\\^@]} Ï "
776 static struct dos_keyboard_map dk_keyboard = {
777 /* 0 1 2 3 4 5 */
778 /* 0123456789012345678901234567890123456789012345678901234 */
779 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
780 /* 01 23456789012345678901234567890123456789012345678901234 */
781 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
782 /* 0123456789012345678901234567890123456789012345678901234 */
783 " @œ$ {[]} | "
786 static struct keyboard_layout_list
788 int country_code;
789 struct dos_keyboard_map *keyboard_map;
790 } keyboard_layout_list[] =
792 1, &us_keyboard,
793 33, &fr_keyboard,
794 45, &dk_keyboard
797 static struct dos_keyboard_map *keyboard;
798 static int keyboard_map_all;
801 dos_set_keyboard (code, always)
802 int code;
803 int always;
805 int i;
807 /* Initialize to US settings, for countries that don't have their own. */
808 keyboard = keyboard_layout_list[0].keyboard_map;
809 keyboard_map_all = always;
810 dos_keyboard_layout = 1;
812 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
813 if (code == keyboard_layout_list[i].country_code)
815 keyboard = keyboard_layout_list[i].keyboard_map;
816 keyboard_map_all = always;
817 dos_keyboard_layout = code;
818 return 1;
820 return 0;
823 #define Ignore 0x0000
824 #define Normal 0x0000 /* normal key - alt changes scan-code */
825 #define FctKey 0x1000 /* func key if c == 0, else c */
826 #define Special 0x2000 /* func key even if c != 0 */
827 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
828 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
829 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
830 #define Grey 0x6000 /* Grey keypad key */
832 #define Alt 0x0100 /* alt scan-code */
833 #define Ctrl 0x0200 /* ctrl scan-code */
834 #define Shift 0x0400 /* shift scan-code */
836 static struct
838 unsigned char char_code; /* normal code */
839 unsigned char meta_code; /* M- code */
840 unsigned char keypad_code; /* keypad code */
841 unsigned char editkey_code; /* edit key */
842 } keypad_translate_map[] = {
843 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
844 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
845 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
846 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
847 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
848 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
849 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
850 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
851 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
852 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
853 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
856 static struct
858 unsigned char char_code; /* normal code */
859 unsigned char keypad_code; /* keypad code */
860 } grey_key_translate_map[] = {
861 '/', 0xaf, /* kp-decimal */
862 '*', 0xaa, /* kp-multiply */
863 '-', 0xad, /* kp-subtract */
864 '+', 0xab, /* kp-add */
865 '\r', 0x8d /* kp-enter */
868 static unsigned short
869 ibmpc_translate_map[] =
871 /* --------------- 00 to 0f --------------- */
872 Normal | 0xff, /* Ctrl Break + Alt-NNN */
873 Alt | ModFct | 0x1b, /* Escape */
874 Normal | 1, /* '1' */
875 Normal | 2, /* '2' */
876 Normal | 3, /* '3' */
877 Normal | 4, /* '4' */
878 Normal | 5, /* '5' */
879 Normal | 6, /* '6' */
880 Normal | 7, /* '7' */
881 Normal | 8, /* '8' */
882 Normal | 9, /* '9' */
883 Normal | 10, /* '0' */
884 Normal | 11, /* '-' */
885 Normal | 12, /* '=' */
886 Special | 0x08, /* Backspace */
887 ModFct | 0x74, /* Tab/Backtab */
889 /* --------------- 10 to 1f --------------- */
890 Map | 15, /* 'q' */
891 Map | 16, /* 'w' */
892 Map | 17, /* 'e' */
893 Map | 18, /* 'r' */
894 Map | 19, /* 't' */
895 Map | 20, /* 'y' */
896 Map | 21, /* 'u' */
897 Map | 22, /* 'i' */
898 Map | 23, /* 'o' */
899 Map | 24, /* 'p' */
900 Map | 25, /* '[' */
901 Map | 26, /* ']' */
902 ModFct | 0x0d, /* Return */
903 Ignore, /* Ctrl */
904 Map | 30, /* 'a' */
905 Map | 31, /* 's' */
907 /* --------------- 20 to 2f --------------- */
908 Map | 32, /* 'd' */
909 Map | 33, /* 'f' */
910 Map | 34, /* 'g' */
911 Map | 35, /* 'h' */
912 Map | 36, /* 'j' */
913 Map | 37, /* 'k' */
914 Map | 38, /* 'l' */
915 Map | 39, /* ';' */
916 Map | 40, /* '\'' */
917 Map | 0, /* '`' */
918 Ignore, /* Left shift */
919 Map | 41, /* '\\' */
920 Map | 45, /* 'z' */
921 Map | 46, /* 'x' */
922 Map | 47, /* 'c' */
923 Map | 48, /* 'v' */
925 /* --------------- 30 to 3f --------------- */
926 Map | 49, /* 'b' */
927 Map | 50, /* 'n' */
928 Map | 51, /* 'm' */
929 Map | 52, /* ',' */
930 Map | 53, /* '.' */
931 Map | 54, /* '/' */
932 Ignore, /* Right shift */
933 Grey | 1, /* Grey * */
934 Ignore, /* Alt */
935 Normal | ' ', /* ' ' */
936 Ignore, /* Caps Lock */
937 FctKey | 0xbe, /* F1 */
938 FctKey | 0xbf, /* F2 */
939 FctKey | 0xc0, /* F3 */
940 FctKey | 0xc1, /* F4 */
941 FctKey | 0xc2, /* F5 */
943 /* --------------- 40 to 4f --------------- */
944 FctKey | 0xc3, /* F6 */
945 FctKey | 0xc4, /* F7 */
946 FctKey | 0xc5, /* F8 */
947 FctKey | 0xc6, /* F9 */
948 FctKey | 0xc7, /* F10 */
949 Ignore, /* Num Lock */
950 Ignore, /* Scroll Lock */
951 KeyPad | 7, /* Home */
952 KeyPad | 8, /* Up */
953 KeyPad | 9, /* Page Up */
954 Grey | 2, /* Grey - */
955 KeyPad | 4, /* Left */
956 KeyPad | 5, /* Keypad 5 */
957 KeyPad | 6, /* Right */
958 Grey | 3, /* Grey + */
959 KeyPad | 1, /* End */
961 /* --------------- 50 to 5f --------------- */
962 KeyPad | 2, /* Down */
963 KeyPad | 3, /* Page Down */
964 KeyPad | 0, /* Insert */
965 KeyPad | 10, /* Delete */
966 Shift | FctKey | 0xbe, /* (Shift) F1 */
967 Shift | FctKey | 0xbf, /* (Shift) F2 */
968 Shift | FctKey | 0xc0, /* (Shift) F3 */
969 Shift | FctKey | 0xc1, /* (Shift) F4 */
970 Shift | FctKey | 0xc2, /* (Shift) F5 */
971 Shift | FctKey | 0xc3, /* (Shift) F6 */
972 Shift | FctKey | 0xc4, /* (Shift) F7 */
973 Shift | FctKey | 0xc5, /* (Shift) F8 */
974 Shift | FctKey | 0xc6, /* (Shift) F9 */
975 Shift | FctKey | 0xc7, /* (Shift) F10 */
976 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
977 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
979 /* --------------- 60 to 6f --------------- */
980 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
981 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
982 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
983 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
984 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
985 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
986 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
987 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
988 Alt | FctKey | 0xbe, /* (Alt) F1 */
989 Alt | FctKey | 0xbf, /* (Alt) F2 */
990 Alt | FctKey | 0xc0, /* (Alt) F3 */
991 Alt | FctKey | 0xc1, /* (Alt) F4 */
992 Alt | FctKey | 0xc2, /* (Alt) F5 */
993 Alt | FctKey | 0xc3, /* (Alt) F6 */
994 Alt | FctKey | 0xc4, /* (Alt) F7 */
995 Alt | FctKey | 0xc5, /* (Alt) F8 */
997 /* --------------- 70 to 7f --------------- */
998 Alt | FctKey | 0xc6, /* (Alt) F9 */
999 Alt | FctKey | 0xc7, /* (Alt) F10 */
1000 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1001 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1002 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1003 Ctrl | KeyPad | 1, /* (Ctrl) End */
1004 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1005 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1006 Alt | Map | 1, /* '1' */
1007 Alt | Map | 2, /* '2' */
1008 Alt | Map | 3, /* '3' */
1009 Alt | Map | 4, /* '4' */
1010 Alt | Map | 5, /* '5' */
1011 Alt | Map | 6, /* '6' */
1012 Alt | Map | 7, /* '7' */
1013 Alt | Map | 8, /* '8' */
1015 /* --------------- 80 to 8f --------------- */
1016 Alt | Map | 9, /* '9' */
1017 Alt | Map | 10, /* '0' */
1018 Alt | Map | 11, /* '-' */
1019 Alt | Map | 12, /* '=' */
1020 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1021 FctKey | 0xc8, /* F11 */
1022 FctKey | 0xc9, /* F12 */
1023 Shift | FctKey | 0xc8, /* (Shift) F11 */
1024 Shift | FctKey | 0xc9, /* (Shift) F12 */
1025 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1026 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1027 Alt | FctKey | 0xc8, /* (Alt) F11 */
1028 Alt | FctKey | 0xc9, /* (Alt) F12 */
1029 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1030 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1031 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1033 /* --------------- 90 to 9f --------------- */
1034 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1035 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1036 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1037 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1038 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1039 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1040 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1041 Alt | FctKey | 0x50, /* (Alt) Home */
1042 Alt | FctKey | 0x52, /* (Alt) Up */
1043 Alt | FctKey | 0x55, /* (Alt) Page Up */
1044 Ignore, /* NO KEY */
1045 Alt | FctKey | 0x51, /* (Alt) Left */
1046 Ignore, /* NO KEY */
1047 Alt | FctKey | 0x53, /* (Alt) Right */
1048 Ignore, /* NO KEY */
1049 Alt | FctKey | 0x57, /* (Alt) End */
1051 /* --------------- a0 to af --------------- */
1052 Alt | KeyPad | 2, /* (Alt) Down */
1053 Alt | KeyPad | 3, /* (Alt) Page Down */
1054 Alt | KeyPad | 0, /* (Alt) Insert */
1055 Alt | KeyPad | 10, /* (Alt) Delete */
1056 Alt | Grey | 0, /* (Alt) Grey / */
1057 Alt | FctKey | 0x09, /* (Alt) Tab */
1058 Alt | Grey | 4 /* (Alt) Keypad Enter */
1061 /* These bit-positions corresponds to values returned by BIOS */
1062 #define SHIFT_P 0x0003 /* two bits! */
1063 #define CTRL_P 0x0004
1064 #define ALT_P 0x0008
1065 #define SCRLOCK_P 0x0010
1066 #define NUMLOCK_P 0x0020
1067 #define CAPSLOCK_P 0x0040
1068 #define ALT_GR_P 0x0800
1069 #define SUPER_P 0x4000 /* pseudo */
1070 #define HYPER_P 0x8000 /* pseudo */
1072 static int
1073 dos_get_modifiers (keymask)
1074 int *keymask;
1076 union REGS regs;
1077 int mask;
1078 int modifiers = 0;
1080 /* Calculate modifier bits */
1081 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1082 int86 (0x16, &regs, &regs);
1084 if (!extended_kbd)
1086 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1087 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1089 else
1091 mask = regs.h.al & (SHIFT_P |
1092 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1094 /* Do not break international keyboard support. */
1095 /* When Keyb.Com is loaded, the right Alt key is */
1096 /* used for accessing characters like { and } */
1097 if (regs.h.ah & 2) /* Left ALT pressed ? */
1098 mask |= ALT_P;
1100 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1102 mask |= ALT_GR_P;
1103 if (dos_hyper_key == 1)
1105 mask |= HYPER_P;
1106 modifiers |= hyper_modifier;
1108 else if (dos_super_key == 1)
1110 mask |= SUPER_P;
1111 modifiers |= super_modifier;
1115 if (regs.h.ah & 1) /* Left CTRL pressed
1116 mask |= CTRL_P;
1118 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1120 if (dos_hyper_key == 2)
1122 mask |= HYPER_P;
1123 modifiers |= hyper_modifier;
1125 else if (dos_super_key == 2)
1127 mask |= SUPER_P;
1128 modifiers |= super_modifier;
1130 else
1131 mask |= CTRL_P;
1135 if (mask & SHIFT_P)
1136 modifiers |= shift_modifier;
1137 if (mask & CTRL_P)
1138 modifiers |= ctrl_modifier;
1139 if (mask & ALT_P)
1140 modifiers |= meta_modifier;
1142 if (keymask)
1143 *keymask = mask;
1144 return modifiers;
1147 #define NUM_RECENT_DOSKEYS (100)
1148 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1149 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1150 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1152 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1153 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1154 Each input key receives two values in this vector: first the ASCII code,\n\
1155 and then the scan code.")
1158 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1159 Lisp_Object val;
1161 if (total_doskeys < NUM_RECENT_DOSKEYS)
1162 return Fvector (total_doskeys, keys);
1163 else
1165 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1166 bcopy (keys + recent_doskeys_index,
1167 XVECTOR (val)->contents,
1168 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1169 bcopy (keys,
1170 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1171 recent_doskeys_index * sizeof (Lisp_Object));
1172 return val;
1176 /* Get a char from keyboard. Function keys are put into the event queue. */
1177 static int
1178 dos_rawgetc ()
1180 struct input_event event;
1181 union REGS regs;
1183 #ifndef HAVE_X_WINDOWS
1184 SCREEN_SET_CURSOR ();
1185 if (!mouse_visible) mouse_on ();
1186 #endif
1188 /* The following condition is equivalent to `kbhit ()', except that
1189 it uses the bios to do its job. This pleases DESQview/X. */
1190 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1191 int86 (0x16, &regs, &regs),
1192 (regs.x.flags & 0x40) == 0)
1194 union REGS regs;
1195 register unsigned char c;
1196 int sc, code, mask, kp_mode;
1197 int modifiers;
1199 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1200 int86 (0x16, &regs, &regs);
1201 c = regs.h.al;
1202 sc = regs.h.ah;
1204 total_doskeys += 2;
1205 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1206 = make_number (c);
1207 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1208 recent_doskeys_index = 0;
1209 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1210 = make_number (sc);
1211 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1212 recent_doskeys_index = 0;
1214 modifiers = dos_get_modifiers (&mask);
1216 #ifndef HAVE_X_WINDOWS
1217 if (!NILP (Vdos_display_scancodes))
1219 char buf[10];
1220 sprintf (buf, "%02x:%02x*%04x",
1221 (unsigned) (sc&0xff), (unsigned) c, mask);
1222 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1224 #endif
1226 if (sc == 0xe0)
1228 switch (c)
1230 case 10: /* Ctrl Grey Enter */
1231 code = Ctrl | Grey | 4;
1232 break;
1233 case 13: /* Grey Enter */
1234 code = Grey | 4;
1235 break;
1236 case '/': /* Grey / */
1237 code = Grey | 0;
1238 break;
1239 default:
1240 continue;
1242 c = 0;
1244 else
1246 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1247 continue;
1248 if ((code = ibmpc_translate_map[sc]) == Ignore)
1249 continue;
1252 if (c == 0)
1254 if (code & Alt)
1255 modifiers |= meta_modifier;
1256 if (code & Ctrl)
1257 modifiers |= ctrl_modifier;
1258 if (code & Shift)
1259 modifiers |= shift_modifier;
1262 switch (code & 0xf000)
1264 case ModFct:
1265 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1266 return c;
1267 c = 0; /* Special */
1269 case FctKey:
1270 if (c != 0)
1271 return c;
1273 case Special:
1274 code |= 0xff00;
1275 break;
1277 case Normal:
1278 if (sc == 0)
1280 if (c == 0) /* ctrl-break */
1281 continue;
1282 return c; /* ALT-nnn */
1284 if (!keyboard_map_all)
1286 if (c != ' ')
1287 return c;
1288 code = c;
1289 break;
1292 case Map:
1293 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1294 if (!keyboard_map_all)
1295 return c;
1297 code &= 0xff;
1298 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1299 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1301 if (mask & SHIFT_P)
1303 code = keyboard->shifted[code];
1304 mask -= SHIFT_P;
1305 modifiers &= ~shift_modifier;
1307 else
1308 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1309 code = keyboard->alt_gr[code];
1310 else
1311 code = keyboard->unshifted[code];
1312 break;
1314 case KeyPad:
1315 code &= 0xff;
1316 if (c == 0xe0) /* edit key */
1317 kp_mode = 3;
1318 else
1319 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1320 kp_mode = dos_keypad_mode & 0x03;
1321 else
1322 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1324 switch (kp_mode)
1326 case 0:
1327 if (code == 10 && dos_decimal_point)
1328 return dos_decimal_point;
1329 return keypad_translate_map[code].char_code;
1331 case 1:
1332 code = 0xff00 | keypad_translate_map[code].keypad_code;
1333 break;
1335 case 2:
1336 code = keypad_translate_map[code].meta_code;
1337 modifiers = meta_modifier;
1338 break;
1340 case 3:
1341 code = 0xff00 | keypad_translate_map[code].editkey_code;
1342 break;
1344 break;
1346 case Grey:
1347 code &= 0xff;
1348 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1349 if (dos_keypad_mode & kp_mode)
1350 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1351 else
1352 code = grey_key_translate_map[code].char_code;
1353 break;
1356 make_event:
1357 if (code == 0)
1358 continue;
1360 if (code >= 0x100)
1361 event.kind = non_ascii_keystroke;
1362 else
1363 event.kind = ascii_keystroke;
1364 event.code = code;
1365 event.modifiers = modifiers;
1366 XSETFRAME (event.frame_or_window, selected_frame);
1367 event.timestamp = event_timestamp ();
1368 kbd_buffer_store_event (&event);
1371 if (have_mouse > 0)
1373 int but, press, x, y, ok;
1375 /* Check for mouse movement *before* buttons. */
1376 mouse_check_moved ();
1378 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1379 for (press = 0; press < 2; press++)
1381 if (press)
1382 ok = mouse_pressed (but, &x, &y);
1383 else
1384 ok = mouse_released (but, &x, &y);
1385 if (ok)
1387 event.kind = mouse_click;
1388 event.code = but;
1389 event.modifiers = dos_get_modifiers (0)
1390 | (press ? down_modifier : up_modifier);
1391 event.x = x;
1392 event.y = y;
1393 XSETFRAME (event.frame_or_window, selected_frame);
1394 event.timestamp = event_timestamp ();
1395 kbd_buffer_store_event (&event);
1400 return -1;
1403 static int prev_get_char = -1;
1405 /* Return 1 if a key is ready to be read without suspending execution. */
1406 dos_keysns ()
1408 if (prev_get_char != -1)
1409 return 1;
1410 else
1411 return ((prev_get_char = dos_rawgetc ()) != -1);
1414 /* Read a key. Return -1 if no key is ready. */
1415 dos_keyread ()
1417 if (prev_get_char != -1)
1419 int c = prev_get_char;
1420 prev_get_char = -1;
1421 return c;
1423 else
1424 return dos_rawgetc ();
1427 #ifndef HAVE_X_WINDOWS
1428 /* See xterm.c for more info. */
1429 void
1430 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1431 FRAME_PTR f;
1432 register int pix_x, pix_y;
1433 register int *x, *y;
1434 void /* XRectangle */ *bounds;
1435 int noclip;
1437 if (bounds) abort ();
1439 /* Ignore clipping. */
1441 *x = pix_x;
1442 *y = pix_y;
1445 void
1446 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1447 FRAME_PTR f;
1448 register int x, y;
1449 register int *pix_x, *pix_y;
1451 *pix_x = x;
1452 *pix_y = y;
1455 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1456 for now.
1458 Actually, I don't know the meaning of all the parameters of the functions
1459 here -- I only know how they are called by xmenu.c. I could of course
1460 grab the nearest Xlib manual (down the hall, second-to-last door on the
1461 left), but I don't think it's worth the effort. */
1463 static XMenu *
1464 IT_menu_create ()
1466 XMenu *menu;
1468 menu = (XMenu *) xmalloc (sizeof (XMenu));
1469 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1470 return menu;
1473 /* Allocate some (more) memory for MENU ensuring that there is room for one
1474 for item. */
1476 static void
1477 IT_menu_make_room (XMenu *menu)
1479 if (menu->allocated == 0)
1481 int count = menu->allocated = 10;
1482 menu->text = (char **) xmalloc (count * sizeof (char *));
1483 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1484 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1486 else if (menu->allocated == menu->count)
1488 int count = menu->allocated = menu->allocated + 10;
1489 menu->text
1490 = (char **) xrealloc (menu->text, count * sizeof (char *));
1491 menu->submenu
1492 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1493 menu->panenumber
1494 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1498 /* Search the given menu structure for a given pane number. */
1500 static XMenu *
1501 IT_menu_search_pane (XMenu *menu, int pane)
1503 int i;
1504 XMenu *try;
1506 for (i = 0; i < menu->count; i++)
1507 if (menu->submenu[i])
1509 if (pane == menu->panenumber[i])
1510 return menu->submenu[i];
1511 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1512 return try;
1514 return (XMenu *) 0;
1517 /* Determine how much screen space a given menu needs. */
1519 static void
1520 IT_menu_calc_size (XMenu *menu, int *width, int *height)
1522 int i, h2, w2, maxsubwidth, maxheight;
1524 maxsubwidth = 0;
1525 maxheight = menu->count;
1526 for (i = 0; i < menu->count; i++)
1528 if (menu->submenu[i])
1530 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1531 if (w2 > maxsubwidth) maxsubwidth = w2;
1532 if (i + h2 > maxheight) maxheight = i + h2;
1535 *width = menu->width + maxsubwidth;
1536 *height = maxheight;
1539 /* Display MENU at (X,Y) using FACES. */
1541 static void
1542 IT_menu_display (XMenu *menu, int y, int x, int *faces)
1544 int i, j, face, width;
1545 GLYPH *text, *p;
1546 char *q;
1547 int mx, my;
1548 int enabled, mousehere;
1549 int row, col;
1551 width = menu->width;
1552 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1553 ScreenGetCursor (&row, &col);
1554 mouse_get_xy (&mx, &my);
1555 IT_update_begin ();
1556 for (i = 0; i < menu->count; i++)
1558 IT_cursor_to (y + i, x);
1559 enabled
1560 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
1561 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
1562 face = faces[enabled + mousehere * 2];
1563 p = text;
1564 *p++ = FAST_MAKE_GLYPH (' ', face);
1565 for (j = 0, q = menu->text[i]; *q; j++)
1566 *p++ = FAST_MAKE_GLYPH (*q++, face);
1567 for (; j < width; j++)
1568 *p++ = FAST_MAKE_GLYPH (' ', face);
1569 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
1570 IT_write_glyphs (text, width + 2);
1572 IT_update_end ();
1573 IT_cursor_to (row, col);
1574 xfree (text);
1577 /* --------------------------- X Menu emulation ---------------------- */
1579 /* Create a brand new menu structure. */
1581 XMenu *
1582 XMenuCreate (Display *foo1, Window foo2, char *foo3)
1584 return IT_menu_create ();
1587 /* Create a new pane and place it on the outer-most level. It is not
1588 clear that it should be placed out there, but I don't know what else
1589 to do. */
1592 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
1594 int len;
1596 if (!enable)
1597 abort ();
1599 IT_menu_make_room (menu);
1600 menu->submenu[menu->count] = IT_menu_create ();
1601 menu->text[menu->count] = txt;
1602 menu->panenumber[menu->count] = ++menu->panecount;
1603 menu->count++;
1604 if ((len = strlen (txt)) > menu->width)
1605 menu->width = len;
1606 return menu->panecount;
1609 /* Create a new item in a menu pane. */
1612 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1613 int foo, char *txt, int enable)
1615 int len;
1617 if (pane)
1618 if (!(menu = IT_menu_search_pane (menu, pane)))
1619 return XM_FAILURE;
1620 IT_menu_make_room (menu);
1621 menu->submenu[menu->count] = (XMenu *) 0;
1622 menu->text[menu->count] = txt;
1623 menu->panenumber[menu->count] = enable;
1624 menu->count++;
1625 if ((len = strlen (txt)) > menu->width)
1626 menu->width = len;
1627 return XM_SUCCESS;
1630 /* Decide where the menu would be placed if requested at (X,Y). */
1632 void
1633 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
1634 int *ulx, int *uly, int *width, int *height)
1636 if (menu->count == 1 && menu->submenu[0])
1637 /* Special case: the menu consists of only one pane. */
1638 IT_menu_calc_size (menu->submenu[0], width, height);
1639 else
1640 IT_menu_calc_size (menu, width, height);
1641 *ulx = x + 1;
1642 *uly = y;
1643 *width += 2;
1646 struct IT_menu_state
1648 void *screen_behind;
1649 XMenu *menu;
1650 int pane;
1651 int x, y;
1655 /* Display menu, wait for user's response, and return that response. */
1658 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
1659 int x0, int y0, unsigned ButtonMask, char **txt)
1661 struct IT_menu_state *state;
1662 int statecount;
1663 int x, y, i, b;
1664 int screensize;
1665 int faces[4], selectface;
1666 int leave, result, onepane;
1668 /* Just in case we got here without a mouse present... */
1669 if (have_mouse <= 0)
1670 return XM_IA_SELECT;
1672 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
1673 screensize = screen_size * 2;
1674 faces[0]
1675 = compute_glyph_face (&the_only_frame,
1676 face_name_id_number
1677 (&the_only_frame,
1678 intern ("msdos-menu-passive-face")),
1680 faces[1]
1681 = compute_glyph_face (&the_only_frame,
1682 face_name_id_number
1683 (&the_only_frame,
1684 intern ("msdos-menu-active-face")),
1686 selectface
1687 = face_name_id_number (&the_only_frame, intern ("msdos-menu-select-face"));
1688 faces[2] = compute_glyph_face (&the_only_frame, selectface, faces[0]);
1689 faces[3] = compute_glyph_face (&the_only_frame, selectface, faces[1]);
1691 statecount = 1;
1692 state[0].menu = menu;
1693 mouse_off ();
1694 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
1695 if ((onepane = menu->count == 1 && menu->submenu[0]))
1697 menu->width = menu->submenu[0]->width;
1698 state[0].menu = menu->submenu[0];
1700 else
1702 state[0].menu = menu;
1704 state[0].x = x0 - 1;
1705 state[0].y = y0;
1706 state[0].pane = onepane;
1708 mouse_last_x = -1; /* A hack that forces display. */
1709 leave = 0;
1710 while (!leave)
1712 if (!mouse_visible) mouse_on ();
1713 mouse_check_moved ();
1714 if (selected_frame->mouse_moved)
1716 selected_frame->mouse_moved = 0;
1717 result = XM_IA_SELECT;
1718 mouse_get_xy (&x, &y);
1719 for (i = 0; i < statecount; i++)
1720 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
1722 int dy = y - state[i].y;
1723 if (0 <= dy && dy < state[i].menu->count)
1725 if (!state[i].menu->submenu[dy])
1726 if (state[i].menu->panenumber[dy])
1727 result = XM_SUCCESS;
1728 else
1729 result = XM_IA_SELECT;
1730 *pane = state[i].pane - 1;
1731 *selidx = dy;
1732 /* We hit some part of a menu, so drop extra menues that
1733 have been opened. That does not include an open and
1734 active submenu. */
1735 if (i != statecount - 2
1736 || state[i].menu->submenu[dy] != state[i+1].menu)
1737 while (i != statecount - 1)
1739 statecount--;
1740 mouse_off ();
1741 ScreenUpdate (state[statecount].screen_behind);
1742 xfree (state[statecount].screen_behind);
1744 if (i == statecount - 1 && state[i].menu->submenu[dy])
1746 IT_menu_display (state[i].menu,
1747 state[i].y,
1748 state[i].x,
1749 faces);
1750 state[statecount].menu = state[i].menu->submenu[dy];
1751 state[statecount].pane = state[i].menu->panenumber[dy];
1752 mouse_off ();
1753 ScreenRetrieve (state[statecount].screen_behind
1754 = xmalloc (screensize));
1755 state[statecount].x
1756 = state[i].x + state[i].menu->width + 2;
1757 state[statecount].y = y;
1758 statecount++;
1762 IT_menu_display (state[statecount - 1].menu,
1763 state[statecount - 1].y,
1764 state[statecount - 1].x,
1765 faces);
1767 for (b = 0; b < mouse_button_count; b++)
1769 (void) mouse_pressed (b, &x, &y);
1770 if (mouse_released (b, &x, &y))
1771 leave = 1;
1775 mouse_off ();
1776 ScreenUpdate (state[0].screen_behind);
1777 while (statecount--)
1778 xfree (state[statecount].screen_behind);
1779 return result;
1782 /* Dispose of a menu. */
1784 void
1785 XMenuDestroy (Display *foo, XMenu *menu)
1787 int i;
1788 if (menu->allocated)
1790 for (i = 0; i < menu->count; i++)
1791 if (menu->submenu[i])
1792 XMenuDestroy (foo, menu->submenu[i]);
1793 xfree (menu->text);
1794 xfree (menu->submenu);
1795 xfree (menu->panenumber);
1797 xfree (menu);
1801 x_pixel_width (struct frame *f)
1803 return FRAME_WIDTH (f);
1807 x_pixel_height (struct frame *f)
1809 return FRAME_HEIGHT (f);
1811 #endif /* !HAVE_X_WINDOWS */
1814 /* ----------------------- DOS / UNIX conversion --------------------- */
1816 /* Destructively turn backslashes into slashes. */
1818 void
1819 dostounix_filename (p)
1820 register char *p;
1822 while (*p)
1824 if (*p == '\\')
1825 *p = '/';
1826 p++;
1830 /* Destructively turn slashes into backslashes. */
1832 void
1833 unixtodos_filename (p)
1834 register char *p;
1836 while (*p)
1838 if (*p == '/')
1839 *p = '\\';
1840 p++;
1844 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
1847 getdefdir (drive, dst)
1848 int drive;
1849 char *dst;
1851 union REGS regs;
1853 *dst++ = '/';
1854 regs.h.dl = drive;
1855 regs.x.si = (int) dst;
1856 regs.h.ah = 0x47;
1857 intdos (&regs, &regs);
1858 return !regs.x.cflag;
1861 /* Remove all CR's that are followed by a LF. */
1864 crlf_to_lf (n, buf)
1865 register int n;
1866 register unsigned char *buf;
1868 unsigned char *np = buf;
1869 unsigned char *startp = buf;
1870 unsigned char *endp = buf + n;
1871 unsigned char c;
1873 if (n == 0)
1874 return n;
1875 while (buf < endp - 1)
1877 if (*buf == 0x0d)
1879 if (*(++buf) != 0x0a)
1880 *np++ = 0x0d;
1882 else
1883 *np++ = *buf++;
1885 if (buf < endp)
1886 *np++ = *buf++;
1887 return np - startp;
1890 /* The Emacs root directory as determined by init_environment. */
1892 static char emacsroot[MAXPATHLEN];
1894 char *
1895 rootrelativepath (rel)
1896 char *rel;
1898 static char result[MAXPATHLEN + 10];
1900 strcpy (result, emacsroot);
1901 strcat (result, "/");
1902 strcat (result, rel);
1903 return result;
1906 /* Define a lot of environment variables if not already defined. Don't
1907 remove anything unless you know what you're doing -- lots of code will
1908 break if one or more of these are missing. */
1910 void
1911 init_environment (argc, argv, skip_args)
1912 int argc;
1913 char **argv;
1914 int skip_args;
1916 char *s, *t, *root;
1917 int len;
1919 /* Find our root from argv[0]. Assuming argv[0] is, say,
1920 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
1921 root = alloca (MAXPATHLEN + 20);
1922 _fixpath (argv[0], root);
1923 strlwr (root);
1924 len = strlen (root);
1925 while (len > 0 && root[len] != '/' && root[len] != ':')
1926 len--;
1927 root[len] = '\0';
1928 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
1929 root[len - 4] = '\0';
1930 else
1931 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
1932 len = strlen (root);
1933 strcpy (emacsroot, root);
1935 /* We default HOME to our root. */
1936 setenv ("HOME", root, 0);
1938 /* We default EMACSPATH to root + "/bin". */
1939 strcpy (root + len, "/bin");
1940 setenv ("EMACSPATH", root, 0);
1942 /* I don't expect anybody to ever use other terminals so the internal
1943 terminal is the default. */
1944 setenv ("TERM", "internal", 0);
1946 #ifdef HAVE_X_WINDOWS
1947 /* Emacs expects DISPLAY to be set. */
1948 setenv ("DISPLAY", "unix:0.0", 0);
1949 #endif
1951 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
1952 downcase it and mirror the backslashes. */
1953 s = getenv ("COMSPEC");
1954 if (!s) s = "c:/command.com";
1955 t = alloca (strlen (s) + 1);
1956 strcpy (t, s);
1957 strlwr (t);
1958 dostounix_filename (t);
1959 setenv ("SHELL", t, 0);
1961 /* PATH is also downcased and backslashes mirrored. */
1962 s = getenv ("PATH");
1963 if (!s) s = "";
1964 t = alloca (strlen (s) + 3);
1965 /* Current directory is always considered part of MsDos's path but it is
1966 not normally mentioned. Now it is. */
1967 strcat (strcpy (t, ".;"), s);
1968 strlwr (t);
1969 dostounix_filename (t); /* Not a single file name, but this should work. */
1970 setenv ("PATH", t, 1);
1972 /* In some sense all dos users have root privileges, so... */
1973 setenv ("USER", "root", 0);
1974 setenv ("NAME", getenv ("USER"), 0);
1976 /* Time zone determined from country code. To make this possible, the
1977 country code may not span more than one time zone. In other words,
1978 in the USA, you lose. */
1979 if (!getenv ("TZ"))
1980 switch (dos_country_code)
1982 case 31: /* Belgium */
1983 case 32: /* The Netherlands */
1984 case 33: /* France */
1985 case 34: /* Spain */
1986 case 36: /* Hungary */
1987 case 38: /* Yugoslavia (or what's left of it?) */
1988 case 39: /* Italy */
1989 case 41: /* Switzerland */
1990 case 42: /* Tjekia */
1991 case 45: /* Denmark */
1992 case 46: /* Sweden */
1993 case 47: /* Norway */
1994 case 48: /* Poland */
1995 case 49: /* Germany */
1996 /* Daylight saving from last Sunday in March to last Sunday in
1997 September, both at 2AM. */
1998 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
1999 break;
2000 case 44: /* United Kingdom */
2001 case 351: /* Portugal */
2002 case 354: /* Iceland */
2003 setenv ("TZ", "GMT+00", 0);
2004 break;
2005 case 81: /* Japan */
2006 case 82: /* Korea */
2007 setenv ("TZ", "JST-09", 0);
2008 break;
2009 case 90: /* Turkey */
2010 case 358: /* Finland */
2011 setenv ("TZ", "EET-02", 0);
2012 break;
2013 case 972: /* Israel */
2014 /* This is an approximation. (For exact rules, use the
2015 `zoneinfo/israel' file which comes with DJGPP, but you need
2016 to install it in `/usr/share/zoneinfo/' directory first.) */
2017 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2018 break;
2020 init_gettimeofday ();
2025 static int break_stat; /* BREAK check mode status. */
2026 static int stdin_stat; /* stdin IOCTL status. */
2028 /* These must be global. */
2029 static _go32_dpmi_seginfo ctrl_break_vector;
2030 static _go32_dpmi_registers ctrl_break_regs;
2031 static int ctrlbreakinstalled = 0;
2033 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2035 void
2036 ctrl_break_func (regs)
2037 _go32_dpmi_registers *regs;
2039 Vquit_flag = Qt;
2042 void
2043 install_ctrl_break_check ()
2045 if (!ctrlbreakinstalled)
2047 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2048 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2049 ctrlbreakinstalled = 1;
2050 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2051 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2052 &ctrl_break_regs);
2053 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2058 * Turn off Dos' Ctrl-C checking and inhibit interpretation of
2059 * control chars by Dos.
2060 * Determine the keyboard type.
2064 dos_ttraw ()
2066 union REGS inregs, outregs;
2067 static int first_time = 1;
2069 break_stat = getcbrk ();
2070 setcbrk (0);
2071 install_ctrl_break_check ();
2073 if (first_time)
2075 inregs.h.ah = 0xc0;
2076 int86 (0x15, &inregs, &outregs);
2077 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2079 have_mouse = 0;
2081 if (internal_terminal
2082 #ifdef HAVE_X_WINDOWS
2083 && inhibit_window_system
2084 #endif
2087 inregs.x.ax = 0x0021;
2088 int86 (0x33, &inregs, &outregs);
2089 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2090 if (!have_mouse)
2092 /* Reportedly, the above doesn't work for some mouse drivers. There
2093 is an additional detection method that should work, but might be
2094 a little slower. Use that as an alternative. */
2095 inregs.x.ax = 0x0000;
2096 int86 (0x33, &inregs, &outregs);
2097 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2100 if (have_mouse)
2102 have_mouse = 1; /* enable mouse */
2103 mouse_visible = 0;
2105 if (outregs.x.bx == 3)
2107 mouse_button_count = 3;
2108 mouse_button_translate[0] = 0; /* Left */
2109 mouse_button_translate[1] = 2; /* Middle */
2110 mouse_button_translate[2] = 1; /* Right */
2112 else
2114 mouse_button_count = 2;
2115 mouse_button_translate[0] = 0;
2116 mouse_button_translate[1] = 1;
2118 mouse_position_hook = &mouse_get_pos;
2119 mouse_init ();
2123 first_time = 0;
2126 inregs.x.ax = 0x4400; /* Get IOCTL status. */
2127 inregs.x.bx = 0x00; /* 0 = stdin. */
2128 intdos (&inregs, &outregs);
2129 stdin_stat = outregs.h.dl;
2131 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
2132 inregs.x.ax = 0x4401; /* Set IOCTL status */
2133 intdos (&inregs, &outregs);
2134 return !outregs.x.cflag;
2137 /* Restore status of standard input and Ctrl-C checking. */
2139 dos_ttcooked ()
2141 union REGS inregs, outregs;
2143 setcbrk (break_stat);
2144 mouse_off ();
2146 inregs.x.ax = 0x4401; /* Set IOCTL status. */
2147 inregs.x.bx = 0x00; /* 0 = stdin. */
2148 inregs.x.dx = stdin_stat;
2149 intdos (&inregs, &outregs);
2150 return !outregs.x.cflag;
2154 /* Run command as specified by ARGV in directory DIR.
2155 The command is run with input from TEMPIN and output to file TEMPOUT. */
2157 run_msdos_command (argv, dir, tempin, tempout)
2158 unsigned char **argv;
2159 Lisp_Object dir;
2160 int tempin, tempout;
2162 char *saveargv1, *saveargv2, **envv;
2163 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
2164 int msshell, result = -1;
2165 int in, out, inbak, outbak, errbak;
2166 int x, y;
2167 Lisp_Object cmd;
2169 /* Get current directory as MSDOS cwd is not per-process. */
2170 getwd (oldwd);
2172 cmd = Ffile_name_nondirectory (build_string (argv[0]));
2173 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
2174 && !strcmp ("-c", argv[1]);
2175 if (msshell)
2177 saveargv1 = argv[1];
2178 saveargv2 = argv[2];
2179 argv[1] = "/c";
2180 if (argv[2])
2182 char *p = alloca (strlen (argv[2]) + 1);
2184 strcpy (argv[2] = p, saveargv2);
2185 while (*p && isspace (*p))
2186 p++;
2187 while (*p && !isspace (*p))
2188 if (*p == '/')
2189 *p++ = '\\';
2190 else
2191 p++;
2195 /* Build the environment array. */
2197 extern Lisp_Object Vprocess_environment;
2198 Lisp_Object tmp, lst;
2199 int i, len;
2201 lst = Vprocess_environment;
2202 len = XFASTINT (Flength (lst));
2204 envv = alloca ((len + 1) * sizeof (char *));
2205 for (i = 0; i < len; i++)
2207 tmp = Fcar (lst);
2208 lst = Fcdr (lst);
2209 CHECK_STRING (tmp, 0);
2210 envv[i] = alloca (XSTRING (tmp)->size + 1);
2211 strcpy (envv[i], XSTRING (tmp)->data);
2213 envv[len] = (char *) 0;
2216 if (STRINGP (dir))
2217 chdir (XSTRING (dir)->data);
2218 inbak = dup (0);
2219 outbak = dup (1);
2220 errbak = dup (2);
2221 if (inbak < 0 || outbak < 0 || errbak < 0)
2222 goto done; /* Allocation might fail due to lack of descriptors. */
2224 if (have_mouse > 0)
2225 mouse_get_xy (&x, &y);
2227 dos_ttcooked (); /* do it here while 0 = stdin */
2229 dup2 (tempin, 0);
2230 dup2 (tempout, 1);
2231 dup2 (tempout, 2);
2233 result = spawnve (P_WAIT, argv[0], argv, envv);
2235 dup2 (inbak, 0);
2236 dup2 (outbak, 1);
2237 dup2 (errbak, 2);
2238 close (inbak);
2239 close (outbak);
2240 close (errbak);
2242 dos_ttraw ();
2243 if (have_mouse > 0)
2245 mouse_init ();
2246 mouse_moveto (x, y);
2249 done:
2250 chdir (oldwd);
2251 if (msshell)
2253 argv[1] = saveargv1;
2254 argv[2] = saveargv2;
2256 return result;
2259 croak (badfunc)
2260 char *badfunc;
2262 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
2263 reset_sys_modes ();
2264 exit (1);
2268 /* ------------------------- Compatibility functions -------------------
2269 * gethostname
2270 * gettimeofday
2274 * Hostnames for a pc are not really funny,
2275 * but they are used in change log so we emulate the best we can.
2278 gethostname (p, size)
2279 char *p;
2280 int size;
2282 char *q = egetenv ("HOSTNAME");
2284 if (!q) q = "pc";
2285 strcpy (p, q);
2286 return 0;
2289 /* When time zones are set from Ms-Dos too many C-libraries are playing
2290 tricks with time values. We solve this by defining our own version
2291 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2292 once and after each call to `tzset' with TZ changed. That is
2293 accomplished by aliasing tzset to init_gettimeofday. */
2295 static struct tm time_rec;
2298 gettimeofday (struct timeval *tp, struct timezone *tzp)
2300 if (tp)
2302 struct time t;
2303 struct tm tm;
2305 gettime (&t);
2306 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
2308 struct date d;
2309 getdate (&d);
2310 time_rec.tm_year = d.da_year - 1900;
2311 time_rec.tm_mon = d.da_mon - 1;
2312 time_rec.tm_mday = d.da_day;
2315 time_rec.tm_hour = t.ti_hour;
2316 time_rec.tm_min = t.ti_min;
2317 time_rec.tm_sec = t.ti_sec;
2319 tm = time_rec;
2320 tm.tm_gmtoff = dos_timezone_offset;
2322 tp->tv_sec = mktime (&tm); /* may modify tm */
2323 tp->tv_usec = t.ti_hund * (1000000 / 100);
2325 /* Ignore tzp; it's obsolescent. */
2326 return 0;
2331 * A list of unimplemented functions that we silently ignore.
2334 unsigned alarm (s) unsigned s; {}
2335 fork () { return 0; }
2336 int kill (x, y) int x, y; { return -1; }
2337 nice (p) int p; {}
2338 void volatile pause () {}
2339 request_sigio () {}
2340 setpgrp () {return 0; }
2341 setpriority (x,y,z) int x,y,z; { return 0; }
2342 sigsetmask (x) int x; { return 0; }
2343 unrequest_sigio () {}
2345 int run_dos_timer_hooks = 0;
2347 #ifndef HAVE_SELECT
2348 #include "sysselect.h"
2350 static int last_ti_sec = -1;
2351 static int dos_menubar_clock_displayed = 0;
2353 static void
2354 check_timer (t)
2355 struct time *t;
2357 gettime (t);
2359 if (t->ti_sec == last_ti_sec)
2360 return;
2361 last_ti_sec = t->ti_sec;
2363 if (!NILP (Vdos_menubar_clock))
2365 char clock_str[16];
2366 int len;
2367 int min = t->ti_min;
2368 int hour = t->ti_hour;
2370 if (dos_timezone_offset)
2372 int tz = dos_timezone_offset;
2373 min -= tz % 60;
2374 if (min < 0)
2375 min += 60, hour--;
2376 else
2377 if (min >= 60)
2378 min -= 60, hour++;
2380 if ((hour -= (tz / 60)) < 0)
2381 hour += 24;
2382 else
2383 hour %= 24;
2386 if ((dos_country_info[0x11] & 0x01) == 0) /* 12 hour clock */
2388 hour %= 12;
2389 if (hour == 0) hour = 12;
2392 len = sprintf (clock_str, "%2d.%02d.%02d", hour, min, t->ti_sec);
2393 dos_direct_output (0, screen_size_X - len - 1, clock_str, len);
2394 dos_menubar_clock_displayed = 1;
2396 else if (dos_menubar_clock_displayed)
2398 /* Erase last displayed time. */
2399 dos_direct_output (0, screen_size_X - 9, " ", 8);
2400 dos_menubar_clock_displayed = 0;
2403 if (!NILP (Vdos_timer_hooks))
2404 run_dos_timer_hooks++;
2407 /* Only event queue is checked. */
2409 sys_select (nfds, rfds, wfds, efds, timeout)
2410 int nfds;
2411 SELECT_TYPE *rfds, *wfds, *efds;
2412 EMACS_TIME *timeout;
2414 int check_input;
2415 long timeoutval, clnow, cllast;
2416 struct time t;
2418 check_input = 0;
2419 if (rfds)
2421 check_input = FD_ISSET (0, rfds);
2422 FD_ZERO (rfds);
2424 if (wfds)
2425 FD_ZERO (wfds);
2426 if (efds)
2427 FD_ZERO (efds);
2429 if (nfds != 1)
2430 abort ();
2432 /* If we are looking only for the terminal, with no timeout,
2433 just read it and wait -- that's more efficient. */
2434 if (!timeout)
2436 while (! detect_input_pending ())
2437 check_timer (&t);
2439 else
2441 timeoutval = EMACS_SECS (*timeout) * 100 + EMACS_USECS (*timeout) / 10000;
2442 check_timer (&t);
2443 cllast = t.ti_sec * 100 + t.ti_hund;
2445 while (!check_input || !detect_input_pending ())
2447 check_timer (&t);
2448 clnow = t.ti_sec * 100 + t.ti_hund;
2449 if (clnow < cllast) /* time wrap */
2450 timeoutval -= clnow + 6000 - cllast;
2451 else
2452 timeoutval -= clnow - cllast;
2453 if (timeoutval <= 0) /* Stop on timer being cleared */
2454 return 0;
2455 cllast = clnow;
2459 FD_SET (0, rfds);
2460 return 1;
2462 #endif
2465 * Define overlayed functions:
2467 * chdir -> sys_chdir
2468 * tzset -> init_gettimeofday
2469 * abort -> dos_abort
2472 #ifdef chdir
2473 #undef chdir
2474 extern int chdir ();
2477 sys_chdir (path)
2478 const char* path;
2480 int len = strlen (path);
2481 char *tmp = (char *)path;
2483 if (*tmp && tmp[1] == ':')
2485 if (getdisk () != tolower (tmp[0]) - 'a')
2486 setdisk (tolower (tmp[0]) - 'a');
2487 tmp += 2; /* strip drive: KFS 1995-07-06 */
2488 len -= 2;
2491 if (len > 1 && (tmp[len - 1] == '/'))
2493 char *tmp1 = (char *) alloca (len + 1);
2494 strcpy (tmp1, tmp);
2495 tmp1[len - 1] = 0;
2496 tmp = tmp1;
2498 return chdir (tmp);
2500 #endif
2502 #ifdef tzset
2503 #undef tzset
2504 extern void tzset (void);
2506 void
2507 init_gettimeofday ()
2509 time_t ltm, gtm;
2510 struct tm *lstm;
2512 tzset ();
2513 ltm = gtm = time (NULL);
2514 ltm = mktime (lstm = localtime (&ltm));
2515 gtm = mktime (gmtime (&gtm));
2516 time_rec.tm_hour = 99; /* force gettimeofday to get date */
2517 time_rec.tm_isdst = lstm->tm_isdst;
2518 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
2520 #endif
2522 #ifdef abort
2523 #undef abort
2524 void
2525 dos_abort (file, line)
2526 char *file;
2527 int line;
2529 char buffer1[200], buffer2[400];
2530 int i, j;
2532 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
2533 for (i = j = 0; buffer1[i]; i++) {
2534 buffer2[j++] = buffer1[i];
2535 buffer2[j++] = 0x70;
2537 dosmemput (buffer2, j, (int)ScreenPrimary);
2538 ScreenSetCursor (2, 0);
2539 abort ();
2541 #endif
2543 syms_of_msdos ()
2545 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
2546 staticpro (&recent_doskeys);
2548 defsubr (&Srecent_doskeys);
2551 #endif /* MSDOS */