1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997 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
);
161 mouse_get_xy (int *x
, int *y
)
166 int86 (0x33, ®s
, ®s
);
178 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
180 mouse_last_x
= regs
.x
.cx
= x
* 8;
181 mouse_last_y
= regs
.x
.dx
= y
* 8;
182 int86 (0x33, ®s
, ®s
);
186 mouse_pressed (b
, xp
, yp
)
191 if (b
>= mouse_button_count
)
194 regs
.x
.bx
= mouse_button_translate
[b
];
195 int86 (0x33, ®s
, ®s
);
197 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
198 return (regs
.x
.bx
!= 0);
202 mouse_released (b
, xp
, yp
)
207 if (b
>= mouse_button_count
)
210 regs
.x
.bx
= mouse_button_translate
[b
];
211 int86 (0x33, ®s
, ®s
);
213 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
214 return (regs
.x
.bx
!= 0);
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
;
226 Lisp_Object frame
, tail
;
228 /* Clear the mouse-moved flag for every frame on this display. */
229 FOR_EACH_FRAME (tail
, frame
)
230 XFRAME (frame
)->mouse_moved
= 0;
234 mouse_get_xy (&ix
, &iy
);
235 *time
= event_timestamp ();
236 *x
= make_number (mouse_last_x
= ix
);
237 *y
= make_number (mouse_last_y
= iy
);
245 mouse_get_xy (&x
, &y
);
246 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
257 fprintf (termscript
, "<M_INIT>");
260 int86 (0x33, ®s
, ®s
);
264 regs
.x
.dx
= 8 * (ScreenCols () - 1);
265 int86 (0x33, ®s
, ®s
);
269 regs
.x
.dx
= 8 * (ScreenRows () - 1);
270 int86 (0x33, ®s
, ®s
);
276 /* ------------------------- Screen control ----------------------
280 static int internal_terminal
= 0;
282 #ifndef HAVE_X_WINDOWS
283 extern unsigned char ScreenAttrib
;
284 static int screen_face
;
285 static int highlight
;
287 static int screen_size_X
;
288 static int screen_size_Y
;
289 static int screen_size
;
291 static int current_pos_X
;
292 static int current_pos_Y
;
293 static int new_pos_X
;
294 static int new_pos_Y
;
296 static void *startup_screen_buffer
;
297 static int startup_screen_size_X
;
298 static int startup_screen_size_Y
;
299 static int startup_pos_X
;
300 static int startup_pos_Y
;
301 static unsigned char startup_screen_attrib
;
303 static int term_setup_done
;
305 /* Similar to the_only_frame. */
306 struct x_output the_only_x_display
;
308 /* This is never dereferenced. */
309 Display
*x_current_display
;
312 dos_direct_output (y
, x
, buf
, len
)
318 int t
= (int) ScreenPrimary
+ 2 * (x
+ y
* screen_size_X
);
322 dosmemput (buf
++, 1, t
);
326 /* This is faster. */
327 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
328 _farnspokeb (t
, *buf
);
333 /* Flash the screen as a substitute for BEEPs. */
337 do_visible_bell (xorattr
)
338 unsigned char xorattr
;
343 movl _ScreenPrimary,%%eax
350 xorb %%al,%%gs:(%%ebx)
366 : "m" (xorattr
), "g" (screen_size
)
367 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
371 ScreenVisualBell (void)
373 /* This creates an xor-mask that will swap the default fore- and
374 background colors. */
375 do_visible_bell (((the_only_x_display
.foreground_pixel
376 ^ the_only_x_display
.background_pixel
)
381 #ifndef HAVE_X_WINDOWS
383 static int blink_bit
= -1; /* the state of the blink bit at startup */
385 /* Enable bright background colors. */
391 /* Remember the original state of the blink/bright-background bit.
392 It is stored at 0040:0065h in the BIOS data area. */
394 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
398 int86 (0x10, ®s
, ®s
);
401 /* Disable bright background colors (and enable blinking) if we found
402 the video system in that state at startup. */
404 maybe_enable_blinking (void)
412 int86 (0x10, ®s
, ®s
);
416 /* Set the screen dimensions so that it can show no less than
417 ROWS x COLS frame. */
420 dos_set_window_size (rows
, cols
)
424 Lisp_Object video_mode
;
425 int video_mode_value
;
428 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
430 if (*rows
== current_rows
&& *cols
== current_cols
)
433 /* Do we have a VGA? */
435 int86 (0x10, ®s
, ®s
);
436 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
441 /* If the user specified a special video mode for these dimensions,
443 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
444 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
447 if (INTEGERP (video_mode
)
448 && (video_mode_value
= XINT (video_mode
)) > 0)
450 regs
.x
.ax
= video_mode_value
;
451 int86 (0x10, ®s
, ®s
);
455 /* Must hardware-reset the mouse, or else it won't update
456 its notion of screen dimensions for some non-standard
457 video modes. This is *painfully* slow... */
459 int86 (0x33, ®s
, ®s
);
463 /* Find one of the dimensions supported by standard EGA/VGA
464 which gives us at least the required dimensions. */
473 } std_dimension
[] = {
483 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
485 if (std_dimension
[i
].need_vga
<= have_vga
486 && std_dimension
[i
].rows
>= *rows
)
488 if (std_dimension
[i
].rows
!= current_rows
489 || *cols
!= current_cols
)
490 _set_screen_lines (std_dimension
[i
].rows
);
497 #else /* not __DJGPP__ > 1 */
499 else if (*rows
<= 25)
501 if (current_rows
!= 25 || current_cols
!= 80)
504 int86 (0x10, ®s
, ®s
);
507 int86 (0x10, ®s
, ®s
);
510 int86 (0x10, ®s
, ®s
);
512 int86 (0x10, ®s
, ®s
);
515 else if (*rows
<= 50)
516 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
517 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
520 int86 (0x10, ®s
, ®s
);
523 int86 (0x10, ®s
, ®s
);
526 int86 (0x10, ®s
, ®s
);
529 int86 (0x10, ®s
, ®s
);
531 #endif /* not __DJGPP__ > 1 */
539 /* Tell the caller what dimensions have been REALLY set. */
540 *rows
= ScreenRows ();
541 *cols
= ScreenCols ();
543 /* Enable bright background colors. */
547 /* If we write a character in the position where the mouse is,
548 the mouse cursor may need to be refreshed. */
558 mouse_get_xy (&x
, &y
);
559 if (y
!= new_pos_Y
|| x
< new_pos_X
)
575 union REGS inregs
, outregs
;
578 intdos (&inregs
, &outregs
);
583 IT_set_face (int face
)
586 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
588 if (face
== 1 || (face
== 0 && highlight
))
589 fp
= FRAME_MODE_LINE_FACE (foo
);
590 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
591 fp
= FRAME_DEFAULT_FACE (foo
);
593 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
595 fprintf (termscript
, "<FACE %d: %d/%d>",
596 face
, FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
598 ScreenAttrib
= (FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
);
602 IT_write_glyphs (GLYPH
*str
, int len
)
606 unsigned char *buf
, *bp
;
608 if (len
== 0) return;
610 buf
= bp
= alloca (len
* 2);
614 newface
= FAST_GLYPH_FACE (*str
);
615 if (newface
!= screen_face
)
616 IT_set_face (newface
);
617 ch
= FAST_GLYPH_CHAR (*str
);
618 *bp
++ = (unsigned char)ch
;
619 *bp
++ = ScreenAttrib
;
622 fputc (ch
, termscript
);
627 dosmemput (buf
, 2 * len
,
628 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
633 IT_clear_end_of_line (first_unused
)
640 fprintf (termscript
, "<CLR:EOL>");
641 i
= (j
= screen_size_X
- new_pos_X
) * 2;
642 spaces
= sp
= alloca (i
);
647 *sp
++ = ScreenAttrib
;
651 dosmemput (spaces
, i
,
652 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
656 IT_clear_screen (void)
659 fprintf (termscript
, "<CLR:SCR>");
663 new_pos_X
= new_pos_Y
= 0;
667 IT_clear_to_end (void)
670 fprintf (termscript
, "<CLR:EOS>");
672 while (new_pos_Y
< screen_size_Y
) {
674 IT_clear_end_of_line (0);
680 IT_cursor_to (int y
, int x
)
683 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
688 static int cursor_cleared
;
691 IT_display_cursor (int on
)
693 if (on
&& cursor_cleared
)
695 ScreenSetCursor (current_pos_Y
, current_pos_X
);
698 else if (!on
&& !cursor_cleared
)
700 ScreenSetCursor (-1, -1);
705 /* Emacs calls cursor-movement functions a lot when it updates the
706 display (probably a legacy of old terminals where you cannot
707 update a screen line without first moving the cursor there).
708 However, cursor movement is expensive on MSDOS (it calls a slow
709 BIOS function and requires 2 mode switches), while actual screen
710 updates access the video memory directly and don't depend on
711 cursor position. To avoid slowing down the redisplay, we cheat:
712 all functions that move the cursor only set internal variables
713 which record the cursor position, whereas the cursor is only
714 moved to its final position whenever screen update is complete.
716 `IT_cmgoto' is called from the keyboard reading loop and when the
717 frame update is complete. This means that we are ready for user
718 input, so we update the cursor position to show where the point is,
719 and also make the mouse pointer visible.
721 Special treatment is required when the cursor is in the echo area,
722 to put the cursor at the end of the text displayed there. */
728 /* Only set the cursor to where it should be if the display is
729 already in sync with the window contents. */
730 int update_cursor_pos
= MODIFF
== unchanged_modified
;
732 /* If we are in the echo area, put the cursor at the end of text. */
733 if (!update_cursor_pos
734 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
736 new_pos_X
= FRAME_DESIRED_GLYPHS (f
)->used
[new_pos_Y
];
737 update_cursor_pos
= 1;
740 if (update_cursor_pos
741 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
743 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
745 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
748 /* Maybe cursor is invisible, so make it visible. */
749 IT_display_cursor (1);
751 /* Mouse pointer should be always visible if we are waiting for
758 IT_reassert_line_highlight (new, vpos
)
762 IT_set_face (0); /* To possibly clear the highlighting. */
766 IT_change_line_highlight (new_highlight
, vpos
, first_unused_hpos
)
768 highlight
= new_highlight
;
769 IT_set_face (0); /* To possibly clear the highlighting. */
770 IT_cursor_to (vpos
, 0);
771 IT_clear_end_of_line (first_unused_hpos
);
778 IT_set_face (0); /* To possibly clear the highlighting. */
787 /* set-window-configuration on window.c needs this. */
789 x_set_menu_bar_lines (f
, value
, oldval
)
791 Lisp_Object value
, oldval
;
793 set_menu_bar_lines (f
, value
, oldval
);
796 /* This was copied from xfns.c */
798 Lisp_Object Qbackground_color
;
799 Lisp_Object Qforeground_color
;
800 extern Lisp_Object Qtitle
;
802 /* IT_set_terminal_modes is called when emacs is started,
803 resumed, and whenever the screen is redrawn! */
806 IT_set_terminal_modes (void)
809 fprintf (termscript
, "\n<SET_TERM>");
812 screen_size_X
= ScreenCols ();
813 screen_size_Y
= ScreenRows ();
814 screen_size
= screen_size_X
* screen_size_Y
;
816 new_pos_X
= new_pos_Y
= 0;
817 current_pos_X
= current_pos_Y
= -1;
823 startup_screen_size_X
= screen_size_X
;
824 startup_screen_size_Y
= screen_size_Y
;
825 startup_screen_attrib
= ScreenAttrib
;
827 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
828 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
831 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
832 screen_size_X
, screen_size_Y
);
837 /* IT_reset_terminal_modes is called when emacs is
838 suspended or killed. */
841 IT_reset_terminal_modes (void)
843 int display_row_start
= (int) ScreenPrimary
;
844 int saved_row_len
= startup_screen_size_X
* 2;
845 int update_row_len
= ScreenCols () * 2;
846 int current_rows
= ScreenRows ();
847 int to_next_row
= update_row_len
;
848 unsigned char *saved_row
= startup_screen_buffer
;
849 int cursor_pos_X
= ScreenCols () - 1;
850 int cursor_pos_Y
= ScreenRows () - 1;
853 fprintf (termscript
, "\n<RESET_TERM>");
857 if (!term_setup_done
)
862 /* Leave the video system in the same state as we found it,
863 as far as the blink/bright-background bit is concerned. */
864 maybe_enable_blinking ();
866 /* We have a situation here.
867 We cannot just do ScreenUpdate(startup_screen_buffer) because
868 the luser could have changed screen dimensions inside Emacs
869 and failed (or didn't want) to restore them before killing
870 Emacs. ScreenUpdate() uses the *current* screen dimensions and
871 thus will happily use memory outside what was allocated for
872 `startup_screen_buffer'.
873 Thus we only restore as much as the current screen dimensions
874 can hold, and clear the rest (if the saved screen is smaller than
875 the current) with the color attribute saved at startup. The cursor
876 is also restored within the visible dimensions. */
878 ScreenAttrib
= startup_screen_attrib
;
881 if (update_row_len
> saved_row_len
)
882 update_row_len
= saved_row_len
;
883 if (current_rows
> startup_screen_size_Y
)
884 current_rows
= startup_screen_size_Y
;
887 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
888 update_row_len
/ 2, current_rows
);
890 while (current_rows
--)
892 dosmemput (saved_row
, update_row_len
, display_row_start
);
893 saved_row
+= saved_row_len
;
894 display_row_start
+= to_next_row
;
896 if (startup_pos_X
< cursor_pos_X
)
897 cursor_pos_X
= startup_pos_X
;
898 if (startup_pos_Y
< cursor_pos_Y
)
899 cursor_pos_Y
= startup_pos_Y
;
901 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
902 xfree (startup_screen_buffer
);
908 IT_set_terminal_window (void)
913 IT_set_frame_parameters (f
, alist
)
918 int length
= XINT (Flength (alist
));
921 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
923 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
925 extern unsigned long load_color ();
929 /* Extract parm names and values into those vectors. */
931 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
936 parms
[i
] = Fcar (elt
);
937 CHECK_SYMBOL (parms
[i
], 1);
938 values
[i
] = Fcdr (elt
);
943 /* Now process them in reverse of specified order. */
944 for (i
--; i
>= 0; i
--)
946 Lisp_Object prop
= parms
[i
];
947 Lisp_Object val
= values
[i
];
949 if (EQ (prop
, Qforeground_color
))
951 unsigned long new_color
= load_color (f
, val
);
954 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
957 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
960 else if (EQ (prop
, Qbackground_color
))
962 unsigned long new_color
= load_color (f
, val
);
965 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
968 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
971 else if (EQ (prop
, Qtitle
))
973 x_set_title (f
, val
);
975 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
977 else if (EQ (prop
, intern ("reverse")) && EQ (val
, Qt
))
979 unsigned long fg
= FRAME_FOREGROUND_PIXEL (f
);
981 FRAME_FOREGROUND_PIXEL (f
) = FRAME_BACKGROUND_PIXEL (f
);
982 FRAME_BACKGROUND_PIXEL (f
) = fg
;
984 fprintf (termscript
, "<INVERSE-VIDEO>\n");
986 store_frame_param (f
, prop
, val
);
992 extern void recompute_basic_faces (FRAME_PTR
);
993 extern void redraw_frame (FRAME_PTR
);
995 recompute_basic_faces (f
);
996 if (f
== selected_frame
)
1001 extern void init_frame_faces (FRAME_PTR
);
1003 #endif /* !HAVE_X_WINDOWS */
1006 /* Do we need the internal terminal? */
1009 internal_terminal_init ()
1011 char *term
= getenv ("TERM");
1014 #ifdef HAVE_X_WINDOWS
1015 if (!inhibit_window_system
)
1020 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1022 if (getenv ("EMACSTEST"))
1023 termscript
= fopen (getenv ("EMACSTEST"), "wt");
1025 #ifndef HAVE_X_WINDOWS
1026 if (!internal_terminal
|| inhibit_window_system
)
1028 selected_frame
->output_method
= output_termcap
;
1032 Vwindow_system
= intern ("pc");
1033 Vwindow_system_version
= make_number (1);
1035 bzero (&the_only_x_display
, sizeof the_only_x_display
);
1036 the_only_x_display
.background_pixel
= 7; /* White */
1037 the_only_x_display
.foreground_pixel
= 0; /* Black */
1039 colors
= getenv ("EMACSCOLORS");
1040 if (colors
&& strlen (colors
) >= 2)
1042 /* The colors use 4 bits each (we enable bright background). */
1043 if (isdigit (colors
[0]))
1045 else if (isxdigit (colors
[0]))
1046 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1047 if (colors
[0] >= 0 && colors
[0] < 16)
1048 the_only_x_display
.foreground_pixel
= colors
[0];
1049 if (isdigit (colors
[1]))
1051 else if (isxdigit (colors
[1]))
1052 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1053 if (colors
[1] >= 0 && colors
[1] < 16)
1054 the_only_x_display
.background_pixel
= colors
[1];
1056 the_only_x_display
.line_height
= 1;
1057 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
1059 init_frame_faces (selected_frame
);
1061 ring_bell_hook
= IT_ring_bell
;
1062 write_glyphs_hook
= IT_write_glyphs
;
1063 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
1064 clear_to_end_hook
= IT_clear_to_end
;
1065 clear_end_of_line_hook
= IT_clear_end_of_line
;
1066 clear_frame_hook
= IT_clear_screen
;
1067 change_line_highlight_hook
= IT_change_line_highlight
;
1068 update_begin_hook
= IT_update_begin
;
1069 update_end_hook
= IT_update_end
;
1070 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
1071 frame_up_to_date_hook
= IT_cmgoto
; /* position cursor when update is done */
1073 /* These hooks are called by term.c without being checked. */
1074 set_terminal_modes_hook
= IT_set_terminal_modes
;
1075 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1076 set_terminal_window_hook
= IT_set_terminal_window
;
1080 dos_get_saved_screen (screen
, rows
, cols
)
1085 #ifndef HAVE_X_WINDOWS
1086 *screen
= startup_screen_buffer
;
1087 *cols
= startup_screen_size_X
;
1088 *rows
= startup_screen_size_Y
;
1095 #ifndef HAVE_X_WINDOWS
1097 /* We are not X, but we can emulate it well enough for our needs... */
1101 if (! FRAME_MSDOS_P (selected_frame
))
1102 error ("Not running under a windows system");
1108 /* ----------------------- Keyboard control ----------------------
1110 * Keymaps reflect the following keyboard layout:
1112 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1113 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1114 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1115 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1119 static int extended_kbd
; /* 101 (102) keyboard present. */
1121 struct dos_keyboard_map
1129 static struct dos_keyboard_map us_keyboard
= {
1131 /* 01234567890123456789012345678901234567890 12345678901234 */
1132 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1133 /* 0123456789012345678901234567890123456789 012345678901234 */
1134 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1135 0 /* no Alt-Gr key */
1138 static struct dos_keyboard_map fr_keyboard
= {
1140 /* 012 3456789012345678901234567890123456789012345678901234 */
1141 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1142 /* 0123456789012345678901234567890123456789012345678901234 */
1143 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1144 /* 01234567 89012345678901234567890123456789012345678901234 */
1148 static struct dos_keyboard_map dk_keyboard
= {
1150 /* 0123456789012345678901234567890123456789012345678901234 */
1151 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
1152 /* 01 23456789012345678901234567890123456789012345678901234 */
1153 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
1154 /* 0123456789012345678901234567890123456789012345678901234 */
1158 static struct keyboard_layout_list
1161 struct dos_keyboard_map
*keyboard_map
;
1162 } keyboard_layout_list
[] =
1169 static struct dos_keyboard_map
*keyboard
;
1170 static int keyboard_map_all
;
1171 static int international_keyboard
;
1174 dos_set_keyboard (code
, always
)
1181 /* See if Keyb.Com is installed (for international keyboard support). */
1183 int86 (0x2f, ®s
, ®s
);
1184 if (regs
.h
.al
== 0xff)
1185 international_keyboard
= 1;
1187 /* Initialize to US settings, for countries that don't have their own. */
1188 keyboard
= keyboard_layout_list
[0].keyboard_map
;
1189 keyboard_map_all
= always
;
1190 dos_keyboard_layout
= 1;
1192 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
1193 if (code
== keyboard_layout_list
[i
].country_code
)
1195 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
1196 keyboard_map_all
= always
;
1197 dos_keyboard_layout
= code
;
1203 #define Ignore 0x0000
1204 #define Normal 0x0000 /* normal key - alt changes scan-code */
1205 #define FctKey 0x1000 /* func key if c == 0, else c */
1206 #define Special 0x2000 /* func key even if c != 0 */
1207 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1208 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1209 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1210 #define Grey 0x6000 /* Grey keypad key */
1212 #define Alt 0x0100 /* alt scan-code */
1213 #define Ctrl 0x0200 /* ctrl scan-code */
1214 #define Shift 0x0400 /* shift scan-code */
1218 unsigned char char_code
; /* normal code */
1219 unsigned char meta_code
; /* M- code */
1220 unsigned char keypad_code
; /* keypad code */
1221 unsigned char editkey_code
; /* edit key */
1222 } keypad_translate_map
[] = {
1223 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1224 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1225 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1226 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1227 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1228 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1229 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1230 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1231 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1232 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1233 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1238 unsigned char char_code
; /* normal code */
1239 unsigned char keypad_code
; /* keypad code */
1240 } grey_key_translate_map
[] = {
1241 '/', 0xaf, /* kp-decimal */
1242 '*', 0xaa, /* kp-multiply */
1243 '-', 0xad, /* kp-subtract */
1244 '+', 0xab, /* kp-add */
1245 '\r', 0x8d /* kp-enter */
1248 static unsigned short
1249 ibmpc_translate_map
[] =
1251 /* --------------- 00 to 0f --------------- */
1252 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
1253 Alt
| ModFct
| 0x1b, /* Escape */
1254 Normal
| 1, /* '1' */
1255 Normal
| 2, /* '2' */
1256 Normal
| 3, /* '3' */
1257 Normal
| 4, /* '4' */
1258 Normal
| 5, /* '5' */
1259 Normal
| 6, /* '6' */
1260 Normal
| 7, /* '7' */
1261 Normal
| 8, /* '8' */
1262 Normal
| 9, /* '9' */
1263 Normal
| 10, /* '0' */
1264 Normal
| 11, /* '-' */
1265 Normal
| 12, /* '=' */
1266 Special
| 0x08, /* Backspace */
1267 ModFct
| 0x74, /* Tab/Backtab */
1269 /* --------------- 10 to 1f --------------- */
1282 ModFct
| 0x0d, /* Return */
1287 /* --------------- 20 to 2f --------------- */
1296 Map
| 40, /* '\'' */
1298 Ignore
, /* Left shift */
1299 Map
| 41, /* '\\' */
1305 /* --------------- 30 to 3f --------------- */
1312 Ignore
, /* Right shift */
1313 Grey
| 1, /* Grey * */
1315 Normal
| ' ', /* ' ' */
1316 Ignore
, /* Caps Lock */
1317 FctKey
| 0xbe, /* F1 */
1318 FctKey
| 0xbf, /* F2 */
1319 FctKey
| 0xc0, /* F3 */
1320 FctKey
| 0xc1, /* F4 */
1321 FctKey
| 0xc2, /* F5 */
1323 /* --------------- 40 to 4f --------------- */
1324 FctKey
| 0xc3, /* F6 */
1325 FctKey
| 0xc4, /* F7 */
1326 FctKey
| 0xc5, /* F8 */
1327 FctKey
| 0xc6, /* F9 */
1328 FctKey
| 0xc7, /* F10 */
1329 Ignore
, /* Num Lock */
1330 Ignore
, /* Scroll Lock */
1331 KeyPad
| 7, /* Home */
1332 KeyPad
| 8, /* Up */
1333 KeyPad
| 9, /* Page Up */
1334 Grey
| 2, /* Grey - */
1335 KeyPad
| 4, /* Left */
1336 KeyPad
| 5, /* Keypad 5 */
1337 KeyPad
| 6, /* Right */
1338 Grey
| 3, /* Grey + */
1339 KeyPad
| 1, /* End */
1341 /* --------------- 50 to 5f --------------- */
1342 KeyPad
| 2, /* Down */
1343 KeyPad
| 3, /* Page Down */
1344 KeyPad
| 0, /* Insert */
1345 KeyPad
| 10, /* Delete */
1346 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1347 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1348 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1349 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1350 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1351 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1352 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1353 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1354 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1355 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1356 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1357 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1359 /* --------------- 60 to 6f --------------- */
1360 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1361 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1362 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1363 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1364 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1365 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1366 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1367 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1368 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1369 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1370 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1371 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1372 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1373 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1374 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1375 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1377 /* --------------- 70 to 7f --------------- */
1378 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1379 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1380 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1381 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1382 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1383 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1384 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1385 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1386 Alt
| Map
| 1, /* '1' */
1387 Alt
| Map
| 2, /* '2' */
1388 Alt
| Map
| 3, /* '3' */
1389 Alt
| Map
| 4, /* '4' */
1390 Alt
| Map
| 5, /* '5' */
1391 Alt
| Map
| 6, /* '6' */
1392 Alt
| Map
| 7, /* '7' */
1393 Alt
| Map
| 8, /* '8' */
1395 /* --------------- 80 to 8f --------------- */
1396 Alt
| Map
| 9, /* '9' */
1397 Alt
| Map
| 10, /* '0' */
1398 Alt
| Map
| 11, /* '-' */
1399 Alt
| Map
| 12, /* '=' */
1400 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1401 FctKey
| 0xc8, /* F11 */
1402 FctKey
| 0xc9, /* F12 */
1403 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1404 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1405 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1406 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1407 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1408 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1409 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1410 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1411 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1413 /* --------------- 90 to 9f --------------- */
1414 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1415 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1416 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1417 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1418 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1419 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1420 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1421 Alt
| FctKey
| 0x50, /* (Alt) Home */
1422 Alt
| FctKey
| 0x52, /* (Alt) Up */
1423 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1424 Ignore
, /* NO KEY */
1425 Alt
| FctKey
| 0x51, /* (Alt) Left */
1426 Ignore
, /* NO KEY */
1427 Alt
| FctKey
| 0x53, /* (Alt) Right */
1428 Ignore
, /* NO KEY */
1429 Alt
| FctKey
| 0x57, /* (Alt) End */
1431 /* --------------- a0 to af --------------- */
1432 Alt
| KeyPad
| 2, /* (Alt) Down */
1433 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1434 Alt
| KeyPad
| 0, /* (Alt) Insert */
1435 Alt
| KeyPad
| 10, /* (Alt) Delete */
1436 Alt
| Grey
| 0, /* (Alt) Grey / */
1437 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1438 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1441 /* These bit-positions corresponds to values returned by BIOS */
1442 #define SHIFT_P 0x0003 /* two bits! */
1443 #define CTRL_P 0x0004
1444 #define ALT_P 0x0008
1445 #define SCRLOCK_P 0x0010
1446 #define NUMLOCK_P 0x0020
1447 #define CAPSLOCK_P 0x0040
1448 #define ALT_GR_P 0x0800
1449 #define SUPER_P 0x4000 /* pseudo */
1450 #define HYPER_P 0x8000 /* pseudo */
1453 dos_get_modifiers (keymask
)
1460 /* Calculate modifier bits */
1461 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1462 int86 (0x16, ®s
, ®s
);
1466 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1467 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1471 mask
= regs
.h
.al
& (SHIFT_P
|
1472 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1474 /* Do not break international keyboard support. */
1475 /* When Keyb.Com is loaded, the right Alt key is */
1476 /* used for accessing characters like { and } */
1477 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1480 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1483 if (dos_hyper_key
== 1)
1486 modifiers
|= hyper_modifier
;
1488 else if (dos_super_key
== 1)
1491 modifiers
|= super_modifier
;
1493 else if (!international_keyboard
)
1495 /* If Keyb.Com is NOT installed, let Right Alt behave
1496 like the Left Alt. */
1502 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
1505 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
1507 if (dos_hyper_key
== 2)
1510 modifiers
|= hyper_modifier
;
1512 else if (dos_super_key
== 2)
1515 modifiers
|= super_modifier
;
1523 modifiers
|= shift_modifier
;
1525 modifiers
|= ctrl_modifier
;
1527 modifiers
|= meta_modifier
;
1534 #define NUM_RECENT_DOSKEYS (100)
1535 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1536 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1537 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1539 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1540 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1541 Each input key receives two values in this vector: first the ASCII code,\n\
1542 and then the scan code.")
1545 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1548 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1549 return Fvector (total_doskeys
, keys
);
1552 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1553 bcopy (keys
+ recent_doskeys_index
,
1554 XVECTOR (val
)->contents
,
1555 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1557 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1558 recent_doskeys_index
* sizeof (Lisp_Object
));
1563 /* Get a char from keyboard. Function keys are put into the event queue. */
1565 extern void kbd_buffer_store_event (struct input_event
*);
1570 struct input_event event
;
1573 #ifndef HAVE_X_WINDOWS
1574 /* Maybe put the cursor where it should be. */
1575 IT_cmgoto (selected_frame
);
1578 /* The following condition is equivalent to `kbhit ()', except that
1579 it uses the bios to do its job. This pleases DESQview/X. */
1580 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1581 int86 (0x16, ®s
, ®s
),
1582 (regs
.x
.flags
& 0x40) == 0)
1585 register unsigned char c
;
1586 int sc
, code
, mask
, kp_mode
;
1589 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1590 int86 (0x16, ®s
, ®s
);
1595 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1597 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1598 recent_doskeys_index
= 0;
1599 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1601 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1602 recent_doskeys_index
= 0;
1604 modifiers
= dos_get_modifiers (&mask
);
1606 #ifndef HAVE_X_WINDOWS
1607 if (!NILP (Vdos_display_scancodes
))
1610 sprintf (buf
, "%02x:%02x*%04x",
1611 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1612 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1620 case 10: /* Ctrl Grey Enter */
1621 code
= Ctrl
| Grey
| 4;
1623 case 13: /* Grey Enter */
1626 case '/': /* Grey / */
1636 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1638 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1644 /* We only look at the keyboard Ctrl/Shift/Alt keys when
1645 Emacs is ready to read a key. Therefore, if they press
1646 `Alt-x' when Emacs is busy, by the time we get to
1647 `dos_get_modifiers', they might have already released the
1648 Alt key, and Emacs gets just `x', which is BAD.
1649 However, for keys with the `Map' property set, the ASCII
1650 code returns zero iff Alt is pressed. So, when we DON'T
1651 have to support international_keyboard, we don't have to
1652 distinguish between the left and right Alt keys, and we
1653 can set the META modifier for any keys with the `Map'
1654 property if they return zero ASCII code (c = 0). */
1656 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
1657 modifiers
|= meta_modifier
;
1659 modifiers
|= ctrl_modifier
;
1661 modifiers
|= shift_modifier
;
1664 switch (code
& 0xf000)
1667 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1669 c
= 0; /* Special */
1682 if (c
== 0) /* ctrl-break */
1684 return c
; /* ALT-nnn */
1686 if (!keyboard_map_all
)
1695 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1696 if (!keyboard_map_all
)
1700 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1701 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1705 code
= keyboard
->shifted
[code
];
1707 modifiers
&= ~shift_modifier
;
1710 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1711 code
= keyboard
->alt_gr
[code
];
1713 code
= keyboard
->unshifted
[code
];
1718 if (c
== 0xe0) /* edit key */
1721 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1722 kp_mode
= dos_keypad_mode
& 0x03;
1724 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1729 if (code
== 10 && dos_decimal_point
)
1730 return dos_decimal_point
;
1731 return keypad_translate_map
[code
].char_code
;
1734 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1738 code
= keypad_translate_map
[code
].meta_code
;
1739 modifiers
= meta_modifier
;
1743 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1750 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1751 if (dos_keypad_mode
& kp_mode
)
1752 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1754 code
= grey_key_translate_map
[code
].char_code
;
1763 event
.kind
= non_ascii_keystroke
;
1765 event
.kind
= ascii_keystroke
;
1767 event
.modifiers
= modifiers
;
1768 XSETFRAME (event
.frame_or_window
, selected_frame
);
1769 event
.timestamp
= event_timestamp ();
1770 kbd_buffer_store_event (&event
);
1775 int but
, press
, x
, y
, ok
;
1777 /* Check for mouse movement *before* buttons. */
1778 mouse_check_moved ();
1780 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1781 for (press
= 0; press
< 2; press
++)
1783 int button_num
= but
;
1786 ok
= mouse_pressed (but
, &x
, &y
);
1788 ok
= mouse_released (but
, &x
, &y
);
1791 /* Allow a simultaneous press/release of Mouse-1 and
1792 Mouse-2 to simulate Mouse-3 on two-button mice. */
1793 if (mouse_button_count
== 2 && but
< 2)
1795 int x2
, y2
; /* don't clobber original coordinates */
1797 /* If only one button is pressed, wait 100 msec and
1798 check again. This way, Speedy Gonzales isn't
1799 punished, while the slow get their chance. */
1800 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1801 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1806 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
1807 || !press
&& mouse_released (1-but
, &x2
, &y2
))
1812 event
.kind
= mouse_click
;
1813 event
.code
= button_num
;
1814 event
.modifiers
= dos_get_modifiers (0)
1815 | (press
? down_modifier
: up_modifier
);
1818 XSETFRAME (event
.frame_or_window
, selected_frame
);
1819 event
.timestamp
= event_timestamp ();
1820 kbd_buffer_store_event (&event
);
1828 static int prev_get_char
= -1;
1830 /* Return 1 if a key is ready to be read without suspending execution. */
1834 if (prev_get_char
!= -1)
1837 return ((prev_get_char
= dos_rawgetc ()) != -1);
1840 /* Read a key. Return -1 if no key is ready. */
1844 if (prev_get_char
!= -1)
1846 int c
= prev_get_char
;
1851 return dos_rawgetc ();
1854 #ifndef HAVE_X_WINDOWS
1855 /* See xterm.c for more info. */
1857 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1859 register int pix_x
, pix_y
;
1860 register int *x
, *y
;
1861 void /* XRectangle */ *bounds
;
1864 if (bounds
) abort ();
1866 /* Ignore clipping. */
1873 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1876 register int *pix_x
, *pix_y
;
1882 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1885 Actually, I don't know the meaning of all the parameters of the functions
1886 here -- I only know how they are called by xmenu.c. I could of course
1887 grab the nearest Xlib manual (down the hall, second-to-last door on the
1888 left), but I don't think it's worth the effort. */
1895 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1896 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1900 /* Allocate some (more) memory for MENU ensuring that there is room for one
1904 IT_menu_make_room (XMenu
*menu
)
1906 if (menu
->allocated
== 0)
1908 int count
= menu
->allocated
= 10;
1909 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1910 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1911 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1913 else if (menu
->allocated
== menu
->count
)
1915 int count
= menu
->allocated
= menu
->allocated
+ 10;
1917 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1919 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1921 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1925 /* Search the given menu structure for a given pane number. */
1928 IT_menu_search_pane (XMenu
*menu
, int pane
)
1933 for (i
= 0; i
< menu
->count
; i
++)
1934 if (menu
->submenu
[i
])
1936 if (pane
== menu
->panenumber
[i
])
1937 return menu
->submenu
[i
];
1938 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1944 /* Determine how much screen space a given menu needs. */
1947 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1949 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1952 maxheight
= menu
->count
;
1953 for (i
= 0; i
< menu
->count
; i
++)
1955 if (menu
->submenu
[i
])
1957 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1958 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1959 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1962 *width
= menu
->width
+ maxsubwidth
;
1963 *height
= maxheight
;
1966 /* Display MENU at (X,Y) using FACES. */
1969 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1971 int i
, j
, face
, width
;
1975 int enabled
, mousehere
;
1978 width
= menu
->width
;
1979 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1980 ScreenGetCursor (&row
, &col
);
1981 mouse_get_xy (&mx
, &my
);
1983 for (i
= 0; i
< menu
->count
; i
++)
1985 IT_cursor_to (y
+ i
, x
);
1987 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1988 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1989 face
= faces
[enabled
+ mousehere
* 2];
1991 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1992 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
1995 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
1996 else /* make '^x' */
1998 *p
++ = FAST_MAKE_GLYPH ('^', face
);
2000 *p
++ = FAST_MAKE_GLYPH (*q
++ + 64, face
);
2004 for (; j
< width
; j
++)
2005 *p
++ = FAST_MAKE_GLYPH (' ', face
);
2006 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
2007 IT_write_glyphs (text
, width
+ 2);
2010 IT_cursor_to (row
, col
);
2014 /* --------------------------- X Menu emulation ---------------------- */
2016 /* Report availability of menus. */
2024 /* Create a brand new menu structure. */
2027 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2029 return IT_menu_create ();
2032 /* Create a new pane and place it on the outer-most level. It is not
2033 clear that it should be placed out there, but I don't know what else
2037 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
2045 IT_menu_make_room (menu
);
2046 menu
->submenu
[menu
->count
] = IT_menu_create ();
2047 menu
->text
[menu
->count
] = txt
;
2048 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
2051 /* Adjust length for possible control characters (which will
2052 be written as ^x). */
2053 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2057 if (len
> menu
->width
)
2060 return menu
->panecount
;
2063 /* Create a new item in a menu pane. */
2066 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
2067 int foo
, char *txt
, int enable
)
2073 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
2075 IT_menu_make_room (menu
);
2076 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
2077 menu
->text
[menu
->count
] = txt
;
2078 menu
->panenumber
[menu
->count
] = enable
;
2081 /* Adjust length for possible control characters (which will
2082 be written as ^x). */
2083 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2087 if (len
> menu
->width
)
2093 /* Decide where the menu would be placed if requested at (X,Y). */
2096 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
2097 int *ulx
, int *uly
, int *width
, int *height
)
2099 IT_menu_calc_size (menu
, width
, height
);
2105 struct IT_menu_state
2107 void *screen_behind
;
2114 /* Display menu, wait for user's response, and return that response. */
2117 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
2118 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
2120 struct IT_menu_state
*state
;
2124 int faces
[4], selectface
;
2125 int leave
, result
, onepane
;
2126 int title_faces
[4]; /* face to display the menu title */
2127 int buffers_num_deleted
= 0;
2129 /* Just in case we got here without a mouse present... */
2130 if (have_mouse
<= 0)
2131 return XM_IA_SELECT
;
2132 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2133 around the display. */
2139 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
2140 screensize
= screen_size
* 2;
2142 = compute_glyph_face (selected_frame
,
2145 intern ("msdos-menu-passive-face")),
2148 = compute_glyph_face (selected_frame
,
2151 intern ("msdos-menu-active-face")),
2154 = face_name_id_number (selected_frame
, intern ("msdos-menu-select-face"));
2155 faces
[2] = compute_glyph_face (selected_frame
, selectface
, faces
[0]);
2156 faces
[3] = compute_glyph_face (selected_frame
, selectface
, faces
[1]);
2158 /* Make sure the menu title is always displayed with
2159 `msdos-menu-active-face', no matter where the mouse pointer is. */
2160 for (i
= 0; i
< 4; i
++)
2161 title_faces
[i
] = faces
[3];
2165 /* Don't let the title for the "Buffers" popup menu include a
2166 digit (which is ugly).
2168 This is a terrible kludge, but I think the "Buffers" case is
2169 the only one where the title includes a number, so it doesn't
2170 seem to be necessary to make this more general. */
2171 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
2173 menu
->text
[0][7] = '\0';
2174 buffers_num_deleted
= 1;
2176 state
[0].menu
= menu
;
2178 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
2180 /* Turn off the cursor. Otherwise it shows through the menu
2181 panes, which is ugly. */
2182 IT_display_cursor (0);
2184 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
2185 if (buffers_num_deleted
)
2186 menu
->text
[0][7] = ' ';
2187 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
2189 menu
->width
= menu
->submenu
[0]->width
;
2190 state
[0].menu
= menu
->submenu
[0];
2194 state
[0].menu
= menu
;
2196 state
[0].x
= x0
- 1;
2198 state
[0].pane
= onepane
;
2200 mouse_last_x
= -1; /* A hack that forces display. */
2204 if (!mouse_visible
) mouse_on ();
2205 mouse_check_moved ();
2206 if (selected_frame
->mouse_moved
)
2208 selected_frame
->mouse_moved
= 0;
2209 result
= XM_IA_SELECT
;
2210 mouse_get_xy (&x
, &y
);
2211 for (i
= 0; i
< statecount
; i
++)
2212 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
2214 int dy
= y
- state
[i
].y
;
2215 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
2217 if (!state
[i
].menu
->submenu
[dy
])
2218 if (state
[i
].menu
->panenumber
[dy
])
2219 result
= XM_SUCCESS
;
2221 result
= XM_IA_SELECT
;
2222 *pane
= state
[i
].pane
- 1;
2224 /* We hit some part of a menu, so drop extra menus that
2225 have been opened. That does not include an open and
2227 if (i
!= statecount
- 2
2228 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
2229 while (i
!= statecount
- 1)
2233 ScreenUpdate (state
[statecount
].screen_behind
);
2234 xfree (state
[statecount
].screen_behind
);
2236 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2238 IT_menu_display (state
[i
].menu
,
2242 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2243 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2245 ScreenRetrieve (state
[statecount
].screen_behind
2246 = xmalloc (screensize
));
2248 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2249 state
[statecount
].y
= y
;
2254 IT_menu_display (state
[statecount
- 1].menu
,
2255 state
[statecount
- 1].y
,
2256 state
[statecount
- 1].x
,
2259 for (b
= 0; b
< mouse_button_count
; b
++)
2261 (void) mouse_pressed (b
, &x
, &y
);
2262 if (mouse_released (b
, &x
, &y
))
2268 ScreenUpdate (state
[0].screen_behind
);
2269 while (statecount
--)
2270 xfree (state
[statecount
].screen_behind
);
2271 IT_display_cursor (1); /* turn cursor back on */
2275 /* Dispose of a menu. */
2278 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2281 if (menu
->allocated
)
2283 for (i
= 0; i
< menu
->count
; i
++)
2284 if (menu
->submenu
[i
])
2285 XMenuDestroy (foo
, menu
->submenu
[i
]);
2287 xfree (menu
->submenu
);
2288 xfree (menu
->panenumber
);
2294 x_pixel_width (struct frame
*f
)
2296 return FRAME_WIDTH (f
);
2300 x_pixel_height (struct frame
*f
)
2302 return FRAME_HEIGHT (f
);
2304 #endif /* !HAVE_X_WINDOWS */
2306 /* ----------------------- DOS / UNIX conversion --------------------- */
2308 void msdos_downcase_filename (unsigned char *);
2310 /* Destructively turn backslashes into slashes. */
2313 dostounix_filename (p
)
2316 msdos_downcase_filename (p
);
2326 /* Destructively turn slashes into backslashes. */
2329 unixtodos_filename (p
)
2332 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2346 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2349 getdefdir (drive
, dst
)
2353 char in_path
[4], *p
= in_path
;
2356 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2359 *p
++ = drive
+ 'A' - 1;
2366 _fixpath (in_path
, dst
);
2370 msdos_downcase_filename (dst
);
2376 /* Remove all CR's that are followed by a LF. */
2381 register unsigned char *buf
;
2383 unsigned char *np
= buf
;
2384 unsigned char *startp
= buf
;
2385 unsigned char *endp
= buf
+ n
;
2389 while (buf
< endp
- 1)
2393 if (*(++buf
) != 0x0a)
2404 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2406 /* In DJGPP v2.0, library `write' can call `malloc', which might
2407 cause relocation of the buffer whose address we get in ADDR.
2408 Here is a version of `write' that avoids calling `malloc',
2409 to serve us until such time as the library is fixed.
2410 Actually, what we define here is called `__write', because
2411 `write' is a stub that just jmp's to `__write' (to be
2412 POSIXLY-correct with respect to the global name-space). */
2414 #include <io.h> /* for _write */
2415 #include <libc/dosio.h> /* for __file_handle_modes[] */
2417 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
2419 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2422 __write (int handle
, const void *buffer
, size_t count
)
2427 if(__file_handle_modes
[handle
] & O_BINARY
)
2428 return _write (handle
, buffer
, count
);
2432 const char *bp
= buffer
;
2433 int total_written
= 0;
2434 int nmoved
= 0, ncr
= 0;
2438 /* The next test makes sure there's space for at least 2 more
2439 characters in xbuf[], so both CR and LF can be put there. */
2451 if (xbp
>= XBUF_END
|| !count
)
2453 size_t to_write
= nmoved
+ ncr
;
2454 int written
= _write (handle
, xbuf
, to_write
);
2459 total_written
+= nmoved
; /* CRs aren't counted in ret value */
2461 /* If some, but not all were written (disk full?), return
2462 an estimate of the total written bytes not counting CRs. */
2463 if (written
< to_write
)
2464 return total_written
- (to_write
- written
) * nmoved
/to_write
;
2471 return total_written
;
2475 /* A low-level file-renaming function which works around Windows 95 bug.
2476 This is pulled directly out of DJGPP v2.01 library sources, and only
2477 used when you compile with DJGPP v2.0. */
2481 int _rename(const char *old
, const char *new)
2484 int olen
= strlen(old
) + 1;
2486 int use_lfn
= _USE_LFN
;
2487 char tempfile
[FILENAME_MAX
];
2488 const char *orig
= old
;
2491 r
.x
.dx
= __tb_offset
;
2492 r
.x
.di
= __tb_offset
+ olen
;
2493 r
.x
.ds
= r
.x
.es
= __tb_segment
;
2497 /* Windows 95 bug: for some filenames, when you rename
2498 file -> file~ (as in Emacs, to leave a backup), the
2499 short 8+3 alias doesn't change, which effectively
2500 makes OLD and NEW the same file. We must rename
2501 through a temporary file to work around this. */
2503 char *pbase
= 0, *p
;
2504 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
2505 int idx
= sizeof(try_char
) - 1;
2507 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
2508 might point to another drive, which will fail the DOS call. */
2509 strcpy(tempfile
, old
);
2510 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
2511 if (*p
== '/' || *p
== '\\' || *p
== ':')
2517 strcpy(pbase
, "X$$djren$$.$$temp$$");
2523 *pbase
= try_char
[--idx
];
2524 } while (_chmod(tempfile
, 0) != -1);
2527 _put_path2(tempfile
, olen
);
2529 __dpmi_int(0x21, &r
);
2532 errno
= __doserr_to_errno(r
.x
.ax
);
2536 /* Now create a file with the original name. This will
2537 ensure that NEW will always have a 8+3 alias
2538 different from that of OLD. (Seems to be required
2539 when NameNumericTail in the Registry is set to 0.) */
2540 lfn_fd
= _creat(old
, 0);
2542 olen
= strlen(tempfile
) + 1;
2544 r
.x
.di
= __tb_offset
+ olen
;
2553 _put_path2(new, olen
);
2555 __dpmi_int(0x21, &r
);
2558 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
2559 remove(new); /* and try again */
2562 errno
= __doserr_to_errno(r
.x
.ax
);
2564 /* Restore to original name if we renamed it to temporary. */
2572 _put_path2(orig
, olen
);
2573 _put_path(tempfile
);
2575 __dpmi_int(0x21, &r
);
2584 /* Success. Delete the file possibly created to work
2585 around the Windows 95 bug. */
2587 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
2591 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
2593 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
2595 "Return non-nil if long file names are supported on MSDOS.")
2598 return (_USE_LFN
? Qt
: Qnil
);
2601 /* Convert alphabetic characters in a filename to lower-case. */
2604 msdos_downcase_filename (p
)
2605 register unsigned char *p
;
2607 /* Always lower-case drive letters a-z, even if the filesystem
2608 preserves case in filenames.
2609 This is so MSDOS filenames could be compared by string comparison
2610 functions that are case-sensitive. Even case-preserving filesystems
2611 do not distinguish case in drive letters. */
2612 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2618 /* Under LFN we expect to get pathnames in their true case. */
2619 if (NILP (Fmsdos_long_file_names ()))
2621 if (*p
>= 'A' && *p
<= 'Z')
2625 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
2627 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
2628 When long filenames are supported, doesn't change FILENAME.\n\
2629 If FILENAME is not a string, returns nil.\n\
2630 The argument object is never altered--the value is a copy.")
2632 Lisp_Object filename
;
2636 if (! STRINGP (filename
))
2639 tem
= Fcopy_sequence (filename
);
2640 msdos_downcase_filename (XSTRING (tem
)->data
);
2644 /* The Emacs root directory as determined by init_environment. */
2646 static char emacsroot
[MAXPATHLEN
];
2649 rootrelativepath (rel
)
2652 static char result
[MAXPATHLEN
+ 10];
2654 strcpy (result
, emacsroot
);
2655 strcat (result
, "/");
2656 strcat (result
, rel
);
2660 /* Define a lot of environment variables if not already defined. Don't
2661 remove anything unless you know what you're doing -- lots of code will
2662 break if one or more of these are missing. */
2665 init_environment (argc
, argv
, skip_args
)
2673 /* Find our root from argv[0]. Assuming argv[0] is, say,
2674 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2675 root
= alloca (MAXPATHLEN
+ 20);
2676 _fixpath (argv
[0], root
);
2677 msdos_downcase_filename (root
);
2678 len
= strlen (root
);
2679 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
2683 && (strcmp (root
+ len
- 4, "/bin") == 0
2684 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
2685 root
[len
- 4] = '\0';
2687 strcpy (root
, "c:/emacs"); /* let's be defensive */
2688 len
= strlen (root
);
2689 strcpy (emacsroot
, root
);
2691 /* We default HOME to our root. */
2692 setenv ("HOME", root
, 0);
2694 /* We default EMACSPATH to root + "/bin". */
2695 strcpy (root
+ len
, "/bin");
2696 setenv ("EMACSPATH", root
, 0);
2698 /* I don't expect anybody to ever use other terminals so the internal
2699 terminal is the default. */
2700 setenv ("TERM", "internal", 0);
2702 #ifdef HAVE_X_WINDOWS
2703 /* Emacs expects DISPLAY to be set. */
2704 setenv ("DISPLAY", "unix:0.0", 0);
2707 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2708 downcase it and mirror the backslashes. */
2709 s
= getenv ("COMSPEC");
2710 if (!s
) s
= "c:/command.com";
2711 t
= alloca (strlen (s
) + 1);
2713 dostounix_filename (t
);
2714 setenv ("SHELL", t
, 0);
2716 /* PATH is also downcased and backslashes mirrored. */
2717 s
= getenv ("PATH");
2719 t
= alloca (strlen (s
) + 3);
2720 /* Current directory is always considered part of MsDos's path but it is
2721 not normally mentioned. Now it is. */
2722 strcat (strcpy (t
, ".;"), s
);
2723 dostounix_filename (t
); /* Not a single file name, but this should work. */
2724 setenv ("PATH", t
, 1);
2726 /* In some sense all dos users have root privileges, so... */
2727 setenv ("USER", "root", 0);
2728 setenv ("NAME", getenv ("USER"), 0);
2730 /* Time zone determined from country code. To make this possible, the
2731 country code may not span more than one time zone. In other words,
2732 in the USA, you lose. */
2734 switch (dos_country_code
)
2736 case 31: /* Belgium */
2737 case 32: /* The Netherlands */
2738 case 33: /* France */
2739 case 34: /* Spain */
2740 case 36: /* Hungary */
2741 case 38: /* Yugoslavia (or what's left of it?) */
2742 case 39: /* Italy */
2743 case 41: /* Switzerland */
2744 case 42: /* Tjekia */
2745 case 45: /* Denmark */
2746 case 46: /* Sweden */
2747 case 47: /* Norway */
2748 case 48: /* Poland */
2749 case 49: /* Germany */
2750 /* Daylight saving from last Sunday in March to last Sunday in
2751 September, both at 2AM. */
2752 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2754 case 44: /* United Kingdom */
2755 case 351: /* Portugal */
2756 case 354: /* Iceland */
2757 setenv ("TZ", "GMT+00", 0);
2759 case 81: /* Japan */
2760 case 82: /* Korea */
2761 setenv ("TZ", "JST-09", 0);
2763 case 90: /* Turkey */
2764 case 358: /* Finland */
2765 setenv ("TZ", "EET-02", 0);
2767 case 972: /* Israel */
2768 /* This is an approximation. (For exact rules, use the
2769 `zoneinfo/israel' file which comes with DJGPP, but you need
2770 to install it in `/usr/share/zoneinfo/' directory first.) */
2771 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2779 static int break_stat
; /* BREAK check mode status. */
2780 static int stdin_stat
; /* stdin IOCTL status. */
2784 /* These must be global. */
2785 static _go32_dpmi_seginfo ctrl_break_vector
;
2786 static _go32_dpmi_registers ctrl_break_regs
;
2787 static int ctrlbreakinstalled
= 0;
2789 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2792 ctrl_break_func (regs
)
2793 _go32_dpmi_registers
*regs
;
2799 install_ctrl_break_check ()
2801 if (!ctrlbreakinstalled
)
2803 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2804 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2805 ctrlbreakinstalled
= 1;
2806 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2807 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2809 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2813 #endif /* __DJGPP__ < 2 */
2815 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2816 control chars by DOS. Determine the keyboard type. */
2821 union REGS inregs
, outregs
;
2822 static int first_time
= 1;
2824 break_stat
= getcbrk ();
2827 install_ctrl_break_check ();
2833 int86 (0x15, &inregs
, &outregs
);
2834 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2838 if (internal_terminal
2839 #ifdef HAVE_X_WINDOWS
2840 && inhibit_window_system
2844 inregs
.x
.ax
= 0x0021;
2845 int86 (0x33, &inregs
, &outregs
);
2846 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2849 /* Reportedly, the above doesn't work for some mouse drivers. There
2850 is an additional detection method that should work, but might be
2851 a little slower. Use that as an alternative. */
2852 inregs
.x
.ax
= 0x0000;
2853 int86 (0x33, &inregs
, &outregs
);
2854 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2859 have_mouse
= 1; /* enable mouse */
2862 if (outregs
.x
.bx
== 3)
2864 mouse_button_count
= 3;
2865 mouse_button_translate
[0] = 0; /* Left */
2866 mouse_button_translate
[1] = 2; /* Middle */
2867 mouse_button_translate
[2] = 1; /* Right */
2871 mouse_button_count
= 2;
2872 mouse_button_translate
[0] = 0;
2873 mouse_button_translate
[1] = 1;
2875 mouse_position_hook
= &mouse_get_pos
;
2884 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
2885 return (stdin_stat
!= -1);
2888 return (setmode (fileno (stdin
), O_BINARY
) != -1);
2890 #else /* __DJGPP__ < 2 */
2894 /* I think it is wrong to overwrite `stdin_stat' every time
2895 but the first one this function is called, but I don't
2896 want to change the way it used to work in v1.x.--EZ */
2898 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2899 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2900 intdos (&inregs
, &outregs
);
2901 stdin_stat
= outregs
.h
.dl
;
2903 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
2904 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
2905 intdos (&inregs
, &outregs
);
2906 return !outregs
.x
.cflag
;
2908 #endif /* __DJGPP__ < 2 */
2911 /* Restore status of standard input and Ctrl-C checking. */
2916 union REGS inregs
, outregs
;
2918 setcbrk (break_stat
);
2923 return (setmode (fileno (stdin
), stdin_stat
) != -1);
2925 #else /* not __DJGPP__ >= 2 */
2927 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
2928 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2929 inregs
.x
.dx
= stdin_stat
;
2930 intdos (&inregs
, &outregs
);
2931 return !outregs
.x
.cflag
;
2933 #endif /* not __DJGPP__ >= 2 */
2937 /* Run command as specified by ARGV in directory DIR.
2938 The command is run with input from TEMPIN, output to
2939 file TEMPOUT and stderr to TEMPERR. */
2942 run_msdos_command (argv
, dir
, tempin
, tempout
, temperr
)
2943 unsigned char **argv
;
2945 int tempin
, tempout
, temperr
;
2947 char *saveargv1
, *saveargv2
, **envv
, *lowcase_argv0
, *pa
, *pl
;
2948 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
2949 int msshell
, result
= -1;
2950 int inbak
, outbak
, errbak
;
2954 /* Get current directory as MSDOS cwd is not per-process. */
2957 /* If argv[0] is the shell, it might come in any lettercase.
2958 Since `Fmember' is case-sensitive, we need to downcase
2959 argv[0], even if we are on case-preserving filesystems. */
2960 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
2961 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
2964 if (*pl
>= 'A' && *pl
<= 'Z')
2969 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
2970 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
2971 && !strcmp ("-c", argv
[1]);
2974 saveargv1
= argv
[1];
2975 saveargv2
= argv
[2];
2979 char *p
= alloca (strlen (argv
[2]) + 1);
2981 strcpy (argv
[2] = p
, saveargv2
);
2982 while (*p
&& isspace (*p
))
2984 while (*p
&& !isspace (*p
))
2992 /* Build the environment array. */
2994 extern Lisp_Object Vprocess_environment
;
2995 Lisp_Object tmp
, lst
;
2998 lst
= Vprocess_environment
;
2999 len
= XFASTINT (Flength (lst
));
3001 envv
= alloca ((len
+ 1) * sizeof (char *));
3002 for (i
= 0; i
< len
; i
++)
3006 CHECK_STRING (tmp
, 0);
3007 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
3008 strcpy (envv
[i
], XSTRING (tmp
)->data
);
3010 envv
[len
] = (char *) 0;
3014 chdir (XSTRING (dir
)->data
);
3018 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3019 goto done
; /* Allocation might fail due to lack of descriptors. */
3022 mouse_get_xy (&x
, &y
);
3024 dos_ttcooked (); /* do it here while 0 = stdin */
3032 if (msshell
&& !argv
[3])
3034 /* MS-DOS native shells are too restrictive. For starters, they
3035 cannot grok commands longer than 126 characters. In DJGPP v2
3036 and later, `system' is much smarter, so we'll call it instead. */
3038 extern char **environ
;
3041 /* A shell gets a single argument--its full command
3042 line--whose original was saved in `saveargv2'. */
3043 result
= system (saveargv2
);
3047 #endif /* __DJGPP__ > 1 */
3049 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
3062 mouse_moveto (x
, y
);
3065 /* Some programs might change the meaning of the highest bit of the
3066 text attribute byte, so we get blinking characters instead of the
3067 bright background colors. Restore that. */
3074 argv
[1] = saveargv1
;
3075 argv
[2] = saveargv2
;
3083 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3090 /* ------------------------- Compatibility functions -------------------
3095 /* Hostnames for a pc are not really funny,
3096 but they are used in change log so we emulate the best we can. */
3098 gethostname (p
, size
)
3102 char *q
= egetenv ("HOSTNAME");
3109 /* When time zones are set from Ms-Dos too many C-libraries are playing
3110 tricks with time values. We solve this by defining our own version
3111 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3112 once and after each call to `tzset' with TZ changed. That is
3113 accomplished by aliasing tzset to init_gettimeofday. */
3115 static struct tm time_rec
;
3118 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
3126 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
3130 time_rec
.tm_year
= d
.da_year
- 1900;
3131 time_rec
.tm_mon
= d
.da_mon
- 1;
3132 time_rec
.tm_mday
= d
.da_day
;
3135 time_rec
.tm_hour
= t
.ti_hour
;
3136 time_rec
.tm_min
= t
.ti_min
;
3137 time_rec
.tm_sec
= t
.ti_sec
;
3140 tm
.tm_gmtoff
= dos_timezone_offset
;
3142 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
3143 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
3145 /* Ignore tzp; it's obsolescent. */
3149 #endif /* __DJGPP__ < 2 */
3152 * A list of unimplemented functions that we silently ignore.
3156 unsigned alarm (s
) unsigned s
; {}
3157 fork () { return 0; }
3158 int kill (x
, y
) int x
, y
; { return -1; }
3160 void volatile pause () {}
3161 sigsetmask (x
) int x
; { return 0; }
3162 sigblock (mask
) int mask
; { return 0; }
3166 setpgrp () {return 0; }
3167 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
3168 unrequest_sigio () {}
3172 #ifdef POSIX_SIGNALS
3174 /* Augment DJGPP library POSIX signal functions. This is needed
3175 as of DJGPP v2.01, but might be in the library in later releases. */
3177 #include <libc/bss.h>
3179 /* A counter to know when to re-initialize the static sets. */
3180 static int sigprocmask_count
= -1;
3182 /* Which signals are currently blocked (initially none). */
3183 static sigset_t current_mask
;
3185 /* Which signals are pending (initially none). */
3186 static sigset_t pending_signals
;
3188 /* Previous handlers to restore when the blocked signals are unblocked. */
3189 typedef void (*sighandler_t
)(int);
3190 static sighandler_t prev_handlers
[320];
3192 /* A signal handler which just records that a signal occured
3193 (it will be raised later, if and when the signal is unblocked). */
3195 sig_suspender (signo
)
3198 sigaddset (&pending_signals
, signo
);
3202 sigprocmask (how
, new_set
, old_set
)
3204 const sigset_t
*new_set
;
3210 /* If called for the first time, initialize. */
3211 if (sigprocmask_count
!= __bss_count
)
3213 sigprocmask_count
= __bss_count
;
3214 sigemptyset (&pending_signals
);
3215 sigemptyset (¤t_mask
);
3216 for (signo
= 0; signo
< 320; signo
++)
3217 prev_handlers
[signo
] = SIG_ERR
;
3221 *old_set
= current_mask
;
3226 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
3232 sigemptyset (&new_mask
);
3234 /* DJGPP supports upto 320 signals. */
3235 for (signo
= 0; signo
< 320; signo
++)
3237 if (sigismember (¤t_mask
, signo
))
3238 sigaddset (&new_mask
, signo
);
3239 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
3241 sigaddset (&new_mask
, signo
);
3243 /* SIGKILL is silently ignored, as on other platforms. */
3244 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
3245 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
3247 if (( how
== SIG_UNBLOCK
3248 && sigismember (&new_mask
, signo
)
3249 && sigismember (new_set
, signo
))
3250 || (how
== SIG_SETMASK
3251 && sigismember (&new_mask
, signo
)
3252 && !sigismember (new_set
, signo
)))
3254 sigdelset (&new_mask
, signo
);
3255 if (prev_handlers
[signo
] != SIG_ERR
)
3257 signal (signo
, prev_handlers
[signo
]);
3258 prev_handlers
[signo
] = SIG_ERR
;
3260 if (sigismember (&pending_signals
, signo
))
3262 sigdelset (&pending_signals
, signo
);
3267 current_mask
= new_mask
;
3271 #else /* not POSIX_SIGNALS */
3273 sigsetmask (x
) int x
; { return 0; }
3274 sigblock (mask
) int mask
; { return 0; }
3276 #endif /* not POSIX_SIGNALS */
3277 #endif /* __DJGPP__ > 1 */
3280 #include "sysselect.h"
3282 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3283 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3284 ((long)(time).tv_sec < 0 \
3285 || ((time).tv_sec == 0 \
3286 && (long)(time).tv_usec <= 0))
3290 /* Only event queue is checked. */
3291 /* We don't have to call timer_check here
3292 because wait_reading_process_input takes care of that. */
3294 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
3296 SELECT_TYPE
*rfds
, *wfds
, *efds
;
3297 EMACS_TIME
*timeout
;
3305 check_input
= FD_ISSET (0, rfds
);
3316 /* If we are looking only for the terminal, with no timeout,
3317 just read it and wait -- that's more efficient. */
3320 while (!detect_input_pending ())
3329 EMACS_TIME clnow
, cllast
, cldiff
;
3332 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
3334 while (!check_input
|| !detect_input_pending ())
3337 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
3338 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
3340 /* When seconds wrap around, we assume that no more than
3341 1 minute passed since last `gettime'. */
3342 if (EMACS_TIME_NEG_P (cldiff
))
3343 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
3344 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
3346 /* Stop when timeout value crosses zero. */
3347 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
3362 * Define overlaid functions:
3364 * chdir -> sys_chdir
3365 * tzset -> init_gettimeofday
3366 * abort -> dos_abort
3371 extern int chdir ();
3377 int len
= strlen (path
);
3378 char *tmp
= (char *)path
;
3380 if (*tmp
&& tmp
[1] == ':')
3382 if (getdisk () != tolower (tmp
[0]) - 'a')
3383 setdisk (tolower (tmp
[0]) - 'a');
3384 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
3388 if (len
> 1 && (tmp
[len
- 1] == '/'))
3390 char *tmp1
= (char *) alloca (len
+ 1);
3401 extern void tzset (void);
3404 init_gettimeofday ()
3410 ltm
= gtm
= time (NULL
);
3411 ltm
= mktime (lstm
= localtime (<m
));
3412 gtm
= mktime (gmtime (>m
));
3413 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
3414 time_rec
.tm_isdst
= lstm
->tm_isdst
;
3415 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
3422 dos_abort (file
, line
)
3426 char buffer1
[200], buffer2
[400];
3429 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
3430 for (i
= j
= 0; buffer1
[i
]; i
++) {
3431 buffer2
[j
++] = buffer1
[i
];
3432 buffer2
[j
++] = 0x70;
3434 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
3435 ScreenSetCursor (2, 0);
3443 ScreenSetCursor (10, 0);
3444 cputs ("\r\n\nEmacs aborted!\r\n");
3446 /* Generate traceback, so we could tell whodunit. */
3447 signal (SIGINT
, SIG_DFL
);
3448 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3454 /* The following two are required so that customization feature
3455 won't complain about unbound variables. */
3456 #ifndef HAVE_X_WINDOWS
3457 /* Search path for bitmap files (xfns.c). */
3458 Lisp_Object Vx_bitmap_file_path
;
3460 #ifndef subprocesses
3461 /* Nonzero means delete a process right away if it exits (process.c). */
3462 static int delete_exited_processes
;
3467 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
3468 staticpro (&recent_doskeys
);
3469 #ifndef HAVE_X_WINDOWS
3470 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
3471 "List of directories to search for bitmap files for X.");
3472 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
3474 /* The following two are from xfns.c: */
3475 Qbackground_color
= intern ("background-color");
3476 staticpro (&Qbackground_color
);
3477 Qforeground_color
= intern ("foreground-color");
3478 staticpro (&Qforeground_color
);
3480 #ifndef subprocesses
3481 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
3482 "*Non-nil means delete processes immediately when they exit.\n\
3483 nil means don't delete them until `list-processes' is run.");
3484 delete_exited_processes
= 0;
3487 defsubr (&Srecent_doskeys
);
3488 defsubr (&Smsdos_long_file_names
);
3489 defsubr (&Smsdos_downcase_filename
);