1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 94, 95, 96, 97, 1999 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
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. */
33 #include <sys/param.h>
37 #include <string.h> /* for bzero and string functions */
38 #include <sys/stat.h> /* for _fixpath */
39 #include <unistd.h> /* for chdir, dup, dup2, etc. */
42 #include <io.h> /* for setmode */
43 #include <dpmi.h> /* for __dpmi_xxx stuff */
44 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
45 #include <libc/dosio.h> /* for _USE_LFN */
46 #include <conio.h> /* for cputs */
51 #include "termhooks.h"
53 #include "dispextern.h"
63 #include "blockinput.h"
67 /* #include <process.h> */
68 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
76 #define _dos_ds _go32_info_block.selector_for_linear_memory
82 #include "syssignal.h"
88 /* If other `malloc' than ours is used, force our `sbrk' behave like
89 Unix programs expect (resize memory blocks to keep them contiguous).
90 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
91 because that's what `gmalloc' expects to get. */
95 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
96 #else /* not REL_ALLOC */
97 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
98 #endif /* not REL_ALLOC */
99 #endif /* GNU_MALLOC */
101 #endif /* not SYSTEM_MALLOC */
102 #endif /* __DJGPP__ > 1 */
121 /* ------------------------ Mouse control ---------------------------
123 * Coordinates are in screen positions and zero based.
124 * Mouse buttons are numbered from left to right and also zero based.
127 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
128 static int mouse_visible
;
130 static int mouse_last_x
;
131 static int mouse_last_y
;
133 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
134 static int mouse_button_count
;
141 if (have_mouse
> 0 && !mouse_visible
)
144 fprintf (termscript
, "<M_ON>");
146 int86 (0x33, ®s
, ®s
);
156 if (have_mouse
> 0 && mouse_visible
)
159 fprintf (termscript
, "<M_OFF>");
161 int86 (0x33, ®s
, ®s
);
167 mouse_get_xy (int *x
, int *y
)
172 int86 (0x33, ®s
, ®s
);
184 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
186 mouse_last_x
= regs
.x
.cx
= x
* 8;
187 mouse_last_y
= regs
.x
.dx
= y
* 8;
188 int86 (0x33, ®s
, ®s
);
192 mouse_pressed (b
, xp
, yp
)
197 if (b
>= mouse_button_count
)
200 regs
.x
.bx
= mouse_button_translate
[b
];
201 int86 (0x33, ®s
, ®s
);
203 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
204 return (regs
.x
.bx
!= 0);
208 mouse_released (b
, xp
, yp
)
213 if (b
>= mouse_button_count
)
216 regs
.x
.bx
= mouse_button_translate
[b
];
217 int86 (0x33, ®s
, ®s
);
219 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
220 return (regs
.x
.bx
!= 0);
224 mouse_button_depressed (b
, xp
, yp
)
229 if (b
>= mouse_button_count
)
232 int86 (0x33, ®s
, ®s
);
233 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
243 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
246 Lisp_Object
*bar_window
, *x
, *y
;
247 enum scroll_bar_part
*part
;
251 Lisp_Object frame
, tail
;
253 /* Clear the mouse-moved flag for every frame on this display. */
254 FOR_EACH_FRAME (tail
, frame
)
255 XFRAME (frame
)->mouse_moved
= 0;
257 *f
= SELECTED_FRAME();
259 mouse_get_xy (&ix
, &iy
);
260 *time
= event_timestamp ();
261 *x
= make_number (mouse_last_x
= ix
);
262 *y
= make_number (mouse_last_y
= iy
);
270 mouse_get_xy (&x
, &y
);
271 SELECTED_FRAME()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
283 fprintf (termscript
, "<M_INIT>");
286 int86 (0x33, ®s
, ®s
);
288 /* Reset the mouse last press/release info. It seems that Windows
289 doesn't do that automatically when function 21h is called, which
290 causes Emacs to ``remember'' the click that switched focus to the
291 window just before Emacs was started from that window. */
292 for (b
= 0; b
< mouse_button_count
; b
++)
294 int dummy_x
, dummy_y
;
296 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
297 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
302 regs
.x
.dx
= 8 * (ScreenCols () - 1);
303 int86 (0x33, ®s
, ®s
);
307 regs
.x
.dx
= 8 * (ScreenRows () - 1);
308 int86 (0x33, ®s
, ®s
);
314 /* ------------------------- Screen control ----------------------
318 static int internal_terminal
= 0;
320 #ifndef HAVE_X_WINDOWS
321 extern unsigned char ScreenAttrib
;
322 static int screen_face
;
323 static int highlight
;
325 static int screen_size_X
;
326 static int screen_size_Y
;
327 static int screen_size
;
329 static int current_pos_X
;
330 static int current_pos_Y
;
331 static int new_pos_X
;
332 static int new_pos_Y
;
334 static void *startup_screen_buffer
;
335 static int startup_screen_size_X
;
336 static int startup_screen_size_Y
;
337 static int startup_pos_X
;
338 static int startup_pos_Y
;
339 static unsigned char startup_screen_attrib
;
341 static clock_t startup_time
;
343 static int term_setup_done
;
345 static unsigned short outside_cursor
;
347 /* Similar to the_only_frame. */
348 struct x_output the_only_x_display
;
350 /* Support for DOS/V (allows Japanese characters to be displayed on
351 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
353 /* Holds the address of the text-mode screen buffer. */
354 static unsigned long screen_old_address
= 0;
355 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
356 static unsigned short screen_virtual_segment
= 0;
357 static unsigned short screen_virtual_offset
= 0;
358 /* A flag to control how to display unibyte 8-bit characters. */
359 extern int unibyte_display_via_language_environment
;
364 /* Update the screen from a part of relocated DOS/V screen buffer which
365 begins at OFFSET and includes COUNT characters. */
367 dosv_refresh_virtual_screen (int offset
, int count
)
371 if (offset
< 0 || count
< 0) /* paranoia; illegal values crash DOS/V */
374 regs
.h
.ah
= 0xff; /* update relocated screen */
375 regs
.x
.es
= screen_virtual_segment
;
376 regs
.x
.di
= screen_virtual_offset
+ offset
;
378 __dpmi_int (0x10, ®s
);
383 dos_direct_output (y
, x
, buf
, len
)
389 int t0
= 2 * (x
+ y
* screen_size_X
);
390 int t
= t0
+ (int) ScreenPrimary
;
395 dosmemput (buf
++, 1, t
);
399 /* This is faster. */
400 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
401 _farnspokeb (t
, *buf
);
403 if (screen_virtual_segment
)
404 dosv_refresh_virtual_screen (t0
, l0
);
409 /* Flash the screen as a substitute for BEEPs. */
413 do_visible_bell (xorattr
)
414 unsigned char xorattr
;
419 movl _ScreenPrimary,%%eax
426 xorb %%al,%%gs:(%%ebx)
442 : "m" (xorattr
), "g" (screen_size
)
443 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
447 ScreenVisualBell (void)
449 /* This creates an xor-mask that will swap the default fore- and
450 background colors. */
451 do_visible_bell (((the_only_x_display
.foreground_pixel
452 ^ the_only_x_display
.background_pixel
)
457 #ifndef HAVE_X_WINDOWS
459 static int blink_bit
= -1; /* the state of the blink bit at startup */
461 /* Enable bright background colors. */
467 /* Remember the original state of the blink/bright-background bit.
468 It is stored at 0040:0065h in the BIOS data area. */
470 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
474 int86 (0x10, ®s
, ®s
);
477 /* Disable bright background colors (and enable blinking) if we found
478 the video system in that state at startup. */
480 maybe_enable_blinking (void)
488 int86 (0x10, ®s
, ®s
);
492 /* Return non-zero if the system has a VGA adapter. */
499 int86 (0x10, ®s
, ®s
);
500 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
505 /* Set the screen dimensions so that it can show no less than
506 ROWS x COLS frame. */
509 dos_set_window_size (rows
, cols
)
513 Lisp_Object video_mode
;
514 int video_mode_value
;
517 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
519 if (*rows
== current_rows
&& *cols
== current_cols
)
523 have_vga
= vga_installed ();
525 /* If the user specified a special video mode for these dimensions,
527 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
528 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
531 if (INTEGERP (video_mode
)
532 && (video_mode_value
= XINT (video_mode
)) > 0)
534 regs
.x
.ax
= video_mode_value
;
535 int86 (0x10, ®s
, ®s
);
539 /* Must hardware-reset the mouse, or else it won't update
540 its notion of screen dimensions for some non-standard
541 video modes. This is *painfully* slow... */
543 int86 (0x33, ®s
, ®s
);
547 /* Find one of the dimensions supported by standard EGA/VGA
548 which gives us at least the required dimensions. */
557 } std_dimension
[] = {
567 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
569 if (std_dimension
[i
].need_vga
<= have_vga
570 && std_dimension
[i
].rows
>= *rows
)
572 if (std_dimension
[i
].rows
!= current_rows
573 || *cols
!= current_cols
)
574 _set_screen_lines (std_dimension
[i
].rows
);
581 #else /* not __DJGPP__ > 1 */
583 else if (*rows
<= 25)
585 if (current_rows
!= 25 || current_cols
!= 80)
588 int86 (0x10, ®s
, ®s
);
591 int86 (0x10, ®s
, ®s
);
594 int86 (0x10, ®s
, ®s
);
596 int86 (0x10, ®s
, ®s
);
599 else if (*rows
<= 50)
600 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
601 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
604 int86 (0x10, ®s
, ®s
);
607 int86 (0x10, ®s
, ®s
);
610 int86 (0x10, ®s
, ®s
);
613 int86 (0x10, ®s
, ®s
);
615 #endif /* not __DJGPP__ > 1 */
623 /* Tell the caller what dimensions have been REALLY set. */
624 *rows
= ScreenRows ();
625 *cols
= ScreenCols ();
628 /* If the dimensions changed, the mouse highlight info is invalid. */
629 if (current_rows
!= *rows
|| current_cols
!= *cols
)
631 struct frame
*f
= SELECTED_FRAME();
632 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
633 Lisp_Object window
= dpyinfo
->mouse_face_window
;
635 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
637 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
638 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
639 dpyinfo
->mouse_face_window
= Qnil
;
644 /* Enable bright background colors. */
647 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
648 be defensive anyway. */
649 if (screen_virtual_segment
)
650 dosv_refresh_virtual_screen (0, *cols
* *rows
);
653 /* If we write a character in the position where the mouse is,
654 the mouse cursor may need to be refreshed. */
664 mouse_get_xy (&x
, &y
);
665 if (y
!= new_pos_Y
|| x
< new_pos_X
)
671 #define DEFAULT_CURSOR_START (-1)
672 #define DEFAULT_CURSOR_WIDTH (-1)
673 #define BOX_CURSOR_WIDTH (-32)
675 /* Set cursor to begin at scan line START_LINE in the character cell
676 and extend for WIDTH scan lines. Scan lines are counted from top
677 of the character cell, starting from zero. */
679 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
682 unsigned desired_cursor
;
684 int max_line
, top_line
, bot_line
;
686 /* Avoid the costly BIOS call if F isn't the currently selected
687 frame. Allow for NULL as unconditionally meaning the selected
689 if (f
&& f
!= SELECTED_FRAME())
692 /* The character cell size in scan lines is stored at 40:85 in the
694 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
697 default: /* this relies on CGA cursor emulation being ON! */
714 if (width
== BOX_CURSOR_WIDTH
)
719 else if (start_line
!= DEFAULT_CURSOR_START
)
721 top_line
= start_line
;
722 bot_line
= top_line
- width
- 1;
724 else if (width
!= DEFAULT_CURSOR_WIDTH
)
727 bot_line
= -1 - width
;
730 top_line
= bot_line
+ 1;
734 /* [31, 0] seems to DTRT for all screen sizes. */
738 else /* WIDTH is positive */
740 if (start_line
!= DEFAULT_CURSOR_START
)
741 bot_line
= start_line
;
742 top_line
= bot_line
- (width
- 1);
745 /* If the current cursor shape is already what they want, we are
747 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
748 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
752 regs
.x
.cx
= desired_cursor
;
753 __dpmi_int (0x10, ®s
);
754 #endif /* __DJGPP__ > 1 */
758 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
760 if (EQ (cursor_type
, Qbar
))
762 /* Just BAR means the normal EGA/VGA cursor. */
763 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
765 else if (CONSP (cursor_type
) && EQ (XCAR (cursor_type
), Qbar
))
767 Lisp_Object bar_parms
= XCDR (cursor_type
);
770 if (INTEGERP (bar_parms
))
772 /* Feature: negative WIDTH means cursor at the top
773 of the character cell, zero means invisible cursor. */
774 width
= XINT (bar_parms
);
775 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
778 else if (CONSP (bar_parms
)
779 && INTEGERP (XCAR (bar_parms
))
780 && INTEGERP (XCDR (bar_parms
)))
782 int start_line
= XINT (XCDR (bar_parms
));
784 width
= XINT (XCAR (bar_parms
));
785 msdos_set_cursor_shape (f
, start_line
, width
);
789 /* Treat anything unknown as "box cursor". This includes nil, so
790 that a frame which doesn't specify a cursor type gets a box,
791 which is the default in Emacs. */
792 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
805 union REGS inregs
, outregs
;
808 intdos (&inregs
, &outregs
);
812 /* Given a face id FACE, extract the face parameters to be used for
813 display until the face changes. The face parameters (actually, its
814 color) are used to construct the video attribute byte for each
815 glyph during the construction of the buffer that is then blitted to
818 IT_set_face (int face
)
820 struct frame
*sf
= SELECTED_FRAME();
821 struct face
*fp
= FACE_FROM_ID (sf
, face
);
822 unsigned long fg
, bg
;
826 fp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
827 /* The default face for the frame should always be realized and
836 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_*
837 colors mean use the colors of the default face, except that if
838 highlight is on, invert the foreground and the background. Note
839 that we assume all 16 colors to be available for the background,
840 since Emacs switches on this mode (and loses the blinking
841 attribute) at startup. */
842 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
843 fg
= FRAME_FOREGROUND_PIXEL (sf
);
844 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
845 fg
= FRAME_BACKGROUND_PIXEL (sf
);
846 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
847 bg
= FRAME_BACKGROUND_PIXEL (sf
);
848 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
849 bg
= FRAME_FOREGROUND_PIXEL (sf
);
851 /* Make sure highlighted lines really stand out, come what may. */
852 if ((highlight
|| fp
->tty_reverse_p
)
853 && (fg
== FRAME_FOREGROUND_PIXEL (sf
)
854 && bg
== FRAME_BACKGROUND_PIXEL (sf
)))
856 unsigned long tem
= fg
;
862 fprintf (termscript
, "<FACE %d%s: %d/%d[FG:%d/BG:%d]>", face
,
863 highlight
? "H" : "", fp
->foreground
, fp
->background
, fg
, bg
);
864 if (fg
>= 0 && fg
< 16)
866 ScreenAttrib
&= 0xf0;
869 if (bg
>= 0 && bg
< 16)
871 ScreenAttrib
&= 0x0f;
872 ScreenAttrib
|= ((bg
& 0x0f) << 4);
876 Lisp_Object Vdos_unsupported_char_glyph
;
879 IT_write_glyphs (struct glyph
*str
, int str_len
)
881 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
882 int unsupported_face
= FAST_GLYPH_FACE (Vdos_unsupported_char_glyph
);
883 unsigned unsupported_char
= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph
);
884 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
885 register int sl
= str_len
;
886 register int tlen
= GLYPH_TABLE_LENGTH
;
887 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
889 struct coding_system
*coding
= (CODING_REQUIRE_ENCODING (&terminal_coding
)
891 : &safe_terminal_coding
);
894 /* Do we need to consider conversion of unibyte characters to
896 int convert_unibyte_characters
897 = (NILP (current_buffer
->enable_multibyte_characters
)
898 && unibyte_display_via_language_environment
);
900 if (str_len
<= 0) return;
902 screen_buf
= screen_bp
= alloca (str_len
* 2);
903 screen_buf_end
= screen_buf
+ str_len
* 2;
904 sf
= SELECTED_FRAME();
906 /* Since faces get cached and uncached behind our back, we can't
907 rely on their indices in the cache being consistent across
908 invocations. So always reset the screen face to the default
909 face of the frame, before writing glyphs, and let the glyphs
910 set the right face if it's different from the default. */
911 IT_set_face (DEFAULT_FACE_ID
);
913 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
915 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
918 int cf
, chlen
, enclen
;
919 unsigned char workbuf
[MAX_MULTIBYTE_LENGTH
], *buf
;
922 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
923 only for the redisplay code to know how many columns does
924 this character occupy on the screen. Skip padding glyphs. */
925 if (CHAR_GLYPH_PADDING_P (*str
))
932 register GLYPH g
= GLYPH_FROM_CHAR_GLYPH (*str
);
933 int glyph_not_in_table
= 0;
935 if (g
< 0 || g
>= tlen
)
937 /* This glyph doesn't have an entry in Vglyph_table. */
939 glyph_not_in_table
= 1;
943 /* This glyph has an entry in Vglyph_table, so process
944 any aliases before testing for simpleness. */
945 GLYPH_FOLLOW_ALIASES (tbase
, tlen
, g
);
946 ch
= FAST_GLYPH_CHAR (g
);
949 /* Convert the character code to multibyte, if they
950 requested display via language environment. We only want
951 to convert unibyte characters to multibyte in unibyte
952 buffers! Otherwise, the 8-bit value in CH came from the
953 display table set up to display foreign characters. */
954 if (SINGLE_BYTE_CHAR_P (ch
) && convert_unibyte_characters
956 || (ch
>= 0200 && !NILP (Vnonascii_translation_table
))))
957 ch
= unibyte_char_to_multibyte (ch
);
959 /* Invalid characters are displayed with a special glyph. */
960 if (! CHAR_VALID_P (ch
, 0))
962 g
= !NILP (Vdos_unsupported_char_glyph
)
963 ? Vdos_unsupported_char_glyph
964 : MAKE_GLYPH (sf
, '\177', GLYPH_FACE (sf
, g
));
965 ch
= FAST_GLYPH_CHAR (g
);
968 /* If the face of this glyph is different from the current
969 screen face, update the screen attribute byte. */
970 cf
= FAST_GLYPH_FACE (g
);
971 if (cf
!= screen_face
)
972 IT_set_face (cf
); /* handles invalid faces gracefully */
974 if (glyph_not_in_table
|| GLYPH_SIMPLE_P (tbase
, tlen
, g
))
976 /* We generate the multi-byte form of CH in WORKBUF. */
977 chlen
= CHAR_STRING (ch
, workbuf
);
982 /* We have a string in Vglyph_table. */
983 chlen
= GLYPH_LENGTH (tbase
, g
);
984 buf
= GLYPH_STRING (tbase
, g
);
987 /* If the character is not multibyte, don't bother converting it. */
990 *conversion_buffer
= (unsigned char)ch
;
996 encode_coding (coding
, buf
, conversion_buffer
, chlen
,
997 conversion_buffer_size
);
998 chlen
-= coding
->consumed
;
999 enclen
= coding
->produced
;
1001 /* Replace glyph codes that cannot be converted by
1002 terminal_coding with Vdos_unsupported_char_glyph. */
1003 if (*conversion_buffer
== '?')
1005 char *cbp
= conversion_buffer
;
1007 while (cbp
< conversion_buffer
+ enclen
&& *cbp
== '?')
1008 *cbp
++ = unsupported_char
;
1009 if (unsupported_face
!= screen_face
)
1010 IT_set_face (unsupported_face
);
1014 if (enclen
+ chlen
> screen_buf_end
- screen_bp
)
1016 /* The allocated buffer for screen writes is too small.
1017 Flush it and loop again without incrementing STR, so
1018 that the next loop will begin with the same glyph. */
1019 int nbytes
= screen_bp
- screen_buf
;
1022 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
1023 if (screen_virtual_segment
)
1024 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
1025 new_pos_X
+= nbytes
/ 2;
1028 /* Prepare to reuse the same buffer again. */
1029 screen_bp
= screen_buf
;
1033 /* There's enough place in the allocated buffer to add
1034 the encoding of this glyph. */
1036 /* First, copy the encoded bytes. */
1037 for (bp
= conversion_buffer
; enclen
--; bp
++)
1039 *screen_bp
++ = (unsigned char)*bp
;
1040 *screen_bp
++ = ScreenAttrib
;
1042 fputc (*bp
, termscript
);
1045 /* Now copy the bytes not consumed by the encoding. */
1048 buf
+= coding
->consumed
;
1052 fputc (*buf
, termscript
);
1053 *screen_bp
++ = (unsigned char)*buf
++;
1054 *screen_bp
++ = ScreenAttrib
;
1058 /* Update STR and its remaining length. */
1065 /* Dump whatever is left in the screen buffer. */
1067 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
1068 if (screen_virtual_segment
)
1069 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1070 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1072 /* We may have to output some codes to terminate the writing. */
1073 if (CODING_REQUIRE_FLUSHING (coding
))
1075 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
1076 encode_coding (coding
, "", conversion_buffer
, 0, conversion_buffer_size
);
1077 if (coding
->produced
> 0)
1079 screen_buf
= alloca (coding
->produced
* 2);
1080 for (screen_bp
= screen_buf
, bp
= conversion_buffer
;
1081 coding
->produced
--; bp
++)
1083 *screen_bp
++ = (unsigned char)*bp
;
1084 *screen_bp
++ = ScreenAttrib
;
1086 fputc (*bp
, termscript
);
1088 offset
+= screen_bp
- screen_buf
;
1090 dosmemput (screen_buf
, screen_bp
- screen_buf
,
1091 (int)ScreenPrimary
+ offset
);
1092 if (screen_virtual_segment
)
1093 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1094 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1099 /************************************************************************
1100 Mouse Highlight (and friends..)
1101 ************************************************************************/
1103 /* This is used for debugging, to turn off note_mouse_highlight. */
1104 int disable_mouse_highlight
;
1106 /* If a string, dos_rawgetc generates an event to display that string.
1107 (The display is done in keyboard.c:read_char.) */
1108 static Lisp_Object help_echo
;
1109 static Lisp_Object previous_help_echo
; /* a helper temporary variable */
1111 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1113 /* Set the mouse pointer shape according to whether it is in the
1114 area where the mouse highlight is in effect. */
1116 IT_set_mouse_pointer (int mode
)
1118 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1119 many possibilities to change its shape, and the available
1120 functionality pretty much sucks (e.g., almost every reasonable
1121 shape will conceal the character it is on). Since the color of
1122 the pointer changes in the highlighted area, it is not clear to
1123 me whether anything else is required, anyway. */
1126 /* Display the active region described by mouse_face_*
1127 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1129 show_mouse_face (struct display_info
*dpyinfo
, int hl
)
1131 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
1132 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
1137 /* If window is in the process of being destroyed, don't bother
1139 if (w
->current_matrix
== NULL
)
1140 goto set_cursor_shape
;
1142 /* Recognize when we are called to operate on rows that don't exist
1143 anymore. This can happen when a window is split. */
1144 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
1145 goto set_cursor_shape
;
1147 /* There's no sense to do anything if the mouse face isn't realized. */
1150 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1152 goto set_cursor_shape
;
1155 /* Note that mouse_face_beg_row etc. are window relative. */
1156 for (i
= dpyinfo
->mouse_face_beg_row
;
1157 i
<= dpyinfo
->mouse_face_end_row
;
1160 int start_hpos
, end_hpos
;
1161 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1163 /* Don't do anything if row doesn't have valid contents. */
1164 if (!row
->enabled_p
)
1167 /* For all but the first row, the highlight starts at column 0. */
1168 if (i
== dpyinfo
->mouse_face_beg_row
)
1169 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1173 if (i
== dpyinfo
->mouse_face_end_row
)
1174 end_hpos
= dpyinfo
->mouse_face_end_col
;
1176 end_hpos
= row
->used
[TEXT_AREA
];
1178 if (end_hpos
<= start_hpos
)
1182 int vpos
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1183 int kstart
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1184 int nglyphs
= end_hpos
- start_hpos
;
1185 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1186 int start_offset
= offset
;
1189 fprintf (termscript
, "\n<MH+ %d-%d:%d>",
1190 kstart
, kstart
+ nglyphs
- 1, vpos
);
1193 IT_set_face (dpyinfo
->mouse_face_face_id
);
1194 /* Since we are going to change only the _colors_ of the
1195 displayed text, there's no need to go through all the
1196 pain of generating and encoding the text from the glyphs.
1197 Instead, we simply poke the attribute byte of each
1198 affected position in video memory with the colors
1199 computed by IT_set_face! */
1200 _farsetsel (_dos_ds
);
1203 _farnspokeb (offset
, ScreenAttrib
);
1206 if (screen_virtual_segment
)
1207 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1212 /* We are removing a previously-drawn mouse highlight. The
1213 safest way to do so is to redraw the glyphs anew, since
1214 all kinds of faces and display tables could have changed
1216 int nglyphs
= end_hpos
- start_hpos
;
1217 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1219 if (end_hpos
>= row
->used
[TEXT_AREA
])
1220 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1222 /* IT_write_glyphs writes at cursor position, so we need to
1223 temporarily move cursor coordinates to the beginning of
1224 the highlight region. */
1225 new_pos_X
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1226 new_pos_Y
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1229 fprintf (termscript
, "<MH- %d-%d:%d>",
1230 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1231 IT_write_glyphs (row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1233 fputs ("\n", termscript
);
1241 /* Change the mouse pointer shape. */
1242 IT_set_mouse_pointer (hl
);
1245 /* Clear out the mouse-highlighted active region.
1246 Redraw it un-highlighted first. */
1248 clear_mouse_face (struct display_info
*dpyinfo
)
1250 if (! NILP (dpyinfo
->mouse_face_window
))
1251 show_mouse_face (dpyinfo
, 0);
1253 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1254 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1255 dpyinfo
->mouse_face_window
= Qnil
;
1258 /* Find the glyph matrix position of buffer position POS in window W.
1259 *HPOS and *VPOS are set to the positions found. W's current glyphs
1260 must be up to date. If POS is above window start return (0, 0).
1261 If POS is after end of W, return end of last line in W. */
1263 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1267 int maybe_next_line_p
= 0;
1268 int line_start_position
;
1269 int yb
= window_text_bottom_y (w
);
1270 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0);
1271 struct glyph_row
*best_row
= row
;
1275 if (row
->used
[TEXT_AREA
])
1276 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1278 line_start_position
= 0;
1280 if (line_start_position
> pos
)
1282 /* If the position sought is the end of the buffer,
1283 don't include the blank lines at the bottom of the window. */
1284 else if (line_start_position
== pos
1285 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1287 maybe_next_line_p
= 1;
1290 else if (line_start_position
> 0)
1296 /* Find the right column within BEST_ROW. */
1299 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1301 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1304 charpos
= glyph
->charpos
;
1311 else if (charpos
> pos
)
1313 else if (charpos
> 0)
1317 /* If we're looking for the end of the buffer,
1318 and we didn't find it in the line we scanned,
1319 use the start of the following line. */
1320 if (maybe_next_line_p
)
1327 *hpos
= lastcol
+ 1;
1331 /* Take proper action when mouse has moved to the mode or top line of
1332 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1333 mode line. X is relative to the start of the text display area of
1334 W, so the width of bitmap areas and scroll bars must be subtracted
1335 to get a position relative to the start of the mode line. */
1337 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1339 struct frame
*f
= XFRAME (w
->frame
);
1340 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1341 struct glyph_row
*row
;
1344 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1346 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1350 extern Lisp_Object Qhelp_echo
;
1351 struct glyph
*glyph
, *end
;
1352 Lisp_Object help
, map
;
1354 /* Find the glyph under X. */
1355 glyph
= row
->glyphs
[TEXT_AREA
]
1356 + x
- FRAME_LEFT_SCROLL_BAR_WIDTH (f
) * CANON_X_UNIT (f
);
1357 end
= glyph
+ row
->used
[TEXT_AREA
];
1359 && STRINGP (glyph
->object
)
1360 && XSTRING (glyph
->object
)->intervals
1361 && glyph
->charpos
>= 0
1362 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1364 /* If we're on a string with `help-echo' text property,
1365 arrange for the help to be displayed. This is done by
1366 setting the global variable help_echo to the help string. */
1367 help
= Fget_text_property (make_number (glyph
->charpos
),
1368 Qhelp_echo
, glyph
->object
);
1375 /* Take proper action when the mouse has moved to position X, Y on
1376 frame F as regards highlighting characters that have mouse-face
1377 properties. Also de-highlighting chars where the mouse was before.
1378 X and Y can be negative or out of range. */
1380 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1382 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1387 /* When a menu is active, don't highlight because this looks odd. */
1388 if (mouse_preempted
)
1391 if (disable_mouse_highlight
1392 || !f
->glyphs_initialized_p
)
1395 dpyinfo
->mouse_face_mouse_x
= x
;
1396 dpyinfo
->mouse_face_mouse_y
= y
;
1397 dpyinfo
->mouse_face_mouse_frame
= f
;
1399 if (dpyinfo
->mouse_face_defer
)
1404 dpyinfo
->mouse_face_deferred_gc
= 1;
1408 /* Which window is that in? */
1409 window
= window_from_coordinates (f
, x
, y
, &portion
, 0);
1411 /* If we were displaying active text in another window, clear that. */
1412 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1413 clear_mouse_face (dpyinfo
);
1415 /* Not on a window -> return. */
1416 if (!WINDOWP (window
))
1419 /* Convert to window-relative coordinates. */
1420 w
= XWINDOW (window
);
1421 x
-= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1422 y
-= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1424 if (portion
== 1 || portion
== 3)
1426 /* Mouse is on the mode or top line. */
1427 IT_note_mode_line_highlight (w
, x
, portion
== 1);
1431 IT_set_mouse_pointer (0);
1433 /* Are we in a window whose display is up to date?
1434 And verify the buffer's text has not changed. */
1435 if (/* Within text portion of the window. */
1437 && EQ (w
->window_end_valid
, w
->buffer
)
1438 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1439 && (XFASTINT (w
->last_overlay_modified
)
1440 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1443 struct glyph_row
*row
;
1444 struct glyph
*glyph
;
1446 /* Find the glyph under X/Y. */
1448 if (y
< w
->current_matrix
->nrows
)
1450 row
= MATRIX_ROW (w
->current_matrix
, y
);
1452 && row
->displays_text_p
1453 && x
< window_box_width (w
, TEXT_AREA
))
1455 glyph
= row
->glyphs
[TEXT_AREA
];
1456 if (x
>= row
->used
[TEXT_AREA
])
1461 if (!BUFFERP (glyph
->object
))
1467 /* Clear mouse face if X/Y not over text. */
1470 clear_mouse_face (dpyinfo
);
1474 if (!BUFFERP (glyph
->object
))
1476 pos
= glyph
->charpos
;
1478 /* Check for mouse-face and help-echo. */
1480 extern Lisp_Object Qmouse_face
;
1481 Lisp_Object mouse_face
, overlay
, position
;
1482 Lisp_Object
*overlay_vec
;
1484 struct buffer
*obuf
;
1487 /* If we get an out-of-range value, return now; avoid an error. */
1488 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1491 /* Make the window's buffer temporarily current for
1492 overlays_at and compute_char_face. */
1493 obuf
= current_buffer
;
1494 current_buffer
= XBUFFER (w
->buffer
);
1500 /* Is this char mouse-active or does it have help-echo? */
1501 XSETINT (position
, pos
);
1503 /* Put all the overlays we want in a vector in overlay_vec.
1504 Store the length in len. If there are more than 10, make
1505 enough space for all, and try again. */
1507 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1508 noverlays
= overlays_at (pos
, 0, &overlay_vec
, &len
, NULL
, NULL
);
1509 if (noverlays
> len
)
1512 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1513 noverlays
= overlays_at (pos
, 0, &overlay_vec
, &len
, NULL
, NULL
);
1516 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1518 /* Check mouse-face highlighting. */
1519 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1520 && y
>= dpyinfo
->mouse_face_beg_row
1521 && y
<= dpyinfo
->mouse_face_end_row
1522 && (y
> dpyinfo
->mouse_face_beg_row
1523 || x
>= dpyinfo
->mouse_face_beg_col
)
1524 && (y
< dpyinfo
->mouse_face_end_row
1525 || x
< dpyinfo
->mouse_face_end_col
1526 || dpyinfo
->mouse_face_past_end
)))
1528 /* Clear the display of the old active region, if any. */
1529 clear_mouse_face (dpyinfo
);
1531 /* Find highest priority overlay that has a mouse-face prop. */
1533 for (i
= 0; i
< noverlays
; i
++)
1535 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1536 if (!NILP (mouse_face
))
1538 overlay
= overlay_vec
[i
];
1543 /* If no overlay applies, get a text property. */
1545 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1548 /* Handle the overlay case. */
1549 if (! NILP (overlay
))
1551 /* Find the range of text around this char that
1552 should be active. */
1553 Lisp_Object before
, after
;
1556 before
= Foverlay_start (overlay
);
1557 after
= Foverlay_end (overlay
);
1558 /* Record this as the current active region. */
1559 fast_find_position (w
, XFASTINT (before
),
1560 &dpyinfo
->mouse_face_beg_col
,
1561 &dpyinfo
->mouse_face_beg_row
);
1562 dpyinfo
->mouse_face_past_end
1563 = !fast_find_position (w
, XFASTINT (after
),
1564 &dpyinfo
->mouse_face_end_col
,
1565 &dpyinfo
->mouse_face_end_row
);
1566 dpyinfo
->mouse_face_window
= window
;
1567 dpyinfo
->mouse_face_face_id
1568 = face_at_buffer_position (w
, pos
, 0, 0,
1569 &ignore
, pos
+ 1, 1);
1571 /* Display it as active. */
1572 show_mouse_face (dpyinfo
, 1);
1574 /* Handle the text property case. */
1575 else if (! NILP (mouse_face
))
1577 /* Find the range of text around this char that
1578 should be active. */
1579 Lisp_Object before
, after
, beginning
, end
;
1582 beginning
= Fmarker_position (w
->start
);
1583 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1584 - XFASTINT (w
->window_end_pos
)));
1586 = Fprevious_single_property_change (make_number (pos
+ 1),
1588 w
->buffer
, beginning
);
1590 = Fnext_single_property_change (position
, Qmouse_face
,
1592 /* Record this as the current active region. */
1593 fast_find_position (w
, XFASTINT (before
),
1594 &dpyinfo
->mouse_face_beg_col
,
1595 &dpyinfo
->mouse_face_beg_row
);
1596 dpyinfo
->mouse_face_past_end
1597 = !fast_find_position (w
, XFASTINT (after
),
1598 &dpyinfo
->mouse_face_end_col
,
1599 &dpyinfo
->mouse_face_end_row
);
1600 dpyinfo
->mouse_face_window
= window
;
1601 dpyinfo
->mouse_face_face_id
1602 = face_at_buffer_position (w
, pos
, 0, 0,
1603 &ignore
, pos
+ 1, 1);
1605 /* Display it as active. */
1606 show_mouse_face (dpyinfo
, 1);
1610 /* Look for a `help-echo' property. */
1613 extern Lisp_Object Qhelp_echo
;
1615 /* Check overlays first. */
1617 for (i
= 0; i
< noverlays
&& !STRINGP (help
); ++i
)
1618 help
= Foverlay_get (overlay_vec
[i
], Qhelp_echo
);
1620 /* Try text properties. */
1622 && ((STRINGP (glyph
->object
)
1623 && glyph
->charpos
>= 0
1624 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1625 || (BUFFERP (glyph
->object
)
1626 && glyph
->charpos
>= BEGV
1627 && glyph
->charpos
< ZV
)))
1628 help
= Fget_text_property (make_number (glyph
->charpos
),
1629 Qhelp_echo
, glyph
->object
);
1637 current_buffer
= obuf
;
1643 IT_clear_end_of_line (int first_unused
)
1647 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1648 extern int fatal_error_in_progress
;
1650 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1654 i
= (j
= first_unused
- new_pos_X
) * 2;
1656 fprintf (termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1657 spaces
= sp
= alloca (i
);
1662 *sp
++ = ScreenAttrib
;
1666 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1667 if (screen_virtual_segment
)
1668 dosv_refresh_virtual_screen (offset
, i
/ 2);
1670 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1671 Let's follow their lead, in case someone relies on this. */
1672 new_pos_X
= first_unused
;
1676 IT_clear_screen (void)
1679 fprintf (termscript
, "<CLR:SCR>");
1683 if (screen_virtual_segment
)
1684 dosv_refresh_virtual_screen (0, screen_size
);
1685 new_pos_X
= new_pos_Y
= 0;
1689 IT_clear_to_end (void)
1692 fprintf (termscript
, "<CLR:EOS>");
1694 while (new_pos_Y
< screen_size_Y
) {
1696 IT_clear_end_of_line (screen_size_X
);
1702 IT_cursor_to (int y
, int x
)
1705 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
1710 static int cursor_cleared
;
1713 IT_display_cursor (int on
)
1715 if (on
&& cursor_cleared
)
1717 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1720 else if (!on
&& !cursor_cleared
)
1722 ScreenSetCursor (-1, -1);
1727 /* Emacs calls cursor-movement functions a lot when it updates the
1728 display (probably a legacy of old terminals where you cannot
1729 update a screen line without first moving the cursor there).
1730 However, cursor movement is expensive on MSDOS (it calls a slow
1731 BIOS function and requires 2 mode switches), while actual screen
1732 updates access the video memory directly and don't depend on
1733 cursor position. To avoid slowing down the redisplay, we cheat:
1734 all functions that move the cursor only set internal variables
1735 which record the cursor position, whereas the cursor is only
1736 moved to its final position whenever screen update is complete.
1738 `IT_cmgoto' is called from the keyboard reading loop and when the
1739 frame update is complete. This means that we are ready for user
1740 input, so we update the cursor position to show where the point is,
1741 and also make the mouse pointer visible.
1743 Special treatment is required when the cursor is in the echo area,
1744 to put the cursor at the end of the text displayed there. */
1747 IT_cmgoto (FRAME_PTR f
)
1749 /* Only set the cursor to where it should be if the display is
1750 already in sync with the window contents. */
1751 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1753 /* FIXME: This needs to be rewritten for the new redisplay, or
1756 static int previous_pos_X
= -1;
1758 update_cursor_pos
= 1; /* temporary!!! */
1760 /* If the display is in sync, forget any previous knowledge about
1761 cursor position. This is primarily for unexpected events like
1762 C-g in the minibuffer. */
1763 if (update_cursor_pos
&& previous_pos_X
>= 0)
1764 previous_pos_X
= -1;
1765 /* If we are in the echo area, put the cursor at the
1766 end of the echo area message. */
1767 if (!update_cursor_pos
1768 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1770 int tem_X
= current_pos_X
, dummy
;
1772 if (echo_area_glyphs
)
1774 tem_X
= echo_area_glyphs_length
;
1775 /* Save current cursor position, to be restored after the
1776 echo area message is erased. Only remember one level
1777 of previous cursor position. */
1778 if (previous_pos_X
== -1)
1779 ScreenGetCursor (&dummy
, &previous_pos_X
);
1781 else if (previous_pos_X
>= 0)
1783 /* We wind up here after the echo area message is erased.
1784 Restore the cursor position we remembered above. */
1785 tem_X
= previous_pos_X
;
1786 previous_pos_X
= -1;
1789 if (current_pos_X
!= tem_X
)
1792 update_cursor_pos
= 1;
1797 if (update_cursor_pos
1798 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1800 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1802 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1805 /* Maybe cursor is invisible, so make it visible. */
1806 IT_display_cursor (1);
1808 /* Mouse pointer should be always visible if we are waiting for
1815 IT_reassert_line_highlight (int new, int vpos
)
1821 IT_change_line_highlight (int new_highlight
, int y
, int vpos
, int first_unused_hpos
)
1823 highlight
= new_highlight
;
1824 IT_cursor_to (vpos
, 0);
1825 IT_clear_end_of_line (first_unused_hpos
);
1829 IT_update_begin (struct frame
*f
)
1831 struct display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1837 if (f
== display_info
->mouse_face_mouse_frame
)
1839 /* Don't do highlighting for mouse motion during the update. */
1840 display_info
->mouse_face_defer
= 1;
1842 /* If F needs to be redrawn, simply forget about any prior mouse
1844 if (FRAME_GARBAGED_P (f
))
1845 display_info
->mouse_face_window
= Qnil
;
1847 /* Can we tell that this update does not affect the window
1848 where the mouse highlight is? If so, no need to turn off.
1849 Likewise, don't do anything if the frame is garbaged;
1850 in that case, the frame's current matrix that we would use
1851 is all wrong, and we will redisplay that line anyway. */
1852 if (!NILP (display_info
->mouse_face_window
)
1853 && WINDOWP (display_info
->mouse_face_window
))
1855 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1858 /* If the mouse highlight is in the window that was deleted
1859 (e.g., if it was popped by completion), clear highlight
1861 if (NILP (w
->buffer
))
1862 display_info
->mouse_face_window
= Qnil
;
1865 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1866 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
))
1870 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1871 clear_mouse_face (display_info
);
1874 else if (!FRAME_LIVE_P (display_info
->mouse_face_mouse_frame
))
1876 /* If the frame with mouse highlight was deleted, invalidate the
1878 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1879 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1880 display_info
->mouse_face_window
= Qnil
;
1881 display_info
->mouse_face_deferred_gc
= 0;
1882 display_info
->mouse_face_mouse_frame
= NULL
;
1889 IT_update_end (struct frame
*f
)
1892 FRAME_X_DISPLAY_INFO (f
)->mouse_face_defer
= 0;
1895 Lisp_Object Qcursor_type
;
1898 IT_frame_up_to_date (struct frame
*f
)
1900 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1902 if (dpyinfo
->mouse_face_deferred_gc
1903 || f
== dpyinfo
->mouse_face_mouse_frame
)
1906 if (dpyinfo
->mouse_face_mouse_frame
)
1907 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
1908 dpyinfo
->mouse_face_mouse_x
,
1909 dpyinfo
->mouse_face_mouse_y
);
1910 dpyinfo
->mouse_face_deferred_gc
= 0;
1914 /* Set the cursor type to whatever they wanted. */
1915 IT_set_cursor_type (f
, Fcdr (Fassq (Qcursor_type
, f
->param_alist
)));
1917 IT_cmgoto (f
); /* position cursor when update is done */
1920 /* Copy LEN glyphs displayed on a single line whose vertical position
1921 is YPOS, beginning at horizontal position XFROM to horizontal
1922 position XTO, by moving blocks in the video memory. Used by
1923 functions that insert and delete glyphs. */
1925 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1927 /* The offsets of source and destination relative to the
1928 conventional memorty selector. */
1929 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1930 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1932 if (from
== to
|| len
<= 0)
1935 _farsetsel (_dos_ds
);
1937 /* The source and destination might overlap, so we need to move
1938 glyphs non-destructively. */
1941 for ( ; len
; from
+= 2, to
+= 2, len
--)
1942 _farnspokew (to
, _farnspeekw (from
));
1946 from
+= (len
- 1) * 2;
1947 to
+= (len
- 1) * 2;
1948 for ( ; len
; from
-= 2, to
-= 2, len
--)
1949 _farnspokew (to
, _farnspeekw (from
));
1951 if (screen_virtual_segment
)
1952 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1955 /* Insert and delete glyphs. */
1957 IT_insert_glyphs (start
, len
)
1958 register struct glyph
*start
;
1961 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1963 /* Shift right the glyphs from the nominal cursor position to the
1964 end of this line. */
1965 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
1967 /* Now write the glyphs to be inserted. */
1968 IT_write_glyphs (start
, len
);
1972 IT_delete_glyphs (n
)
1978 /* set-window-configuration on window.c needs this. */
1980 x_set_menu_bar_lines (f
, value
, oldval
)
1982 Lisp_Object value
, oldval
;
1984 set_menu_bar_lines (f
, value
, oldval
);
1987 /* This was copied from xfns.c */
1989 Lisp_Object Qbackground_color
;
1990 Lisp_Object Qforeground_color
;
1991 Lisp_Object Qreverse
;
1992 extern Lisp_Object Qtitle
;
1994 /* IT_set_terminal_modes is called when emacs is started,
1995 resumed, and whenever the screen is redrawn! */
1998 IT_set_terminal_modes (void)
2001 fprintf (termscript
, "\n<SET_TERM>");
2004 screen_size_X
= ScreenCols ();
2005 screen_size_Y
= ScreenRows ();
2006 screen_size
= screen_size_X
* screen_size_Y
;
2008 new_pos_X
= new_pos_Y
= 0;
2009 current_pos_X
= current_pos_Y
= -1;
2011 if (term_setup_done
)
2013 term_setup_done
= 1;
2015 startup_screen_size_X
= screen_size_X
;
2016 startup_screen_size_Y
= screen_size_Y
;
2017 startup_screen_attrib
= ScreenAttrib
;
2020 /* Is DOS/V (or any other RSIS software which relocates
2021 the screen) installed? */
2023 unsigned short es_value
;
2026 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2027 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2028 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2029 else if (screen_old_address
) /* already switched to Japanese mode once */
2030 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2032 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2034 es_value
= regs
.x
.es
;
2035 __dpmi_int (0x10, ®s
);
2037 if (regs
.x
.es
!= es_value
)
2039 /* screen_old_address is only set if ScreenPrimary does NOT
2040 already point to the relocated buffer address returned by
2041 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2042 ScreenPrimary to that address at startup under DOS/V. */
2043 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2044 screen_old_address
= ScreenPrimary
;
2045 screen_virtual_segment
= regs
.x
.es
;
2046 screen_virtual_offset
= regs
.x
.di
;
2047 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2050 #endif /* __DJGPP__ > 1 */
2052 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2053 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2056 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2057 screen_size_X
, screen_size_Y
);
2062 /* IT_reset_terminal_modes is called when emacs is
2063 suspended or killed. */
2066 IT_reset_terminal_modes (void)
2068 int display_row_start
= (int) ScreenPrimary
;
2069 int saved_row_len
= startup_screen_size_X
* 2;
2070 int update_row_len
= ScreenCols () * 2;
2071 int current_rows
= ScreenRows ();
2072 int to_next_row
= update_row_len
;
2073 unsigned char *saved_row
= startup_screen_buffer
;
2074 int cursor_pos_X
= ScreenCols () - 1;
2075 int cursor_pos_Y
= ScreenRows () - 1;
2078 fprintf (termscript
, "\n<RESET_TERM>");
2082 if (!term_setup_done
)
2087 /* Leave the video system in the same state as we found it,
2088 as far as the blink/bright-background bit is concerned. */
2089 maybe_enable_blinking ();
2091 /* We have a situation here.
2092 We cannot just do ScreenUpdate(startup_screen_buffer) because
2093 the luser could have changed screen dimensions inside Emacs
2094 and failed (or didn't want) to restore them before killing
2095 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2096 thus will happily use memory outside what was allocated for
2097 `startup_screen_buffer'.
2098 Thus we only restore as much as the current screen dimensions
2099 can hold, and clear the rest (if the saved screen is smaller than
2100 the current) with the color attribute saved at startup. The cursor
2101 is also restored within the visible dimensions. */
2103 ScreenAttrib
= startup_screen_attrib
;
2105 /* Don't restore the screen if we are exiting less than 2 seconds
2106 after startup: we might be crashing, and the screen might show
2107 some vital clues to what's wrong. */
2108 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2111 if (screen_virtual_segment
)
2112 dosv_refresh_virtual_screen (0, screen_size
);
2114 if (update_row_len
> saved_row_len
)
2115 update_row_len
= saved_row_len
;
2116 if (current_rows
> startup_screen_size_Y
)
2117 current_rows
= startup_screen_size_Y
;
2120 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2121 update_row_len
/ 2, current_rows
);
2123 while (current_rows
--)
2125 dosmemput (saved_row
, update_row_len
, display_row_start
);
2126 if (screen_virtual_segment
)
2127 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2128 update_row_len
/ 2);
2129 saved_row
+= saved_row_len
;
2130 display_row_start
+= to_next_row
;
2133 if (startup_pos_X
< cursor_pos_X
)
2134 cursor_pos_X
= startup_pos_X
;
2135 if (startup_pos_Y
< cursor_pos_Y
)
2136 cursor_pos_Y
= startup_pos_Y
;
2138 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2139 xfree (startup_screen_buffer
);
2141 term_setup_done
= 0;
2145 IT_set_terminal_window (int foo
)
2149 /* Remember the screen colors of the curent frame, to serve as the
2150 default colors for newly-created frames. */
2152 static int initial_screen_colors
[2];
2154 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2155 Smsdos_remember_default_colors
, 1, 1, 0,
2156 "Remember the screen colors of the current frame.")
2163 CHECK_FRAME (frame
, 0);
2165 reverse
= EQ (Fcdr (Fassq (intern ("reverse"), f
->param_alist
)), Qt
);
2167 initial_screen_colors
[0]
2168 = reverse
? FRAME_BACKGROUND_PIXEL (f
) : FRAME_FOREGROUND_PIXEL (f
);
2169 initial_screen_colors
[1]
2170 = reverse
? FRAME_FOREGROUND_PIXEL (f
) : FRAME_BACKGROUND_PIXEL (f
);
2174 IT_set_frame_parameters (f
, alist
)
2179 int length
= XINT (Flength (alist
));
2182 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2184 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2185 /* Do we have to reverse the foreground and background colors? */
2186 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2187 int was_reverse
= reverse
;
2188 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2189 unsigned long orig_fg
;
2190 unsigned long orig_bg
;
2192 /* If we are creating a new frame, begin with the original screen colors
2193 used for the initial frame. */
2194 if (alist
== Vdefault_frame_alist
2195 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2197 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2198 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2200 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2201 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2203 /* Extract parm names and values into those vectors. */
2205 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2210 parms
[i
] = Fcar (elt
);
2211 CHECK_SYMBOL (parms
[i
], 1);
2212 values
[i
] = Fcdr (elt
);
2218 for (i
= 0; i
< j
; i
++)
2220 Lisp_Object prop
= parms
[i
];
2221 Lisp_Object val
= values
[i
];
2223 if (EQ (prop
, Qreverse
))
2224 reverse
= EQ (val
, Qt
);
2227 if (termscript
&& reverse
&& !was_reverse
)
2228 fprintf (termscript
, "<INVERSE-VIDEO>\n");
2230 /* Now process the alist elements in reverse of specified order. */
2231 for (i
--; i
>= 0; i
--)
2233 Lisp_Object prop
= parms
[i
];
2234 Lisp_Object val
= values
[i
];
2236 if (EQ (prop
, Qforeground_color
))
2238 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
2239 ? LFACE_BACKGROUND_INDEX
2240 : LFACE_FOREGROUND_INDEX
);
2241 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2242 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2243 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2246 /* FIXME: should the fore-/background of the default
2247 face change here as well? */
2248 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2250 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2254 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
2257 else if (EQ (prop
, Qbackground_color
))
2259 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
2260 ? LFACE_FOREGROUND_INDEX
2261 : LFACE_BACKGROUND_INDEX
);
2262 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2263 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2264 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2267 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2269 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2273 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
2276 else if (EQ (prop
, Qtitle
))
2278 x_set_title (f
, val
);
2280 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
2282 else if (EQ (prop
, Qcursor_type
))
2284 IT_set_cursor_type (f
, val
);
2286 fprintf (termscript
, "<CTYPE: %s>\n",
2287 EQ (val
, Qbar
) || CONSP (val
) && EQ (XCAR (val
), Qbar
)
2290 store_frame_param (f
, prop
, val
);
2293 /* If they specified "reverse", but not the colors, we need to swap
2294 the current frame colors. */
2295 if (reverse
&& !was_reverse
)
2299 FRAME_BACKGROUND_PIXEL (f
) = orig_fg
;
2304 FRAME_FOREGROUND_PIXEL (f
) = orig_bg
;
2311 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2312 if (f
== SELECTED_FRAME())
2317 extern void init_frame_faces (FRAME_PTR
);
2319 #endif /* !HAVE_X_WINDOWS */
2322 /* Do we need the internal terminal? */
2325 internal_terminal_init ()
2327 char *term
= getenv ("TERM");
2329 struct frame
*sf
= SELECTED_FRAME();
2331 #ifdef HAVE_X_WINDOWS
2332 if (!inhibit_window_system
)
2337 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2339 if (getenv ("EMACSTEST"))
2340 termscript
= fopen (getenv ("EMACSTEST"), "wt");
2342 #ifndef HAVE_X_WINDOWS
2343 if (!internal_terminal
|| inhibit_window_system
)
2345 sf
->output_method
= output_termcap
;
2349 Vwindow_system
= intern ("pc");
2350 Vwindow_system_version
= make_number (1);
2351 sf
->output_method
= output_msdos_raw
;
2353 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2354 screen_old_address
= 0;
2356 /* Forget the stale screen colors as well. */
2357 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2359 bzero (&the_only_x_display
, sizeof the_only_x_display
);
2360 the_only_x_display
.background_pixel
= 7; /* White */
2361 the_only_x_display
.foreground_pixel
= 0; /* Black */
2363 colors
= getenv ("EMACSCOLORS");
2364 if (colors
&& strlen (colors
) >= 2)
2366 /* The colors use 4 bits each (we enable bright background). */
2367 if (isdigit (colors
[0]))
2369 else if (isxdigit (colors
[0]))
2370 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2371 if (colors
[0] >= 0 && colors
[0] < 16)
2372 the_only_x_display
.foreground_pixel
= colors
[0];
2373 if (isdigit (colors
[1]))
2375 else if (isxdigit (colors
[1]))
2376 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2377 if (colors
[1] >= 0 && colors
[1] < 16)
2378 the_only_x_display
.background_pixel
= colors
[1];
2380 the_only_x_display
.line_height
= 1;
2381 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
2382 the_only_x_display
.display_info
.mouse_face_mouse_frame
= NULL
;
2383 the_only_x_display
.display_info
.mouse_face_deferred_gc
= 0;
2384 the_only_x_display
.display_info
.mouse_face_beg_row
=
2385 the_only_x_display
.display_info
.mouse_face_beg_col
= -1;
2386 the_only_x_display
.display_info
.mouse_face_end_row
=
2387 the_only_x_display
.display_info
.mouse_face_end_col
= -1;
2388 the_only_x_display
.display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2389 the_only_x_display
.display_info
.mouse_face_window
= Qnil
;
2390 the_only_x_display
.display_info
.mouse_face_mouse_x
=
2391 the_only_x_display
.display_info
.mouse_face_mouse_y
= 0;
2392 the_only_x_display
.display_info
.mouse_face_defer
= 0;
2394 init_frame_faces (sf
);
2396 ring_bell_hook
= IT_ring_bell
;
2397 insert_glyphs_hook
= IT_insert_glyphs
;
2398 delete_glyphs_hook
= IT_delete_glyphs
;
2399 write_glyphs_hook
= IT_write_glyphs
;
2400 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
2401 clear_to_end_hook
= IT_clear_to_end
;
2402 clear_end_of_line_hook
= IT_clear_end_of_line
;
2403 clear_frame_hook
= IT_clear_screen
;
2404 change_line_highlight_hook
= IT_change_line_highlight
;
2405 update_begin_hook
= IT_update_begin
;
2406 update_end_hook
= IT_update_end
;
2407 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
2408 frame_up_to_date_hook
= IT_frame_up_to_date
;
2410 /* These hooks are called by term.c without being checked. */
2411 set_terminal_modes_hook
= IT_set_terminal_modes
;
2412 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2413 set_terminal_window_hook
= IT_set_terminal_window
;
2414 char_ins_del_ok
= 0;
2418 dos_get_saved_screen (screen
, rows
, cols
)
2423 #ifndef HAVE_X_WINDOWS
2424 *screen
= startup_screen_buffer
;
2425 *cols
= startup_screen_size_X
;
2426 *rows
= startup_screen_size_Y
;
2427 return *screen
!= (char *)0;
2433 #ifndef HAVE_X_WINDOWS
2435 /* We are not X, but we can emulate it well enough for our needs... */
2439 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2440 error ("Not running under a window system");
2446 /* ----------------------- Keyboard control ----------------------
2448 * Keymaps reflect the following keyboard layout:
2450 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2451 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2452 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2453 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2457 #define Ignore 0x0000
2458 #define Normal 0x0000 /* normal key - alt changes scan-code */
2459 #define FctKey 0x1000 /* func key if c == 0, else c */
2460 #define Special 0x2000 /* func key even if c != 0 */
2461 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2462 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2463 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2464 #define Grey 0x6000 /* Grey keypad key */
2466 #define Alt 0x0100 /* alt scan-code */
2467 #define Ctrl 0x0200 /* ctrl scan-code */
2468 #define Shift 0x0400 /* shift scan-code */
2470 static int extended_kbd
; /* 101 (102) keyboard present. */
2472 struct kbd_translate
{
2475 unsigned short code
;
2478 struct dos_keyboard_map
2483 struct kbd_translate
*translate_table
;
2487 static struct dos_keyboard_map us_keyboard
= {
2489 /* 01234567890123456789012345678901234567890 12345678901234 */
2490 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2491 /* 0123456789012345678901234567890123456789 012345678901234 */
2492 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2493 0, /* no Alt-Gr key */
2494 0 /* no translate table */
2497 static struct dos_keyboard_map fr_keyboard
= {
2499 /* 012 3456789012345678901234567890123456789012345678901234 */
2500 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2501 /* 0123456789012345678901234567890123456789012345678901234 */
2502 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2503 /* 01234567 89012345678901234567890123456789012345678901234 */
2505 0 /* no translate table */
2509 * Italian keyboard support, country code 39.
2512 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2513 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2516 static struct kbd_translate it_kbd_translate_table
[] = {
2517 { 0x56, 0x3c, Normal
| 13 },
2518 { 0x56, 0x3e, Normal
| 27 },
2521 static struct dos_keyboard_map it_keyboard
= {
2523 /* 0 123456789012345678901234567890123456789012345678901234 */
2524 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2525 /* 01 23456789012345678901234567890123456789012345678901234 */
2526 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2527 /* 0123456789012345678901234567890123456789012345678901234 */
2529 it_kbd_translate_table
2532 static struct dos_keyboard_map dk_keyboard
= {
2534 /* 0123456789012345678901234567890123456789012345678901234 */
2535 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2536 /* 01 23456789012345678901234567890123456789012345678901234 */
2537 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2538 /* 0123456789012345678901234567890123456789012345678901234 */
2540 0 /* no translate table */
2543 static struct kbd_translate jp_kbd_translate_table
[] = {
2544 { 0x73, 0x5c, Normal
| 0 },
2545 { 0x73, 0x5f, Normal
| 0 },
2546 { 0x73, 0x1c, Map
| 0 },
2547 { 0x7d, 0x5c, Normal
| 13 },
2548 { 0x7d, 0x7c, Normal
| 13 },
2549 { 0x7d, 0x1c, Map
| 13 },
2552 static struct dos_keyboard_map jp_keyboard
= {
2554 /* 0123456789012 345678901234567890123456789012345678901234 */
2555 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2556 /* 01 23456789012345678901234567890123456789012345678901234 */
2557 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2558 0, /* no Alt-Gr key */
2559 jp_kbd_translate_table
2562 static struct keyboard_layout_list
2565 struct dos_keyboard_map
*keyboard_map
;
2566 } keyboard_layout_list
[] =
2575 static struct dos_keyboard_map
*keyboard
;
2576 static int keyboard_map_all
;
2577 static int international_keyboard
;
2580 dos_set_keyboard (code
, always
)
2585 _go32_dpmi_registers regs
;
2587 /* See if Keyb.Com is installed (for international keyboard support).
2588 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2589 of Windows 9X! So don't do that! */
2591 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2592 _go32_dpmi_simulate_int (0x2f, ®s
);
2593 if (regs
.h
.al
== 0xff)
2594 international_keyboard
= 1;
2596 /* Initialize to US settings, for countries that don't have their own. */
2597 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2598 keyboard_map_all
= always
;
2599 dos_keyboard_layout
= 1;
2601 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2602 if (code
== keyboard_layout_list
[i
].country_code
)
2604 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2605 keyboard_map_all
= always
;
2606 dos_keyboard_layout
= code
;
2614 unsigned char char_code
; /* normal code */
2615 unsigned char meta_code
; /* M- code */
2616 unsigned char keypad_code
; /* keypad code */
2617 unsigned char editkey_code
; /* edit key */
2618 } keypad_translate_map
[] = {
2619 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2620 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2621 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2622 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2623 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2624 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2625 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2626 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2627 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2628 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2629 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2634 unsigned char char_code
; /* normal code */
2635 unsigned char keypad_code
; /* keypad code */
2636 } grey_key_translate_map
[] = {
2637 '/', 0xaf, /* kp-decimal */
2638 '*', 0xaa, /* kp-multiply */
2639 '-', 0xad, /* kp-subtract */
2640 '+', 0xab, /* kp-add */
2641 '\r', 0x8d /* kp-enter */
2644 static unsigned short
2645 ibmpc_translate_map
[] =
2647 /* --------------- 00 to 0f --------------- */
2648 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2649 Alt
| ModFct
| 0x1b, /* Escape */
2650 Normal
| 1, /* '1' */
2651 Normal
| 2, /* '2' */
2652 Normal
| 3, /* '3' */
2653 Normal
| 4, /* '4' */
2654 Normal
| 5, /* '5' */
2655 Normal
| 6, /* '6' */
2656 Normal
| 7, /* '7' */
2657 Normal
| 8, /* '8' */
2658 Normal
| 9, /* '9' */
2659 Normal
| 10, /* '0' */
2660 Normal
| 11, /* '-' */
2661 Normal
| 12, /* '=' */
2662 Special
| 0x08, /* Backspace */
2663 ModFct
| 0x74, /* Tab/Backtab */
2665 /* --------------- 10 to 1f --------------- */
2678 ModFct
| 0x0d, /* Return */
2683 /* --------------- 20 to 2f --------------- */
2692 Map
| 40, /* '\'' */
2694 Ignore
, /* Left shift */
2695 Map
| 41, /* '\\' */
2701 /* --------------- 30 to 3f --------------- */
2708 Ignore
, /* Right shift */
2709 Grey
| 1, /* Grey * */
2711 Normal
| 55, /* ' ' */
2712 Ignore
, /* Caps Lock */
2713 FctKey
| 0xbe, /* F1 */
2714 FctKey
| 0xbf, /* F2 */
2715 FctKey
| 0xc0, /* F3 */
2716 FctKey
| 0xc1, /* F4 */
2717 FctKey
| 0xc2, /* F5 */
2719 /* --------------- 40 to 4f --------------- */
2720 FctKey
| 0xc3, /* F6 */
2721 FctKey
| 0xc4, /* F7 */
2722 FctKey
| 0xc5, /* F8 */
2723 FctKey
| 0xc6, /* F9 */
2724 FctKey
| 0xc7, /* F10 */
2725 Ignore
, /* Num Lock */
2726 Ignore
, /* Scroll Lock */
2727 KeyPad
| 7, /* Home */
2728 KeyPad
| 8, /* Up */
2729 KeyPad
| 9, /* Page Up */
2730 Grey
| 2, /* Grey - */
2731 KeyPad
| 4, /* Left */
2732 KeyPad
| 5, /* Keypad 5 */
2733 KeyPad
| 6, /* Right */
2734 Grey
| 3, /* Grey + */
2735 KeyPad
| 1, /* End */
2737 /* --------------- 50 to 5f --------------- */
2738 KeyPad
| 2, /* Down */
2739 KeyPad
| 3, /* Page Down */
2740 KeyPad
| 0, /* Insert */
2741 KeyPad
| 10, /* Delete */
2742 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2743 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2744 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2745 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2746 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2747 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2748 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2749 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2750 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2751 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2752 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2753 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2755 /* --------------- 60 to 6f --------------- */
2756 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2757 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2758 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2759 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2760 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2761 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2762 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2763 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2764 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2765 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2766 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2767 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2768 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2769 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2770 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2771 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2773 /* --------------- 70 to 7f --------------- */
2774 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2775 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2776 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2777 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2778 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2779 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2780 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2781 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2782 Alt
| Map
| 1, /* '1' */
2783 Alt
| Map
| 2, /* '2' */
2784 Alt
| Map
| 3, /* '3' */
2785 Alt
| Map
| 4, /* '4' */
2786 Alt
| Map
| 5, /* '5' */
2787 Alt
| Map
| 6, /* '6' */
2788 Alt
| Map
| 7, /* '7' */
2789 Alt
| Map
| 8, /* '8' */
2791 /* --------------- 80 to 8f --------------- */
2792 Alt
| Map
| 9, /* '9' */
2793 Alt
| Map
| 10, /* '0' */
2794 Alt
| Map
| 11, /* '-' */
2795 Alt
| Map
| 12, /* '=' */
2796 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2797 FctKey
| 0xc8, /* F11 */
2798 FctKey
| 0xc9, /* F12 */
2799 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2800 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2801 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2802 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2803 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2804 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2805 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2806 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2807 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2809 /* --------------- 90 to 9f --------------- */
2810 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2811 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2812 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2813 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2814 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2815 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2816 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2817 Alt
| FctKey
| 0x50, /* (Alt) Home */
2818 Alt
| FctKey
| 0x52, /* (Alt) Up */
2819 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2820 Ignore
, /* NO KEY */
2821 Alt
| FctKey
| 0x51, /* (Alt) Left */
2822 Ignore
, /* NO KEY */
2823 Alt
| FctKey
| 0x53, /* (Alt) Right */
2824 Ignore
, /* NO KEY */
2825 Alt
| FctKey
| 0x57, /* (Alt) End */
2827 /* --------------- a0 to af --------------- */
2828 Alt
| KeyPad
| 2, /* (Alt) Down */
2829 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2830 Alt
| KeyPad
| 0, /* (Alt) Insert */
2831 Alt
| KeyPad
| 10, /* (Alt) Delete */
2832 Alt
| Grey
| 0, /* (Alt) Grey / */
2833 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2834 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2837 /* These bit-positions corresponds to values returned by BIOS */
2838 #define SHIFT_P 0x0003 /* two bits! */
2839 #define CTRL_P 0x0004
2840 #define ALT_P 0x0008
2841 #define SCRLOCK_P 0x0010
2842 #define NUMLOCK_P 0x0020
2843 #define CAPSLOCK_P 0x0040
2844 #define ALT_GR_P 0x0800
2845 #define SUPER_P 0x4000 /* pseudo */
2846 #define HYPER_P 0x8000 /* pseudo */
2849 dos_get_modifiers (keymask
)
2856 /* Calculate modifier bits */
2857 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2858 int86 (0x16, ®s
, ®s
);
2862 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2863 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2867 mask
= regs
.h
.al
& (SHIFT_P
|
2868 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2870 /* Do not break international keyboard support. */
2871 /* When Keyb.Com is loaded, the right Alt key is */
2872 /* used for accessing characters like { and } */
2873 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2876 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2879 if (dos_hyper_key
== 1)
2882 modifiers
|= hyper_modifier
;
2884 else if (dos_super_key
== 1)
2887 modifiers
|= super_modifier
;
2889 else if (!international_keyboard
)
2891 /* If Keyb.Com is NOT installed, let Right Alt behave
2892 like the Left Alt. */
2898 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2901 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2903 if (dos_hyper_key
== 2)
2906 modifiers
|= hyper_modifier
;
2908 else if (dos_super_key
== 2)
2911 modifiers
|= super_modifier
;
2919 modifiers
|= shift_modifier
;
2921 modifiers
|= ctrl_modifier
;
2923 modifiers
|= meta_modifier
;
2930 #define NUM_RECENT_DOSKEYS (100)
2931 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2932 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
2933 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
2935 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
2936 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
2937 Each input key receives two values in this vector: first the ASCII code,\n\
2938 and then the scan code.")
2941 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
2944 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
2945 return Fvector (total_doskeys
, keys
);
2948 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
2949 bcopy (keys
+ recent_doskeys_index
,
2950 XVECTOR (val
)->contents
,
2951 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
2953 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
2954 recent_doskeys_index
* sizeof (Lisp_Object
));
2959 /* Get a char from keyboard. Function keys are put into the event queue. */
2961 extern void kbd_buffer_store_event (struct input_event
*);
2966 struct input_event event
;
2969 #ifndef HAVE_X_WINDOWS
2970 /* Maybe put the cursor where it should be. */
2971 IT_cmgoto (SELECTED_FRAME());
2974 /* The following condition is equivalent to `kbhit ()', except that
2975 it uses the bios to do its job. This pleases DESQview/X. */
2976 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
2977 int86 (0x16, ®s
, ®s
),
2978 (regs
.x
.flags
& 0x40) == 0)
2981 register unsigned char c
;
2982 int sc
, code
= -1, mask
, kp_mode
;
2985 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
2986 int86 (0x16, ®s
, ®s
);
2991 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2993 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2994 recent_doskeys_index
= 0;
2995 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2997 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2998 recent_doskeys_index
= 0;
3000 modifiers
= dos_get_modifiers (&mask
);
3002 #ifndef HAVE_X_WINDOWS
3003 if (!NILP (Vdos_display_scancodes
))
3006 sprintf (buf
, "%02x:%02x*%04x",
3007 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3008 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3016 case 10: /* Ctrl Grey Enter */
3017 code
= Ctrl
| Grey
| 4;
3019 case 13: /* Grey Enter */
3022 case '/': /* Grey / */
3032 /* Try the keyboard-private translation table first. */
3033 if (keyboard
->translate_table
)
3035 struct kbd_translate
*p
= keyboard
->translate_table
;
3039 if (p
->sc
== sc
&& p
->ch
== c
)
3047 /* If the private table didn't translate it, use the general
3051 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3053 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3060 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3061 Emacs is ready to read a key. Therefore, if they press
3062 `Alt-x' when Emacs is busy, by the time we get to
3063 `dos_get_modifiers', they might have already released the
3064 Alt key, and Emacs gets just `x', which is BAD.
3065 However, for keys with the `Map' property set, the ASCII
3066 code returns zero iff Alt is pressed. So, when we DON'T
3067 have to support international_keyboard, we don't have to
3068 distinguish between the left and right Alt keys, and we
3069 can set the META modifier for any keys with the `Map'
3070 property if they return zero ASCII code (c = 0). */
3072 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3073 modifiers
|= meta_modifier
;
3075 modifiers
|= ctrl_modifier
;
3077 modifiers
|= shift_modifier
;
3080 switch (code
& 0xf000)
3083 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3085 c
= 0; /* Special */
3098 if (c
== 0) /* ctrl-break */
3100 return c
; /* ALT-nnn */
3102 if (!keyboard_map_all
)
3111 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3112 if (!keyboard_map_all
)
3116 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3117 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3121 code
= keyboard
->shifted
[code
];
3123 modifiers
&= ~shift_modifier
;
3126 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3127 code
= keyboard
->alt_gr
[code
];
3129 code
= keyboard
->unshifted
[code
];
3134 if (c
== 0xe0) /* edit key */
3137 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3138 kp_mode
= dos_keypad_mode
& 0x03;
3140 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3145 if (code
== 10 && dos_decimal_point
)
3146 return dos_decimal_point
;
3147 return keypad_translate_map
[code
].char_code
;
3150 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3154 code
= keypad_translate_map
[code
].meta_code
;
3155 modifiers
= meta_modifier
;
3159 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3166 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3167 if (dos_keypad_mode
& kp_mode
)
3168 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3170 code
= grey_key_translate_map
[code
].char_code
;
3179 event
.kind
= non_ascii_keystroke
;
3181 event
.kind
= ascii_keystroke
;
3183 event
.modifiers
= modifiers
;
3184 event
.frame_or_window
= selected_frame
;
3185 event
.timestamp
= event_timestamp ();
3186 kbd_buffer_store_event (&event
);
3189 if (have_mouse
> 0 && !mouse_preempted
)
3191 int but
, press
, x
, y
, ok
;
3192 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3194 /* Check for mouse movement *before* buttons. */
3195 mouse_check_moved ();
3197 /* If the mouse moved from the spot of its last sighting, we
3198 might need to update mouse highlight. */
3199 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3201 previous_help_echo
= help_echo
;
3203 IT_note_mouse_highlight (SELECTED_FRAME(),
3204 mouse_last_x
, mouse_last_y
);
3205 /* If the contents of the global variable help_echo has
3206 changed, generate a HELP_EVENT. */
3207 if (STRINGP (help_echo
) || STRINGP (previous_help_echo
))
3209 event
.kind
= HELP_EVENT
;
3210 event
.frame_or_window
= Fcons (selected_frame
, help_echo
);
3211 event
.timestamp
= event_timestamp ();
3212 kbd_buffer_store_event (&event
);
3216 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3217 for (press
= 0; press
< 2; press
++)
3219 int button_num
= but
;
3222 ok
= mouse_pressed (but
, &x
, &y
);
3224 ok
= mouse_released (but
, &x
, &y
);
3227 /* Allow a simultaneous press/release of Mouse-1 and
3228 Mouse-2 to simulate Mouse-3 on two-button mice. */
3229 if (mouse_button_count
== 2 && but
< 2)
3231 int x2
, y2
; /* don't clobber original coordinates */
3233 /* If only one button is pressed, wait 100 msec and
3234 check again. This way, Speedy Gonzales isn't
3235 punished, while the slow get their chance. */
3236 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3237 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3242 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3243 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3248 event
.kind
= mouse_click
;
3249 event
.code
= button_num
;
3250 event
.modifiers
= dos_get_modifiers (0)
3251 | (press
? down_modifier
: up_modifier
);
3254 event
.frame_or_window
= selected_frame
;
3255 event
.timestamp
= event_timestamp ();
3256 kbd_buffer_store_event (&event
);
3264 static int prev_get_char
= -1;
3266 /* Return 1 if a key is ready to be read without suspending execution. */
3270 if (prev_get_char
!= -1)
3273 return ((prev_get_char
= dos_rawgetc ()) != -1);
3276 /* Read a key. Return -1 if no key is ready. */
3280 if (prev_get_char
!= -1)
3282 int c
= prev_get_char
;
3287 return dos_rawgetc ();
3290 #ifndef HAVE_X_WINDOWS
3291 /* See xterm.c for more info. */
3293 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
3295 register int pix_x
, pix_y
;
3296 register int *x
, *y
;
3300 if (bounds
) abort ();
3302 /* Ignore clipping. */
3309 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
3312 register int *pix_x
, *pix_y
;
3318 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3321 Actually, I don't know the meaning of all the parameters of the functions
3322 here -- I only know how they are called by xmenu.c. I could of course
3323 grab the nearest Xlib manual (down the hall, second-to-last door on the
3324 left), but I don't think it's worth the effort. */
3326 static char *menu_help_message
, *prev_menu_help_message
;
3333 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3334 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3338 /* Allocate some (more) memory for MENU ensuring that there is room for one
3342 IT_menu_make_room (XMenu
*menu
)
3344 if (menu
->allocated
== 0)
3346 int count
= menu
->allocated
= 10;
3347 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3348 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3349 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3350 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3352 else if (menu
->allocated
== menu
->count
)
3354 int count
= menu
->allocated
= menu
->allocated
+ 10;
3356 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3358 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3360 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3362 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3366 /* Search the given menu structure for a given pane number. */
3369 IT_menu_search_pane (XMenu
*menu
, int pane
)
3374 for (i
= 0; i
< menu
->count
; i
++)
3375 if (menu
->submenu
[i
])
3377 if (pane
== menu
->panenumber
[i
])
3378 return menu
->submenu
[i
];
3379 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3385 /* Determine how much screen space a given menu needs. */
3388 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3390 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3393 maxheight
= menu
->count
;
3394 for (i
= 0; i
< menu
->count
; i
++)
3396 if (menu
->submenu
[i
])
3398 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3399 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3400 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3403 *width
= menu
->width
+ maxsubwidth
;
3404 *height
= maxheight
;
3407 /* Display MENU at (X,Y) using FACES. */
3410 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
, int disp_help
)
3412 int i
, j
, face
, width
;
3413 struct glyph
*text
, *p
;
3416 int enabled
, mousehere
;
3418 struct frame
*sf
= SELECTED_FRAME();
3420 menu_help_message
= NULL
;
3422 width
= menu
->width
;
3423 text
= (struct glyph
*) xmalloc ((width
+ 2) * sizeof (struct glyph
));
3424 ScreenGetCursor (&row
, &col
);
3425 mouse_get_xy (&mx
, &my
);
3426 IT_update_begin (sf
);
3427 for (i
= 0; i
< menu
->count
; i
++)
3429 int max_width
= width
+ 2;
3431 IT_cursor_to (y
+ i
, x
);
3433 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3434 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
3435 face
= faces
[enabled
+ mousehere
* 2];
3436 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3437 menu_help_message
= menu
->help_text
[i
];
3439 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3441 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3445 SET_CHAR_GLYPH (*p
, *q
++, face
, 0);
3448 else /* make '^x' */
3450 SET_CHAR_GLYPH (*p
, '^', face
, 0);
3453 SET_CHAR_GLYPH (*p
, *q
++ + 64, face
, 0);
3457 /* Don't let the menu text overflow into the next screen row. */
3458 if (x
+ max_width
> screen_size_X
)
3460 max_width
= screen_size_X
- x
;
3461 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3463 for (; j
< max_width
- 2; j
++, p
++)
3464 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3466 SET_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3468 IT_write_glyphs (text
, max_width
);
3471 IT_cursor_to (row
, col
);
3475 /* --------------------------- X Menu emulation ---------------------- */
3477 /* Report availability of menus. */
3485 /* Create a brand new menu structure. */
3488 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3490 return IT_menu_create ();
3493 /* Create a new pane and place it on the outer-most level. It is not
3494 clear that it should be placed out there, but I don't know what else
3498 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3506 IT_menu_make_room (menu
);
3507 menu
->submenu
[menu
->count
] = IT_menu_create ();
3508 menu
->text
[menu
->count
] = txt
;
3509 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3510 menu
->help_text
[menu
->count
] = NULL
;
3513 /* Adjust length for possible control characters (which will
3514 be written as ^x). */
3515 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3519 if (len
> menu
->width
)
3522 return menu
->panecount
;
3525 /* Create a new item in a menu pane. */
3528 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3529 int foo
, char *txt
, int enable
, char *help_text
)
3535 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3537 IT_menu_make_room (menu
);
3538 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3539 menu
->text
[menu
->count
] = txt
;
3540 menu
->panenumber
[menu
->count
] = enable
;
3541 menu
->help_text
[menu
->count
] = help_text
;
3544 /* Adjust length for possible control characters (which will
3545 be written as ^x). */
3546 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3550 if (len
> menu
->width
)
3556 /* Decide where the menu would be placed if requested at (X,Y). */
3559 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3560 int *ulx
, int *uly
, int *width
, int *height
)
3562 IT_menu_calc_size (menu
, width
, height
);
3568 struct IT_menu_state
3570 void *screen_behind
;
3577 /* Display menu, wait for user's response, and return that response. */
3580 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3581 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3582 void (*help_callback
)(char *))
3584 struct IT_menu_state
*state
;
3589 Lisp_Object selectface
;
3590 int leave
, result
, onepane
;
3591 int title_faces
[4]; /* face to display the menu title */
3592 int buffers_num_deleted
= 0;
3593 struct frame
*sf
= SELECTED_FRAME();
3595 /* Just in case we got here without a mouse present... */
3596 if (have_mouse
<= 0)
3597 return XM_IA_SELECT
;
3598 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3599 around the display. */
3605 /* We will process all the mouse events directly, so we had
3606 better prevented dos_rawgetc from stealing them from us. */
3609 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3610 screensize
= screen_size
* 2;
3612 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3613 CHARSET_ASCII
, DEFAULT_FACE_ID
);
3615 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3616 CHARSET_ASCII
, DEFAULT_FACE_ID
);
3617 selectface
= intern ("msdos-menu-select-face");
3618 faces
[2] = lookup_derived_face (sf
, selectface
,
3619 CHARSET_ASCII
, faces
[0]);
3620 faces
[3] = lookup_derived_face (sf
, selectface
,
3621 CHARSET_ASCII
, faces
[1]);
3623 /* Make sure the menu title is always displayed with
3624 `msdos-menu-active-face', no matter where the mouse pointer is. */
3625 for (i
= 0; i
< 4; i
++)
3626 title_faces
[i
] = faces
[3];
3630 /* Don't let the title for the "Buffers" popup menu include a
3631 digit (which is ugly).
3633 This is a terrible kludge, but I think the "Buffers" case is
3634 the only one where the title includes a number, so it doesn't
3635 seem to be necessary to make this more general. */
3636 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3638 menu
->text
[0][7] = '\0';
3639 buffers_num_deleted
= 1;
3641 state
[0].menu
= menu
;
3643 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3645 /* Turn off the cursor. Otherwise it shows through the menu
3646 panes, which is ugly. */
3647 IT_display_cursor (0);
3649 /* Display the menu title. */
3650 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
, 0);
3651 if (buffers_num_deleted
)
3652 menu
->text
[0][7] = ' ';
3653 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3655 menu
->width
= menu
->submenu
[0]->width
;
3656 state
[0].menu
= menu
->submenu
[0];
3660 state
[0].menu
= menu
;
3662 state
[0].x
= x0
- 1;
3664 state
[0].pane
= onepane
;
3666 mouse_last_x
= -1; /* A hack that forces display. */
3670 if (!mouse_visible
) mouse_on ();
3671 mouse_check_moved ();
3672 if (sf
->mouse_moved
)
3674 sf
->mouse_moved
= 0;
3675 result
= XM_IA_SELECT
;
3676 mouse_get_xy (&x
, &y
);
3677 for (i
= 0; i
< statecount
; i
++)
3678 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3680 int dy
= y
- state
[i
].y
;
3681 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3683 if (!state
[i
].menu
->submenu
[dy
])
3684 if (state
[i
].menu
->panenumber
[dy
])
3685 result
= XM_SUCCESS
;
3687 result
= XM_IA_SELECT
;
3688 *pane
= state
[i
].pane
- 1;
3690 /* We hit some part of a menu, so drop extra menus that
3691 have been opened. That does not include an open and
3693 if (i
!= statecount
- 2
3694 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3695 while (i
!= statecount
- 1)
3699 ScreenUpdate (state
[statecount
].screen_behind
);
3700 if (screen_virtual_segment
)
3701 dosv_refresh_virtual_screen (0, screen_size
);
3702 xfree (state
[statecount
].screen_behind
);
3704 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3706 IT_menu_display (state
[i
].menu
,
3710 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3711 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3713 ScreenRetrieve (state
[statecount
].screen_behind
3714 = xmalloc (screensize
));
3716 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3717 state
[statecount
].y
= y
;
3722 IT_menu_display (state
[statecount
- 1].menu
,
3723 state
[statecount
- 1].y
,
3724 state
[statecount
- 1].x
,
3729 if ((menu_help_message
|| prev_menu_help_message
)
3730 && menu_help_message
!= prev_menu_help_message
)
3732 help_callback (menu_help_message
);
3733 IT_display_cursor (0);
3734 prev_menu_help_message
= menu_help_message
;
3736 /* We are busy-waiting for the mouse to move, so let's be nice
3737 to other Windows applications by releasing our time slice. */
3740 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3742 /* Only leave if user both pressed and released the mouse, and in
3743 that order. This avoids popping down the menu pane unless
3744 the user is really done with it. */
3745 if (mouse_pressed (b
, &x
, &y
))
3747 while (mouse_button_depressed (b
, &x
, &y
))
3751 (void) mouse_released (b
, &x
, &y
);
3756 ScreenUpdate (state
[0].screen_behind
);
3757 if (screen_virtual_segment
)
3758 dosv_refresh_virtual_screen (0, screen_size
);
3760 while (statecount
--)
3761 xfree (state
[statecount
].screen_behind
);
3762 IT_display_cursor (1); /* turn cursor back on */
3763 /* Clean up any mouse events that are waiting inside Emacs event queue.
3764 These events are likely to be generated before the menu was even
3765 displayed, probably because the user pressed and released the button
3766 (which invoked the menu) too quickly. If we don't remove these events,
3767 Emacs will process them after we return and surprise the user. */
3768 discard_mouse_events ();
3769 /* Allow mouse events generation by dos_rawgetc. */
3774 /* Dispose of a menu. */
3777 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3780 if (menu
->allocated
)
3782 for (i
= 0; i
< menu
->count
; i
++)
3783 if (menu
->submenu
[i
])
3784 XMenuDestroy (foo
, menu
->submenu
[i
]);
3786 xfree (menu
->submenu
);
3787 xfree (menu
->panenumber
);
3788 xfree (menu
->help_text
);
3791 menu_help_message
= prev_menu_help_message
= NULL
;
3795 x_pixel_width (struct frame
*f
)
3797 return FRAME_WIDTH (f
);
3801 x_pixel_height (struct frame
*f
)
3803 return FRAME_HEIGHT (f
);
3805 #endif /* !HAVE_X_WINDOWS */
3807 /* ----------------------- DOS / UNIX conversion --------------------- */
3809 void msdos_downcase_filename (unsigned char *);
3811 /* Destructively turn backslashes into slashes. */
3814 dostounix_filename (p
)
3817 msdos_downcase_filename (p
);
3827 /* Destructively turn slashes into backslashes. */
3830 unixtodos_filename (p
)
3833 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3847 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3850 getdefdir (drive
, dst
)
3854 char in_path
[4], *p
= in_path
;
3857 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3860 *p
++ = drive
+ 'A' - 1;
3867 _fixpath (in_path
, dst
);
3868 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3869 it queries the LFN support, so ignore that error. */
3870 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
3873 msdos_downcase_filename (dst
);
3879 /* Remove all CR's that are followed by a LF. */
3884 register unsigned char *buf
;
3886 unsigned char *np
= buf
;
3887 unsigned char *startp
= buf
;
3888 unsigned char *endp
= buf
+ n
;
3892 while (buf
< endp
- 1)
3896 if (*(++buf
) != 0x0a)
3907 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
3909 /* In DJGPP v2.0, library `write' can call `malloc', which might
3910 cause relocation of the buffer whose address we get in ADDR.
3911 Here is a version of `write' that avoids calling `malloc',
3912 to serve us until such time as the library is fixed.
3913 Actually, what we define here is called `__write', because
3914 `write' is a stub that just jmp's to `__write' (to be
3915 POSIXLY-correct with respect to the global name-space). */
3917 #include <io.h> /* for _write */
3918 #include <libc/dosio.h> /* for __file_handle_modes[] */
3920 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
3922 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
3925 __write (int handle
, const void *buffer
, size_t count
)
3930 if(__file_handle_modes
[handle
] & O_BINARY
)
3931 return _write (handle
, buffer
, count
);
3935 const char *bp
= buffer
;
3936 int total_written
= 0;
3937 int nmoved
= 0, ncr
= 0;
3941 /* The next test makes sure there's space for at least 2 more
3942 characters in xbuf[], so both CR and LF can be put there. */
3954 if (xbp
>= XBUF_END
|| !count
)
3956 size_t to_write
= nmoved
+ ncr
;
3957 int written
= _write (handle
, xbuf
, to_write
);
3962 total_written
+= nmoved
; /* CRs aren't counted in ret value */
3964 /* If some, but not all were written (disk full?), return
3965 an estimate of the total written bytes not counting CRs. */
3966 if (written
< to_write
)
3967 return total_written
- (to_write
- written
) * nmoved
/to_write
;
3974 return total_written
;
3978 /* A low-level file-renaming function which works around Windows 95 bug.
3979 This is pulled directly out of DJGPP v2.01 library sources, and only
3980 used when you compile with DJGPP v2.0. */
3984 int _rename(const char *old
, const char *new)
3987 int olen
= strlen(old
) + 1;
3989 int use_lfn
= _USE_LFN
;
3990 char tempfile
[FILENAME_MAX
];
3991 const char *orig
= old
;
3994 r
.x
.dx
= __tb_offset
;
3995 r
.x
.di
= __tb_offset
+ olen
;
3996 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4000 /* Windows 95 bug: for some filenames, when you rename
4001 file -> file~ (as in Emacs, to leave a backup), the
4002 short 8+3 alias doesn't change, which effectively
4003 makes OLD and NEW the same file. We must rename
4004 through a temporary file to work around this. */
4006 char *pbase
= 0, *p
;
4007 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4008 int idx
= sizeof(try_char
) - 1;
4010 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4011 might point to another drive, which will fail the DOS call. */
4012 strcpy(tempfile
, old
);
4013 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4014 if (*p
== '/' || *p
== '\\' || *p
== ':')
4020 strcpy(pbase
, "X$$djren$$.$$temp$$");
4026 *pbase
= try_char
[--idx
];
4027 } while (_chmod(tempfile
, 0) != -1);
4030 _put_path2(tempfile
, olen
);
4032 __dpmi_int(0x21, &r
);
4035 errno
= __doserr_to_errno(r
.x
.ax
);
4039 /* Now create a file with the original name. This will
4040 ensure that NEW will always have a 8+3 alias
4041 different from that of OLD. (Seems to be required
4042 when NameNumericTail in the Registry is set to 0.) */
4043 lfn_fd
= _creat(old
, 0);
4045 olen
= strlen(tempfile
) + 1;
4047 r
.x
.di
= __tb_offset
+ olen
;
4056 _put_path2(new, olen
);
4058 __dpmi_int(0x21, &r
);
4061 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4062 remove(new); /* and try again */
4065 errno
= __doserr_to_errno(r
.x
.ax
);
4067 /* Restore to original name if we renamed it to temporary. */
4075 _put_path2(orig
, olen
);
4076 _put_path(tempfile
);
4078 __dpmi_int(0x21, &r
);
4087 /* Success. Delete the file possibly created to work
4088 around the Windows 95 bug. */
4090 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4094 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4096 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4098 "Return non-nil if long file names are supported on MSDOS.")
4101 return (_USE_LFN
? Qt
: Qnil
);
4104 /* Convert alphabetic characters in a filename to lower-case. */
4107 msdos_downcase_filename (p
)
4108 register unsigned char *p
;
4110 /* Always lower-case drive letters a-z, even if the filesystem
4111 preserves case in filenames.
4112 This is so MSDOS filenames could be compared by string comparison
4113 functions that are case-sensitive. Even case-preserving filesystems
4114 do not distinguish case in drive letters. */
4115 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4121 /* Under LFN we expect to get pathnames in their true case. */
4122 if (NILP (Fmsdos_long_file_names ()))
4124 if (*p
>= 'A' && *p
<= 'Z')
4128 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4130 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
4131 When long filenames are supported, doesn't change FILENAME.\n\
4132 If FILENAME is not a string, returns nil.\n\
4133 The argument object is never altered--the value is a copy.")
4135 Lisp_Object filename
;
4139 if (! STRINGP (filename
))
4142 tem
= Fcopy_sequence (filename
);
4143 msdos_downcase_filename (XSTRING (tem
)->data
);
4147 /* The Emacs root directory as determined by init_environment. */
4149 static char emacsroot
[MAXPATHLEN
];
4152 rootrelativepath (rel
)
4155 static char result
[MAXPATHLEN
+ 10];
4157 strcpy (result
, emacsroot
);
4158 strcat (result
, "/");
4159 strcat (result
, rel
);
4163 /* Define a lot of environment variables if not already defined. Don't
4164 remove anything unless you know what you're doing -- lots of code will
4165 break if one or more of these are missing. */
4168 init_environment (argc
, argv
, skip_args
)
4175 static const char * const tempdirs
[] = {
4176 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4179 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4181 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4182 temporary files and assume "/tmp" if $TMPDIR is unset, which
4183 will break on DOS/Windows. Refuse to work if we cannot find
4184 a directory, not even "c:/", usable for that purpose. */
4185 for (i
= 0; i
< imax
; i
++)
4187 const char *tmp
= tempdirs
[i
];
4190 tmp
= getenv (tmp
+ 1);
4191 /* Note that `access' can lie to us if the directory resides on a
4192 read-only filesystem, like CD-ROM or a write-protected floppy.
4193 The only way to be really sure is to actually create a file and
4194 see if it succeeds. But I think that's too much to ask. */
4195 if (tmp
&& access (tmp
, D_OK
) == 0)
4197 setenv ("TMPDIR", tmp
, 1);
4204 Fcons (build_string ("no usable temporary directories found!!"),
4206 "While setting TMPDIR: ");
4208 /* Note the startup time, so we know not to clear the screen if we
4209 exit immediately; see IT_reset_terminal_modes.
4210 (Yes, I know `clock' returns zero the first time it's called, but
4211 I do this anyway, in case some wiseguy changes that at some point.) */
4212 startup_time
= clock ();
4214 /* Find our root from argv[0]. Assuming argv[0] is, say,
4215 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4216 root
= alloca (MAXPATHLEN
+ 20);
4217 _fixpath (argv
[0], root
);
4218 msdos_downcase_filename (root
);
4219 len
= strlen (root
);
4220 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4224 && (strcmp (root
+ len
- 4, "/bin") == 0
4225 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4226 root
[len
- 4] = '\0';
4228 strcpy (root
, "c:/emacs"); /* let's be defensive */
4229 len
= strlen (root
);
4230 strcpy (emacsroot
, root
);
4232 /* We default HOME to our root. */
4233 setenv ("HOME", root
, 0);
4235 /* We default EMACSPATH to root + "/bin". */
4236 strcpy (root
+ len
, "/bin");
4237 setenv ("EMACSPATH", root
, 0);
4239 /* I don't expect anybody to ever use other terminals so the internal
4240 terminal is the default. */
4241 setenv ("TERM", "internal", 0);
4243 #ifdef HAVE_X_WINDOWS
4244 /* Emacs expects DISPLAY to be set. */
4245 setenv ("DISPLAY", "unix:0.0", 0);
4248 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4249 downcase it and mirror the backslashes. */
4250 s
= getenv ("COMSPEC");
4251 if (!s
) s
= "c:/command.com";
4252 t
= alloca (strlen (s
) + 1);
4254 dostounix_filename (t
);
4255 setenv ("SHELL", t
, 0);
4257 /* PATH is also downcased and backslashes mirrored. */
4258 s
= getenv ("PATH");
4260 t
= alloca (strlen (s
) + 3);
4261 /* Current directory is always considered part of MsDos's path but it is
4262 not normally mentioned. Now it is. */
4263 strcat (strcpy (t
, ".;"), s
);
4264 dostounix_filename (t
); /* Not a single file name, but this should work. */
4265 setenv ("PATH", t
, 1);
4267 /* In some sense all dos users have root privileges, so... */
4268 setenv ("USER", "root", 0);
4269 setenv ("NAME", getenv ("USER"), 0);
4271 /* Time zone determined from country code. To make this possible, the
4272 country code may not span more than one time zone. In other words,
4273 in the USA, you lose. */
4275 switch (dos_country_code
)
4277 case 31: /* Belgium */
4278 case 32: /* The Netherlands */
4279 case 33: /* France */
4280 case 34: /* Spain */
4281 case 36: /* Hungary */
4282 case 38: /* Yugoslavia (or what's left of it?) */
4283 case 39: /* Italy */
4284 case 41: /* Switzerland */
4285 case 42: /* Tjekia */
4286 case 45: /* Denmark */
4287 case 46: /* Sweden */
4288 case 47: /* Norway */
4289 case 48: /* Poland */
4290 case 49: /* Germany */
4291 /* Daylight saving from last Sunday in March to last Sunday in
4292 September, both at 2AM. */
4293 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4295 case 44: /* United Kingdom */
4296 case 351: /* Portugal */
4297 case 354: /* Iceland */
4298 setenv ("TZ", "GMT+00", 0);
4300 case 81: /* Japan */
4301 case 82: /* Korea */
4302 setenv ("TZ", "JST-09", 0);
4304 case 90: /* Turkey */
4305 case 358: /* Finland */
4306 setenv ("TZ", "EET-02", 0);
4308 case 972: /* Israel */
4309 /* This is an approximation. (For exact rules, use the
4310 `zoneinfo/israel' file which comes with DJGPP, but you need
4311 to install it in `/usr/share/zoneinfo/' directory first.) */
4312 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4320 static int break_stat
; /* BREAK check mode status. */
4321 static int stdin_stat
; /* stdin IOCTL status. */
4325 /* These must be global. */
4326 static _go32_dpmi_seginfo ctrl_break_vector
;
4327 static _go32_dpmi_registers ctrl_break_regs
;
4328 static int ctrlbreakinstalled
= 0;
4330 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4333 ctrl_break_func (regs
)
4334 _go32_dpmi_registers
*regs
;
4340 install_ctrl_break_check ()
4342 if (!ctrlbreakinstalled
)
4344 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4345 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4346 ctrlbreakinstalled
= 1;
4347 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4348 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4350 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4354 #endif /* __DJGPP__ < 2 */
4356 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4357 control chars by DOS. Determine the keyboard type. */
4362 union REGS inregs
, outregs
;
4363 static int first_time
= 1;
4365 break_stat
= getcbrk ();
4368 install_ctrl_break_check ();
4374 int86 (0x15, &inregs
, &outregs
);
4375 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4379 if (internal_terminal
4380 #ifdef HAVE_X_WINDOWS
4381 && inhibit_window_system
4385 inregs
.x
.ax
= 0x0021;
4386 int86 (0x33, &inregs
, &outregs
);
4387 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4390 /* Reportedly, the above doesn't work for some mouse drivers. There
4391 is an additional detection method that should work, but might be
4392 a little slower. Use that as an alternative. */
4393 inregs
.x
.ax
= 0x0000;
4394 int86 (0x33, &inregs
, &outregs
);
4395 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4400 have_mouse
= 1; /* enable mouse */
4403 if (outregs
.x
.bx
== 3)
4405 mouse_button_count
= 3;
4406 mouse_button_translate
[0] = 0; /* Left */
4407 mouse_button_translate
[1] = 2; /* Middle */
4408 mouse_button_translate
[2] = 1; /* Right */
4412 mouse_button_count
= 2;
4413 mouse_button_translate
[0] = 0;
4414 mouse_button_translate
[1] = 1;
4416 mouse_position_hook
= &mouse_get_pos
;
4420 #ifndef HAVE_X_WINDOWS
4422 /* Save the cursor shape used outside Emacs. */
4423 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4432 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4433 return (stdin_stat
!= -1);
4436 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4438 #else /* __DJGPP__ < 2 */
4442 /* I think it is wrong to overwrite `stdin_stat' every time
4443 but the first one this function is called, but I don't
4444 want to change the way it used to work in v1.x.--EZ */
4446 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4447 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4448 intdos (&inregs
, &outregs
);
4449 stdin_stat
= outregs
.h
.dl
;
4451 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4452 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4453 intdos (&inregs
, &outregs
);
4454 return !outregs
.x
.cflag
;
4456 #endif /* __DJGPP__ < 2 */
4459 /* Restore status of standard input and Ctrl-C checking. */
4464 union REGS inregs
, outregs
;
4466 setcbrk (break_stat
);
4471 #ifndef HAVE_X_WINDOWS
4472 /* Restore the cursor shape we found on startup. */
4476 inregs
.x
.cx
= outside_cursor
;
4477 int86 (0x10, &inregs
, &outregs
);
4481 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4483 #else /* not __DJGPP__ >= 2 */
4485 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4486 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4487 inregs
.x
.dx
= stdin_stat
;
4488 intdos (&inregs
, &outregs
);
4489 return !outregs
.x
.cflag
;
4491 #endif /* not __DJGPP__ >= 2 */
4495 /* Run command as specified by ARGV in directory DIR.
4496 The command is run with input from TEMPIN, output to
4497 file TEMPOUT and stderr to TEMPERR. */
4500 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4501 unsigned char **argv
;
4502 const char *working_dir
;
4503 int tempin
, tempout
, temperr
;
4506 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4507 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4508 int msshell
, result
= -1;
4509 int inbak
, outbak
, errbak
;
4513 /* Get current directory as MSDOS cwd is not per-process. */
4516 /* If argv[0] is the shell, it might come in any lettercase.
4517 Since `Fmember' is case-sensitive, we need to downcase
4518 argv[0], even if we are on case-preserving filesystems. */
4519 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4520 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4523 if (*pl
>= 'A' && *pl
<= 'Z')
4528 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4529 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4530 && !strcmp ("-c", argv
[1]);
4533 saveargv1
= argv
[1];
4534 saveargv2
= argv
[2];
4538 char *p
= alloca (strlen (argv
[2]) + 1);
4540 strcpy (argv
[2] = p
, saveargv2
);
4541 while (*p
&& isspace (*p
))
4543 while (*p
&& !isspace (*p
))
4551 chdir (working_dir
);
4555 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4556 goto done
; /* Allocation might fail due to lack of descriptors. */
4559 mouse_get_xy (&x
, &y
);
4561 dos_ttcooked (); /* do it here while 0 = stdin */
4569 if (msshell
&& !argv
[3])
4571 /* MS-DOS native shells are too restrictive. For starters, they
4572 cannot grok commands longer than 126 characters. In DJGPP v2
4573 and later, `system' is much smarter, so we'll call it instead. */
4577 /* A shell gets a single argument--its full command
4578 line--whose original was saved in `saveargv2'. */
4580 /* Don't let them pass empty command lines to `system', since
4581 with some shells it will try to invoke an interactive shell,
4582 which will hang Emacs. */
4583 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4587 extern char **environ
;
4588 int save_system_flags
= __system_flags
;
4590 /* Request the most powerful version of `system'. We need
4591 all the help we can get to avoid calling stock DOS shells. */
4592 __system_flags
= (__system_redirect
4593 | __system_use_shell
4594 | __system_allow_multiple_cmds
4595 | __system_allow_long_cmds
4596 | __system_handle_null_commands
4597 | __system_emulate_chdir
);
4600 result
= system (cmnd
);
4601 __system_flags
= save_system_flags
;
4604 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4608 #endif /* __DJGPP__ > 1 */
4610 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4615 emacs_close (inbak
);
4616 emacs_close (outbak
);
4617 emacs_close (errbak
);
4623 mouse_moveto (x
, y
);
4626 /* Some programs might change the meaning of the highest bit of the
4627 text attribute byte, so we get blinking characters instead of the
4628 bright background colors. Restore that. */
4635 argv
[1] = saveargv1
;
4636 argv
[2] = saveargv2
;
4644 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4651 /* ------------------------- Compatibility functions -------------------
4656 /* Hostnames for a pc are not really funny,
4657 but they are used in change log so we emulate the best we can. */
4659 gethostname (p
, size
)
4663 char *q
= egetenv ("HOSTNAME");
4670 /* When time zones are set from Ms-Dos too many C-libraries are playing
4671 tricks with time values. We solve this by defining our own version
4672 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4673 once and after each call to `tzset' with TZ changed. That is
4674 accomplished by aliasing tzset to init_gettimeofday. */
4676 static struct tm time_rec
;
4679 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4687 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4691 time_rec
.tm_year
= d
.da_year
- 1900;
4692 time_rec
.tm_mon
= d
.da_mon
- 1;
4693 time_rec
.tm_mday
= d
.da_day
;
4696 time_rec
.tm_hour
= t
.ti_hour
;
4697 time_rec
.tm_min
= t
.ti_min
;
4698 time_rec
.tm_sec
= t
.ti_sec
;
4701 tm
.tm_gmtoff
= dos_timezone_offset
;
4703 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4704 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4706 /* Ignore tzp; it's obsolescent. */
4710 #endif /* __DJGPP__ < 2 */
4713 * A list of unimplemented functions that we silently ignore.
4717 unsigned alarm (s
) unsigned s
; {}
4718 fork () { return 0; }
4719 int kill (x
, y
) int x
, y
; { return -1; }
4721 void volatile pause () {}
4722 sigsetmask (x
) int x
; { return 0; }
4723 sigblock (mask
) int mask
; { return 0; }
4726 void request_sigio (void) {}
4727 setpgrp () {return 0; }
4728 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4729 void unrequest_sigio (void) {}
4733 #ifdef POSIX_SIGNALS
4735 /* Augment DJGPP library POSIX signal functions. This is needed
4736 as of DJGPP v2.01, but might be in the library in later releases. */
4738 #include <libc/bss.h>
4740 /* A counter to know when to re-initialize the static sets. */
4741 static int sigprocmask_count
= -1;
4743 /* Which signals are currently blocked (initially none). */
4744 static sigset_t current_mask
;
4746 /* Which signals are pending (initially none). */
4747 static sigset_t pending_signals
;
4749 /* Previous handlers to restore when the blocked signals are unblocked. */
4750 typedef void (*sighandler_t
)(int);
4751 static sighandler_t prev_handlers
[320];
4753 /* A signal handler which just records that a signal occured
4754 (it will be raised later, if and when the signal is unblocked). */
4756 sig_suspender (signo
)
4759 sigaddset (&pending_signals
, signo
);
4763 sigprocmask (how
, new_set
, old_set
)
4765 const sigset_t
*new_set
;
4771 /* If called for the first time, initialize. */
4772 if (sigprocmask_count
!= __bss_count
)
4774 sigprocmask_count
= __bss_count
;
4775 sigemptyset (&pending_signals
);
4776 sigemptyset (¤t_mask
);
4777 for (signo
= 0; signo
< 320; signo
++)
4778 prev_handlers
[signo
] = SIG_ERR
;
4782 *old_set
= current_mask
;
4787 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4793 sigemptyset (&new_mask
);
4795 /* DJGPP supports upto 320 signals. */
4796 for (signo
= 0; signo
< 320; signo
++)
4798 if (sigismember (¤t_mask
, signo
))
4799 sigaddset (&new_mask
, signo
);
4800 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4802 sigaddset (&new_mask
, signo
);
4804 /* SIGKILL is silently ignored, as on other platforms. */
4805 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4806 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4808 if (( how
== SIG_UNBLOCK
4809 && sigismember (&new_mask
, signo
)
4810 && sigismember (new_set
, signo
))
4811 || (how
== SIG_SETMASK
4812 && sigismember (&new_mask
, signo
)
4813 && !sigismember (new_set
, signo
)))
4815 sigdelset (&new_mask
, signo
);
4816 if (prev_handlers
[signo
] != SIG_ERR
)
4818 signal (signo
, prev_handlers
[signo
]);
4819 prev_handlers
[signo
] = SIG_ERR
;
4821 if (sigismember (&pending_signals
, signo
))
4823 sigdelset (&pending_signals
, signo
);
4828 current_mask
= new_mask
;
4832 #else /* not POSIX_SIGNALS */
4834 sigsetmask (x
) int x
; { return 0; }
4835 sigblock (mask
) int mask
; { return 0; }
4837 #endif /* not POSIX_SIGNALS */
4838 #endif /* __DJGPP__ > 1 */
4841 #include "sysselect.h"
4843 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4844 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4845 ((long)(time).tv_sec < 0 \
4846 || ((time).tv_sec == 0 \
4847 && (long)(time).tv_usec <= 0))
4850 /* This yields the rest of the current time slice to the task manager.
4851 It should be called by any code which knows that it has nothing
4852 useful to do except idle.
4854 I don't use __dpmi_yield here, since versions of library before 2.02
4855 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4856 on some versions of Windows 9X. */
4859 dos_yield_time_slice (void)
4861 _go32_dpmi_registers r
;
4864 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
4865 _go32_dpmi_simulate_int (0x2f, &r
);
4870 /* Only event queue is checked. */
4871 /* We don't have to call timer_check here
4872 because wait_reading_process_input takes care of that. */
4874 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
4876 SELECT_TYPE
*rfds
, *wfds
, *efds
;
4877 EMACS_TIME
*timeout
;
4885 check_input
= FD_ISSET (0, rfds
);
4896 /* If we are looking only for the terminal, with no timeout,
4897 just read it and wait -- that's more efficient. */
4900 while (!detect_input_pending ())
4902 dos_yield_time_slice ();
4907 EMACS_TIME clnow
, cllast
, cldiff
;
4910 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
4912 while (!check_input
|| !detect_input_pending ())
4915 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
4916 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
4918 /* When seconds wrap around, we assume that no more than
4919 1 minute passed since last `gettime'. */
4920 if (EMACS_TIME_NEG_P (cldiff
))
4921 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
4922 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
4924 /* Stop when timeout value crosses zero. */
4925 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
4928 dos_yield_time_slice ();
4938 * Define overlaid functions:
4940 * chdir -> sys_chdir
4941 * tzset -> init_gettimeofday
4942 * abort -> dos_abort
4947 extern int chdir ();
4953 int len
= strlen (path
);
4954 char *tmp
= (char *)path
;
4956 if (*tmp
&& tmp
[1] == ':')
4958 if (getdisk () != tolower (tmp
[0]) - 'a')
4959 setdisk (tolower (tmp
[0]) - 'a');
4960 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
4964 if (len
> 1 && (tmp
[len
- 1] == '/'))
4966 char *tmp1
= (char *) alloca (len
+ 1);
4977 extern void tzset (void);
4980 init_gettimeofday ()
4986 ltm
= gtm
= time (NULL
);
4987 ltm
= mktime (lstm
= localtime (<m
));
4988 gtm
= mktime (gmtime (>m
));
4989 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
4990 time_rec
.tm_isdst
= lstm
->tm_isdst
;
4991 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
4998 dos_abort (file
, line
)
5002 char buffer1
[200], buffer2
[400];
5005 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5006 for (i
= j
= 0; buffer1
[i
]; i
++) {
5007 buffer2
[j
++] = buffer1
[i
];
5008 buffer2
[j
++] = 0x70;
5010 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5011 ScreenSetCursor (2, 0);
5019 ScreenSetCursor (10, 0);
5020 cputs ("\r\n\nEmacs aborted!\r\n");
5022 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5023 if (screen_virtual_segment
)
5024 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5025 /* Generate traceback, so we could tell whodunit. */
5026 signal (SIGINT
, SIG_DFL
);
5027 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5028 #else /* __DJGPP_MINOR__ >= 2 */
5030 #endif /* __DJGPP_MINOR__ >= 2 */
5036 /* The following variables are required so that cus-start.el won't
5037 complain about unbound variables. */
5038 #ifndef HAVE_X_WINDOWS
5039 /* Search path for bitmap files (xfns.c). */
5040 Lisp_Object Vx_bitmap_file_path
;
5041 int x_stretch_cursor_p
;
5043 #ifndef subprocesses
5044 /* Nonzero means delete a process right away if it exits (process.c). */
5045 static int delete_exited_processes
;
5050 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5051 staticpro (&recent_doskeys
);
5052 #ifndef HAVE_X_WINDOWS
5053 staticpro (&help_echo
);
5055 staticpro (&previous_help_echo
);
5056 previous_help_echo
= Qnil
;
5058 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
5059 "List of directories to search for bitmap files for X.");
5060 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
5062 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p
,
5063 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
5064 For example, if a block cursor is over a tab, it will be drawn as\n\
5065 wide as that tab on the display. (No effect on MS-DOS.)");
5066 x_stretch_cursor_p
= 0;
5068 /* The following three are from xfns.c: */
5069 Qbackground_color
= intern ("background-color");
5070 staticpro (&Qbackground_color
);
5071 Qforeground_color
= intern ("foreground-color");
5072 staticpro (&Qforeground_color
);
5073 Qbar
= intern ("bar");
5075 Qcursor_type
= intern ("cursor-type");
5076 staticpro (&Qcursor_type
);
5077 Qreverse
= intern ("reverse");
5078 staticpro (&Qreverse
);
5080 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5081 "*Glyph to display instead of chars not supported by current codepage.\n\
5083 This variable is used only by MSDOS terminals.");
5084 Vdos_unsupported_char_glyph
= '\177';
5086 #ifndef subprocesses
5087 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5088 "*Non-nil means delete processes immediately when they exit.\n\
5089 nil means don't delete them until `list-processes' is run.");
5090 delete_exited_processes
= 0;
5093 defsubr (&Srecent_doskeys
);
5094 defsubr (&Smsdos_long_file_names
);
5095 defsubr (&Smsdos_downcase_filename
);
5096 defsubr (&Smsdos_remember_default_colors
);