1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995, 1996 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)
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. */
32 #include <sys/param.h>
36 #include <string.h> /* for bzero and string functions */
37 #include <sys/stat.h> /* for _fixpath */
38 #include <unistd.h> /* for chdir, dup, dup2, etc. */
41 #include <io.h> /* for setmode */
42 #include <dpmi.h> /* for __dpmi_xxx stuff */
43 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
44 #include <libc/dosio.h> /* for _USE_LFN */
45 #include <conio.h> /* for cputs */
51 #include "termhooks.h"
52 #include "dispextern.h"
61 /* #include <process.h> */
62 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
70 #define _dos_ds _go32_info_block.selector_for_linear_memory
76 #include "syssignal.h"
82 /* If other `malloc' than ours is used, force our `sbrk' behave like
83 Unix programs expect (resize memory blocks to keep them contiguous).
84 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
85 because that's what `gmalloc' expects to get. */
89 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
90 #else /* not REL_ALLOC */
91 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
92 #endif /* not REL_ALLOC */
93 #endif /* GNU_MALLOC */
95 #endif /* not SYSTEM_MALLOC */
96 #endif /* __DJGPP__ > 1 */
115 /* ------------------------ Mouse control ---------------------------
117 * Coordinates are in screen positions and zero based.
118 * Mouse buttons are numbered from left to right and also zero based.
121 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
122 static int mouse_visible
;
124 static int mouse_last_x
;
125 static int mouse_last_y
;
127 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
128 static int mouse_button_count
;
135 if (have_mouse
> 0 && !mouse_visible
)
138 fprintf (termscript
, "<M_ON>");
140 int86 (0x33, ®s
, ®s
);
150 if (have_mouse
> 0 && mouse_visible
)
153 fprintf (termscript
, "<M_OFF>");
155 int86 (0x33, ®s
, ®s
);
167 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
169 mouse_last_x
= regs
.x
.cx
= x
* 8;
170 mouse_last_y
= regs
.x
.dx
= y
* 8;
171 int86 (0x33, ®s
, ®s
);
175 mouse_pressed (b
, xp
, yp
)
180 if (b
>= mouse_button_count
)
183 regs
.x
.bx
= mouse_button_translate
[b
];
184 int86 (0x33, ®s
, ®s
);
186 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
187 return (regs
.x
.bx
!= 0);
191 mouse_released (b
, xp
, yp
)
196 if (b
>= mouse_button_count
)
199 regs
.x
.bx
= mouse_button_translate
[b
];
200 int86 (0x33, ®s
, ®s
);
202 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
203 return (regs
.x
.bx
!= 0);
207 mouse_get_xy (int *x
, int *y
)
212 int86 (0x33, ®s
, ®s
);
218 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
221 Lisp_Object
*bar_window
, *x
, *y
;
222 enum scroll_bar_part
*part
;
229 int86 (0x33, ®s
, ®s
);
232 mouse_get_xy (&ix
, &iy
);
233 selected_frame
->mouse_moved
= 0;
234 *x
= make_number (ix
);
235 *y
= make_number (iy
);
236 *time
= event_timestamp ();
244 mouse_get_xy (&x
, &y
);
245 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
256 fprintf (termscript
, "<M_INIT>");
259 int86 (0x33, ®s
, ®s
);
263 regs
.x
.dx
= 8 * (ScreenCols () - 1);
264 int86 (0x33, ®s
, ®s
);
268 regs
.x
.dx
= 8 * (ScreenRows () - 1);
269 int86 (0x33, ®s
, ®s
);
275 /* ------------------------- Screen control ----------------------
279 static int internal_terminal
= 0;
281 #ifndef HAVE_X_WINDOWS
282 extern unsigned char ScreenAttrib
;
283 static int screen_face
;
284 static int highlight
;
286 static int screen_size_X
;
287 static int screen_size_Y
;
288 static int screen_size
;
290 static int current_pos_X
;
291 static int current_pos_Y
;
292 static int new_pos_X
;
293 static int new_pos_Y
;
295 static void *startup_screen_buffer
;
296 static int startup_screen_size_X
;
297 static int startup_screen_size_Y
;
298 static int startup_pos_X
;
299 static int startup_pos_Y
;
300 static unsigned char startup_screen_attrib
;
302 static int term_setup_done
;
304 /* Similar to the_only_frame. */
305 struct x_output the_only_x_display
;
307 /* This is never dereferenced. */
308 Display
*x_current_display
;
311 dos_direct_output (y
, x
, buf
, len
)
317 int t
= (int) ScreenPrimary
+ 2 * (x
+ y
* screen_size_X
);
321 dosmemput (buf
++, 1, t
);
325 /* This is faster. */
326 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
327 _farnspokeb (t
, *buf
);
332 /* Flash the screen as a substitute for BEEPs. */
336 do_visible_bell (xorattr
)
337 unsigned char xorattr
;
342 movl _ScreenPrimary,%%eax
349 xorb %%al,%%gs:(%%ebx)
365 : "m" (xorattr
), "g" (screen_size
)
366 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
370 ScreenVisualBell (void)
372 /* This creates an xor-mask that will swap the default fore- and
373 background colors. */
374 do_visible_bell (((the_only_x_display
.foreground_pixel
375 ^ the_only_x_display
.background_pixel
)
380 #ifndef HAVE_X_WINDOWS
382 static int blink_bit
= -1; /* the state of the blink bit at startup */
384 /* Enable bright background colors. */
390 /* Remember the original state of the blink/bright-background bit.
391 It is stored at 0040:0065h in the BIOS data area. */
393 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
397 int86 (0x10, ®s
, ®s
);
400 /* Disable bright background colors (and enable blinking) if we found
401 the video system in that state at startup. */
403 maybe_enable_blinking (void)
411 int86 (0x10, ®s
, ®s
);
415 /* Set the screen dimensions so that it can show no less than
416 ROWS x COLS frame. */
419 dos_set_window_size (rows
, cols
)
423 Lisp_Object video_mode
;
424 int video_mode_value
;
427 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
429 if (*rows
== current_rows
&& *cols
== current_cols
)
432 /* Do we have a VGA? */
434 int86 (0x10, ®s
, ®s
);
435 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
440 /* If the user specified a special video mode for these dimensions,
442 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
443 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
446 if (INTEGERP (video_mode
)
447 && (video_mode_value
= XINT (video_mode
)) > 0)
449 regs
.x
.ax
= video_mode_value
;
450 int86 (0x10, ®s
, ®s
);
454 /* Must hardware-reset the mouse, or else it won't update
455 its notion of screen dimensions for some non-standard
456 video modes. This is *painfully* slow... */
458 int86 (0x33, ®s
, ®s
);
462 /* Find one of the dimensions supported by standard EGA/VGA
463 which gives us at least the required dimensions. */
472 } std_dimension
[] = {
482 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
484 if (std_dimension
[i
].need_vga
<= have_vga
485 && std_dimension
[i
].rows
>= *rows
)
487 if (std_dimension
[i
].rows
!= current_rows
488 || *cols
!= current_cols
)
489 _set_screen_lines (std_dimension
[i
].rows
);
496 #else /* not __DJGPP__ > 1 */
498 else if (*rows
<= 25)
500 if (current_rows
!= 25 || current_cols
!= 80)
503 int86 (0x10, ®s
, ®s
);
506 int86 (0x10, ®s
, ®s
);
509 int86 (0x10, ®s
, ®s
);
511 int86 (0x10, ®s
, ®s
);
514 else if (*rows
<= 50)
515 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
516 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
519 int86 (0x10, ®s
, ®s
);
522 int86 (0x10, ®s
, ®s
);
525 int86 (0x10, ®s
, ®s
);
528 int86 (0x10, ®s
, ®s
);
530 #endif /* not __DJGPP__ > 1 */
538 /* Tell the caller what dimensions have been REALLY set. */
539 *rows
= ScreenRows ();
540 *cols
= ScreenCols ();
542 /* Enable bright background colors. */
546 /* If we write a character in the position where the mouse is,
547 the mouse cursor may need to be refreshed. */
557 mouse_get_xy (&x
, &y
);
558 if (y
!= new_pos_Y
|| x
< new_pos_X
)
574 union REGS inregs
, outregs
;
577 intdos (&inregs
, &outregs
);
582 IT_set_face (int face
)
585 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
587 if (face
== 1 || (face
== 0 && highlight
))
588 fp
= FRAME_MODE_LINE_FACE (foo
);
589 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
590 fp
= FRAME_DEFAULT_FACE (foo
);
592 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
594 fprintf (termscript
, "<FACE:%d:%d>", FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
596 ScreenAttrib
= (FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
);
600 IT_write_glyphs (GLYPH
*str
, int len
)
604 unsigned char *buf
, *bp
;
606 if (len
== 0) return;
608 buf
= bp
= alloca (len
* 2);
612 newface
= FAST_GLYPH_FACE (*str
);
613 if (newface
!= screen_face
)
614 IT_set_face (newface
);
615 ch
= FAST_GLYPH_CHAR (*str
);
616 *bp
++ = (unsigned char)ch
;
617 *bp
++ = ScreenAttrib
;
620 fputc (ch
, termscript
);
625 dosmemput (buf
, 2 * len
,
626 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
631 IT_clear_end_of_line (first_unused
)
638 fprintf (termscript
, "<CLR:EOL>");
639 i
= (j
= screen_size_X
- new_pos_X
) * 2;
640 spaces
= sp
= alloca (i
);
645 *sp
++ = ScreenAttrib
;
649 dosmemput (spaces
, i
,
650 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
654 IT_clear_screen (void)
657 fprintf (termscript
, "<CLR:SCR>");
661 new_pos_X
= new_pos_Y
= 0;
665 IT_clear_to_end (void)
668 fprintf (termscript
, "<CLR:EOS>");
670 while (new_pos_Y
< screen_size_Y
) {
672 IT_clear_end_of_line (0);
678 IT_cursor_to (int y
, int x
)
681 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
686 static int cursor_cleared
;
689 IT_display_cursor (int on
)
691 if (on
&& cursor_cleared
)
693 ScreenSetCursor (current_pos_Y
, current_pos_X
);
696 else if (!on
&& !cursor_cleared
)
698 ScreenSetCursor (-1, -1);
703 /* Emacs calls cursor-movement functions a lot when it updates the
704 display (probably a legacy of old terminals where you cannot
705 update a screen line without first moving the cursor there).
706 However, cursor movement is expensive on MSDOS (it calls a slow
707 BIOS function and requires 2 mode switches), while actual screen
708 updates access the video memory directly and don't depend on
709 cursor position. To avoid slowing down the redisplay, we cheat:
710 all functions that move the cursor only set internal variables
711 which record the cursor position, whereas the cursor is only
712 moved to its final position whenever screen update is complete.
714 `IT_cmgoto' is called from the keyboard reading loop and when the
715 frame update is complete. This means that we are ready for user
716 input, so we update the cursor position to show where the point is,
717 and also make the mouse pointer visible.
719 Special treatment is required when the cursor is in the echo area,
720 to put the cursor at the end of the text displayed there. */
726 /* Only set the cursor to where it should be if the display is
727 already in sync with the window contents. */
728 int update_cursor_pos
= MODIFF
== unchanged_modified
;
730 /* If we are in the echo area, put the cursor at the end of text. */
731 if (!update_cursor_pos
732 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
734 new_pos_X
= FRAME_DESIRED_GLYPHS (f
)->used
[new_pos_Y
];
735 update_cursor_pos
= 1;
738 if (update_cursor_pos
739 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
741 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
743 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
746 /* Maybe cursor is invisible, so make it visible. */
747 IT_display_cursor (1);
749 /* Mouse pointer should be always visible if we are waiting for
756 IT_reassert_line_highlight (new, vpos
)
760 IT_set_face (0); /* To possibly clear the highlighting. */
764 IT_change_line_highlight (new_highlight
, vpos
, first_unused_hpos
)
766 highlight
= new_highlight
;
767 IT_set_face (0); /* To possibly clear the highlighting. */
768 IT_cursor_to (vpos
, 0);
769 IT_clear_end_of_line (first_unused_hpos
);
776 IT_set_face (0); /* To possibly clear the highlighting. */
785 /* This was more or less copied from xterm.c
787 Nowadays, the corresponding function under X is `x_set_menu_bar_lines_1'
791 IT_set_menu_bar_lines (window
, n
)
795 struct window
*w
= XWINDOW (window
);
797 XSETFASTINT (w
->last_modified
, 0);
798 XSETFASTINT (w
->last_overlay_modified
, 0);
799 XSETFASTINT (w
->top
, XFASTINT (w
->top
) + n
);
800 XSETFASTINT (w
->height
, XFASTINT (w
->height
) - n
);
802 /* Handle just the top child in a vertical split. */
803 if (!NILP (w
->vchild
))
804 IT_set_menu_bar_lines (w
->vchild
, n
);
806 /* Adjust all children in a horizontal split. */
807 for (window
= w
->hchild
; !NILP (window
); window
= w
->next
)
809 w
= XWINDOW (window
);
810 IT_set_menu_bar_lines (window
, n
);
814 /* This was copied from xfns.c */
817 x_set_menu_bar_lines (f
, value
, oldval
)
819 Lisp_Object value
, oldval
;
822 int olines
= FRAME_MENU_BAR_LINES (f
);
824 /* Right now, menu bars don't work properly in minibuf-only frames;
825 most of the commands try to apply themselves to the minibuffer
826 frame itslef, and get an error because you can't switch buffers
827 in or split the minibuffer window. */
828 if (FRAME_MINIBUF_ONLY_P (f
))
831 if (INTEGERP (value
))
832 nlines
= XINT (value
);
836 FRAME_MENU_BAR_LINES (f
) = nlines
;
837 IT_set_menu_bar_lines (f
->root_window
, nlines
- olines
);
840 /* IT_set_terminal_modes is called when emacs is started,
841 resumed, and whenever the screen is redrawn! */
844 IT_set_terminal_modes (void)
847 fprintf (termscript
, "\n<SET_TERM>");
850 screen_size_X
= ScreenCols ();
851 screen_size_Y
= ScreenRows ();
852 screen_size
= screen_size_X
* screen_size_Y
;
854 new_pos_X
= new_pos_Y
= 0;
855 current_pos_X
= current_pos_Y
= -1;
861 startup_screen_size_X
= screen_size_X
;
862 startup_screen_size_Y
= screen_size_Y
;
863 startup_screen_attrib
= ScreenAttrib
;
865 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
866 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
869 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
870 screen_size_X
, screen_size_Y
);
875 /* IT_reset_terminal_modes is called when emacs is
876 suspended or killed. */
879 IT_reset_terminal_modes (void)
881 int display_row_start
= (int) ScreenPrimary
;
882 int saved_row_len
= startup_screen_size_X
* 2;
883 int update_row_len
= ScreenCols () * 2;
884 int current_rows
= ScreenRows ();
885 int to_next_row
= update_row_len
;
886 unsigned char *saved_row
= startup_screen_buffer
;
887 int cursor_pos_X
= ScreenCols () - 1;
888 int cursor_pos_Y
= ScreenRows () - 1;
891 fprintf (termscript
, "\n<RESET_TERM>");
895 if (!term_setup_done
)
900 /* Leave the video system in the same state as we found it,
901 as far as the blink/bright-background bit is concerned. */
902 maybe_enable_blinking ();
904 /* We have a situation here.
905 We cannot just do ScreenUpdate(startup_screen_buffer) because
906 the luser could have changed screen dimensions inside Emacs
907 and failed (or didn't want) to restore them before killing
908 Emacs. ScreenUpdate() uses the *current* screen dimensions and
909 thus will happily use memory outside what was allocated for
910 `startup_screen_buffer'.
911 Thus we only restore as much as the current screen dimensions
912 can hold, and clear the rest (if the saved screen is smaller than
913 the current) with the color attribute saved at startup. The cursor
914 is also restored within the visible dimensions. */
916 ScreenAttrib
= startup_screen_attrib
;
919 if (update_row_len
> saved_row_len
)
920 update_row_len
= saved_row_len
;
921 if (current_rows
> startup_screen_size_Y
)
922 current_rows
= startup_screen_size_Y
;
925 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
926 update_row_len
/ 2, current_rows
);
928 while (current_rows
--)
930 dosmemput (saved_row
, update_row_len
, display_row_start
);
931 saved_row
+= saved_row_len
;
932 display_row_start
+= to_next_row
;
934 if (startup_pos_X
< cursor_pos_X
)
935 cursor_pos_X
= startup_pos_X
;
936 if (startup_pos_Y
< cursor_pos_Y
)
937 cursor_pos_Y
= startup_pos_Y
;
939 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
940 xfree (startup_screen_buffer
);
946 IT_set_terminal_window (void)
951 IT_set_frame_parameters (f
, alist
)
957 extern unsigned long load_color ();
960 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
962 Lisp_Object elt
, prop
, val
;
967 CHECK_SYMBOL (prop
, 1);
969 if (EQ (prop
, intern ("foreground-color")))
971 unsigned long new_color
= load_color (f
, val
);
974 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
977 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
980 else if (EQ (prop
, intern ("background-color")))
982 unsigned long new_color
= load_color (f
, val
);
985 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
988 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
991 else if (EQ (prop
, intern ("menu-bar-lines")))
992 x_set_menu_bar_lines (f
, val
, 0);
997 extern void recompute_basic_faces (FRAME_PTR
);
998 extern void redraw_frame (FRAME_PTR
);
1000 recompute_basic_faces (f
);
1001 if (f
== selected_frame
)
1006 extern void init_frame_faces (FRAME_PTR
);
1008 #endif /* !HAVE_X_WINDOWS */
1011 /* Do we need the internal terminal? */
1014 internal_terminal_init ()
1016 char *term
= getenv ("TERM");
1019 #ifdef HAVE_X_WINDOWS
1020 if (!inhibit_window_system
)
1025 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1027 if (getenv ("EMACSTEST"))
1028 termscript
= fopen (getenv ("EMACSTEST"), "wt");
1030 #ifndef HAVE_X_WINDOWS
1031 if (!internal_terminal
|| inhibit_window_system
)
1033 selected_frame
->output_method
= output_termcap
;
1037 Vwindow_system
= intern ("pc");
1038 Vwindow_system_version
= make_number (1);
1040 bzero (&the_only_x_display
, sizeof the_only_x_display
);
1041 the_only_x_display
.background_pixel
= 7; /* White */
1042 the_only_x_display
.foreground_pixel
= 0; /* Black */
1044 colors
= getenv ("EMACSCOLORS");
1045 if (colors
&& strlen (colors
) >= 2)
1047 /* The colors use 4 bits each (we enable bright background). */
1048 if (isdigit (colors
[0]))
1050 else if (isxdigit (colors
[0]))
1051 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1052 if (colors
[0] >= 0 && colors
[0] < 16)
1053 the_only_x_display
.foreground_pixel
= colors
[0];
1054 if (isdigit (colors
[1]))
1056 else if (isxdigit (colors
[1]))
1057 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1058 if (colors
[1] >= 0 && colors
[1] < 16)
1059 the_only_x_display
.background_pixel
= colors
[1];
1061 the_only_x_display
.line_height
= 1;
1062 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
1064 init_frame_faces (selected_frame
);
1066 ring_bell_hook
= IT_ring_bell
;
1067 write_glyphs_hook
= IT_write_glyphs
;
1068 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
1069 clear_to_end_hook
= IT_clear_to_end
;
1070 clear_end_of_line_hook
= IT_clear_end_of_line
;
1071 clear_frame_hook
= IT_clear_screen
;
1072 change_line_highlight_hook
= IT_change_line_highlight
;
1073 update_begin_hook
= IT_update_begin
;
1074 update_end_hook
= IT_update_end
;
1075 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
1076 frame_up_to_date_hook
= IT_cmgoto
; /* position cursor when update is done */
1078 /* These hooks are called by term.c without being checked. */
1079 set_terminal_modes_hook
= IT_set_terminal_modes
;
1080 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1081 set_terminal_window_hook
= IT_set_terminal_window
;
1085 dos_get_saved_screen (screen
, rows
, cols
)
1090 #ifndef HAVE_X_WINDOWS
1091 *screen
= startup_screen_buffer
;
1092 *cols
= startup_screen_size_X
;
1093 *rows
= startup_screen_size_Y
;
1100 #ifndef HAVE_X_WINDOWS
1102 /* We are not X, but we can emulate it well enough for our needs... */
1106 if (! FRAME_MSDOS_P (selected_frame
))
1107 error ("Not running under a windows system");
1113 /* ----------------------- Keyboard control ----------------------
1115 * Keymaps reflect the following keyboard layout:
1117 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1118 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1119 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1120 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1124 static int extended_kbd
; /* 101 (102) keyboard present. */
1126 struct dos_keyboard_map
1134 static struct dos_keyboard_map us_keyboard
= {
1136 /* 01234567890123456789012345678901234567890 12345678901234 */
1137 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1138 /* 0123456789012345678901234567890123456789 012345678901234 */
1139 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1140 0 /* no Alt-Gr key */
1143 static struct dos_keyboard_map fr_keyboard
= {
1145 /* 012 3456789012345678901234567890123456789012345678901234 */
1146 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1147 /* 0123456789012345678901234567890123456789012345678901234 */
1148 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1149 /* 01234567 89012345678901234567890123456789012345678901234 */
1153 static struct dos_keyboard_map dk_keyboard
= {
1155 /* 0123456789012345678901234567890123456789012345678901234 */
1156 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
1157 /* 01 23456789012345678901234567890123456789012345678901234 */
1158 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
1159 /* 0123456789012345678901234567890123456789012345678901234 */
1163 static struct keyboard_layout_list
1166 struct dos_keyboard_map
*keyboard_map
;
1167 } keyboard_layout_list
[] =
1174 static struct dos_keyboard_map
*keyboard
;
1175 static int keyboard_map_all
;
1176 static int international_keyboard
;
1179 dos_set_keyboard (code
, always
)
1186 /* See if Keyb.Com is installed (for international keyboard support). */
1188 int86 (0x2f, ®s
, ®s
);
1189 if (regs
.h
.al
== 0xff)
1190 international_keyboard
= 1;
1192 /* Initialize to US settings, for countries that don't have their own. */
1193 keyboard
= keyboard_layout_list
[0].keyboard_map
;
1194 keyboard_map_all
= always
;
1195 dos_keyboard_layout
= 1;
1197 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
1198 if (code
== keyboard_layout_list
[i
].country_code
)
1200 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
1201 keyboard_map_all
= always
;
1202 dos_keyboard_layout
= code
;
1208 #define Ignore 0x0000
1209 #define Normal 0x0000 /* normal key - alt changes scan-code */
1210 #define FctKey 0x1000 /* func key if c == 0, else c */
1211 #define Special 0x2000 /* func key even if c != 0 */
1212 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1213 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1214 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1215 #define Grey 0x6000 /* Grey keypad key */
1217 #define Alt 0x0100 /* alt scan-code */
1218 #define Ctrl 0x0200 /* ctrl scan-code */
1219 #define Shift 0x0400 /* shift scan-code */
1223 unsigned char char_code
; /* normal code */
1224 unsigned char meta_code
; /* M- code */
1225 unsigned char keypad_code
; /* keypad code */
1226 unsigned char editkey_code
; /* edit key */
1227 } keypad_translate_map
[] = {
1228 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1229 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1230 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1231 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1232 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1233 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1234 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1235 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1236 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1237 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1238 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1243 unsigned char char_code
; /* normal code */
1244 unsigned char keypad_code
; /* keypad code */
1245 } grey_key_translate_map
[] = {
1246 '/', 0xaf, /* kp-decimal */
1247 '*', 0xaa, /* kp-multiply */
1248 '-', 0xad, /* kp-subtract */
1249 '+', 0xab, /* kp-add */
1250 '\r', 0x8d /* kp-enter */
1253 static unsigned short
1254 ibmpc_translate_map
[] =
1256 /* --------------- 00 to 0f --------------- */
1257 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
1258 Alt
| ModFct
| 0x1b, /* Escape */
1259 Normal
| 1, /* '1' */
1260 Normal
| 2, /* '2' */
1261 Normal
| 3, /* '3' */
1262 Normal
| 4, /* '4' */
1263 Normal
| 5, /* '5' */
1264 Normal
| 6, /* '6' */
1265 Normal
| 7, /* '7' */
1266 Normal
| 8, /* '8' */
1267 Normal
| 9, /* '9' */
1268 Normal
| 10, /* '0' */
1269 Normal
| 11, /* '-' */
1270 Normal
| 12, /* '=' */
1271 Special
| 0x08, /* Backspace */
1272 ModFct
| 0x74, /* Tab/Backtab */
1274 /* --------------- 10 to 1f --------------- */
1287 ModFct
| 0x0d, /* Return */
1292 /* --------------- 20 to 2f --------------- */
1301 Map
| 40, /* '\'' */
1303 Ignore
, /* Left shift */
1304 Map
| 41, /* '\\' */
1310 /* --------------- 30 to 3f --------------- */
1317 Ignore
, /* Right shift */
1318 Grey
| 1, /* Grey * */
1320 Normal
| ' ', /* ' ' */
1321 Ignore
, /* Caps Lock */
1322 FctKey
| 0xbe, /* F1 */
1323 FctKey
| 0xbf, /* F2 */
1324 FctKey
| 0xc0, /* F3 */
1325 FctKey
| 0xc1, /* F4 */
1326 FctKey
| 0xc2, /* F5 */
1328 /* --------------- 40 to 4f --------------- */
1329 FctKey
| 0xc3, /* F6 */
1330 FctKey
| 0xc4, /* F7 */
1331 FctKey
| 0xc5, /* F8 */
1332 FctKey
| 0xc6, /* F9 */
1333 FctKey
| 0xc7, /* F10 */
1334 Ignore
, /* Num Lock */
1335 Ignore
, /* Scroll Lock */
1336 KeyPad
| 7, /* Home */
1337 KeyPad
| 8, /* Up */
1338 KeyPad
| 9, /* Page Up */
1339 Grey
| 2, /* Grey - */
1340 KeyPad
| 4, /* Left */
1341 KeyPad
| 5, /* Keypad 5 */
1342 KeyPad
| 6, /* Right */
1343 Grey
| 3, /* Grey + */
1344 KeyPad
| 1, /* End */
1346 /* --------------- 50 to 5f --------------- */
1347 KeyPad
| 2, /* Down */
1348 KeyPad
| 3, /* Page Down */
1349 KeyPad
| 0, /* Insert */
1350 KeyPad
| 10, /* Delete */
1351 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1352 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1353 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1354 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1355 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1356 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1357 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1358 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1359 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1360 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1361 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1362 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1364 /* --------------- 60 to 6f --------------- */
1365 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1366 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1367 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1368 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1369 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1370 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1371 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1372 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1373 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1374 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1375 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1376 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1377 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1378 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1379 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1380 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1382 /* --------------- 70 to 7f --------------- */
1383 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1384 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1385 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1386 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1387 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1388 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1389 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1390 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1391 Alt
| Map
| 1, /* '1' */
1392 Alt
| Map
| 2, /* '2' */
1393 Alt
| Map
| 3, /* '3' */
1394 Alt
| Map
| 4, /* '4' */
1395 Alt
| Map
| 5, /* '5' */
1396 Alt
| Map
| 6, /* '6' */
1397 Alt
| Map
| 7, /* '7' */
1398 Alt
| Map
| 8, /* '8' */
1400 /* --------------- 80 to 8f --------------- */
1401 Alt
| Map
| 9, /* '9' */
1402 Alt
| Map
| 10, /* '0' */
1403 Alt
| Map
| 11, /* '-' */
1404 Alt
| Map
| 12, /* '=' */
1405 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1406 FctKey
| 0xc8, /* F11 */
1407 FctKey
| 0xc9, /* F12 */
1408 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1409 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1410 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1411 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1412 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1413 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1414 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1415 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1416 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1418 /* --------------- 90 to 9f --------------- */
1419 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1420 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1421 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1422 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1423 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1424 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1425 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1426 Alt
| FctKey
| 0x50, /* (Alt) Home */
1427 Alt
| FctKey
| 0x52, /* (Alt) Up */
1428 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1429 Ignore
, /* NO KEY */
1430 Alt
| FctKey
| 0x51, /* (Alt) Left */
1431 Ignore
, /* NO KEY */
1432 Alt
| FctKey
| 0x53, /* (Alt) Right */
1433 Ignore
, /* NO KEY */
1434 Alt
| FctKey
| 0x57, /* (Alt) End */
1436 /* --------------- a0 to af --------------- */
1437 Alt
| KeyPad
| 2, /* (Alt) Down */
1438 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1439 Alt
| KeyPad
| 0, /* (Alt) Insert */
1440 Alt
| KeyPad
| 10, /* (Alt) Delete */
1441 Alt
| Grey
| 0, /* (Alt) Grey / */
1442 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1443 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1446 /* These bit-positions corresponds to values returned by BIOS */
1447 #define SHIFT_P 0x0003 /* two bits! */
1448 #define CTRL_P 0x0004
1449 #define ALT_P 0x0008
1450 #define SCRLOCK_P 0x0010
1451 #define NUMLOCK_P 0x0020
1452 #define CAPSLOCK_P 0x0040
1453 #define ALT_GR_P 0x0800
1454 #define SUPER_P 0x4000 /* pseudo */
1455 #define HYPER_P 0x8000 /* pseudo */
1458 dos_get_modifiers (keymask
)
1465 /* Calculate modifier bits */
1466 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1467 int86 (0x16, ®s
, ®s
);
1471 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1472 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1476 mask
= regs
.h
.al
& (SHIFT_P
|
1477 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1479 /* Do not break international keyboard support. */
1480 /* When Keyb.Com is loaded, the right Alt key is */
1481 /* used for accessing characters like { and } */
1482 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1485 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1488 if (dos_hyper_key
== 1)
1491 modifiers
|= hyper_modifier
;
1493 else if (dos_super_key
== 1)
1496 modifiers
|= super_modifier
;
1498 else if (!international_keyboard
)
1500 /* If Keyb.Com is NOT installed, let Right Alt behave
1501 like the Left Alt. */
1507 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
1510 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
1512 if (dos_hyper_key
== 2)
1515 modifiers
|= hyper_modifier
;
1517 else if (dos_super_key
== 2)
1520 modifiers
|= super_modifier
;
1528 modifiers
|= shift_modifier
;
1530 modifiers
|= ctrl_modifier
;
1532 modifiers
|= meta_modifier
;
1539 #define NUM_RECENT_DOSKEYS (100)
1540 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1541 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1542 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1544 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1545 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1546 Each input key receives two values in this vector: first the ASCII code,\n\
1547 and then the scan code.")
1550 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1553 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1554 return Fvector (total_doskeys
, keys
);
1557 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1558 bcopy (keys
+ recent_doskeys_index
,
1559 XVECTOR (val
)->contents
,
1560 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1562 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1563 recent_doskeys_index
* sizeof (Lisp_Object
));
1568 /* Get a char from keyboard. Function keys are put into the event queue. */
1570 extern void kbd_buffer_store_event (struct input_event
*);
1575 struct input_event event
;
1578 #ifndef HAVE_X_WINDOWS
1579 /* Maybe put the cursor where it should be. */
1580 IT_cmgoto (selected_frame
);
1583 /* The following condition is equivalent to `kbhit ()', except that
1584 it uses the bios to do its job. This pleases DESQview/X. */
1585 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1586 int86 (0x16, ®s
, ®s
),
1587 (regs
.x
.flags
& 0x40) == 0)
1590 register unsigned char c
;
1591 int sc
, code
, mask
, kp_mode
;
1594 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1595 int86 (0x16, ®s
, ®s
);
1600 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1602 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1603 recent_doskeys_index
= 0;
1604 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1606 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1607 recent_doskeys_index
= 0;
1609 modifiers
= dos_get_modifiers (&mask
);
1611 #ifndef HAVE_X_WINDOWS
1612 if (!NILP (Vdos_display_scancodes
))
1615 sprintf (buf
, "%02x:%02x*%04x",
1616 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1617 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1625 case 10: /* Ctrl Grey Enter */
1626 code
= Ctrl
| Grey
| 4;
1628 case 13: /* Grey Enter */
1631 case '/': /* Grey / */
1641 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1643 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1649 /* We only look at the keyboard Ctrl/Shift/Alt keys when
1650 Emacs is ready to read a key. Therefore, if they press
1651 `Alt-x' when Emacs is busy, by the time we get to
1652 `dos_get_modifiers', they might have already released the
1653 Alt key, and Emacs gets just `x', which is BAD.
1654 However, for keys with the `Map' property set, the ASCII
1655 code returns zero iff Alt is pressed. So, when we DON'T
1656 have to support international_keyboard, we don't have to
1657 distinguish between the left and right Alt keys, and we
1658 can set the META modifier for any keys with the `Map'
1659 property if they return zero ASCII code (c = 0). */
1661 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
1662 modifiers
|= meta_modifier
;
1664 modifiers
|= ctrl_modifier
;
1666 modifiers
|= shift_modifier
;
1669 switch (code
& 0xf000)
1672 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1674 c
= 0; /* Special */
1687 if (c
== 0) /* ctrl-break */
1689 return c
; /* ALT-nnn */
1691 if (!keyboard_map_all
)
1700 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1701 if (!keyboard_map_all
)
1705 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1706 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1710 code
= keyboard
->shifted
[code
];
1712 modifiers
&= ~shift_modifier
;
1715 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1716 code
= keyboard
->alt_gr
[code
];
1718 code
= keyboard
->unshifted
[code
];
1723 if (c
== 0xe0) /* edit key */
1726 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1727 kp_mode
= dos_keypad_mode
& 0x03;
1729 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1734 if (code
== 10 && dos_decimal_point
)
1735 return dos_decimal_point
;
1736 return keypad_translate_map
[code
].char_code
;
1739 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1743 code
= keypad_translate_map
[code
].meta_code
;
1744 modifiers
= meta_modifier
;
1748 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1755 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1756 if (dos_keypad_mode
& kp_mode
)
1757 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1759 code
= grey_key_translate_map
[code
].char_code
;
1768 event
.kind
= non_ascii_keystroke
;
1770 event
.kind
= ascii_keystroke
;
1772 event
.modifiers
= modifiers
;
1773 XSETFRAME (event
.frame_or_window
, selected_frame
);
1774 event
.timestamp
= event_timestamp ();
1775 kbd_buffer_store_event (&event
);
1780 int but
, press
, x
, y
, ok
;
1782 /* Check for mouse movement *before* buttons. */
1783 mouse_check_moved ();
1785 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1786 for (press
= 0; press
< 2; press
++)
1788 int button_num
= but
;
1791 ok
= mouse_pressed (but
, &x
, &y
);
1793 ok
= mouse_released (but
, &x
, &y
);
1796 /* Allow a simultaneous press/release of Mouse-1 and
1797 Mouse-2 to simulate Mouse-3 on two-button mice. */
1798 if (mouse_button_count
== 2 && but
< 2)
1800 int x2
, y2
; /* don't clobber original coordinates */
1802 /* If only one button is pressed, wait 100 msec and
1803 check again. This way, Speedy Gonzales isn't
1804 punished, while the slow get their chance. */
1805 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1806 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1811 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1812 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1817 event
.kind
= mouse_click
;
1818 event
.code
= button_num
;
1819 event
.modifiers
= dos_get_modifiers (0)
1820 | (press
? down_modifier
: up_modifier
);
1823 XSETFRAME (event
.frame_or_window
, selected_frame
);
1824 event
.timestamp
= event_timestamp ();
1825 kbd_buffer_store_event (&event
);
1833 static int prev_get_char
= -1;
1835 /* Return 1 if a key is ready to be read without suspending execution. */
1839 if (prev_get_char
!= -1)
1842 return ((prev_get_char
= dos_rawgetc ()) != -1);
1845 /* Read a key. Return -1 if no key is ready. */
1849 if (prev_get_char
!= -1)
1851 int c
= prev_get_char
;
1856 return dos_rawgetc ();
1859 #ifndef HAVE_X_WINDOWS
1860 /* See xterm.c for more info. */
1862 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1864 register int pix_x
, pix_y
;
1865 register int *x
, *y
;
1866 void /* XRectangle */ *bounds
;
1869 if (bounds
) abort ();
1871 /* Ignore clipping. */
1878 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1881 register int *pix_x
, *pix_y
;
1887 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1890 Actually, I don't know the meaning of all the parameters of the functions
1891 here -- I only know how they are called by xmenu.c. I could of course
1892 grab the nearest Xlib manual (down the hall, second-to-last door on the
1893 left), but I don't think it's worth the effort. */
1900 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1901 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1905 /* Allocate some (more) memory for MENU ensuring that there is room for one
1909 IT_menu_make_room (XMenu
*menu
)
1911 if (menu
->allocated
== 0)
1913 int count
= menu
->allocated
= 10;
1914 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1915 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1916 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1918 else if (menu
->allocated
== menu
->count
)
1920 int count
= menu
->allocated
= menu
->allocated
+ 10;
1922 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1924 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1926 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1930 /* Search the given menu structure for a given pane number. */
1933 IT_menu_search_pane (XMenu
*menu
, int pane
)
1938 for (i
= 0; i
< menu
->count
; i
++)
1939 if (menu
->submenu
[i
])
1941 if (pane
== menu
->panenumber
[i
])
1942 return menu
->submenu
[i
];
1943 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1949 /* Determine how much screen space a given menu needs. */
1952 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1954 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1957 maxheight
= menu
->count
;
1958 for (i
= 0; i
< menu
->count
; i
++)
1960 if (menu
->submenu
[i
])
1962 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1963 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1964 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1967 *width
= menu
->width
+ maxsubwidth
;
1968 *height
= maxheight
;
1971 /* Display MENU at (X,Y) using FACES. */
1974 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1976 int i
, j
, face
, width
;
1980 int enabled
, mousehere
;
1983 width
= menu
->width
;
1984 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1985 ScreenGetCursor (&row
, &col
);
1986 mouse_get_xy (&mx
, &my
);
1988 for (i
= 0; i
< menu
->count
; i
++)
1990 IT_cursor_to (y
+ i
, x
);
1992 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1993 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1994 face
= faces
[enabled
+ mousehere
* 2];
1996 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1997 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
2000 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
2001 else /* make '^x' */
2003 *p
++ = FAST_MAKE_GLYPH ('^', face
);
2005 *p
++ = FAST_MAKE_GLYPH (*q
++ + 64, face
);
2009 for (; j
< width
; j
++)
2010 *p
++ = FAST_MAKE_GLYPH (' ', face
);
2011 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
2012 IT_write_glyphs (text
, width
+ 2);
2015 IT_cursor_to (row
, col
);
2019 /* --------------------------- X Menu emulation ---------------------- */
2021 /* Report availability of menus. */
2029 /* Create a brand new menu structure. */
2032 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2034 return IT_menu_create ();
2037 /* Create a new pane and place it on the outer-most level. It is not
2038 clear that it should be placed out there, but I don't know what else
2042 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
2050 IT_menu_make_room (menu
);
2051 menu
->submenu
[menu
->count
] = IT_menu_create ();
2052 menu
->text
[menu
->count
] = txt
;
2053 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
2056 /* Adjust length for possible control characters (which will
2057 be written as ^x). */
2058 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2062 if (len
> menu
->width
)
2065 return menu
->panecount
;
2068 /* Create a new item in a menu pane. */
2071 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
2072 int foo
, char *txt
, int enable
)
2078 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
2080 IT_menu_make_room (menu
);
2081 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
2082 menu
->text
[menu
->count
] = txt
;
2083 menu
->panenumber
[menu
->count
] = enable
;
2086 /* Adjust length for possible control characters (which will
2087 be written as ^x). */
2088 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2092 if (len
> menu
->width
)
2098 /* Decide where the menu would be placed if requested at (X,Y). */
2101 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
2102 int *ulx
, int *uly
, int *width
, int *height
)
2104 IT_menu_calc_size (menu
, width
, height
);
2110 struct IT_menu_state
2112 void *screen_behind
;
2119 /* Display menu, wait for user's response, and return that response. */
2122 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
2123 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
2125 struct IT_menu_state
*state
;
2129 int faces
[4], selectface
;
2130 int leave
, result
, onepane
;
2131 int title_faces
[4]; /* face to display the menu title */
2132 int buffers_num_deleted
= 0;
2134 /* Just in case we got here without a mouse present... */
2135 if (have_mouse
<= 0)
2136 return XM_IA_SELECT
;
2137 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2138 around the display. */
2144 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
2145 screensize
= screen_size
* 2;
2147 = compute_glyph_face (selected_frame
,
2150 intern ("msdos-menu-passive-face")),
2153 = compute_glyph_face (selected_frame
,
2156 intern ("msdos-menu-active-face")),
2159 = face_name_id_number (selected_frame
, intern ("msdos-menu-select-face"));
2160 faces
[2] = compute_glyph_face (selected_frame
, selectface
, faces
[0]);
2161 faces
[3] = compute_glyph_face (selected_frame
, selectface
, faces
[1]);
2163 /* Make sure the menu title is always displayed with
2164 `msdos-menu-active-face', no matter where the mouse pointer is. */
2165 for (i
= 0; i
< 4; i
++)
2166 title_faces
[i
] = faces
[3];
2170 /* Don't let the title for the "Buffers" popup menu include a
2171 digit (which is ugly).
2173 This is a terrible kludge, but I think the "Buffers" case is
2174 the only one where the title includes a number, so it doesn't
2175 seem to be necessary to make this more general. */
2176 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
2178 menu
->text
[0][7] = '\0';
2179 buffers_num_deleted
= 1;
2181 state
[0].menu
= menu
;
2183 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
2185 /* Turn off the cursor. Otherwise it shows through the menu
2186 panes, which is ugly. */
2187 IT_display_cursor (0);
2189 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
2190 if (buffers_num_deleted
)
2191 menu
->text
[0][7] = ' ';
2192 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
2194 menu
->width
= menu
->submenu
[0]->width
;
2195 state
[0].menu
= menu
->submenu
[0];
2199 state
[0].menu
= menu
;
2201 state
[0].x
= x0
- 1;
2203 state
[0].pane
= onepane
;
2205 mouse_last_x
= -1; /* A hack that forces display. */
2209 if (!mouse_visible
) mouse_on ();
2210 mouse_check_moved ();
2211 if (selected_frame
->mouse_moved
)
2213 selected_frame
->mouse_moved
= 0;
2214 result
= XM_IA_SELECT
;
2215 mouse_get_xy (&x
, &y
);
2216 for (i
= 0; i
< statecount
; i
++)
2217 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
2219 int dy
= y
- state
[i
].y
;
2220 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
2222 if (!state
[i
].menu
->submenu
[dy
])
2223 if (state
[i
].menu
->panenumber
[dy
])
2224 result
= XM_SUCCESS
;
2226 result
= XM_IA_SELECT
;
2227 *pane
= state
[i
].pane
- 1;
2229 /* We hit some part of a menu, so drop extra menus that
2230 have been opened. That does not include an open and
2232 if (i
!= statecount
- 2
2233 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
2234 while (i
!= statecount
- 1)
2238 ScreenUpdate (state
[statecount
].screen_behind
);
2239 xfree (state
[statecount
].screen_behind
);
2241 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2243 IT_menu_display (state
[i
].menu
,
2247 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2248 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2250 ScreenRetrieve (state
[statecount
].screen_behind
2251 = xmalloc (screensize
));
2253 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2254 state
[statecount
].y
= y
;
2259 IT_menu_display (state
[statecount
- 1].menu
,
2260 state
[statecount
- 1].y
,
2261 state
[statecount
- 1].x
,
2264 for (b
= 0; b
< mouse_button_count
; b
++)
2266 (void) mouse_pressed (b
, &x
, &y
);
2267 if (mouse_released (b
, &x
, &y
))
2273 ScreenUpdate (state
[0].screen_behind
);
2274 while (statecount
--)
2275 xfree (state
[statecount
].screen_behind
);
2276 IT_display_cursor (1); /* turn cursor back on */
2280 /* Dispose of a menu. */
2283 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2286 if (menu
->allocated
)
2288 for (i
= 0; i
< menu
->count
; i
++)
2289 if (menu
->submenu
[i
])
2290 XMenuDestroy (foo
, menu
->submenu
[i
]);
2292 xfree (menu
->submenu
);
2293 xfree (menu
->panenumber
);
2299 x_pixel_width (struct frame
*f
)
2301 return FRAME_WIDTH (f
);
2305 x_pixel_height (struct frame
*f
)
2307 return FRAME_HEIGHT (f
);
2309 #endif /* !HAVE_X_WINDOWS */
2311 /* ----------------------- DOS / UNIX conversion --------------------- */
2313 void msdos_downcase_filename (unsigned char *);
2315 /* Destructively turn backslashes into slashes. */
2318 dostounix_filename (p
)
2321 msdos_downcase_filename (p
);
2331 /* Destructively turn slashes into backslashes. */
2334 unixtodos_filename (p
)
2337 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2351 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2354 getdefdir (drive
, dst
)
2358 char in_path
[4], *p
= in_path
;
2361 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2364 *p
++ = drive
+ 'A' - 1;
2371 _fixpath (in_path
, dst
);
2375 msdos_downcase_filename (dst
);
2381 /* Remove all CR's that are followed by a LF. */
2386 register unsigned char *buf
;
2388 unsigned char *np
= buf
;
2389 unsigned char *startp
= buf
;
2390 unsigned char *endp
= buf
+ n
;
2394 while (buf
< endp
- 1)
2398 if (*(++buf
) != 0x0a)
2409 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2411 /* In DJGPP v2.0, library `write' can call `malloc', which might
2412 cause relocation of the buffer whose address we get in ADDR.
2413 Here is a version of `write' that avoids calling `malloc',
2414 to serve us until such time as the library is fixed.
2415 Actually, what we define here is called `__write', because
2416 `write' is a stub that just jmp's to `__write' (to be
2417 POSIXLY-correct with respect to the global name-space). */
2419 #include <io.h> /* for _write */
2420 #include <libc/dosio.h> /* for __file_handle_modes[] */
2422 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
2424 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2427 __write (int handle
, const void *buffer
, size_t count
)
2432 if(__file_handle_modes
[handle
] & O_BINARY
)
2433 return _write (handle
, buffer
, count
);
2437 const char *bp
= buffer
;
2438 int total_written
= 0;
2439 int nmoved
= 0, ncr
= 0;
2443 /* The next test makes sure there's space for at least 2 more
2444 characters in xbuf[], so both CR and LF can be put there. */
2456 if (xbp
>= XBUF_END
|| !count
)
2458 size_t to_write
= nmoved
+ ncr
;
2459 int written
= _write (handle
, xbuf
, to_write
);
2464 total_written
+= nmoved
; /* CRs aren't counted in ret value */
2466 /* If some, but not all were written (disk full?), return
2467 an estimate of the total written bytes not counting CRs. */
2468 if (written
< to_write
)
2469 return total_written
- (to_write
- written
) * nmoved
/to_write
;
2476 return total_written
;
2480 /* A low-level file-renaming function which works around Windows 95 bug.
2481 This is pulled directly out of DJGPP v2.01 library sources, and only
2482 used when you compile with DJGPP v2.0. */
2486 int _rename(const char *old
, const char *new)
2489 int olen
= strlen(old
) + 1;
2491 int use_lfn
= _USE_LFN
;
2492 char tempfile
[FILENAME_MAX
];
2493 const char *orig
= old
;
2496 r
.x
.dx
= __tb_offset
;
2497 r
.x
.di
= __tb_offset
+ olen
;
2498 r
.x
.ds
= r
.x
.es
= __tb_segment
;
2502 /* Windows 95 bug: for some filenames, when you rename
2503 file -> file~ (as in Emacs, to leave a backup), the
2504 short 8+3 alias doesn't change, which effectively
2505 makes OLD and NEW the same file. We must rename
2506 through a temporary file to work around this. */
2508 char *pbase
= 0, *p
;
2509 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
2510 int idx
= sizeof(try_char
) - 1;
2512 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
2513 might point to another drive, which will fail the DOS call. */
2514 strcpy(tempfile
, old
);
2515 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
2516 if (*p
== '/' || *p
== '\\' || *p
== ':')
2522 strcpy(pbase
, "X$$djren$$.$$temp$$");
2528 *pbase
= try_char
[--idx
];
2529 } while (_chmod(tempfile
, 0) != -1);
2532 _put_path2(tempfile
, olen
);
2534 __dpmi_int(0x21, &r
);
2537 errno
= __doserr_to_errno(r
.x
.ax
);
2541 /* Now create a file with the original name. This will
2542 ensure that NEW will always have a 8+3 alias
2543 different from that of OLD. (Seems to be required
2544 when NameNumericTail in the Registry is set to 0.) */
2545 lfn_fd
= _creat(old
, 0);
2547 olen
= strlen(tempfile
) + 1;
2549 r
.x
.di
= __tb_offset
+ olen
;
2558 _put_path2(new, olen
);
2560 __dpmi_int(0x21, &r
);
2563 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
2564 remove(new); /* and try again */
2567 errno
= __doserr_to_errno(r
.x
.ax
);
2569 /* Restore to original name if we renamed it to temporary. */
2577 _put_path2(orig
, olen
);
2578 _put_path(tempfile
);
2580 __dpmi_int(0x21, &r
);
2589 /* Success. Delete the file possibly created to work
2590 around the Windows 95 bug. */
2592 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
2596 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2598 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
2600 "Return non-nil if long file names are supported on MSDOS.")
2603 return (_USE_LFN
? Qt
: Qnil
);
2606 /* Convert alphabetic characters in a filename to lower-case. */
2609 msdos_downcase_filename (p
)
2610 register unsigned char *p
;
2612 /* Always lower-case drive letters a-z, even if the filesystem
2613 preserves case in filenames.
2614 This is so MSDOS filenames could be compared by string comparison
2615 functions that are case-sensitive. Even case-preserving filesystems
2616 do not distinguish case in drive letters. */
2617 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2623 /* Under LFN we expect to get pathnames in their true case. */
2624 if (NILP (Fmsdos_long_file_names ()))
2626 if (*p
>= 'A' && *p
<= 'Z')
2630 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
2632 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2633 When long filenames are supported, doesn't change FILENAME.\n\
2634 If FILENAME is not a string, returns nil.\n\
2635 The argument object is never altered--the value is a copy.")
2637 Lisp_Object filename
;
2641 if (! STRINGP (filename
))
2644 tem
= Fcopy_sequence (filename
);
2645 msdos_downcase_filename (XSTRING (tem
)->data
);
2649 /* The Emacs root directory as determined by init_environment. */
2651 static char emacsroot
[MAXPATHLEN
];
2654 rootrelativepath (rel
)
2657 static char result
[MAXPATHLEN
+ 10];
2659 strcpy (result
, emacsroot
);
2660 strcat (result
, "/");
2661 strcat (result
, rel
);
2665 /* Define a lot of environment variables if not already defined. Don't
2666 remove anything unless you know what you're doing -- lots of code will
2667 break if one or more of these are missing. */
2670 init_environment (argc
, argv
, skip_args
)
2678 /* Find our root from argv[0]. Assuming argv[0] is, say,
2679 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2680 root
= alloca (MAXPATHLEN
+ 20);
2681 _fixpath (argv
[0], root
);
2682 msdos_downcase_filename (root
);
2683 len
= strlen (root
);
2684 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
2687 if (len
> 4 && strcmp (root
+ len
- 4, "/bin") == 0)
2688 root
[len
- 4] = '\0';
2690 strcpy (root
, "c:/emacs"); /* Only under debuggers, I think. */
2691 len
= strlen (root
);
2692 strcpy (emacsroot
, root
);
2694 /* We default HOME to our root. */
2695 setenv ("HOME", root
, 0);
2697 /* We default EMACSPATH to root + "/bin". */
2698 strcpy (root
+ len
, "/bin");
2699 setenv ("EMACSPATH", root
, 0);
2701 /* I don't expect anybody to ever use other terminals so the internal
2702 terminal is the default. */
2703 setenv ("TERM", "internal", 0);
2705 #ifdef HAVE_X_WINDOWS
2706 /* Emacs expects DISPLAY to be set. */
2707 setenv ("DISPLAY", "unix:0.0", 0);
2710 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2711 downcase it and mirror the backslashes. */
2712 s
= getenv ("COMSPEC");
2713 if (!s
) s
= "c:/command.com";
2714 t
= alloca (strlen (s
) + 1);
2716 dostounix_filename (t
);
2717 setenv ("SHELL", t
, 0);
2719 /* PATH is also downcased and backslashes mirrored. */
2720 s
= getenv ("PATH");
2722 t
= alloca (strlen (s
) + 3);
2723 /* Current directory is always considered part of MsDos's path but it is
2724 not normally mentioned. Now it is. */
2725 strcat (strcpy (t
, ".;"), s
);
2726 dostounix_filename (t
); /* Not a single file name, but this should work. */
2727 setenv ("PATH", t
, 1);
2729 /* In some sense all dos users have root privileges, so... */
2730 setenv ("USER", "root", 0);
2731 setenv ("NAME", getenv ("USER"), 0);
2733 /* Time zone determined from country code. To make this possible, the
2734 country code may not span more than one time zone. In other words,
2735 in the USA, you lose. */
2737 switch (dos_country_code
)
2739 case 31: /* Belgium */
2740 case 32: /* The Netherlands */
2741 case 33: /* France */
2742 case 34: /* Spain */
2743 case 36: /* Hungary */
2744 case 38: /* Yugoslavia (or what's left of it?) */
2745 case 39: /* Italy */
2746 case 41: /* Switzerland */
2747 case 42: /* Tjekia */
2748 case 45: /* Denmark */
2749 case 46: /* Sweden */
2750 case 47: /* Norway */
2751 case 48: /* Poland */
2752 case 49: /* Germany */
2753 /* Daylight saving from last Sunday in March to last Sunday in
2754 September, both at 2AM. */
2755 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2757 case 44: /* United Kingdom */
2758 case 351: /* Portugal */
2759 case 354: /* Iceland */
2760 setenv ("TZ", "GMT+00", 0);
2762 case 81: /* Japan */
2763 case 82: /* Korea */
2764 setenv ("TZ", "JST-09", 0);
2766 case 90: /* Turkey */
2767 case 358: /* Finland */
2768 setenv ("TZ", "EET-02", 0);
2770 case 972: /* Israel */
2771 /* This is an approximation. (For exact rules, use the
2772 `zoneinfo/israel' file which comes with DJGPP, but you need
2773 to install it in `/usr/share/zoneinfo/' directory first.) */
2774 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2782 static int break_stat
; /* BREAK check mode status. */
2783 static int stdin_stat
; /* stdin IOCTL status. */
2787 /* These must be global. */
2788 static _go32_dpmi_seginfo ctrl_break_vector
;
2789 static _go32_dpmi_registers ctrl_break_regs
;
2790 static int ctrlbreakinstalled
= 0;
2792 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2795 ctrl_break_func (regs
)
2796 _go32_dpmi_registers
*regs
;
2802 install_ctrl_break_check ()
2804 if (!ctrlbreakinstalled
)
2806 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2807 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2808 ctrlbreakinstalled
= 1;
2809 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2810 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2812 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2816 #endif /* __DJGPP__ < 2 */
2818 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2819 control chars by DOS. Determine the keyboard type. */
2824 union REGS inregs
, outregs
;
2825 static int first_time
= 1;
2827 break_stat
= getcbrk ();
2830 install_ctrl_break_check ();
2836 int86 (0x15, &inregs
, &outregs
);
2837 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2841 if (internal_terminal
2842 #ifdef HAVE_X_WINDOWS
2843 && inhibit_window_system
2847 inregs
.x
.ax
= 0x0021;
2848 int86 (0x33, &inregs
, &outregs
);
2849 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2852 /* Reportedly, the above doesn't work for some mouse drivers. There
2853 is an additional detection method that should work, but might be
2854 a little slower. Use that as an alternative. */
2855 inregs
.x
.ax
= 0x0000;
2856 int86 (0x33, &inregs
, &outregs
);
2857 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2862 have_mouse
= 1; /* enable mouse */
2865 if (outregs
.x
.bx
== 3)
2867 mouse_button_count
= 3;
2868 mouse_button_translate
[0] = 0; /* Left */
2869 mouse_button_translate
[1] = 2; /* Middle */
2870 mouse_button_translate
[2] = 1; /* Right */
2874 mouse_button_count
= 2;
2875 mouse_button_translate
[0] = 0;
2876 mouse_button_translate
[1] = 1;
2878 mouse_position_hook
= &mouse_get_pos
;
2887 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
2888 return (stdin_stat
!= -1);
2891 return (setmode (fileno (stdin
), O_BINARY
) != -1);
2893 #else /* __DJGPP__ < 2 */
2897 /* I think it is wrong to overwrite `stdin_stat' every time
2898 but the first one this function is called, but I don't
2899 want to change the way it used to work in v1.x.--EZ */
2901 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2902 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2903 intdos (&inregs
, &outregs
);
2904 stdin_stat
= outregs
.h
.dl
;
2906 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
2907 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
2908 intdos (&inregs
, &outregs
);
2909 return !outregs
.x
.cflag
;
2911 #endif /* __DJGPP__ < 2 */
2914 /* Restore status of standard input and Ctrl-C checking. */
2919 union REGS inregs
, outregs
;
2921 setcbrk (break_stat
);
2926 return (setmode (fileno (stdin
), stdin_stat
) != -1);
2928 #else /* not __DJGPP__ >= 2 */
2930 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
2931 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2932 inregs
.x
.dx
= stdin_stat
;
2933 intdos (&inregs
, &outregs
);
2934 return !outregs
.x
.cflag
;
2936 #endif /* not __DJGPP__ >= 2 */
2940 /* Run command as specified by ARGV in directory DIR.
2941 The command is run with input from TEMPIN, output to
2942 file TEMPOUT and stderr to TEMPERR. */
2945 run_msdos_command (argv
, dir
, tempin
, tempout
, temperr
)
2946 unsigned char **argv
;
2948 int tempin
, tempout
, temperr
;
2950 char *saveargv1
, *saveargv2
, **envv
, *lowcase_argv0
, *pa
, *pl
;
2951 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
2952 int msshell
, result
= -1;
2953 int inbak
, outbak
, errbak
;
2957 /* Get current directory as MSDOS cwd is not per-process. */
2960 /* If argv[0] is the shell, it might come in any lettercase.
2961 Since `Fmember' is case-sensitive, we need to downcase
2962 argv[0], even if we are on case-preserving filesystems. */
2963 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
2964 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
2967 if (*pl
>= 'A' && *pl
<= 'Z')
2972 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
2973 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
2974 && !strcmp ("-c", argv
[1]);
2977 saveargv1
= argv
[1];
2978 saveargv2
= argv
[2];
2982 char *p
= alloca (strlen (argv
[2]) + 1);
2984 strcpy (argv
[2] = p
, saveargv2
);
2985 while (*p
&& isspace (*p
))
2987 while (*p
&& !isspace (*p
))
2995 /* Build the environment array. */
2997 extern Lisp_Object Vprocess_environment
;
2998 Lisp_Object tmp
, lst
;
3001 lst
= Vprocess_environment
;
3002 len
= XFASTINT (Flength (lst
));
3004 envv
= alloca ((len
+ 1) * sizeof (char *));
3005 for (i
= 0; i
< len
; i
++)
3009 CHECK_STRING (tmp
, 0);
3010 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
3011 strcpy (envv
[i
], XSTRING (tmp
)->data
);
3013 envv
[len
] = (char *) 0;
3017 chdir (XSTRING (dir
)->data
);
3021 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3022 goto done
; /* Allocation might fail due to lack of descriptors. */
3025 mouse_get_xy (&x
, &y
);
3027 dos_ttcooked (); /* do it here while 0 = stdin */
3035 if (msshell
&& !argv
[3])
3037 /* MS-DOS native shells are too restrictive. For starters, they
3038 cannot grok commands longer than 126 characters. In DJGPP v2
3039 and later, `system' is much smarter, so we'll call it instead. */
3041 extern char **environ
;
3044 /* A shell gets a single argument--its full command
3045 line--whose original was saved in `saveargv2'. */
3046 result
= system (saveargv2
);
3050 #endif /* __DJGPP__ > 1 */
3052 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
3065 mouse_moveto (x
, y
);
3068 /* Some programs might change the meaning of the highest bit of the
3069 text attribute byte, so we get blinking characters instead of the
3070 bright background colors. Restore that. */
3077 argv
[1] = saveargv1
;
3078 argv
[2] = saveargv2
;
3086 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3093 /* ------------------------- Compatibility functions -------------------
3098 /* Hostnames for a pc are not really funny,
3099 but they are used in change log so we emulate the best we can. */
3101 gethostname (p
, size
)
3105 char *q
= egetenv ("HOSTNAME");
3112 /* When time zones are set from Ms-Dos too many C-libraries are playing
3113 tricks with time values. We solve this by defining our own version
3114 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3115 once and after each call to `tzset' with TZ changed. That is
3116 accomplished by aliasing tzset to init_gettimeofday. */
3118 static struct tm time_rec
;
3121 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
3129 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
3133 time_rec
.tm_year
= d
.da_year
- 1900;
3134 time_rec
.tm_mon
= d
.da_mon
- 1;
3135 time_rec
.tm_mday
= d
.da_day
;
3138 time_rec
.tm_hour
= t
.ti_hour
;
3139 time_rec
.tm_min
= t
.ti_min
;
3140 time_rec
.tm_sec
= t
.ti_sec
;
3143 tm
.tm_gmtoff
= dos_timezone_offset
;
3145 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
3146 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
3148 /* Ignore tzp; it's obsolescent. */
3152 #endif /* __DJGPP__ < 2 */
3155 * A list of unimplemented functions that we silently ignore.
3159 unsigned alarm (s
) unsigned s
; {}
3160 fork () { return 0; }
3161 int kill (x
, y
) int x
, y
; { return -1; }
3163 void volatile pause () {}
3164 sigsetmask (x
) int x
; { return 0; }
3165 sigblock (mask
) int mask
; { return 0; }
3169 setpgrp () {return 0; }
3170 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
3171 unrequest_sigio () {}
3175 #ifdef POSIX_SIGNALS
3177 /* Augment DJGPP library POSIX signal functions. This is needed
3178 as of DJGPP v2.01, but might be in the library in later releases. */
3180 #include <libc/bss.h>
3182 /* A counter to know when to re-initialize the static sets. */
3183 static int sigprocmask_count
= -1;
3185 /* Which signals are currently blocked (initially none). */
3186 static sigset_t current_mask
;
3188 /* Which signals are pending (initially none). */
3189 static sigset_t pending_signals
;
3191 /* Previous handlers to restore when the blocked signals are unblocked. */
3192 typedef void (*sighandler_t
)(int);
3193 static sighandler_t prev_handlers
[320];
3195 /* A signal handler which just records that a signal occured
3196 (it will be raised later, if and when the signal is unblocked). */
3198 sig_suspender (signo
)
3201 sigaddset (&pending_signals
, signo
);
3205 sigprocmask (how
, new_set
, old_set
)
3207 const sigset_t
*new_set
;
3213 /* If called for the first time, initialize. */
3214 if (sigprocmask_count
!= __bss_count
)
3216 sigprocmask_count
= __bss_count
;
3217 sigemptyset (&pending_signals
);
3218 sigemptyset (¤t_mask
);
3219 for (signo
= 0; signo
< 320; signo
++)
3220 prev_handlers
[signo
] = SIG_ERR
;
3224 *old_set
= current_mask
;
3229 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
3235 sigemptyset (&new_mask
);
3237 /* DJGPP supports upto 320 signals. */
3238 for (signo
= 0; signo
< 320; signo
++)
3240 if (sigismember (¤t_mask
, signo
))
3241 sigaddset (&new_mask
, signo
);
3242 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
3244 sigaddset (&new_mask
, signo
);
3246 /* SIGKILL is silently ignored, as on other platforms. */
3247 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
3248 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
3250 if (( how
== SIG_UNBLOCK
3251 && sigismember (&new_mask
, signo
)
3252 && sigismember (new_set
, signo
))
3253 || (how
== SIG_SETMASK
3254 && sigismember (&new_mask
, signo
)
3255 && !sigismember (new_set
, signo
)))
3257 sigdelset (&new_mask
, signo
);
3258 if (prev_handlers
[signo
] != SIG_ERR
)
3260 signal (signo
, prev_handlers
[signo
]);
3261 prev_handlers
[signo
] = SIG_ERR
;
3263 if (sigismember (&pending_signals
, signo
))
3265 sigdelset (&pending_signals
, signo
);
3270 current_mask
= new_mask
;
3274 #else /* not POSIX_SIGNALS */
3276 sigsetmask (x
) int x
; { return 0; }
3277 sigblock (mask
) int mask
; { return 0; }
3279 #endif /* not POSIX_SIGNALS */
3280 #endif /* __DJGPP__ > 1 */
3283 #include "sysselect.h"
3285 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3286 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3287 ((long)(time).tv_sec < 0 \
3288 || ((time).tv_sec == 0 \
3289 && (long)(time).tv_usec <= 0))
3293 /* Only event queue is checked. */
3294 /* We don't have to call timer_check here
3295 because wait_reading_process_input takes care of that. */
3297 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
3299 SELECT_TYPE
*rfds
, *wfds
, *efds
;
3300 EMACS_TIME
*timeout
;
3308 check_input
= FD_ISSET (0, rfds
);
3319 /* If we are looking only for the terminal, with no timeout,
3320 just read it and wait -- that's more efficient. */
3323 while (!detect_input_pending ())
3332 EMACS_TIME clnow
, cllast
, cldiff
;
3335 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
3337 while (!check_input
|| !detect_input_pending ())
3340 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
3341 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
3343 /* When seconds wrap around, we assume that no more than
3344 1 minute passed since last `gettime'. */
3345 if (EMACS_TIME_NEG_P (cldiff
))
3346 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
3347 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
3349 /* Stop when timeout value crosses zero. */
3350 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
3365 * Define overlaid functions:
3367 * chdir -> sys_chdir
3368 * tzset -> init_gettimeofday
3369 * abort -> dos_abort
3374 extern int chdir ();
3380 int len
= strlen (path
);
3381 char *tmp
= (char *)path
;
3383 if (*tmp
&& tmp
[1] == ':')
3385 if (getdisk () != tolower (tmp
[0]) - 'a')
3386 setdisk (tolower (tmp
[0]) - 'a');
3387 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
3391 if (len
> 1 && (tmp
[len
- 1] == '/'))
3393 char *tmp1
= (char *) alloca (len
+ 1);
3404 extern void tzset (void);
3407 init_gettimeofday ()
3413 ltm
= gtm
= time (NULL
);
3414 ltm
= mktime (lstm
= localtime (<m
));
3415 gtm
= mktime (gmtime (>m
));
3416 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
3417 time_rec
.tm_isdst
= lstm
->tm_isdst
;
3418 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
3425 dos_abort (file
, line
)
3429 char buffer1
[200], buffer2
[400];
3432 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
3433 for (i
= j
= 0; buffer1
[i
]; i
++) {
3434 buffer2
[j
++] = buffer1
[i
];
3435 buffer2
[j
++] = 0x70;
3437 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
3438 ScreenSetCursor (2, 0);
3446 ScreenSetCursor (10, 0);
3447 cputs ("\r\n\nEmacs aborted!\r\n");
3449 /* Generate traceback, so we could tell whodunit. */
3450 signal (SIGINT
, SIG_DFL
);
3451 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3459 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
3460 staticpro (&recent_doskeys
);
3462 defsubr (&Srecent_doskeys
);
3463 defsubr (&Smsdos_long_file_names
);
3464 defsubr (&Smsdos_downcase_filename
);