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 /* This used to be in termhooks.h, but mainstream Emacs code no longer
128 uses it, and it was removed... */
129 #define NUM_MOUSE_BUTTONS (5)
131 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
132 static int mouse_visible
;
134 static int mouse_last_x
;
135 static int mouse_last_y
;
137 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
138 static int mouse_button_count
;
145 if (have_mouse
> 0 && !mouse_visible
)
148 fprintf (termscript
, "<M_ON>");
150 int86 (0x33, ®s
, ®s
);
160 if (have_mouse
> 0 && mouse_visible
)
163 fprintf (termscript
, "<M_OFF>");
165 int86 (0x33, ®s
, ®s
);
171 mouse_get_xy (int *x
, int *y
)
176 int86 (0x33, ®s
, ®s
);
188 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
190 mouse_last_x
= regs
.x
.cx
= x
* 8;
191 mouse_last_y
= regs
.x
.dx
= y
* 8;
192 int86 (0x33, ®s
, ®s
);
196 mouse_pressed (b
, xp
, yp
)
201 if (b
>= mouse_button_count
)
204 regs
.x
.bx
= mouse_button_translate
[b
];
205 int86 (0x33, ®s
, ®s
);
207 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
208 return (regs
.x
.bx
!= 0);
212 mouse_released (b
, xp
, yp
)
217 if (b
>= mouse_button_count
)
220 regs
.x
.bx
= mouse_button_translate
[b
];
221 int86 (0x33, ®s
, ®s
);
223 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
224 return (regs
.x
.bx
!= 0);
228 mouse_button_depressed (b
, xp
, yp
)
233 if (b
>= mouse_button_count
)
236 int86 (0x33, ®s
, ®s
);
237 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
247 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
250 Lisp_Object
*bar_window
, *x
, *y
;
251 enum scroll_bar_part
*part
;
255 Lisp_Object frame
, tail
;
257 /* Clear the mouse-moved flag for every frame on this display. */
258 FOR_EACH_FRAME (tail
, frame
)
259 XFRAME (frame
)->mouse_moved
= 0;
261 *f
= SELECTED_FRAME();
263 mouse_get_xy (&ix
, &iy
);
264 *time
= event_timestamp ();
265 *x
= make_number (mouse_last_x
= ix
);
266 *y
= make_number (mouse_last_y
= iy
);
274 mouse_get_xy (&x
, &y
);
275 SELECTED_FRAME()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
287 fprintf (termscript
, "<M_INIT>");
290 int86 (0x33, ®s
, ®s
);
292 /* Reset the mouse last press/release info. It seems that Windows
293 doesn't do that automatically when function 21h is called, which
294 causes Emacs to ``remember'' the click that switched focus to the
295 window just before Emacs was started from that window. */
296 for (b
= 0; b
< mouse_button_count
; b
++)
298 int dummy_x
, dummy_y
;
300 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
301 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
306 regs
.x
.dx
= 8 * (ScreenCols () - 1);
307 int86 (0x33, ®s
, ®s
);
311 regs
.x
.dx
= 8 * (ScreenRows () - 1);
312 int86 (0x33, ®s
, ®s
);
318 /* ------------------------- Screen control ----------------------
322 static int internal_terminal
= 0;
324 #ifndef HAVE_X_WINDOWS
325 extern unsigned char ScreenAttrib
;
326 static int screen_face
;
327 static int highlight
;
329 static int screen_size_X
;
330 static int screen_size_Y
;
331 static int screen_size
;
333 static int current_pos_X
;
334 static int current_pos_Y
;
335 static int new_pos_X
;
336 static int new_pos_Y
;
338 static void *startup_screen_buffer
;
339 static int startup_screen_size_X
;
340 static int startup_screen_size_Y
;
341 static int startup_pos_X
;
342 static int startup_pos_Y
;
343 static unsigned char startup_screen_attrib
;
345 static clock_t startup_time
;
347 static int term_setup_done
;
349 static unsigned short outside_cursor
;
351 /* Similar to the_only_frame. */
352 struct x_output the_only_x_display
;
354 /* Support for DOS/V (allows Japanese characters to be displayed on
355 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
357 /* Holds the address of the text-mode screen buffer. */
358 static unsigned long screen_old_address
= 0;
359 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
360 static unsigned short screen_virtual_segment
= 0;
361 static unsigned short screen_virtual_offset
= 0;
362 /* A flag to control how to display unibyte 8-bit characters. */
363 extern int unibyte_display_via_language_environment
;
368 /* Update the screen from a part of relocated DOS/V screen buffer which
369 begins at OFFSET and includes COUNT characters. */
371 dosv_refresh_virtual_screen (int offset
, int count
)
375 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
378 regs
.h
.ah
= 0xff; /* update relocated screen */
379 regs
.x
.es
= screen_virtual_segment
;
380 regs
.x
.di
= screen_virtual_offset
+ offset
;
382 __dpmi_int (0x10, ®s
);
387 dos_direct_output (y
, x
, buf
, len
)
393 int t0
= 2 * (x
+ y
* screen_size_X
);
394 int t
= t0
+ (int) ScreenPrimary
;
399 dosmemput (buf
++, 1, t
);
403 /* This is faster. */
404 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
405 _farnspokeb (t
, *buf
);
407 if (screen_virtual_segment
)
408 dosv_refresh_virtual_screen (t0
, l0
);
413 /* Flash the screen as a substitute for BEEPs. */
417 do_visible_bell (xorattr
)
418 unsigned char xorattr
;
423 movl _ScreenPrimary,%%eax
430 xorb %%al,%%gs:(%%ebx)
446 : "m" (xorattr
), "g" (screen_size
)
447 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
451 ScreenVisualBell (void)
453 /* This creates an xor-mask that will swap the default fore- and
454 background colors. */
455 do_visible_bell (((the_only_x_display
.foreground_pixel
456 ^ the_only_x_display
.background_pixel
)
461 #ifndef HAVE_X_WINDOWS
463 static int blink_bit
= -1; /* the state of the blink bit at startup */
465 /* Enable bright background colors. */
471 /* Remember the original state of the blink/bright-background bit.
472 It is stored at 0040:0065h in the BIOS data area. */
474 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
478 int86 (0x10, ®s
, ®s
);
481 /* Disable bright background colors (and enable blinking) if we found
482 the video system in that state at startup. */
484 maybe_enable_blinking (void)
492 int86 (0x10, ®s
, ®s
);
496 /* Return non-zero if the system has a VGA adapter. */
503 int86 (0x10, ®s
, ®s
);
504 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
509 /* Set the screen dimensions so that it can show no less than
510 ROWS x COLS frame. */
513 dos_set_window_size (rows
, cols
)
517 Lisp_Object video_mode
;
518 int video_mode_value
;
521 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
523 if (*rows
== current_rows
&& *cols
== current_cols
)
527 have_vga
= vga_installed ();
529 /* If the user specified a special video mode for these dimensions,
531 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
532 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
535 if (INTEGERP (video_mode
)
536 && (video_mode_value
= XINT (video_mode
)) > 0)
538 regs
.x
.ax
= video_mode_value
;
539 int86 (0x10, ®s
, ®s
);
543 /* Must hardware-reset the mouse, or else it won't update
544 its notion of screen dimensions for some non-standard
545 video modes. This is *painfully* slow... */
547 int86 (0x33, ®s
, ®s
);
551 /* Find one of the dimensions supported by standard EGA/VGA
552 which gives us at least the required dimensions. */
561 } std_dimension
[] = {
571 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
573 if (std_dimension
[i
].need_vga
<= have_vga
574 && std_dimension
[i
].rows
>= *rows
)
576 if (std_dimension
[i
].rows
!= current_rows
577 || *cols
!= current_cols
)
578 _set_screen_lines (std_dimension
[i
].rows
);
585 #else /* not __DJGPP__ > 1 */
587 else if (*rows
<= 25)
589 if (current_rows
!= 25 || current_cols
!= 80)
592 int86 (0x10, ®s
, ®s
);
595 int86 (0x10, ®s
, ®s
);
598 int86 (0x10, ®s
, ®s
);
600 int86 (0x10, ®s
, ®s
);
603 else if (*rows
<= 50)
604 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
605 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
608 int86 (0x10, ®s
, ®s
);
611 int86 (0x10, ®s
, ®s
);
614 int86 (0x10, ®s
, ®s
);
617 int86 (0x10, ®s
, ®s
);
619 #endif /* not __DJGPP__ > 1 */
627 /* Tell the caller what dimensions have been REALLY set. */
628 *rows
= ScreenRows ();
629 *cols
= ScreenCols ();
632 /* If the dimensions changed, the mouse highlight info is invalid. */
633 if (current_rows
!= *rows
|| current_cols
!= *cols
)
635 struct frame
*f
= SELECTED_FRAME();
636 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
637 Lisp_Object window
= dpyinfo
->mouse_face_window
;
639 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
641 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
642 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
643 dpyinfo
->mouse_face_window
= Qnil
;
648 /* Enable bright background colors. */
651 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
652 be defensive anyway. */
653 if (screen_virtual_segment
)
654 dosv_refresh_virtual_screen (0, *cols
* *rows
);
657 /* If we write a character in the position where the mouse is,
658 the mouse cursor may need to be refreshed. */
668 mouse_get_xy (&x
, &y
);
669 if (y
!= new_pos_Y
|| x
< new_pos_X
)
675 #define DEFAULT_CURSOR_START (-1)
676 #define DEFAULT_CURSOR_WIDTH (-1)
677 #define BOX_CURSOR_WIDTH (-32)
679 /* Set cursor to begin at scan line START_LINE in the character cell
680 and extend for WIDTH scan lines. Scan lines are counted from top
681 of the character cell, starting from zero. */
683 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
686 unsigned desired_cursor
;
688 int max_line
, top_line
, bot_line
;
690 /* Avoid the costly BIOS call if F isn't the currently selected
691 frame. Allow for NULL as unconditionally meaning the selected
693 if (f
&& f
!= SELECTED_FRAME())
696 /* The character cell size in scan lines is stored at 40:85 in the
698 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
701 default: /* this relies on CGA cursor emulation being ON! */
718 if (width
== BOX_CURSOR_WIDTH
)
723 else if (start_line
!= DEFAULT_CURSOR_START
)
725 top_line
= start_line
;
726 bot_line
= top_line
- width
- 1;
728 else if (width
!= DEFAULT_CURSOR_WIDTH
)
731 bot_line
= -1 - width
;
734 top_line
= bot_line
+ 1;
738 /* [31, 0] seems to DTRT for all screen sizes. */
742 else /* WIDTH is positive */
744 if (start_line
!= DEFAULT_CURSOR_START
)
745 bot_line
= start_line
;
746 top_line
= bot_line
- (width
- 1);
749 /* If the current cursor shape is already what they want, we are
751 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
752 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
756 regs
.x
.cx
= desired_cursor
;
757 __dpmi_int (0x10, ®s
);
758 #endif /* __DJGPP__ > 1 */
762 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
764 if (EQ (cursor_type
, Qbar
))
766 /* Just BAR means the normal EGA/VGA cursor. */
767 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
769 else if (CONSP (cursor_type
) && EQ (XCAR (cursor_type
), Qbar
))
771 Lisp_Object bar_parms
= XCDR (cursor_type
);
774 if (INTEGERP (bar_parms
))
776 /* Feature: negative WIDTH means cursor at the top
777 of the character cell, zero means invisible cursor. */
778 width
= XINT (bar_parms
);
779 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
782 else if (CONSP (bar_parms
)
783 && INTEGERP (XCAR (bar_parms
))
784 && INTEGERP (XCDR (bar_parms
)))
786 int start_line
= XINT (XCDR (bar_parms
));
788 width
= XINT (XCAR (bar_parms
));
789 msdos_set_cursor_shape (f
, start_line
, width
);
793 /* Treat anything unknown as "box cursor". This includes nil, so
794 that a frame which doesn't specify a cursor type gets a box,
795 which is the default in Emacs. */
796 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
809 union REGS inregs
, outregs
;
812 intdos (&inregs
, &outregs
);
816 /* Given a face id FACE, extract the face parameters to be used for
817 display until the face changes. The face parameters (actually, its
818 color) are used to construct the video attribute byte for each
819 glyph during the construction of the buffer that is then blitted to
822 IT_set_face (int face
)
824 struct frame
*sf
= SELECTED_FRAME();
825 struct face
*fp
= FACE_FROM_ID (sf
, face
);
826 unsigned long fg
, bg
;
830 fp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
831 /* The default face for the frame should always be realized and
840 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_*
841 colors mean use the colors of the default face, except that if
842 highlight is on, invert the foreground and the background. Note
843 that we assume all 16 colors to be available for the background,
844 since Emacs switches on this mode (and loses the blinking
845 attribute) at startup. */
846 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
847 fg
= FRAME_FOREGROUND_PIXEL (sf
);
848 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
849 fg
= FRAME_BACKGROUND_PIXEL (sf
);
850 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
851 bg
= FRAME_BACKGROUND_PIXEL (sf
);
852 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
853 bg
= FRAME_FOREGROUND_PIXEL (sf
);
855 /* Make sure highlighted lines really stand out, come what may. */
856 if ((highlight
|| fp
->tty_reverse_p
)
857 && (fg
== FRAME_FOREGROUND_PIXEL (sf
)
858 && bg
== FRAME_BACKGROUND_PIXEL (sf
)))
860 unsigned long tem
= fg
;
866 fprintf (termscript
, "<FACE %d%s: %d/%d[FG:%d/BG:%d]>", face
,
867 highlight
? "H" : "", fp
->foreground
, fp
->background
, fg
, bg
);
868 if (fg
>= 0 && fg
< 16)
870 ScreenAttrib
&= 0xf0;
873 if (bg
>= 0 && bg
< 16)
875 ScreenAttrib
&= 0x0f;
876 ScreenAttrib
|= ((bg
& 0x0f) << 4);
880 Lisp_Object Vdos_unsupported_char_glyph
;
883 IT_write_glyphs (struct glyph
*str
, int str_len
)
885 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
886 int unsupported_face
= FAST_GLYPH_FACE (Vdos_unsupported_char_glyph
);
887 unsigned unsupported_char
= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph
);
888 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
889 register int sl
= str_len
;
890 register int tlen
= GLYPH_TABLE_LENGTH
;
891 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
893 /* If terminal_coding does any conversion, use it, otherwise use
894 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
895 because it always returns 1 if terminal_coding.src_multibyte is 1. */
896 struct coding_system
*coding
=
897 (terminal_coding
.common_flags
& CODING_REQUIRE_ENCODING_MASK
899 : &safe_terminal_coding
);
902 /* Do we need to consider conversion of unibyte characters to
904 int convert_unibyte_characters
905 = (NILP (current_buffer
->enable_multibyte_characters
)
906 && unibyte_display_via_language_environment
);
908 if (str_len
<= 0) return;
910 screen_buf
= screen_bp
= alloca (str_len
* 2);
911 screen_buf_end
= screen_buf
+ str_len
* 2;
912 sf
= SELECTED_FRAME();
914 /* Since faces get cached and uncached behind our back, we can't
915 rely on their indices in the cache being consistent across
916 invocations. So always reset the screen face to the default
917 face of the frame, before writing glyphs, and let the glyphs
918 set the right face if it's different from the default. */
919 IT_set_face (DEFAULT_FACE_ID
);
921 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
923 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
926 int cf
, chlen
, enclen
;
927 unsigned char workbuf
[MAX_MULTIBYTE_LENGTH
], *buf
;
930 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
931 only for the redisplay code to know how many columns does
932 this character occupy on the screen. Skip padding glyphs. */
933 if (CHAR_GLYPH_PADDING_P (*str
))
940 register GLYPH g
= GLYPH_FROM_CHAR_GLYPH (*str
);
941 int glyph_not_in_table
= 0;
943 if (g
< 0 || g
>= tlen
)
945 /* This glyph doesn't have an entry in Vglyph_table. */
947 glyph_not_in_table
= 1;
951 /* This glyph has an entry in Vglyph_table, so process
952 any aliases before testing for simpleness. */
953 GLYPH_FOLLOW_ALIASES (tbase
, tlen
, g
);
954 ch
= FAST_GLYPH_CHAR (g
);
957 /* Convert the character code to multibyte, if they
958 requested display via language environment. We only want
959 to convert unibyte characters to multibyte in unibyte
960 buffers! Otherwise, the 8-bit value in CH came from the
961 display table set up to display foreign characters. */
962 if (SINGLE_BYTE_CHAR_P (ch
) && convert_unibyte_characters
964 || (ch
>= 0200 && !NILP (Vnonascii_translation_table
))))
965 ch
= unibyte_char_to_multibyte (ch
);
967 /* Invalid characters are displayed with a special glyph. */
968 if (! CHAR_VALID_P (ch
, 0))
970 g
= !NILP (Vdos_unsupported_char_glyph
)
971 ? Vdos_unsupported_char_glyph
972 : MAKE_GLYPH (sf
, '\177', GLYPH_FACE (sf
, g
));
973 ch
= FAST_GLYPH_CHAR (g
);
976 /* If the face of this glyph is different from the current
977 screen face, update the screen attribute byte. */
978 cf
= FAST_GLYPH_FACE (g
);
979 if (cf
!= screen_face
)
980 IT_set_face (cf
); /* handles invalid faces gracefully */
982 if (glyph_not_in_table
|| GLYPH_SIMPLE_P (tbase
, tlen
, g
))
984 /* We generate the multi-byte form of CH in WORKBUF. */
985 chlen
= CHAR_STRING (ch
, workbuf
);
990 /* We have a string in Vglyph_table. */
991 chlen
= GLYPH_LENGTH (tbase
, g
);
992 buf
= GLYPH_STRING (tbase
, g
);
995 /* If the character is not multibyte, don't bother converting it. */
998 *conversion_buffer
= (unsigned char)ch
;
1004 coding
->src_multibyte
= 1;
1005 encode_coding (coding
, buf
, conversion_buffer
, chlen
,
1006 conversion_buffer_size
);
1007 chlen
-= coding
->consumed
;
1008 enclen
= coding
->produced
;
1010 /* Replace glyph codes that cannot be converted by
1011 terminal_coding with Vdos_unsupported_char_glyph. */
1012 if (*conversion_buffer
== '?')
1014 char *cbp
= conversion_buffer
;
1016 while (cbp
< conversion_buffer
+ enclen
&& *cbp
== '?')
1017 *cbp
++ = unsupported_char
;
1018 if (unsupported_face
!= screen_face
)
1019 IT_set_face (unsupported_face
);
1023 if (enclen
+ chlen
> screen_buf_end
- screen_bp
)
1025 /* The allocated buffer for screen writes is too small.
1026 Flush it and loop again without incrementing STR, so
1027 that the next loop will begin with the same glyph. */
1028 int nbytes
= screen_bp
- screen_buf
;
1031 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
1032 if (screen_virtual_segment
)
1033 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
1034 new_pos_X
+= nbytes
/ 2;
1037 /* Prepare to reuse the same buffer again. */
1038 screen_bp
= screen_buf
;
1042 /* There's enough place in the allocated buffer to add
1043 the encoding of this glyph. */
1045 /* First, copy the encoded bytes. */
1046 for (bp
= conversion_buffer
; enclen
--; bp
++)
1048 *screen_bp
++ = (unsigned char)*bp
;
1049 *screen_bp
++ = ScreenAttrib
;
1051 fputc (*bp
, termscript
);
1054 /* Now copy the bytes not consumed by the encoding. */
1057 buf
+= coding
->consumed
;
1061 fputc (*buf
, termscript
);
1062 *screen_bp
++ = (unsigned char)*buf
++;
1063 *screen_bp
++ = ScreenAttrib
;
1067 /* Update STR and its remaining length. */
1074 /* Dump whatever is left in the screen buffer. */
1076 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
1077 if (screen_virtual_segment
)
1078 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1079 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1081 /* We may have to output some codes to terminate the writing. */
1082 if (CODING_REQUIRE_FLUSHING (coding
))
1084 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
1085 encode_coding (coding
, "", conversion_buffer
, 0, conversion_buffer_size
);
1086 if (coding
->produced
> 0)
1088 screen_buf
= alloca (coding
->produced
* 2);
1089 for (screen_bp
= screen_buf
, bp
= conversion_buffer
;
1090 coding
->produced
--; bp
++)
1092 *screen_bp
++ = (unsigned char)*bp
;
1093 *screen_bp
++ = ScreenAttrib
;
1095 fputc (*bp
, termscript
);
1097 offset
+= screen_bp
- screen_buf
;
1099 dosmemput (screen_buf
, screen_bp
- screen_buf
,
1100 (int)ScreenPrimary
+ offset
);
1101 if (screen_virtual_segment
)
1102 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1103 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1108 /************************************************************************
1109 Mouse Highlight (and friends..)
1110 ************************************************************************/
1112 /* This is used for debugging, to turn off note_mouse_highlight. */
1113 int disable_mouse_highlight
;
1115 /* If a string, dos_rawgetc generates an event to display that string.
1116 (The display is done in keyboard.c:read_char.) */
1117 static Lisp_Object help_echo
;
1118 static Lisp_Object previous_help_echo
; /* a helper temporary variable */
1120 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1122 /* Set the mouse pointer shape according to whether it is in the
1123 area where the mouse highlight is in effect. */
1125 IT_set_mouse_pointer (int mode
)
1127 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1128 many possibilities to change its shape, and the available
1129 functionality pretty much sucks (e.g., almost every reasonable
1130 shape will conceal the character it is on). Since the color of
1131 the pointer changes in the highlighted area, it is not clear to
1132 me whether anything else is required, anyway. */
1135 /* Display the active region described by mouse_face_*
1136 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1138 show_mouse_face (struct display_info
*dpyinfo
, int hl
)
1140 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
1141 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
1146 /* If window is in the process of being destroyed, don't bother
1148 if (w
->current_matrix
== NULL
)
1149 goto set_cursor_shape
;
1151 /* Recognize when we are called to operate on rows that don't exist
1152 anymore. This can happen when a window is split. */
1153 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
1154 goto set_cursor_shape
;
1156 /* There's no sense to do anything if the mouse face isn't realized. */
1159 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1161 goto set_cursor_shape
;
1164 /* Note that mouse_face_beg_row etc. are window relative. */
1165 for (i
= dpyinfo
->mouse_face_beg_row
;
1166 i
<= dpyinfo
->mouse_face_end_row
;
1169 int start_hpos
, end_hpos
;
1170 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1172 /* Don't do anything if row doesn't have valid contents. */
1173 if (!row
->enabled_p
)
1176 /* For all but the first row, the highlight starts at column 0. */
1177 if (i
== dpyinfo
->mouse_face_beg_row
)
1178 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1182 if (i
== dpyinfo
->mouse_face_end_row
)
1183 end_hpos
= dpyinfo
->mouse_face_end_col
;
1185 end_hpos
= row
->used
[TEXT_AREA
];
1187 if (end_hpos
<= start_hpos
)
1191 int vpos
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1192 int kstart
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1193 int nglyphs
= end_hpos
- start_hpos
;
1194 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1195 int start_offset
= offset
;
1198 fprintf (termscript
, "\n<MH+ %d-%d:%d>",
1199 kstart
, kstart
+ nglyphs
- 1, vpos
);
1202 IT_set_face (dpyinfo
->mouse_face_face_id
);
1203 /* Since we are going to change only the _colors_ of the
1204 displayed text, there's no need to go through all the
1205 pain of generating and encoding the text from the glyphs.
1206 Instead, we simply poke the attribute byte of each
1207 affected position in video memory with the colors
1208 computed by IT_set_face! */
1209 _farsetsel (_dos_ds
);
1212 _farnspokeb (offset
, ScreenAttrib
);
1215 if (screen_virtual_segment
)
1216 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1221 /* We are removing a previously-drawn mouse highlight. The
1222 safest way to do so is to redraw the glyphs anew, since
1223 all kinds of faces and display tables could have changed
1225 int nglyphs
= end_hpos
- start_hpos
;
1226 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1228 if (end_hpos
>= row
->used
[TEXT_AREA
])
1229 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1231 /* IT_write_glyphs writes at cursor position, so we need to
1232 temporarily move cursor coordinates to the beginning of
1233 the highlight region. */
1234 new_pos_X
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1235 new_pos_Y
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1238 fprintf (termscript
, "<MH- %d-%d:%d>",
1239 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1240 IT_write_glyphs (row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1242 fputs ("\n", termscript
);
1250 /* Change the mouse pointer shape. */
1251 IT_set_mouse_pointer (hl
);
1254 /* Clear out the mouse-highlighted active region.
1255 Redraw it un-highlighted first. */
1257 clear_mouse_face (struct display_info
*dpyinfo
)
1259 if (! NILP (dpyinfo
->mouse_face_window
))
1260 show_mouse_face (dpyinfo
, 0);
1262 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1263 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1264 dpyinfo
->mouse_face_window
= Qnil
;
1267 /* Find the glyph matrix position of buffer position POS in window W.
1268 *HPOS and *VPOS are set to the positions found. W's current glyphs
1269 must be up to date. If POS is above window start return (0, 0).
1270 If POS is after end of W, return end of last line in W. */
1272 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1276 int maybe_next_line_p
= 0;
1277 int line_start_position
;
1278 int yb
= window_text_bottom_y (w
);
1279 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0);
1280 struct glyph_row
*best_row
= row
;
1284 if (row
->used
[TEXT_AREA
])
1285 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1287 line_start_position
= 0;
1289 if (line_start_position
> pos
)
1291 /* If the position sought is the end of the buffer,
1292 don't include the blank lines at the bottom of the window. */
1293 else if (line_start_position
== pos
1294 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1296 maybe_next_line_p
= 1;
1299 else if (line_start_position
> 0)
1305 /* Find the right column within BEST_ROW. */
1308 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1310 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1313 charpos
= glyph
->charpos
;
1320 else if (charpos
> pos
)
1322 else if (charpos
> 0)
1326 /* If we're looking for the end of the buffer,
1327 and we didn't find it in the line we scanned,
1328 use the start of the following line. */
1329 if (maybe_next_line_p
)
1336 *hpos
= lastcol
+ 1;
1340 /* Take proper action when mouse has moved to the mode or top line of
1341 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1342 mode line. X is relative to the start of the text display area of
1343 W, so the width of bitmap areas and scroll bars must be subtracted
1344 to get a position relative to the start of the mode line. */
1346 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1348 struct frame
*f
= XFRAME (w
->frame
);
1349 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1350 struct glyph_row
*row
;
1353 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1355 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1359 extern Lisp_Object Qhelp_echo
;
1360 struct glyph
*glyph
, *end
;
1361 Lisp_Object help
, map
;
1363 /* Find the glyph under X. */
1364 glyph
= row
->glyphs
[TEXT_AREA
]
1365 + x
- FRAME_LEFT_SCROLL_BAR_WIDTH (f
) * CANON_X_UNIT (f
);
1366 end
= glyph
+ row
->used
[TEXT_AREA
];
1368 && STRINGP (glyph
->object
)
1369 && XSTRING (glyph
->object
)->intervals
1370 && glyph
->charpos
>= 0
1371 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1373 /* If we're on a string with `help-echo' text property,
1374 arrange for the help to be displayed. This is done by
1375 setting the global variable help_echo to the help string. */
1376 help
= Fget_text_property (make_number (glyph
->charpos
),
1377 Qhelp_echo
, glyph
->object
);
1384 /* Take proper action when the mouse has moved to position X, Y on
1385 frame F as regards highlighting characters that have mouse-face
1386 properties. Also de-highlighting chars where the mouse was before.
1387 X and Y can be negative or out of range. */
1389 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1391 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1396 /* When a menu is active, don't highlight because this looks odd. */
1397 if (mouse_preempted
)
1400 if (disable_mouse_highlight
1401 || !f
->glyphs_initialized_p
)
1404 dpyinfo
->mouse_face_mouse_x
= x
;
1405 dpyinfo
->mouse_face_mouse_y
= y
;
1406 dpyinfo
->mouse_face_mouse_frame
= f
;
1408 if (dpyinfo
->mouse_face_defer
)
1413 dpyinfo
->mouse_face_deferred_gc
= 1;
1417 /* Which window is that in? */
1418 window
= window_from_coordinates (f
, x
, y
, &portion
, 0);
1420 /* If we were displaying active text in another window, clear that. */
1421 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1422 clear_mouse_face (dpyinfo
);
1424 /* Not on a window -> return. */
1425 if (!WINDOWP (window
))
1428 /* Convert to window-relative coordinates. */
1429 w
= XWINDOW (window
);
1430 x
-= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1431 y
-= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1433 if (portion
== 1 || portion
== 3)
1435 /* Mouse is on the mode or top line. */
1436 IT_note_mode_line_highlight (w
, x
, portion
== 1);
1440 IT_set_mouse_pointer (0);
1442 /* Are we in a window whose display is up to date?
1443 And verify the buffer's text has not changed. */
1444 if (/* Within text portion of the window. */
1446 && EQ (w
->window_end_valid
, w
->buffer
)
1447 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1448 && (XFASTINT (w
->last_overlay_modified
)
1449 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1452 struct glyph_row
*row
;
1453 struct glyph
*glyph
;
1455 /* Find the glyph under X/Y. */
1457 if (y
< w
->current_matrix
->nrows
)
1459 row
= MATRIX_ROW (w
->current_matrix
, y
);
1461 && row
->displays_text_p
1462 && x
< window_box_width (w
, TEXT_AREA
))
1464 glyph
= row
->glyphs
[TEXT_AREA
];
1465 if (x
>= row
->used
[TEXT_AREA
])
1470 if (!BUFFERP (glyph
->object
))
1476 /* Clear mouse face if X/Y not over text. */
1479 clear_mouse_face (dpyinfo
);
1483 if (!BUFFERP (glyph
->object
))
1485 pos
= glyph
->charpos
;
1487 /* Check for mouse-face and help-echo. */
1489 extern Lisp_Object Qmouse_face
;
1490 Lisp_Object mouse_face
, overlay
, position
;
1491 Lisp_Object
*overlay_vec
;
1493 struct buffer
*obuf
;
1496 /* If we get an out-of-range value, return now; avoid an error. */
1497 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1500 /* Make the window's buffer temporarily current for
1501 overlays_at and compute_char_face. */
1502 obuf
= current_buffer
;
1503 current_buffer
= XBUFFER (w
->buffer
);
1509 /* Is this char mouse-active or does it have help-echo? */
1510 XSETINT (position
, pos
);
1512 /* Put all the overlays we want in a vector in overlay_vec.
1513 Store the length in len. If there are more than 10, make
1514 enough space for all, and try again. */
1516 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1517 noverlays
= overlays_at (pos
, 0, &overlay_vec
, &len
, NULL
, NULL
);
1518 if (noverlays
> len
)
1521 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1522 noverlays
= overlays_at (pos
, 0, &overlay_vec
, &len
, NULL
, NULL
);
1525 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1527 /* Check mouse-face highlighting. */
1528 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1529 && y
>= dpyinfo
->mouse_face_beg_row
1530 && y
<= dpyinfo
->mouse_face_end_row
1531 && (y
> dpyinfo
->mouse_face_beg_row
1532 || x
>= dpyinfo
->mouse_face_beg_col
)
1533 && (y
< dpyinfo
->mouse_face_end_row
1534 || x
< dpyinfo
->mouse_face_end_col
1535 || dpyinfo
->mouse_face_past_end
)))
1537 /* Clear the display of the old active region, if any. */
1538 clear_mouse_face (dpyinfo
);
1540 /* Find highest priority overlay that has a mouse-face prop. */
1542 for (i
= 0; i
< noverlays
; i
++)
1544 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1545 if (!NILP (mouse_face
))
1547 overlay
= overlay_vec
[i
];
1552 /* If no overlay applies, get a text property. */
1554 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1557 /* Handle the overlay case. */
1558 if (! NILP (overlay
))
1560 /* Find the range of text around this char that
1561 should be active. */
1562 Lisp_Object before
, after
;
1565 before
= Foverlay_start (overlay
);
1566 after
= Foverlay_end (overlay
);
1567 /* Record this as the current active region. */
1568 fast_find_position (w
, XFASTINT (before
),
1569 &dpyinfo
->mouse_face_beg_col
,
1570 &dpyinfo
->mouse_face_beg_row
);
1571 dpyinfo
->mouse_face_past_end
1572 = !fast_find_position (w
, XFASTINT (after
),
1573 &dpyinfo
->mouse_face_end_col
,
1574 &dpyinfo
->mouse_face_end_row
);
1575 dpyinfo
->mouse_face_window
= window
;
1576 dpyinfo
->mouse_face_face_id
1577 = face_at_buffer_position (w
, pos
, 0, 0,
1578 &ignore
, pos
+ 1, 1);
1580 /* Display it as active. */
1581 show_mouse_face (dpyinfo
, 1);
1583 /* Handle the text property case. */
1584 else if (! NILP (mouse_face
))
1586 /* Find the range of text around this char that
1587 should be active. */
1588 Lisp_Object before
, after
, beginning
, end
;
1591 beginning
= Fmarker_position (w
->start
);
1592 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1593 - XFASTINT (w
->window_end_pos
)));
1595 = Fprevious_single_property_change (make_number (pos
+ 1),
1597 w
->buffer
, beginning
);
1599 = Fnext_single_property_change (position
, Qmouse_face
,
1601 /* Record this as the current active region. */
1602 fast_find_position (w
, XFASTINT (before
),
1603 &dpyinfo
->mouse_face_beg_col
,
1604 &dpyinfo
->mouse_face_beg_row
);
1605 dpyinfo
->mouse_face_past_end
1606 = !fast_find_position (w
, XFASTINT (after
),
1607 &dpyinfo
->mouse_face_end_col
,
1608 &dpyinfo
->mouse_face_end_row
);
1609 dpyinfo
->mouse_face_window
= window
;
1610 dpyinfo
->mouse_face_face_id
1611 = face_at_buffer_position (w
, pos
, 0, 0,
1612 &ignore
, pos
+ 1, 1);
1614 /* Display it as active. */
1615 show_mouse_face (dpyinfo
, 1);
1619 /* Look for a `help-echo' property. */
1622 extern Lisp_Object Qhelp_echo
;
1624 /* Check overlays first. */
1626 for (i
= 0; i
< noverlays
&& !STRINGP (help
); ++i
)
1627 help
= Foverlay_get (overlay_vec
[i
], Qhelp_echo
);
1629 /* Try text properties. */
1631 && ((STRINGP (glyph
->object
)
1632 && glyph
->charpos
>= 0
1633 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1634 || (BUFFERP (glyph
->object
)
1635 && glyph
->charpos
>= BEGV
1636 && glyph
->charpos
< ZV
)))
1637 help
= Fget_text_property (make_number (glyph
->charpos
),
1638 Qhelp_echo
, glyph
->object
);
1646 current_buffer
= obuf
;
1652 IT_clear_end_of_line (int first_unused
)
1656 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1657 extern int fatal_error_in_progress
;
1659 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1663 i
= (j
= first_unused
- new_pos_X
) * 2;
1665 fprintf (termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1666 spaces
= sp
= alloca (i
);
1671 *sp
++ = ScreenAttrib
;
1675 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1676 if (screen_virtual_segment
)
1677 dosv_refresh_virtual_screen (offset
, i
/ 2);
1679 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1680 Let's follow their lead, in case someone relies on this. */
1681 new_pos_X
= first_unused
;
1685 IT_clear_screen (void)
1688 fprintf (termscript
, "<CLR:SCR>");
1692 if (screen_virtual_segment
)
1693 dosv_refresh_virtual_screen (0, screen_size
);
1694 new_pos_X
= new_pos_Y
= 0;
1698 IT_clear_to_end (void)
1701 fprintf (termscript
, "<CLR:EOS>");
1703 while (new_pos_Y
< screen_size_Y
) {
1705 IT_clear_end_of_line (screen_size_X
);
1711 IT_cursor_to (int y
, int x
)
1714 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
1719 static int cursor_cleared
;
1722 IT_display_cursor (int on
)
1724 if (on
&& cursor_cleared
)
1726 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1729 else if (!on
&& !cursor_cleared
)
1731 ScreenSetCursor (-1, -1);
1736 /* Emacs calls cursor-movement functions a lot when it updates the
1737 display (probably a legacy of old terminals where you cannot
1738 update a screen line without first moving the cursor there).
1739 However, cursor movement is expensive on MSDOS (it calls a slow
1740 BIOS function and requires 2 mode switches), while actual screen
1741 updates access the video memory directly and don't depend on
1742 cursor position. To avoid slowing down the redisplay, we cheat:
1743 all functions that move the cursor only set internal variables
1744 which record the cursor position, whereas the cursor is only
1745 moved to its final position whenever screen update is complete.
1747 `IT_cmgoto' is called from the keyboard reading loop and when the
1748 frame update is complete. This means that we are ready for user
1749 input, so we update the cursor position to show where the point is,
1750 and also make the mouse pointer visible.
1752 Special treatment is required when the cursor is in the echo area,
1753 to put the cursor at the end of the text displayed there. */
1756 IT_cmgoto (FRAME_PTR f
)
1758 /* Only set the cursor to where it should be if the display is
1759 already in sync with the window contents. */
1760 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1762 /* FIXME: This needs to be rewritten for the new redisplay, or
1765 static int previous_pos_X
= -1;
1767 update_cursor_pos
= 1; /* temporary!!! */
1769 /* If the display is in sync, forget any previous knowledge about
1770 cursor position. This is primarily for unexpected events like
1771 C-g in the minibuffer. */
1772 if (update_cursor_pos
&& previous_pos_X
>= 0)
1773 previous_pos_X
= -1;
1774 /* If we are in the echo area, put the cursor at the
1775 end of the echo area message. */
1776 if (!update_cursor_pos
1777 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1779 int tem_X
= current_pos_X
, dummy
;
1781 if (echo_area_glyphs
)
1783 tem_X
= echo_area_glyphs_length
;
1784 /* Save current cursor position, to be restored after the
1785 echo area message is erased. Only remember one level
1786 of previous cursor position. */
1787 if (previous_pos_X
== -1)
1788 ScreenGetCursor (&dummy
, &previous_pos_X
);
1790 else if (previous_pos_X
>= 0)
1792 /* We wind up here after the echo area message is erased.
1793 Restore the cursor position we remembered above. */
1794 tem_X
= previous_pos_X
;
1795 previous_pos_X
= -1;
1798 if (current_pos_X
!= tem_X
)
1801 update_cursor_pos
= 1;
1806 if (update_cursor_pos
1807 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1809 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1811 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1814 /* Maybe cursor is invisible, so make it visible. */
1815 IT_display_cursor (1);
1817 /* Mouse pointer should be always visible if we are waiting for
1824 IT_reassert_line_highlight (int new, int vpos
)
1830 IT_change_line_highlight (int new_highlight
, int y
, int vpos
, int first_unused_hpos
)
1832 highlight
= new_highlight
;
1833 IT_cursor_to (vpos
, 0);
1834 IT_clear_end_of_line (first_unused_hpos
);
1838 IT_update_begin (struct frame
*f
)
1840 struct display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1846 if (f
== display_info
->mouse_face_mouse_frame
)
1848 /* Don't do highlighting for mouse motion during the update. */
1849 display_info
->mouse_face_defer
= 1;
1851 /* If F needs to be redrawn, simply forget about any prior mouse
1853 if (FRAME_GARBAGED_P (f
))
1854 display_info
->mouse_face_window
= Qnil
;
1856 /* Can we tell that this update does not affect the window
1857 where the mouse highlight is? If so, no need to turn off.
1858 Likewise, don't do anything if the frame is garbaged;
1859 in that case, the frame's current matrix that we would use
1860 is all wrong, and we will redisplay that line anyway. */
1861 if (!NILP (display_info
->mouse_face_window
)
1862 && WINDOWP (display_info
->mouse_face_window
))
1864 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1867 /* If the mouse highlight is in the window that was deleted
1868 (e.g., if it was popped by completion), clear highlight
1870 if (NILP (w
->buffer
))
1871 display_info
->mouse_face_window
= Qnil
;
1874 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1875 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
))
1879 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1880 clear_mouse_face (display_info
);
1883 else if (!FRAME_LIVE_P (display_info
->mouse_face_mouse_frame
))
1885 /* If the frame with mouse highlight was deleted, invalidate the
1887 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1888 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1889 display_info
->mouse_face_window
= Qnil
;
1890 display_info
->mouse_face_deferred_gc
= 0;
1891 display_info
->mouse_face_mouse_frame
= NULL
;
1898 IT_update_end (struct frame
*f
)
1901 FRAME_X_DISPLAY_INFO (f
)->mouse_face_defer
= 0;
1904 Lisp_Object Qcursor_type
;
1907 IT_frame_up_to_date (struct frame
*f
)
1909 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1910 Lisp_Object new_cursor
, frame_desired_cursor
;
1913 if (dpyinfo
->mouse_face_deferred_gc
1914 || f
== dpyinfo
->mouse_face_mouse_frame
)
1917 if (dpyinfo
->mouse_face_mouse_frame
)
1918 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
1919 dpyinfo
->mouse_face_mouse_x
,
1920 dpyinfo
->mouse_face_mouse_y
);
1921 dpyinfo
->mouse_face_deferred_gc
= 0;
1925 /* Set the cursor type to whatever they wanted. In a minibuffer
1926 window, we want the cursor to appear only if we are reading input
1927 from this window, and we want the cursor to be taken from the
1928 frame parameters. For the selected window, we use either its
1929 buffer-local value or the value from the frame parameters if the
1930 buffer doesn't define its local value for the cursor type. */
1931 sw
= XWINDOW (f
->selected_window
);
1932 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1933 if (cursor_in_echo_area
1934 && FRAME_HAS_MINIBUF_P (f
)
1935 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1936 && sw
== XWINDOW (echo_area_window
))
1937 new_cursor
= frame_desired_cursor
;
1940 struct buffer
*b
= XBUFFER (sw
->buffer
);
1942 if (EQ (b
->cursor_type
, Qt
))
1943 new_cursor
= frame_desired_cursor
;
1944 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
1945 new_cursor
= Fcons (Qbar
, make_number (0));
1947 new_cursor
= b
->cursor_type
;
1950 IT_set_cursor_type (f
, new_cursor
);
1952 IT_cmgoto (f
); /* position cursor when update is done */
1955 /* Copy LEN glyphs displayed on a single line whose vertical position
1956 is YPOS, beginning at horizontal position XFROM to horizontal
1957 position XTO, by moving blocks in the video memory. Used by
1958 functions that insert and delete glyphs. */
1960 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1962 /* The offsets of source and destination relative to the
1963 conventional memorty selector. */
1964 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1965 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1967 if (from
== to
|| len
<= 0)
1970 _farsetsel (_dos_ds
);
1972 /* The source and destination might overlap, so we need to move
1973 glyphs non-destructively. */
1976 for ( ; len
; from
+= 2, to
+= 2, len
--)
1977 _farnspokew (to
, _farnspeekw (from
));
1981 from
+= (len
- 1) * 2;
1982 to
+= (len
- 1) * 2;
1983 for ( ; len
; from
-= 2, to
-= 2, len
--)
1984 _farnspokew (to
, _farnspeekw (from
));
1986 if (screen_virtual_segment
)
1987 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1990 /* Insert and delete glyphs. */
1992 IT_insert_glyphs (start
, len
)
1993 register struct glyph
*start
;
1996 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1998 /* Shift right the glyphs from the nominal cursor position to the
1999 end of this line. */
2000 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
2002 /* Now write the glyphs to be inserted. */
2003 IT_write_glyphs (start
, len
);
2007 IT_delete_glyphs (n
)
2013 /* set-window-configuration on window.c needs this. */
2015 x_set_menu_bar_lines (f
, value
, oldval
)
2017 Lisp_Object value
, oldval
;
2019 set_menu_bar_lines (f
, value
, oldval
);
2022 /* This was copied from xfns.c */
2024 Lisp_Object Qbackground_color
;
2025 Lisp_Object Qforeground_color
;
2026 Lisp_Object Qreverse
;
2027 extern Lisp_Object Qtitle
;
2029 /* IT_set_terminal_modes is called when emacs is started,
2030 resumed, and whenever the screen is redrawn! */
2033 IT_set_terminal_modes (void)
2036 fprintf (termscript
, "\n<SET_TERM>");
2039 screen_size_X
= ScreenCols ();
2040 screen_size_Y
= ScreenRows ();
2041 screen_size
= screen_size_X
* screen_size_Y
;
2043 new_pos_X
= new_pos_Y
= 0;
2044 current_pos_X
= current_pos_Y
= -1;
2046 if (term_setup_done
)
2048 term_setup_done
= 1;
2050 startup_screen_size_X
= screen_size_X
;
2051 startup_screen_size_Y
= screen_size_Y
;
2052 startup_screen_attrib
= ScreenAttrib
;
2055 /* Is DOS/V (or any other RSIS software which relocates
2056 the screen) installed? */
2058 unsigned short es_value
;
2061 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2062 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2063 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2064 else if (screen_old_address
) /* already switched to Japanese mode once */
2065 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2067 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2069 es_value
= regs
.x
.es
;
2070 __dpmi_int (0x10, ®s
);
2072 if (regs
.x
.es
!= es_value
)
2074 /* screen_old_address is only set if ScreenPrimary does NOT
2075 already point to the relocated buffer address returned by
2076 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2077 ScreenPrimary to that address at startup under DOS/V. */
2078 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2079 screen_old_address
= ScreenPrimary
;
2080 screen_virtual_segment
= regs
.x
.es
;
2081 screen_virtual_offset
= regs
.x
.di
;
2082 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2085 #endif /* __DJGPP__ > 1 */
2087 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2088 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2091 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2092 screen_size_X
, screen_size_Y
);
2097 /* IT_reset_terminal_modes is called when emacs is
2098 suspended or killed. */
2101 IT_reset_terminal_modes (void)
2103 int display_row_start
= (int) ScreenPrimary
;
2104 int saved_row_len
= startup_screen_size_X
* 2;
2105 int update_row_len
= ScreenCols () * 2;
2106 int current_rows
= ScreenRows ();
2107 int to_next_row
= update_row_len
;
2108 unsigned char *saved_row
= startup_screen_buffer
;
2109 int cursor_pos_X
= ScreenCols () - 1;
2110 int cursor_pos_Y
= ScreenRows () - 1;
2113 fprintf (termscript
, "\n<RESET_TERM>");
2117 if (!term_setup_done
)
2122 /* Leave the video system in the same state as we found it,
2123 as far as the blink/bright-background bit is concerned. */
2124 maybe_enable_blinking ();
2126 /* We have a situation here.
2127 We cannot just do ScreenUpdate(startup_screen_buffer) because
2128 the luser could have changed screen dimensions inside Emacs
2129 and failed (or didn't want) to restore them before killing
2130 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2131 thus will happily use memory outside what was allocated for
2132 `startup_screen_buffer'.
2133 Thus we only restore as much as the current screen dimensions
2134 can hold, and clear the rest (if the saved screen is smaller than
2135 the current) with the color attribute saved at startup. The cursor
2136 is also restored within the visible dimensions. */
2138 ScreenAttrib
= startup_screen_attrib
;
2140 /* Don't restore the screen if we are exiting less than 2 seconds
2141 after startup: we might be crashing, and the screen might show
2142 some vital clues to what's wrong. */
2143 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2146 if (screen_virtual_segment
)
2147 dosv_refresh_virtual_screen (0, screen_size
);
2149 if (update_row_len
> saved_row_len
)
2150 update_row_len
= saved_row_len
;
2151 if (current_rows
> startup_screen_size_Y
)
2152 current_rows
= startup_screen_size_Y
;
2155 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2156 update_row_len
/ 2, current_rows
);
2158 while (current_rows
--)
2160 dosmemput (saved_row
, update_row_len
, display_row_start
);
2161 if (screen_virtual_segment
)
2162 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2163 update_row_len
/ 2);
2164 saved_row
+= saved_row_len
;
2165 display_row_start
+= to_next_row
;
2168 if (startup_pos_X
< cursor_pos_X
)
2169 cursor_pos_X
= startup_pos_X
;
2170 if (startup_pos_Y
< cursor_pos_Y
)
2171 cursor_pos_Y
= startup_pos_Y
;
2173 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2174 xfree (startup_screen_buffer
);
2176 term_setup_done
= 0;
2180 IT_set_terminal_window (int foo
)
2184 /* Remember the screen colors of the curent frame, to serve as the
2185 default colors for newly-created frames. */
2187 static int initial_screen_colors
[2];
2189 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2190 Smsdos_remember_default_colors
, 1, 1, 0,
2191 "Remember the screen colors of the current frame.")
2198 CHECK_FRAME (frame
, 0);
2200 reverse
= EQ (Fcdr (Fassq (intern ("reverse"), f
->param_alist
)), Qt
);
2202 initial_screen_colors
[0]
2203 = reverse
? FRAME_BACKGROUND_PIXEL (f
) : FRAME_FOREGROUND_PIXEL (f
);
2204 initial_screen_colors
[1]
2205 = reverse
? FRAME_FOREGROUND_PIXEL (f
) : FRAME_BACKGROUND_PIXEL (f
);
2209 IT_set_frame_parameters (f
, alist
)
2214 int length
= XINT (Flength (alist
));
2217 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2219 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2220 /* Do we have to reverse the foreground and background colors? */
2221 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2222 int was_reverse
= reverse
;
2223 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2224 unsigned long orig_fg
;
2225 unsigned long orig_bg
;
2227 /* If we are creating a new frame, begin with the original screen colors
2228 used for the initial frame. */
2229 if (alist
== Vdefault_frame_alist
2230 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2232 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2233 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2235 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2236 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2238 /* Extract parm names and values into those vectors. */
2240 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2245 parms
[i
] = Fcar (elt
);
2246 CHECK_SYMBOL (parms
[i
], 1);
2247 values
[i
] = Fcdr (elt
);
2253 for (i
= 0; i
< j
; i
++)
2255 Lisp_Object prop
= parms
[i
];
2256 Lisp_Object val
= values
[i
];
2258 if (EQ (prop
, Qreverse
))
2259 reverse
= EQ (val
, Qt
);
2262 if (termscript
&& reverse
&& !was_reverse
)
2263 fprintf (termscript
, "<INVERSE-VIDEO>\n");
2265 /* Now process the alist elements in reverse of specified order. */
2266 for (i
--; i
>= 0; i
--)
2268 Lisp_Object prop
= parms
[i
];
2269 Lisp_Object val
= values
[i
];
2271 if (EQ (prop
, Qforeground_color
))
2273 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
2274 ? LFACE_BACKGROUND_INDEX
2275 : LFACE_FOREGROUND_INDEX
);
2276 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2277 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2278 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2281 /* FIXME: should the fore-/background of the default
2282 face change here as well? */
2283 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2285 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2289 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
2292 else if (EQ (prop
, Qbackground_color
))
2294 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
2295 ? LFACE_FOREGROUND_INDEX
2296 : LFACE_BACKGROUND_INDEX
);
2297 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2298 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2299 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2302 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2304 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2308 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
2311 else if (EQ (prop
, Qtitle
))
2313 x_set_title (f
, val
);
2315 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
2317 else if (EQ (prop
, Qcursor_type
))
2319 IT_set_cursor_type (f
, val
);
2321 fprintf (termscript
, "<CTYPE: %s>\n",
2322 EQ (val
, Qbar
) || CONSP (val
) && EQ (XCAR (val
), Qbar
)
2325 store_frame_param (f
, prop
, val
);
2328 /* If they specified "reverse", but not the colors, we need to swap
2329 the current frame colors. */
2330 if (reverse
&& !was_reverse
)
2334 FRAME_BACKGROUND_PIXEL (f
) = orig_fg
;
2339 FRAME_FOREGROUND_PIXEL (f
) = orig_bg
;
2346 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2347 if (f
== SELECTED_FRAME())
2352 extern void init_frame_faces (FRAME_PTR
);
2354 #endif /* !HAVE_X_WINDOWS */
2357 /* Do we need the internal terminal? */
2360 internal_terminal_init ()
2362 char *term
= getenv ("TERM");
2364 struct frame
*sf
= SELECTED_FRAME();
2366 #ifdef HAVE_X_WINDOWS
2367 if (!inhibit_window_system
)
2372 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2374 if (getenv ("EMACSTEST"))
2375 termscript
= fopen (getenv ("EMACSTEST"), "wt");
2377 #ifndef HAVE_X_WINDOWS
2378 if (!internal_terminal
|| inhibit_window_system
)
2380 sf
->output_method
= output_termcap
;
2384 Vwindow_system
= intern ("pc");
2385 Vwindow_system_version
= make_number (1);
2386 sf
->output_method
= output_msdos_raw
;
2388 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2389 screen_old_address
= 0;
2391 /* Forget the stale screen colors as well. */
2392 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2394 bzero (&the_only_x_display
, sizeof the_only_x_display
);
2395 the_only_x_display
.background_pixel
= 7; /* White */
2396 the_only_x_display
.foreground_pixel
= 0; /* Black */
2398 colors
= getenv ("EMACSCOLORS");
2399 if (colors
&& strlen (colors
) >= 2)
2401 /* The colors use 4 bits each (we enable bright background). */
2402 if (isdigit (colors
[0]))
2404 else if (isxdigit (colors
[0]))
2405 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2406 if (colors
[0] >= 0 && colors
[0] < 16)
2407 the_only_x_display
.foreground_pixel
= colors
[0];
2408 if (isdigit (colors
[1]))
2410 else if (isxdigit (colors
[1]))
2411 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2412 if (colors
[1] >= 0 && colors
[1] < 16)
2413 the_only_x_display
.background_pixel
= colors
[1];
2415 the_only_x_display
.line_height
= 1;
2416 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
2417 the_only_x_display
.display_info
.mouse_face_mouse_frame
= NULL
;
2418 the_only_x_display
.display_info
.mouse_face_deferred_gc
= 0;
2419 the_only_x_display
.display_info
.mouse_face_beg_row
=
2420 the_only_x_display
.display_info
.mouse_face_beg_col
= -1;
2421 the_only_x_display
.display_info
.mouse_face_end_row
=
2422 the_only_x_display
.display_info
.mouse_face_end_col
= -1;
2423 the_only_x_display
.display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2424 the_only_x_display
.display_info
.mouse_face_window
= Qnil
;
2425 the_only_x_display
.display_info
.mouse_face_mouse_x
=
2426 the_only_x_display
.display_info
.mouse_face_mouse_y
= 0;
2427 the_only_x_display
.display_info
.mouse_face_defer
= 0;
2429 init_frame_faces (sf
);
2431 ring_bell_hook
= IT_ring_bell
;
2432 insert_glyphs_hook
= IT_insert_glyphs
;
2433 delete_glyphs_hook
= IT_delete_glyphs
;
2434 write_glyphs_hook
= IT_write_glyphs
;
2435 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
2436 clear_to_end_hook
= IT_clear_to_end
;
2437 clear_end_of_line_hook
= IT_clear_end_of_line
;
2438 clear_frame_hook
= IT_clear_screen
;
2439 change_line_highlight_hook
= IT_change_line_highlight
;
2440 update_begin_hook
= IT_update_begin
;
2441 update_end_hook
= IT_update_end
;
2442 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
2443 frame_up_to_date_hook
= IT_frame_up_to_date
;
2445 /* These hooks are called by term.c without being checked. */
2446 set_terminal_modes_hook
= IT_set_terminal_modes
;
2447 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2448 set_terminal_window_hook
= IT_set_terminal_window
;
2449 char_ins_del_ok
= 0;
2453 dos_get_saved_screen (screen
, rows
, cols
)
2458 #ifndef HAVE_X_WINDOWS
2459 *screen
= startup_screen_buffer
;
2460 *cols
= startup_screen_size_X
;
2461 *rows
= startup_screen_size_Y
;
2462 return *screen
!= (char *)0;
2468 #ifndef HAVE_X_WINDOWS
2470 /* We are not X, but we can emulate it well enough for our needs... */
2474 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2475 error ("Not running under a window system");
2481 /* ----------------------- Keyboard control ----------------------
2483 * Keymaps reflect the following keyboard layout:
2485 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2486 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2487 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2488 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2492 #define Ignore 0x0000
2493 #define Normal 0x0000 /* normal key - alt changes scan-code */
2494 #define FctKey 0x1000 /* func key if c == 0, else c */
2495 #define Special 0x2000 /* func key even if c != 0 */
2496 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2497 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2498 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2499 #define Grey 0x6000 /* Grey keypad key */
2501 #define Alt 0x0100 /* alt scan-code */
2502 #define Ctrl 0x0200 /* ctrl scan-code */
2503 #define Shift 0x0400 /* shift scan-code */
2505 static int extended_kbd
; /* 101 (102) keyboard present. */
2507 struct kbd_translate
{
2510 unsigned short code
;
2513 struct dos_keyboard_map
2518 struct kbd_translate
*translate_table
;
2522 static struct dos_keyboard_map us_keyboard
= {
2524 /* 01234567890123456789012345678901234567890 12345678901234 */
2525 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2526 /* 0123456789012345678901234567890123456789 012345678901234 */
2527 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2528 0, /* no Alt-Gr key */
2529 0 /* no translate table */
2532 static struct dos_keyboard_map fr_keyboard
= {
2534 /* 012 3456789012345678901234567890123456789012345678901234 */
2535 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2536 /* 0123456789012345678901234567890123456789012345678901234 */
2537 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2538 /* 01234567 89012345678901234567890123456789012345678901234 */
2540 0 /* no translate table */
2544 * Italian keyboard support, country code 39.
2547 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2548 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2551 static struct kbd_translate it_kbd_translate_table
[] = {
2552 { 0x56, 0x3c, Normal
| 13 },
2553 { 0x56, 0x3e, Normal
| 27 },
2556 static struct dos_keyboard_map it_keyboard
= {
2558 /* 0 123456789012345678901234567890123456789012345678901234 */
2559 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2560 /* 01 23456789012345678901234567890123456789012345678901234 */
2561 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2562 /* 0123456789012345678901234567890123456789012345678901234 */
2564 it_kbd_translate_table
2567 static struct dos_keyboard_map dk_keyboard
= {
2569 /* 0123456789012345678901234567890123456789012345678901234 */
2570 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2571 /* 01 23456789012345678901234567890123456789012345678901234 */
2572 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2573 /* 0123456789012345678901234567890123456789012345678901234 */
2575 0 /* no translate table */
2578 static struct kbd_translate jp_kbd_translate_table
[] = {
2579 { 0x73, 0x5c, Normal
| 0 },
2580 { 0x73, 0x5f, Normal
| 0 },
2581 { 0x73, 0x1c, Map
| 0 },
2582 { 0x7d, 0x5c, Normal
| 13 },
2583 { 0x7d, 0x7c, Normal
| 13 },
2584 { 0x7d, 0x1c, Map
| 13 },
2587 static struct dos_keyboard_map jp_keyboard
= {
2589 /* 0123456789012 345678901234567890123456789012345678901234 */
2590 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2591 /* 01 23456789012345678901234567890123456789012345678901234 */
2592 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2593 0, /* no Alt-Gr key */
2594 jp_kbd_translate_table
2597 static struct keyboard_layout_list
2600 struct dos_keyboard_map
*keyboard_map
;
2601 } keyboard_layout_list
[] =
2610 static struct dos_keyboard_map
*keyboard
;
2611 static int keyboard_map_all
;
2612 static int international_keyboard
;
2615 dos_set_keyboard (code
, always
)
2620 _go32_dpmi_registers regs
;
2622 /* See if Keyb.Com is installed (for international keyboard support).
2623 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2624 of Windows 9X! So don't do that! */
2626 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2627 _go32_dpmi_simulate_int (0x2f, ®s
);
2628 if (regs
.h
.al
== 0xff)
2629 international_keyboard
= 1;
2631 /* Initialize to US settings, for countries that don't have their own. */
2632 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2633 keyboard_map_all
= always
;
2634 dos_keyboard_layout
= 1;
2636 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2637 if (code
== keyboard_layout_list
[i
].country_code
)
2639 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2640 keyboard_map_all
= always
;
2641 dos_keyboard_layout
= code
;
2649 unsigned char char_code
; /* normal code */
2650 unsigned char meta_code
; /* M- code */
2651 unsigned char keypad_code
; /* keypad code */
2652 unsigned char editkey_code
; /* edit key */
2653 } keypad_translate_map
[] = {
2654 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2655 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2656 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2657 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2658 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2659 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2660 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2661 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2662 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2663 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2664 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2669 unsigned char char_code
; /* normal code */
2670 unsigned char keypad_code
; /* keypad code */
2671 } grey_key_translate_map
[] = {
2672 '/', 0xaf, /* kp-decimal */
2673 '*', 0xaa, /* kp-multiply */
2674 '-', 0xad, /* kp-subtract */
2675 '+', 0xab, /* kp-add */
2676 '\r', 0x8d /* kp-enter */
2679 static unsigned short
2680 ibmpc_translate_map
[] =
2682 /* --------------- 00 to 0f --------------- */
2683 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2684 Alt
| ModFct
| 0x1b, /* Escape */
2685 Normal
| 1, /* '1' */
2686 Normal
| 2, /* '2' */
2687 Normal
| 3, /* '3' */
2688 Normal
| 4, /* '4' */
2689 Normal
| 5, /* '5' */
2690 Normal
| 6, /* '6' */
2691 Normal
| 7, /* '7' */
2692 Normal
| 8, /* '8' */
2693 Normal
| 9, /* '9' */
2694 Normal
| 10, /* '0' */
2695 Normal
| 11, /* '-' */
2696 Normal
| 12, /* '=' */
2697 Special
| 0x08, /* Backspace */
2698 ModFct
| 0x74, /* Tab/Backtab */
2700 /* --------------- 10 to 1f --------------- */
2713 ModFct
| 0x0d, /* Return */
2718 /* --------------- 20 to 2f --------------- */
2727 Map
| 40, /* '\'' */
2729 Ignore
, /* Left shift */
2730 Map
| 41, /* '\\' */
2736 /* --------------- 30 to 3f --------------- */
2743 Ignore
, /* Right shift */
2744 Grey
| 1, /* Grey * */
2746 Normal
| 55, /* ' ' */
2747 Ignore
, /* Caps Lock */
2748 FctKey
| 0xbe, /* F1 */
2749 FctKey
| 0xbf, /* F2 */
2750 FctKey
| 0xc0, /* F3 */
2751 FctKey
| 0xc1, /* F4 */
2752 FctKey
| 0xc2, /* F5 */
2754 /* --------------- 40 to 4f --------------- */
2755 FctKey
| 0xc3, /* F6 */
2756 FctKey
| 0xc4, /* F7 */
2757 FctKey
| 0xc5, /* F8 */
2758 FctKey
| 0xc6, /* F9 */
2759 FctKey
| 0xc7, /* F10 */
2760 Ignore
, /* Num Lock */
2761 Ignore
, /* Scroll Lock */
2762 KeyPad
| 7, /* Home */
2763 KeyPad
| 8, /* Up */
2764 KeyPad
| 9, /* Page Up */
2765 Grey
| 2, /* Grey - */
2766 KeyPad
| 4, /* Left */
2767 KeyPad
| 5, /* Keypad 5 */
2768 KeyPad
| 6, /* Right */
2769 Grey
| 3, /* Grey + */
2770 KeyPad
| 1, /* End */
2772 /* --------------- 50 to 5f --------------- */
2773 KeyPad
| 2, /* Down */
2774 KeyPad
| 3, /* Page Down */
2775 KeyPad
| 0, /* Insert */
2776 KeyPad
| 10, /* Delete */
2777 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2778 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2779 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2780 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2781 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2782 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2783 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2784 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2785 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2786 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2787 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2788 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2790 /* --------------- 60 to 6f --------------- */
2791 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2792 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2793 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2794 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2795 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2796 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2797 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2798 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2799 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2800 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2801 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2802 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2803 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2804 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2805 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2806 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2808 /* --------------- 70 to 7f --------------- */
2809 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2810 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2811 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2812 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2813 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2814 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2815 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2816 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2817 Alt
| Map
| 1, /* '1' */
2818 Alt
| Map
| 2, /* '2' */
2819 Alt
| Map
| 3, /* '3' */
2820 Alt
| Map
| 4, /* '4' */
2821 Alt
| Map
| 5, /* '5' */
2822 Alt
| Map
| 6, /* '6' */
2823 Alt
| Map
| 7, /* '7' */
2824 Alt
| Map
| 8, /* '8' */
2826 /* --------------- 80 to 8f --------------- */
2827 Alt
| Map
| 9, /* '9' */
2828 Alt
| Map
| 10, /* '0' */
2829 Alt
| Map
| 11, /* '-' */
2830 Alt
| Map
| 12, /* '=' */
2831 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2832 FctKey
| 0xc8, /* F11 */
2833 FctKey
| 0xc9, /* F12 */
2834 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2835 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2836 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2837 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2838 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2839 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2840 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2841 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2842 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2844 /* --------------- 90 to 9f --------------- */
2845 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2846 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2847 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2848 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2849 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2850 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2851 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2852 Alt
| FctKey
| 0x50, /* (Alt) Home */
2853 Alt
| FctKey
| 0x52, /* (Alt) Up */
2854 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2855 Ignore
, /* NO KEY */
2856 Alt
| FctKey
| 0x51, /* (Alt) Left */
2857 Ignore
, /* NO KEY */
2858 Alt
| FctKey
| 0x53, /* (Alt) Right */
2859 Ignore
, /* NO KEY */
2860 Alt
| FctKey
| 0x57, /* (Alt) End */
2862 /* --------------- a0 to af --------------- */
2863 Alt
| KeyPad
| 2, /* (Alt) Down */
2864 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2865 Alt
| KeyPad
| 0, /* (Alt) Insert */
2866 Alt
| KeyPad
| 10, /* (Alt) Delete */
2867 Alt
| Grey
| 0, /* (Alt) Grey / */
2868 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2869 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2872 /* These bit-positions corresponds to values returned by BIOS */
2873 #define SHIFT_P 0x0003 /* two bits! */
2874 #define CTRL_P 0x0004
2875 #define ALT_P 0x0008
2876 #define SCRLOCK_P 0x0010
2877 #define NUMLOCK_P 0x0020
2878 #define CAPSLOCK_P 0x0040
2879 #define ALT_GR_P 0x0800
2880 #define SUPER_P 0x4000 /* pseudo */
2881 #define HYPER_P 0x8000 /* pseudo */
2884 dos_get_modifiers (keymask
)
2891 /* Calculate modifier bits */
2892 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2893 int86 (0x16, ®s
, ®s
);
2897 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2898 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2902 mask
= regs
.h
.al
& (SHIFT_P
|
2903 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2905 /* Do not break international keyboard support. */
2906 /* When Keyb.Com is loaded, the right Alt key is */
2907 /* used for accessing characters like { and } */
2908 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2911 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2914 if (dos_hyper_key
== 1)
2917 modifiers
|= hyper_modifier
;
2919 else if (dos_super_key
== 1)
2922 modifiers
|= super_modifier
;
2924 else if (!international_keyboard
)
2926 /* If Keyb.Com is NOT installed, let Right Alt behave
2927 like the Left Alt. */
2933 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2936 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2938 if (dos_hyper_key
== 2)
2941 modifiers
|= hyper_modifier
;
2943 else if (dos_super_key
== 2)
2946 modifiers
|= super_modifier
;
2954 modifiers
|= shift_modifier
;
2956 modifiers
|= ctrl_modifier
;
2958 modifiers
|= meta_modifier
;
2965 #define NUM_RECENT_DOSKEYS (100)
2966 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2967 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
2968 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
2970 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
2971 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
2972 Each input key receives two values in this vector: first the ASCII code,\n\
2973 and then the scan code.")
2976 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
2979 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
2980 return Fvector (total_doskeys
, keys
);
2983 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
2984 bcopy (keys
+ recent_doskeys_index
,
2985 XVECTOR (val
)->contents
,
2986 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
2988 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
2989 recent_doskeys_index
* sizeof (Lisp_Object
));
2994 /* Get a char from keyboard. Function keys are put into the event queue. */
2996 extern void kbd_buffer_store_event (struct input_event
*);
3001 struct input_event event
;
3004 #ifndef HAVE_X_WINDOWS
3005 /* Maybe put the cursor where it should be. */
3006 IT_cmgoto (SELECTED_FRAME());
3009 /* The following condition is equivalent to `kbhit ()', except that
3010 it uses the bios to do its job. This pleases DESQview/X. */
3011 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
3012 int86 (0x16, ®s
, ®s
),
3013 (regs
.x
.flags
& 0x40) == 0)
3016 register unsigned char c
;
3017 int sc
, code
= -1, mask
, kp_mode
;
3020 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
3021 int86 (0x16, ®s
, ®s
);
3026 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3028 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3029 recent_doskeys_index
= 0;
3030 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3032 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3033 recent_doskeys_index
= 0;
3035 modifiers
= dos_get_modifiers (&mask
);
3037 #ifndef HAVE_X_WINDOWS
3038 if (!NILP (Vdos_display_scancodes
))
3041 sprintf (buf
, "%02x:%02x*%04x",
3042 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3043 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3051 case 10: /* Ctrl Grey Enter */
3052 code
= Ctrl
| Grey
| 4;
3054 case 13: /* Grey Enter */
3057 case '/': /* Grey / */
3067 /* Try the keyboard-private translation table first. */
3068 if (keyboard
->translate_table
)
3070 struct kbd_translate
*p
= keyboard
->translate_table
;
3074 if (p
->sc
== sc
&& p
->ch
== c
)
3082 /* If the private table didn't translate it, use the general
3086 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3088 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3095 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3096 Emacs is ready to read a key. Therefore, if they press
3097 `Alt-x' when Emacs is busy, by the time we get to
3098 `dos_get_modifiers', they might have already released the
3099 Alt key, and Emacs gets just `x', which is BAD.
3100 However, for keys with the `Map' property set, the ASCII
3101 code returns zero iff Alt is pressed. So, when we DON'T
3102 have to support international_keyboard, we don't have to
3103 distinguish between the left and right Alt keys, and we
3104 can set the META modifier for any keys with the `Map'
3105 property if they return zero ASCII code (c = 0). */
3107 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3108 modifiers
|= meta_modifier
;
3110 modifiers
|= ctrl_modifier
;
3112 modifiers
|= shift_modifier
;
3115 switch (code
& 0xf000)
3118 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3120 c
= 0; /* Special */
3133 if (c
== 0) /* ctrl-break */
3135 return c
; /* ALT-nnn */
3137 if (!keyboard_map_all
)
3146 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3147 if (!keyboard_map_all
)
3151 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3152 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3156 code
= keyboard
->shifted
[code
];
3158 modifiers
&= ~shift_modifier
;
3161 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3162 code
= keyboard
->alt_gr
[code
];
3164 code
= keyboard
->unshifted
[code
];
3169 if (c
== 0xe0) /* edit key */
3172 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3173 kp_mode
= dos_keypad_mode
& 0x03;
3175 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3180 if (code
== 10 && dos_decimal_point
)
3181 return dos_decimal_point
;
3182 return keypad_translate_map
[code
].char_code
;
3185 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3189 code
= keypad_translate_map
[code
].meta_code
;
3190 modifiers
= meta_modifier
;
3194 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3201 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3202 if (dos_keypad_mode
& kp_mode
)
3203 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3205 code
= grey_key_translate_map
[code
].char_code
;
3214 event
.kind
= non_ascii_keystroke
;
3216 event
.kind
= ascii_keystroke
;
3218 event
.modifiers
= modifiers
;
3219 event
.frame_or_window
= selected_frame
;
3220 event
.timestamp
= event_timestamp ();
3221 kbd_buffer_store_event (&event
);
3224 if (have_mouse
> 0 && !mouse_preempted
)
3226 int but
, press
, x
, y
, ok
;
3227 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3229 /* Check for mouse movement *before* buttons. */
3230 mouse_check_moved ();
3232 /* If the mouse moved from the spot of its last sighting, we
3233 might need to update mouse highlight. */
3234 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3236 previous_help_echo
= help_echo
;
3238 IT_note_mouse_highlight (SELECTED_FRAME(),
3239 mouse_last_x
, mouse_last_y
);
3240 /* If the contents of the global variable help_echo has
3241 changed, generate a HELP_EVENT. */
3242 if (STRINGP (help_echo
) || STRINGP (previous_help_echo
))
3244 event
.kind
= HELP_EVENT
;
3245 event
.frame_or_window
= Fcons (selected_frame
, help_echo
);
3246 event
.timestamp
= event_timestamp ();
3247 kbd_buffer_store_event (&event
);
3251 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3252 for (press
= 0; press
< 2; press
++)
3254 int button_num
= but
;
3257 ok
= mouse_pressed (but
, &x
, &y
);
3259 ok
= mouse_released (but
, &x
, &y
);
3262 /* Allow a simultaneous press/release of Mouse-1 and
3263 Mouse-2 to simulate Mouse-3 on two-button mice. */
3264 if (mouse_button_count
== 2 && but
< 2)
3266 int x2
, y2
; /* don't clobber original coordinates */
3268 /* If only one button is pressed, wait 100 msec and
3269 check again. This way, Speedy Gonzales isn't
3270 punished, while the slow get their chance. */
3271 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3272 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3277 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3278 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3283 event
.kind
= mouse_click
;
3284 event
.code
= button_num
;
3285 event
.modifiers
= dos_get_modifiers (0)
3286 | (press
? down_modifier
: up_modifier
);
3289 event
.frame_or_window
= selected_frame
;
3290 event
.timestamp
= event_timestamp ();
3291 kbd_buffer_store_event (&event
);
3299 static int prev_get_char
= -1;
3301 /* Return 1 if a key is ready to be read without suspending execution. */
3305 if (prev_get_char
!= -1)
3308 return ((prev_get_char
= dos_rawgetc ()) != -1);
3311 /* Read a key. Return -1 if no key is ready. */
3315 if (prev_get_char
!= -1)
3317 int c
= prev_get_char
;
3322 return dos_rawgetc ();
3325 #ifndef HAVE_X_WINDOWS
3326 /* See xterm.c for more info. */
3328 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
3330 register int pix_x
, pix_y
;
3331 register int *x
, *y
;
3335 if (bounds
) abort ();
3337 /* Ignore clipping. */
3344 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
3347 register int *pix_x
, *pix_y
;
3353 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3356 Actually, I don't know the meaning of all the parameters of the functions
3357 here -- I only know how they are called by xmenu.c. I could of course
3358 grab the nearest Xlib manual (down the hall, second-to-last door on the
3359 left), but I don't think it's worth the effort. */
3361 static char *menu_help_message
, *prev_menu_help_message
;
3368 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3369 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3373 /* Allocate some (more) memory for MENU ensuring that there is room for one
3377 IT_menu_make_room (XMenu
*menu
)
3379 if (menu
->allocated
== 0)
3381 int count
= menu
->allocated
= 10;
3382 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3383 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3384 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3385 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3387 else if (menu
->allocated
== menu
->count
)
3389 int count
= menu
->allocated
= menu
->allocated
+ 10;
3391 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3393 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3395 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3397 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3401 /* Search the given menu structure for a given pane number. */
3404 IT_menu_search_pane (XMenu
*menu
, int pane
)
3409 for (i
= 0; i
< menu
->count
; i
++)
3410 if (menu
->submenu
[i
])
3412 if (pane
== menu
->panenumber
[i
])
3413 return menu
->submenu
[i
];
3414 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3420 /* Determine how much screen space a given menu needs. */
3423 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3425 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3428 maxheight
= menu
->count
;
3429 for (i
= 0; i
< menu
->count
; i
++)
3431 if (menu
->submenu
[i
])
3433 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3434 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3435 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3438 *width
= menu
->width
+ maxsubwidth
;
3439 *height
= maxheight
;
3442 /* Display MENU at (X,Y) using FACES. */
3445 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
, int disp_help
)
3447 int i
, j
, face
, width
;
3448 struct glyph
*text
, *p
;
3451 int enabled
, mousehere
;
3453 struct frame
*sf
= SELECTED_FRAME();
3455 menu_help_message
= NULL
;
3457 width
= menu
->width
;
3458 text
= (struct glyph
*) xmalloc ((width
+ 2) * sizeof (struct glyph
));
3459 ScreenGetCursor (&row
, &col
);
3460 mouse_get_xy (&mx
, &my
);
3461 IT_update_begin (sf
);
3462 for (i
= 0; i
< menu
->count
; i
++)
3464 int max_width
= width
+ 2;
3466 IT_cursor_to (y
+ i
, x
);
3468 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3469 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
3470 face
= faces
[enabled
+ mousehere
* 2];
3471 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3472 menu_help_message
= menu
->help_text
[i
];
3474 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3476 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3480 SET_CHAR_GLYPH (*p
, *q
++, face
, 0);
3483 else /* make '^x' */
3485 SET_CHAR_GLYPH (*p
, '^', face
, 0);
3488 SET_CHAR_GLYPH (*p
, *q
++ + 64, face
, 0);
3492 /* Don't let the menu text overflow into the next screen row. */
3493 if (x
+ max_width
> screen_size_X
)
3495 max_width
= screen_size_X
- x
;
3496 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3498 for (; j
< max_width
- 2; j
++, p
++)
3499 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3501 SET_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3503 IT_write_glyphs (text
, max_width
);
3506 IT_cursor_to (row
, col
);
3510 /* --------------------------- X Menu emulation ---------------------- */
3512 /* Report availability of menus. */
3520 /* Create a brand new menu structure. */
3523 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3525 return IT_menu_create ();
3528 /* Create a new pane and place it on the outer-most level. It is not
3529 clear that it should be placed out there, but I don't know what else
3533 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3541 IT_menu_make_room (menu
);
3542 menu
->submenu
[menu
->count
] = IT_menu_create ();
3543 menu
->text
[menu
->count
] = txt
;
3544 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3545 menu
->help_text
[menu
->count
] = NULL
;
3548 /* Adjust length for possible control characters (which will
3549 be written as ^x). */
3550 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3554 if (len
> menu
->width
)
3557 return menu
->panecount
;
3560 /* Create a new item in a menu pane. */
3563 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3564 int foo
, char *txt
, int enable
, char *help_text
)
3570 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3572 IT_menu_make_room (menu
);
3573 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3574 menu
->text
[menu
->count
] = txt
;
3575 menu
->panenumber
[menu
->count
] = enable
;
3576 menu
->help_text
[menu
->count
] = help_text
;
3579 /* Adjust length for possible control characters (which will
3580 be written as ^x). */
3581 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3585 if (len
> menu
->width
)
3591 /* Decide where the menu would be placed if requested at (X,Y). */
3594 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3595 int *ulx
, int *uly
, int *width
, int *height
)
3597 IT_menu_calc_size (menu
, width
, height
);
3603 struct IT_menu_state
3605 void *screen_behind
;
3612 /* Display menu, wait for user's response, and return that response. */
3615 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3616 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3617 void (*help_callback
)(char *))
3619 struct IT_menu_state
*state
;
3624 Lisp_Object selectface
;
3625 int leave
, result
, onepane
;
3626 int title_faces
[4]; /* face to display the menu title */
3627 int buffers_num_deleted
= 0;
3628 struct frame
*sf
= SELECTED_FRAME();
3630 /* Just in case we got here without a mouse present... */
3631 if (have_mouse
<= 0)
3632 return XM_IA_SELECT
;
3633 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3634 around the display. */
3640 /* We will process all the mouse events directly, so we had
3641 better prevented dos_rawgetc from stealing them from us. */
3644 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3645 screensize
= screen_size
* 2;
3647 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3648 0, DEFAULT_FACE_ID
);
3650 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3651 0, DEFAULT_FACE_ID
);
3652 selectface
= intern ("msdos-menu-select-face");
3653 faces
[2] = lookup_derived_face (sf
, selectface
,
3655 faces
[3] = lookup_derived_face (sf
, selectface
,
3658 /* Make sure the menu title is always displayed with
3659 `msdos-menu-active-face', no matter where the mouse pointer is. */
3660 for (i
= 0; i
< 4; i
++)
3661 title_faces
[i
] = faces
[3];
3665 /* Don't let the title for the "Buffers" popup menu include a
3666 digit (which is ugly).
3668 This is a terrible kludge, but I think the "Buffers" case is
3669 the only one where the title includes a number, so it doesn't
3670 seem to be necessary to make this more general. */
3671 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3673 menu
->text
[0][7] = '\0';
3674 buffers_num_deleted
= 1;
3676 state
[0].menu
= menu
;
3678 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3680 /* Turn off the cursor. Otherwise it shows through the menu
3681 panes, which is ugly. */
3682 IT_display_cursor (0);
3684 /* Display the menu title. */
3685 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
, 0);
3686 if (buffers_num_deleted
)
3687 menu
->text
[0][7] = ' ';
3688 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3690 menu
->width
= menu
->submenu
[0]->width
;
3691 state
[0].menu
= menu
->submenu
[0];
3695 state
[0].menu
= menu
;
3697 state
[0].x
= x0
- 1;
3699 state
[0].pane
= onepane
;
3701 mouse_last_x
= -1; /* A hack that forces display. */
3705 if (!mouse_visible
) mouse_on ();
3706 mouse_check_moved ();
3707 if (sf
->mouse_moved
)
3709 sf
->mouse_moved
= 0;
3710 result
= XM_IA_SELECT
;
3711 mouse_get_xy (&x
, &y
);
3712 for (i
= 0; i
< statecount
; i
++)
3713 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3715 int dy
= y
- state
[i
].y
;
3716 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3718 if (!state
[i
].menu
->submenu
[dy
])
3719 if (state
[i
].menu
->panenumber
[dy
])
3720 result
= XM_SUCCESS
;
3722 result
= XM_IA_SELECT
;
3723 *pane
= state
[i
].pane
- 1;
3725 /* We hit some part of a menu, so drop extra menus that
3726 have been opened. That does not include an open and
3728 if (i
!= statecount
- 2
3729 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3730 while (i
!= statecount
- 1)
3734 ScreenUpdate (state
[statecount
].screen_behind
);
3735 if (screen_virtual_segment
)
3736 dosv_refresh_virtual_screen (0, screen_size
);
3737 xfree (state
[statecount
].screen_behind
);
3739 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3741 IT_menu_display (state
[i
].menu
,
3745 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3746 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3748 ScreenRetrieve (state
[statecount
].screen_behind
3749 = xmalloc (screensize
));
3751 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3752 state
[statecount
].y
= y
;
3757 IT_menu_display (state
[statecount
- 1].menu
,
3758 state
[statecount
- 1].y
,
3759 state
[statecount
- 1].x
,
3764 if ((menu_help_message
|| prev_menu_help_message
)
3765 && menu_help_message
!= prev_menu_help_message
)
3767 help_callback (menu_help_message
);
3768 IT_display_cursor (0);
3769 prev_menu_help_message
= menu_help_message
;
3771 /* We are busy-waiting for the mouse to move, so let's be nice
3772 to other Windows applications by releasing our time slice. */
3775 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3777 /* Only leave if user both pressed and released the mouse, and in
3778 that order. This avoids popping down the menu pane unless
3779 the user is really done with it. */
3780 if (mouse_pressed (b
, &x
, &y
))
3782 while (mouse_button_depressed (b
, &x
, &y
))
3786 (void) mouse_released (b
, &x
, &y
);
3791 ScreenUpdate (state
[0].screen_behind
);
3792 if (screen_virtual_segment
)
3793 dosv_refresh_virtual_screen (0, screen_size
);
3795 while (statecount
--)
3796 xfree (state
[statecount
].screen_behind
);
3797 IT_display_cursor (1); /* turn cursor back on */
3798 /* Clean up any mouse events that are waiting inside Emacs event queue.
3799 These events are likely to be generated before the menu was even
3800 displayed, probably because the user pressed and released the button
3801 (which invoked the menu) too quickly. If we don't remove these events,
3802 Emacs will process them after we return and surprise the user. */
3803 discard_mouse_events ();
3804 /* Allow mouse events generation by dos_rawgetc. */
3809 /* Dispose of a menu. */
3812 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3815 if (menu
->allocated
)
3817 for (i
= 0; i
< menu
->count
; i
++)
3818 if (menu
->submenu
[i
])
3819 XMenuDestroy (foo
, menu
->submenu
[i
]);
3821 xfree (menu
->submenu
);
3822 xfree (menu
->panenumber
);
3823 xfree (menu
->help_text
);
3826 menu_help_message
= prev_menu_help_message
= NULL
;
3830 x_pixel_width (struct frame
*f
)
3832 return FRAME_WIDTH (f
);
3836 x_pixel_height (struct frame
*f
)
3838 return FRAME_HEIGHT (f
);
3840 #endif /* !HAVE_X_WINDOWS */
3842 /* ----------------------- DOS / UNIX conversion --------------------- */
3844 void msdos_downcase_filename (unsigned char *);
3846 /* Destructively turn backslashes into slashes. */
3849 dostounix_filename (p
)
3852 msdos_downcase_filename (p
);
3862 /* Destructively turn slashes into backslashes. */
3865 unixtodos_filename (p
)
3868 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3882 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3885 getdefdir (drive
, dst
)
3889 char in_path
[4], *p
= in_path
;
3892 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3895 *p
++ = drive
+ 'A' - 1;
3902 _fixpath (in_path
, dst
);
3903 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3904 it queries the LFN support, so ignore that error. */
3905 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
3908 msdos_downcase_filename (dst
);
3914 /* Remove all CR's that are followed by a LF. */
3919 register unsigned char *buf
;
3921 unsigned char *np
= buf
;
3922 unsigned char *startp
= buf
;
3923 unsigned char *endp
= buf
+ n
;
3927 while (buf
< endp
- 1)
3931 if (*(++buf
) != 0x0a)
3942 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
3944 /* In DJGPP v2.0, library `write' can call `malloc', which might
3945 cause relocation of the buffer whose address we get in ADDR.
3946 Here is a version of `write' that avoids calling `malloc',
3947 to serve us until such time as the library is fixed.
3948 Actually, what we define here is called `__write', because
3949 `write' is a stub that just jmp's to `__write' (to be
3950 POSIXLY-correct with respect to the global name-space). */
3952 #include <io.h> /* for _write */
3953 #include <libc/dosio.h> /* for __file_handle_modes[] */
3955 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
3957 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
3960 __write (int handle
, const void *buffer
, size_t count
)
3965 if(__file_handle_modes
[handle
] & O_BINARY
)
3966 return _write (handle
, buffer
, count
);
3970 const char *bp
= buffer
;
3971 int total_written
= 0;
3972 int nmoved
= 0, ncr
= 0;
3976 /* The next test makes sure there's space for at least 2 more
3977 characters in xbuf[], so both CR and LF can be put there. */
3989 if (xbp
>= XBUF_END
|| !count
)
3991 size_t to_write
= nmoved
+ ncr
;
3992 int written
= _write (handle
, xbuf
, to_write
);
3997 total_written
+= nmoved
; /* CRs aren't counted in ret value */
3999 /* If some, but not all were written (disk full?), return
4000 an estimate of the total written bytes not counting CRs. */
4001 if (written
< to_write
)
4002 return total_written
- (to_write
- written
) * nmoved
/to_write
;
4009 return total_written
;
4013 /* A low-level file-renaming function which works around Windows 95 bug.
4014 This is pulled directly out of DJGPP v2.01 library sources, and only
4015 used when you compile with DJGPP v2.0. */
4019 int _rename(const char *old
, const char *new)
4022 int olen
= strlen(old
) + 1;
4024 int use_lfn
= _USE_LFN
;
4025 char tempfile
[FILENAME_MAX
];
4026 const char *orig
= old
;
4029 r
.x
.dx
= __tb_offset
;
4030 r
.x
.di
= __tb_offset
+ olen
;
4031 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4035 /* Windows 95 bug: for some filenames, when you rename
4036 file -> file~ (as in Emacs, to leave a backup), the
4037 short 8+3 alias doesn't change, which effectively
4038 makes OLD and NEW the same file. We must rename
4039 through a temporary file to work around this. */
4041 char *pbase
= 0, *p
;
4042 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4043 int idx
= sizeof(try_char
) - 1;
4045 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4046 might point to another drive, which will fail the DOS call. */
4047 strcpy(tempfile
, old
);
4048 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4049 if (*p
== '/' || *p
== '\\' || *p
== ':')
4055 strcpy(pbase
, "X$$djren$$.$$temp$$");
4061 *pbase
= try_char
[--idx
];
4062 } while (_chmod(tempfile
, 0) != -1);
4065 _put_path2(tempfile
, olen
);
4067 __dpmi_int(0x21, &r
);
4070 errno
= __doserr_to_errno(r
.x
.ax
);
4074 /* Now create a file with the original name. This will
4075 ensure that NEW will always have a 8+3 alias
4076 different from that of OLD. (Seems to be required
4077 when NameNumericTail in the Registry is set to 0.) */
4078 lfn_fd
= _creat(old
, 0);
4080 olen
= strlen(tempfile
) + 1;
4082 r
.x
.di
= __tb_offset
+ olen
;
4091 _put_path2(new, olen
);
4093 __dpmi_int(0x21, &r
);
4096 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4097 remove(new); /* and try again */
4100 errno
= __doserr_to_errno(r
.x
.ax
);
4102 /* Restore to original name if we renamed it to temporary. */
4110 _put_path2(orig
, olen
);
4111 _put_path(tempfile
);
4113 __dpmi_int(0x21, &r
);
4122 /* Success. Delete the file possibly created to work
4123 around the Windows 95 bug. */
4125 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4129 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4131 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4133 "Return non-nil if long file names are supported on MSDOS.")
4136 return (_USE_LFN
? Qt
: Qnil
);
4139 /* Convert alphabetic characters in a filename to lower-case. */
4142 msdos_downcase_filename (p
)
4143 register unsigned char *p
;
4145 /* Always lower-case drive letters a-z, even if the filesystem
4146 preserves case in filenames.
4147 This is so MSDOS filenames could be compared by string comparison
4148 functions that are case-sensitive. Even case-preserving filesystems
4149 do not distinguish case in drive letters. */
4150 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4156 /* Under LFN we expect to get pathnames in their true case. */
4157 if (NILP (Fmsdos_long_file_names ()))
4159 if (*p
>= 'A' && *p
<= 'Z')
4163 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4165 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
4166 When long filenames are supported, doesn't change FILENAME.\n\
4167 If FILENAME is not a string, returns nil.\n\
4168 The argument object is never altered--the value is a copy.")
4170 Lisp_Object filename
;
4174 if (! STRINGP (filename
))
4177 tem
= Fcopy_sequence (filename
);
4178 msdos_downcase_filename (XSTRING (tem
)->data
);
4182 /* The Emacs root directory as determined by init_environment. */
4184 static char emacsroot
[MAXPATHLEN
];
4187 rootrelativepath (rel
)
4190 static char result
[MAXPATHLEN
+ 10];
4192 strcpy (result
, emacsroot
);
4193 strcat (result
, "/");
4194 strcat (result
, rel
);
4198 /* Define a lot of environment variables if not already defined. Don't
4199 remove anything unless you know what you're doing -- lots of code will
4200 break if one or more of these are missing. */
4203 init_environment (argc
, argv
, skip_args
)
4210 static const char * const tempdirs
[] = {
4211 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4214 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4216 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4217 temporary files and assume "/tmp" if $TMPDIR is unset, which
4218 will break on DOS/Windows. Refuse to work if we cannot find
4219 a directory, not even "c:/", usable for that purpose. */
4220 for (i
= 0; i
< imax
; i
++)
4222 const char *tmp
= tempdirs
[i
];
4225 tmp
= getenv (tmp
+ 1);
4226 /* Note that `access' can lie to us if the directory resides on a
4227 read-only filesystem, like CD-ROM or a write-protected floppy.
4228 The only way to be really sure is to actually create a file and
4229 see if it succeeds. But I think that's too much to ask. */
4230 if (tmp
&& access (tmp
, D_OK
) == 0)
4232 setenv ("TMPDIR", tmp
, 1);
4239 Fcons (build_string ("no usable temporary directories found!!"),
4241 "While setting TMPDIR: ");
4243 /* Note the startup time, so we know not to clear the screen if we
4244 exit immediately; see IT_reset_terminal_modes.
4245 (Yes, I know `clock' returns zero the first time it's called, but
4246 I do this anyway, in case some wiseguy changes that at some point.) */
4247 startup_time
= clock ();
4249 /* Find our root from argv[0]. Assuming argv[0] is, say,
4250 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4251 root
= alloca (MAXPATHLEN
+ 20);
4252 _fixpath (argv
[0], root
);
4253 msdos_downcase_filename (root
);
4254 len
= strlen (root
);
4255 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4259 && (strcmp (root
+ len
- 4, "/bin") == 0
4260 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4261 root
[len
- 4] = '\0';
4263 strcpy (root
, "c:/emacs"); /* let's be defensive */
4264 len
= strlen (root
);
4265 strcpy (emacsroot
, root
);
4267 /* We default HOME to our root. */
4268 setenv ("HOME", root
, 0);
4270 /* We default EMACSPATH to root + "/bin". */
4271 strcpy (root
+ len
, "/bin");
4272 setenv ("EMACSPATH", root
, 0);
4274 /* I don't expect anybody to ever use other terminals so the internal
4275 terminal is the default. */
4276 setenv ("TERM", "internal", 0);
4278 #ifdef HAVE_X_WINDOWS
4279 /* Emacs expects DISPLAY to be set. */
4280 setenv ("DISPLAY", "unix:0.0", 0);
4283 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4284 downcase it and mirror the backslashes. */
4285 s
= getenv ("COMSPEC");
4286 if (!s
) s
= "c:/command.com";
4287 t
= alloca (strlen (s
) + 1);
4289 dostounix_filename (t
);
4290 setenv ("SHELL", t
, 0);
4292 /* PATH is also downcased and backslashes mirrored. */
4293 s
= getenv ("PATH");
4295 t
= alloca (strlen (s
) + 3);
4296 /* Current directory is always considered part of MsDos's path but it is
4297 not normally mentioned. Now it is. */
4298 strcat (strcpy (t
, ".;"), s
);
4299 dostounix_filename (t
); /* Not a single file name, but this should work. */
4300 setenv ("PATH", t
, 1);
4302 /* In some sense all dos users have root privileges, so... */
4303 setenv ("USER", "root", 0);
4304 setenv ("NAME", getenv ("USER"), 0);
4306 /* Time zone determined from country code. To make this possible, the
4307 country code may not span more than one time zone. In other words,
4308 in the USA, you lose. */
4310 switch (dos_country_code
)
4312 case 31: /* Belgium */
4313 case 32: /* The Netherlands */
4314 case 33: /* France */
4315 case 34: /* Spain */
4316 case 36: /* Hungary */
4317 case 38: /* Yugoslavia (or what's left of it?) */
4318 case 39: /* Italy */
4319 case 41: /* Switzerland */
4320 case 42: /* Tjekia */
4321 case 45: /* Denmark */
4322 case 46: /* Sweden */
4323 case 47: /* Norway */
4324 case 48: /* Poland */
4325 case 49: /* Germany */
4326 /* Daylight saving from last Sunday in March to last Sunday in
4327 September, both at 2AM. */
4328 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4330 case 44: /* United Kingdom */
4331 case 351: /* Portugal */
4332 case 354: /* Iceland */
4333 setenv ("TZ", "GMT+00", 0);
4335 case 81: /* Japan */
4336 case 82: /* Korea */
4337 setenv ("TZ", "JST-09", 0);
4339 case 90: /* Turkey */
4340 case 358: /* Finland */
4341 setenv ("TZ", "EET-02", 0);
4343 case 972: /* Israel */
4344 /* This is an approximation. (For exact rules, use the
4345 `zoneinfo/israel' file which comes with DJGPP, but you need
4346 to install it in `/usr/share/zoneinfo/' directory first.) */
4347 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4355 static int break_stat
; /* BREAK check mode status. */
4356 static int stdin_stat
; /* stdin IOCTL status. */
4360 /* These must be global. */
4361 static _go32_dpmi_seginfo ctrl_break_vector
;
4362 static _go32_dpmi_registers ctrl_break_regs
;
4363 static int ctrlbreakinstalled
= 0;
4365 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4368 ctrl_break_func (regs
)
4369 _go32_dpmi_registers
*regs
;
4375 install_ctrl_break_check ()
4377 if (!ctrlbreakinstalled
)
4379 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4380 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4381 ctrlbreakinstalled
= 1;
4382 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4383 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4385 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4389 #endif /* __DJGPP__ < 2 */
4391 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4392 control chars by DOS. Determine the keyboard type. */
4397 union REGS inregs
, outregs
;
4398 static int first_time
= 1;
4400 break_stat
= getcbrk ();
4403 install_ctrl_break_check ();
4409 int86 (0x15, &inregs
, &outregs
);
4410 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4414 if (internal_terminal
4415 #ifdef HAVE_X_WINDOWS
4416 && inhibit_window_system
4420 inregs
.x
.ax
= 0x0021;
4421 int86 (0x33, &inregs
, &outregs
);
4422 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4425 /* Reportedly, the above doesn't work for some mouse drivers. There
4426 is an additional detection method that should work, but might be
4427 a little slower. Use that as an alternative. */
4428 inregs
.x
.ax
= 0x0000;
4429 int86 (0x33, &inregs
, &outregs
);
4430 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4435 have_mouse
= 1; /* enable mouse */
4438 if (outregs
.x
.bx
== 3)
4440 mouse_button_count
= 3;
4441 mouse_button_translate
[0] = 0; /* Left */
4442 mouse_button_translate
[1] = 2; /* Middle */
4443 mouse_button_translate
[2] = 1; /* Right */
4447 mouse_button_count
= 2;
4448 mouse_button_translate
[0] = 0;
4449 mouse_button_translate
[1] = 1;
4451 mouse_position_hook
= &mouse_get_pos
;
4455 #ifndef HAVE_X_WINDOWS
4457 /* Save the cursor shape used outside Emacs. */
4458 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4467 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4468 return (stdin_stat
!= -1);
4471 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4473 #else /* __DJGPP__ < 2 */
4477 /* I think it is wrong to overwrite `stdin_stat' every time
4478 but the first one this function is called, but I don't
4479 want to change the way it used to work in v1.x.--EZ */
4481 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4482 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4483 intdos (&inregs
, &outregs
);
4484 stdin_stat
= outregs
.h
.dl
;
4486 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4487 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4488 intdos (&inregs
, &outregs
);
4489 return !outregs
.x
.cflag
;
4491 #endif /* __DJGPP__ < 2 */
4494 /* Restore status of standard input and Ctrl-C checking. */
4499 union REGS inregs
, outregs
;
4501 setcbrk (break_stat
);
4506 #ifndef HAVE_X_WINDOWS
4507 /* Restore the cursor shape we found on startup. */
4511 inregs
.x
.cx
= outside_cursor
;
4512 int86 (0x10, &inregs
, &outregs
);
4516 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4518 #else /* not __DJGPP__ >= 2 */
4520 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4521 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4522 inregs
.x
.dx
= stdin_stat
;
4523 intdos (&inregs
, &outregs
);
4524 return !outregs
.x
.cflag
;
4526 #endif /* not __DJGPP__ >= 2 */
4530 /* Run command as specified by ARGV in directory DIR.
4531 The command is run with input from TEMPIN, output to
4532 file TEMPOUT and stderr to TEMPERR. */
4535 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4536 unsigned char **argv
;
4537 const char *working_dir
;
4538 int tempin
, tempout
, temperr
;
4541 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4542 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4543 int msshell
, result
= -1;
4544 int inbak
, outbak
, errbak
;
4548 /* Get current directory as MSDOS cwd is not per-process. */
4551 /* If argv[0] is the shell, it might come in any lettercase.
4552 Since `Fmember' is case-sensitive, we need to downcase
4553 argv[0], even if we are on case-preserving filesystems. */
4554 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4555 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4558 if (*pl
>= 'A' && *pl
<= 'Z')
4563 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4564 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4565 && !strcmp ("-c", argv
[1]);
4568 saveargv1
= argv
[1];
4569 saveargv2
= argv
[2];
4573 char *p
= alloca (strlen (argv
[2]) + 1);
4575 strcpy (argv
[2] = p
, saveargv2
);
4576 while (*p
&& isspace (*p
))
4578 while (*p
&& !isspace (*p
))
4586 chdir (working_dir
);
4590 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4591 goto done
; /* Allocation might fail due to lack of descriptors. */
4594 mouse_get_xy (&x
, &y
);
4596 dos_ttcooked (); /* do it here while 0 = stdin */
4604 if (msshell
&& !argv
[3])
4606 /* MS-DOS native shells are too restrictive. For starters, they
4607 cannot grok commands longer than 126 characters. In DJGPP v2
4608 and later, `system' is much smarter, so we'll call it instead. */
4612 /* A shell gets a single argument--its full command
4613 line--whose original was saved in `saveargv2'. */
4615 /* Don't let them pass empty command lines to `system', since
4616 with some shells it will try to invoke an interactive shell,
4617 which will hang Emacs. */
4618 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4622 extern char **environ
;
4623 int save_system_flags
= __system_flags
;
4625 /* Request the most powerful version of `system'. We need
4626 all the help we can get to avoid calling stock DOS shells. */
4627 __system_flags
= (__system_redirect
4628 | __system_use_shell
4629 | __system_allow_multiple_cmds
4630 | __system_allow_long_cmds
4631 | __system_handle_null_commands
4632 | __system_emulate_chdir
);
4635 result
= system (cmnd
);
4636 __system_flags
= save_system_flags
;
4639 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4643 #endif /* __DJGPP__ > 1 */
4645 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4650 emacs_close (inbak
);
4651 emacs_close (outbak
);
4652 emacs_close (errbak
);
4658 mouse_moveto (x
, y
);
4661 /* Some programs might change the meaning of the highest bit of the
4662 text attribute byte, so we get blinking characters instead of the
4663 bright background colors. Restore that. */
4670 argv
[1] = saveargv1
;
4671 argv
[2] = saveargv2
;
4679 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4686 /* ------------------------- Compatibility functions -------------------
4691 /* Hostnames for a pc are not really funny,
4692 but they are used in change log so we emulate the best we can. */
4694 gethostname (p
, size
)
4698 char *q
= egetenv ("HOSTNAME");
4705 /* When time zones are set from Ms-Dos too many C-libraries are playing
4706 tricks with time values. We solve this by defining our own version
4707 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4708 once and after each call to `tzset' with TZ changed. That is
4709 accomplished by aliasing tzset to init_gettimeofday. */
4711 static struct tm time_rec
;
4714 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4722 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4726 time_rec
.tm_year
= d
.da_year
- 1900;
4727 time_rec
.tm_mon
= d
.da_mon
- 1;
4728 time_rec
.tm_mday
= d
.da_day
;
4731 time_rec
.tm_hour
= t
.ti_hour
;
4732 time_rec
.tm_min
= t
.ti_min
;
4733 time_rec
.tm_sec
= t
.ti_sec
;
4736 tm
.tm_gmtoff
= dos_timezone_offset
;
4738 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4739 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4741 /* Ignore tzp; it's obsolescent. */
4745 #endif /* __DJGPP__ < 2 */
4748 * A list of unimplemented functions that we silently ignore.
4752 unsigned alarm (s
) unsigned s
; {}
4753 fork () { return 0; }
4754 int kill (x
, y
) int x
, y
; { return -1; }
4756 void volatile pause () {}
4757 sigsetmask (x
) int x
; { return 0; }
4758 sigblock (mask
) int mask
; { return 0; }
4761 void request_sigio (void) {}
4762 setpgrp () {return 0; }
4763 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4764 void unrequest_sigio (void) {}
4768 #ifdef POSIX_SIGNALS
4770 /* Augment DJGPP library POSIX signal functions. This is needed
4771 as of DJGPP v2.01, but might be in the library in later releases. */
4773 #include <libc/bss.h>
4775 /* A counter to know when to re-initialize the static sets. */
4776 static int sigprocmask_count
= -1;
4778 /* Which signals are currently blocked (initially none). */
4779 static sigset_t current_mask
;
4781 /* Which signals are pending (initially none). */
4782 static sigset_t pending_signals
;
4784 /* Previous handlers to restore when the blocked signals are unblocked. */
4785 typedef void (*sighandler_t
)(int);
4786 static sighandler_t prev_handlers
[320];
4788 /* A signal handler which just records that a signal occured
4789 (it will be raised later, if and when the signal is unblocked). */
4791 sig_suspender (signo
)
4794 sigaddset (&pending_signals
, signo
);
4798 sigprocmask (how
, new_set
, old_set
)
4800 const sigset_t
*new_set
;
4806 /* If called for the first time, initialize. */
4807 if (sigprocmask_count
!= __bss_count
)
4809 sigprocmask_count
= __bss_count
;
4810 sigemptyset (&pending_signals
);
4811 sigemptyset (¤t_mask
);
4812 for (signo
= 0; signo
< 320; signo
++)
4813 prev_handlers
[signo
] = SIG_ERR
;
4817 *old_set
= current_mask
;
4822 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4828 sigemptyset (&new_mask
);
4830 /* DJGPP supports upto 320 signals. */
4831 for (signo
= 0; signo
< 320; signo
++)
4833 if (sigismember (¤t_mask
, signo
))
4834 sigaddset (&new_mask
, signo
);
4835 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4837 sigaddset (&new_mask
, signo
);
4839 /* SIGKILL is silently ignored, as on other platforms. */
4840 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4841 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4843 if (( how
== SIG_UNBLOCK
4844 && sigismember (&new_mask
, signo
)
4845 && sigismember (new_set
, signo
))
4846 || (how
== SIG_SETMASK
4847 && sigismember (&new_mask
, signo
)
4848 && !sigismember (new_set
, signo
)))
4850 sigdelset (&new_mask
, signo
);
4851 if (prev_handlers
[signo
] != SIG_ERR
)
4853 signal (signo
, prev_handlers
[signo
]);
4854 prev_handlers
[signo
] = SIG_ERR
;
4856 if (sigismember (&pending_signals
, signo
))
4858 sigdelset (&pending_signals
, signo
);
4863 current_mask
= new_mask
;
4867 #else /* not POSIX_SIGNALS */
4869 sigsetmask (x
) int x
; { return 0; }
4870 sigblock (mask
) int mask
; { return 0; }
4872 #endif /* not POSIX_SIGNALS */
4873 #endif /* __DJGPP__ > 1 */
4876 #include "sysselect.h"
4878 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4879 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4880 ((long)(time).tv_sec < 0 \
4881 || ((time).tv_sec == 0 \
4882 && (long)(time).tv_usec <= 0))
4885 /* This yields the rest of the current time slice to the task manager.
4886 It should be called by any code which knows that it has nothing
4887 useful to do except idle.
4889 I don't use __dpmi_yield here, since versions of library before 2.02
4890 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4891 on some versions of Windows 9X. */
4894 dos_yield_time_slice (void)
4896 _go32_dpmi_registers r
;
4899 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
4900 _go32_dpmi_simulate_int (0x2f, &r
);
4905 /* Only event queue is checked. */
4906 /* We don't have to call timer_check here
4907 because wait_reading_process_input takes care of that. */
4909 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
4911 SELECT_TYPE
*rfds
, *wfds
, *efds
;
4912 EMACS_TIME
*timeout
;
4920 check_input
= FD_ISSET (0, rfds
);
4931 /* If we are looking only for the terminal, with no timeout,
4932 just read it and wait -- that's more efficient. */
4935 while (!detect_input_pending ())
4937 dos_yield_time_slice ();
4942 EMACS_TIME clnow
, cllast
, cldiff
;
4945 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
4947 while (!check_input
|| !detect_input_pending ())
4950 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
4951 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
4953 /* When seconds wrap around, we assume that no more than
4954 1 minute passed since last `gettime'. */
4955 if (EMACS_TIME_NEG_P (cldiff
))
4956 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
4957 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
4959 /* Stop when timeout value crosses zero. */
4960 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
4963 dos_yield_time_slice ();
4973 * Define overlaid functions:
4975 * chdir -> sys_chdir
4976 * tzset -> init_gettimeofday
4977 * abort -> dos_abort
4982 extern int chdir ();
4988 int len
= strlen (path
);
4989 char *tmp
= (char *)path
;
4991 if (*tmp
&& tmp
[1] == ':')
4993 if (getdisk () != tolower (tmp
[0]) - 'a')
4994 setdisk (tolower (tmp
[0]) - 'a');
4995 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
4999 if (len
> 1 && (tmp
[len
- 1] == '/'))
5001 char *tmp1
= (char *) alloca (len
+ 1);
5012 extern void tzset (void);
5015 init_gettimeofday ()
5021 ltm
= gtm
= time (NULL
);
5022 ltm
= mktime (lstm
= localtime (<m
));
5023 gtm
= mktime (gmtime (>m
));
5024 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
5025 time_rec
.tm_isdst
= lstm
->tm_isdst
;
5026 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
5033 dos_abort (file
, line
)
5037 char buffer1
[200], buffer2
[400];
5040 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5041 for (i
= j
= 0; buffer1
[i
]; i
++) {
5042 buffer2
[j
++] = buffer1
[i
];
5043 buffer2
[j
++] = 0x70;
5045 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5046 ScreenSetCursor (2, 0);
5054 ScreenSetCursor (10, 0);
5055 cputs ("\r\n\nEmacs aborted!\r\n");
5057 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5058 if (screen_virtual_segment
)
5059 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5060 /* Generate traceback, so we could tell whodunit. */
5061 signal (SIGINT
, SIG_DFL
);
5062 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5063 #else /* __DJGPP_MINOR__ >= 2 */
5065 #endif /* __DJGPP_MINOR__ >= 2 */
5071 /* The following variables are required so that cus-start.el won't
5072 complain about unbound variables. */
5073 #ifndef HAVE_X_WINDOWS
5074 /* Search path for bitmap files (xfns.c). */
5075 Lisp_Object Vx_bitmap_file_path
;
5076 int x_stretch_cursor_p
;
5078 #ifndef subprocesses
5079 /* Nonzero means delete a process right away if it exits (process.c). */
5080 static int delete_exited_processes
;
5085 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5086 staticpro (&recent_doskeys
);
5087 #ifndef HAVE_X_WINDOWS
5088 staticpro (&help_echo
);
5090 staticpro (&previous_help_echo
);
5091 previous_help_echo
= Qnil
;
5093 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
5094 "List of directories to search for bitmap files for X.");
5095 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
5097 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p
,
5098 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
5099 For example, if a block cursor is over a tab, it will be drawn as\n\
5100 wide as that tab on the display. (No effect on MS-DOS.)");
5101 x_stretch_cursor_p
= 0;
5103 /* The following three are from xfns.c: */
5104 Qbackground_color
= intern ("background-color");
5105 staticpro (&Qbackground_color
);
5106 Qforeground_color
= intern ("foreground-color");
5107 staticpro (&Qforeground_color
);
5108 Qbar
= intern ("bar");
5110 Qcursor_type
= intern ("cursor-type");
5111 staticpro (&Qcursor_type
);
5112 Qreverse
= intern ("reverse");
5113 staticpro (&Qreverse
);
5115 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5116 "*Glyph to display instead of chars not supported by current codepage.\n\
5118 This variable is used only by MSDOS terminals.");
5119 Vdos_unsupported_char_glyph
= '\177';
5121 #ifndef subprocesses
5122 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5123 "*Non-nil means delete processes immediately when they exit.\n\
5124 nil means don't delete them until `list-processes' is run.");
5125 delete_exited_processes
= 0;
5128 defsubr (&Srecent_doskeys
);
5129 defsubr (&Smsdos_long_file_names
);
5130 defsubr (&Smsdos_downcase_filename
);
5131 defsubr (&Smsdos_remember_default_colors
);