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 non-nil, dos_rawgetc generates an event to display that string.
1116 (The display is done in keyboard.c:read_char, by calling
1118 static Lisp_Object help_echo
;
1119 static Lisp_Object previous_help_echo
; /* a helper temporary variable */
1121 /* These record the window, the object and the position where the help
1122 echo string was generated. */
1123 static Lisp_Object help_echo_window
;
1124 static Lisp_Object help_echo_object
;
1125 static int help_echo_pos
;
1127 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1129 /* Set the mouse pointer shape according to whether it is in the
1130 area where the mouse highlight is in effect. */
1132 IT_set_mouse_pointer (int mode
)
1134 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1135 many possibilities to change its shape, and the available
1136 functionality pretty much sucks (e.g., almost every reasonable
1137 shape will conceal the character it is on). Since the color of
1138 the pointer changes in the highlighted area, it is not clear to
1139 me whether anything else is required, anyway. */
1142 /* Display the active region described by mouse_face_*
1143 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1145 show_mouse_face (struct display_info
*dpyinfo
, int hl
)
1147 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
1148 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
1153 /* If window is in the process of being destroyed, don't bother
1155 if (w
->current_matrix
== NULL
)
1156 goto set_cursor_shape
;
1158 /* Recognize when we are called to operate on rows that don't exist
1159 anymore. This can happen when a window is split. */
1160 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
1161 goto set_cursor_shape
;
1163 /* There's no sense to do anything if the mouse face isn't realized. */
1166 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1168 goto set_cursor_shape
;
1171 /* Note that mouse_face_beg_row etc. are window relative. */
1172 for (i
= dpyinfo
->mouse_face_beg_row
;
1173 i
<= dpyinfo
->mouse_face_end_row
;
1176 int start_hpos
, end_hpos
;
1177 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1179 /* Don't do anything if row doesn't have valid contents. */
1180 if (!row
->enabled_p
)
1183 /* For all but the first row, the highlight starts at column 0. */
1184 if (i
== dpyinfo
->mouse_face_beg_row
)
1185 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1189 if (i
== dpyinfo
->mouse_face_end_row
)
1190 end_hpos
= dpyinfo
->mouse_face_end_col
;
1192 end_hpos
= row
->used
[TEXT_AREA
];
1194 if (end_hpos
<= start_hpos
)
1196 /* Record that some glyphs of this row are displayed in
1198 row
->mouse_face_p
= hl
> 0;
1201 int vpos
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1202 int kstart
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1203 int nglyphs
= end_hpos
- start_hpos
;
1204 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1205 int start_offset
= offset
;
1208 fprintf (termscript
, "\n<MH+ %d-%d:%d>",
1209 kstart
, kstart
+ nglyphs
- 1, vpos
);
1212 IT_set_face (dpyinfo
->mouse_face_face_id
);
1213 /* Since we are going to change only the _colors_ of the
1214 displayed text, there's no need to go through all the
1215 pain of generating and encoding the text from the glyphs.
1216 Instead, we simply poke the attribute byte of each
1217 affected position in video memory with the colors
1218 computed by IT_set_face! */
1219 _farsetsel (_dos_ds
);
1222 _farnspokeb (offset
, ScreenAttrib
);
1225 if (screen_virtual_segment
)
1226 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1231 /* We are removing a previously-drawn mouse highlight. The
1232 safest way to do so is to redraw the glyphs anew, since
1233 all kinds of faces and display tables could have changed
1235 int nglyphs
= end_hpos
- start_hpos
;
1236 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1238 if (end_hpos
>= row
->used
[TEXT_AREA
])
1239 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1241 /* IT_write_glyphs writes at cursor position, so we need to
1242 temporarily move cursor coordinates to the beginning of
1243 the highlight region. */
1244 new_pos_X
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1245 new_pos_Y
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1248 fprintf (termscript
, "<MH- %d-%d:%d>",
1249 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1250 IT_write_glyphs (row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1252 fputs ("\n", termscript
);
1260 /* Change the mouse pointer shape. */
1261 IT_set_mouse_pointer (hl
);
1264 /* Clear out the mouse-highlighted active region.
1265 Redraw it un-highlighted first. */
1267 clear_mouse_face (struct display_info
*dpyinfo
)
1269 if (! NILP (dpyinfo
->mouse_face_window
))
1270 show_mouse_face (dpyinfo
, 0);
1272 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1273 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1274 dpyinfo
->mouse_face_window
= Qnil
;
1277 /* Find the glyph matrix position of buffer position POS in window W.
1278 *HPOS and *VPOS are set to the positions found. W's current glyphs
1279 must be up to date. If POS is above window start return (0, 0).
1280 If POS is after end of W, return end of last line in W. */
1282 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1286 int maybe_next_line_p
= 0;
1287 int line_start_position
;
1288 int yb
= window_text_bottom_y (w
);
1289 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0);
1290 struct glyph_row
*best_row
= row
;
1294 if (row
->used
[TEXT_AREA
])
1295 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1297 line_start_position
= 0;
1299 if (line_start_position
> pos
)
1301 /* If the position sought is the end of the buffer,
1302 don't include the blank lines at the bottom of the window. */
1303 else if (line_start_position
== pos
1304 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1306 maybe_next_line_p
= 1;
1309 else if (line_start_position
> 0)
1315 /* Find the right column within BEST_ROW. */
1318 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1320 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1323 charpos
= glyph
->charpos
;
1330 else if (charpos
> pos
)
1332 else if (charpos
> 0)
1336 /* If we're looking for the end of the buffer,
1337 and we didn't find it in the line we scanned,
1338 use the start of the following line. */
1339 if (maybe_next_line_p
)
1346 *hpos
= lastcol
+ 1;
1350 /* Take proper action when mouse has moved to the mode or top line of
1351 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1352 mode line. X is relative to the start of the text display area of
1353 W, so the width of bitmap areas and scroll bars must be subtracted
1354 to get a position relative to the start of the mode line. */
1356 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1358 struct frame
*f
= XFRAME (w
->frame
);
1359 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1360 struct glyph_row
*row
;
1363 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1365 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1369 extern Lisp_Object Qhelp_echo
;
1370 struct glyph
*glyph
, *end
;
1371 Lisp_Object help
, map
;
1373 /* Find the glyph under X. */
1374 glyph
= row
->glyphs
[TEXT_AREA
]
1375 + x
- FRAME_LEFT_SCROLL_BAR_WIDTH (f
) * CANON_X_UNIT (f
);
1376 end
= glyph
+ row
->used
[TEXT_AREA
];
1378 && STRINGP (glyph
->object
)
1379 && XSTRING (glyph
->object
)->intervals
1380 && glyph
->charpos
>= 0
1381 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1383 /* If we're on a string with `help-echo' text property,
1384 arrange for the help to be displayed. This is done by
1385 setting the global variable help_echo to the help string. */
1386 help
= Fget_text_property (make_number (glyph
->charpos
),
1387 Qhelp_echo
, glyph
->object
);
1391 XSETWINDOW (help_echo_window
, w
);
1392 help_echo_object
= glyph
->object
;
1393 help_echo_pos
= glyph
->charpos
;
1399 /* Take proper action when the mouse has moved to position X, Y on
1400 frame F as regards highlighting characters that have mouse-face
1401 properties. Also de-highlighting chars where the mouse was before.
1402 X and Y can be negative or out of range. */
1404 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1406 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1411 /* When a menu is active, don't highlight because this looks odd. */
1412 if (mouse_preempted
)
1415 if (disable_mouse_highlight
1416 || !f
->glyphs_initialized_p
)
1419 dpyinfo
->mouse_face_mouse_x
= x
;
1420 dpyinfo
->mouse_face_mouse_y
= y
;
1421 dpyinfo
->mouse_face_mouse_frame
= f
;
1423 if (dpyinfo
->mouse_face_defer
)
1428 dpyinfo
->mouse_face_deferred_gc
= 1;
1432 /* Which window is that in? */
1433 window
= window_from_coordinates (f
, x
, y
, &portion
, 0);
1435 /* If we were displaying active text in another window, clear that. */
1436 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1437 clear_mouse_face (dpyinfo
);
1439 /* Not on a window -> return. */
1440 if (!WINDOWP (window
))
1443 /* Convert to window-relative coordinates. */
1444 w
= XWINDOW (window
);
1445 x
-= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1446 y
-= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1448 if (portion
== 1 || portion
== 3)
1450 /* Mouse is on the mode or top line. */
1451 IT_note_mode_line_highlight (w
, x
, portion
== 1);
1455 IT_set_mouse_pointer (0);
1457 /* Are we in a window whose display is up to date?
1458 And verify the buffer's text has not changed. */
1459 if (/* Within text portion of the window. */
1461 && EQ (w
->window_end_valid
, w
->buffer
)
1462 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1463 && (XFASTINT (w
->last_overlay_modified
)
1464 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1467 struct glyph_row
*row
;
1468 struct glyph
*glyph
;
1470 /* Find the glyph under X/Y. */
1472 if (y
< w
->current_matrix
->nrows
)
1474 row
= MATRIX_ROW (w
->current_matrix
, y
);
1476 && row
->displays_text_p
1477 && x
< window_box_width (w
, TEXT_AREA
))
1479 glyph
= row
->glyphs
[TEXT_AREA
];
1480 if (x
>= row
->used
[TEXT_AREA
])
1485 if (!BUFFERP (glyph
->object
))
1491 /* Clear mouse face if X/Y not over text. */
1494 clear_mouse_face (dpyinfo
);
1498 if (!BUFFERP (glyph
->object
))
1500 pos
= glyph
->charpos
;
1502 /* Check for mouse-face and help-echo. */
1504 extern Lisp_Object Qmouse_face
;
1505 Lisp_Object mouse_face
, overlay
, position
;
1506 Lisp_Object
*overlay_vec
;
1508 struct buffer
*obuf
;
1511 /* If we get an out-of-range value, return now; avoid an error. */
1512 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1515 /* Make the window's buffer temporarily current for
1516 overlays_at and compute_char_face. */
1517 obuf
= current_buffer
;
1518 current_buffer
= XBUFFER (w
->buffer
);
1524 /* Is this char mouse-active or does it have help-echo? */
1525 XSETINT (position
, pos
);
1527 /* Put all the overlays we want in a vector in overlay_vec.
1528 Store the length in len. If there are more than 10, make
1529 enough space for all, and try again. */
1531 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1532 noverlays
= overlays_at (pos
, 0, &overlay_vec
, &len
, NULL
, NULL
);
1533 if (noverlays
> len
)
1536 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1537 noverlays
= overlays_at (pos
, 0, &overlay_vec
, &len
, NULL
, NULL
);
1540 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1542 /* Check mouse-face highlighting. */
1543 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1544 && y
>= dpyinfo
->mouse_face_beg_row
1545 && y
<= dpyinfo
->mouse_face_end_row
1546 && (y
> dpyinfo
->mouse_face_beg_row
1547 || x
>= dpyinfo
->mouse_face_beg_col
)
1548 && (y
< dpyinfo
->mouse_face_end_row
1549 || x
< dpyinfo
->mouse_face_end_col
1550 || dpyinfo
->mouse_face_past_end
)))
1552 /* Clear the display of the old active region, if any. */
1553 clear_mouse_face (dpyinfo
);
1555 /* Find highest priority overlay that has a mouse-face prop. */
1557 for (i
= 0; i
< noverlays
; i
++)
1559 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1560 if (!NILP (mouse_face
))
1562 overlay
= overlay_vec
[i
];
1567 /* If no overlay applies, get a text property. */
1569 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1572 /* Handle the overlay case. */
1573 if (! NILP (overlay
))
1575 /* Find the range of text around this char that
1576 should be active. */
1577 Lisp_Object before
, after
;
1580 before
= Foverlay_start (overlay
);
1581 after
= Foverlay_end (overlay
);
1582 /* Record this as the current active region. */
1583 fast_find_position (w
, XFASTINT (before
),
1584 &dpyinfo
->mouse_face_beg_col
,
1585 &dpyinfo
->mouse_face_beg_row
);
1586 dpyinfo
->mouse_face_past_end
1587 = !fast_find_position (w
, XFASTINT (after
),
1588 &dpyinfo
->mouse_face_end_col
,
1589 &dpyinfo
->mouse_face_end_row
);
1590 dpyinfo
->mouse_face_window
= window
;
1591 dpyinfo
->mouse_face_face_id
1592 = face_at_buffer_position (w
, pos
, 0, 0,
1593 &ignore
, pos
+ 1, 1);
1595 /* Display it as active. */
1596 show_mouse_face (dpyinfo
, 1);
1598 /* Handle the text property case. */
1599 else if (! NILP (mouse_face
))
1601 /* Find the range of text around this char that
1602 should be active. */
1603 Lisp_Object before
, after
, beginning
, end
;
1606 beginning
= Fmarker_position (w
->start
);
1607 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1608 - XFASTINT (w
->window_end_pos
)));
1610 = Fprevious_single_property_change (make_number (pos
+ 1),
1612 w
->buffer
, beginning
);
1614 = Fnext_single_property_change (position
, Qmouse_face
,
1616 /* Record this as the current active region. */
1617 fast_find_position (w
, XFASTINT (before
),
1618 &dpyinfo
->mouse_face_beg_col
,
1619 &dpyinfo
->mouse_face_beg_row
);
1620 dpyinfo
->mouse_face_past_end
1621 = !fast_find_position (w
, XFASTINT (after
),
1622 &dpyinfo
->mouse_face_end_col
,
1623 &dpyinfo
->mouse_face_end_row
);
1624 dpyinfo
->mouse_face_window
= window
;
1625 dpyinfo
->mouse_face_face_id
1626 = face_at_buffer_position (w
, pos
, 0, 0,
1627 &ignore
, pos
+ 1, 1);
1629 /* Display it as active. */
1630 show_mouse_face (dpyinfo
, 1);
1634 /* Look for a `help-echo' property. */
1637 extern Lisp_Object Qhelp_echo
;
1639 /* Check overlays first. */
1641 for (i
= 0; i
< noverlays
&& NILP (help
); ++i
)
1642 help
= Foverlay_get (overlay_vec
[i
], Qhelp_echo
);
1647 help_echo_window
= window
;
1648 help_echo_object
= w
->buffer
;
1649 help_echo_pos
= pos
;
1651 /* Try text properties. */
1652 else if (NILP (help
)
1653 && ((STRINGP (glyph
->object
)
1654 && glyph
->charpos
>= 0
1655 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1656 || (BUFFERP (glyph
->object
)
1657 && glyph
->charpos
>= BEGV
1658 && glyph
->charpos
< ZV
)))
1660 help
= Fget_text_property (make_number (glyph
->charpos
),
1661 Qhelp_echo
, glyph
->object
);
1665 help_echo_window
= window
;
1666 help_echo_object
= glyph
->object
;
1667 help_echo_pos
= glyph
->charpos
;
1674 current_buffer
= obuf
;
1680 IT_clear_end_of_line (int first_unused
)
1684 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1685 extern int fatal_error_in_progress
;
1687 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1691 i
= (j
= first_unused
- new_pos_X
) * 2;
1693 fprintf (termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1694 spaces
= sp
= alloca (i
);
1699 *sp
++ = ScreenAttrib
;
1703 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1704 if (screen_virtual_segment
)
1705 dosv_refresh_virtual_screen (offset
, i
/ 2);
1707 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1708 Let's follow their lead, in case someone relies on this. */
1709 new_pos_X
= first_unused
;
1713 IT_clear_screen (void)
1716 fprintf (termscript
, "<CLR:SCR>");
1720 if (screen_virtual_segment
)
1721 dosv_refresh_virtual_screen (0, screen_size
);
1722 new_pos_X
= new_pos_Y
= 0;
1726 IT_clear_to_end (void)
1729 fprintf (termscript
, "<CLR:EOS>");
1731 while (new_pos_Y
< screen_size_Y
) {
1733 IT_clear_end_of_line (screen_size_X
);
1739 IT_cursor_to (int y
, int x
)
1742 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
1747 static int cursor_cleared
;
1750 IT_display_cursor (int on
)
1752 if (on
&& cursor_cleared
)
1754 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1757 else if (!on
&& !cursor_cleared
)
1759 ScreenSetCursor (-1, -1);
1764 /* Emacs calls cursor-movement functions a lot when it updates the
1765 display (probably a legacy of old terminals where you cannot
1766 update a screen line without first moving the cursor there).
1767 However, cursor movement is expensive on MSDOS (it calls a slow
1768 BIOS function and requires 2 mode switches), while actual screen
1769 updates access the video memory directly and don't depend on
1770 cursor position. To avoid slowing down the redisplay, we cheat:
1771 all functions that move the cursor only set internal variables
1772 which record the cursor position, whereas the cursor is only
1773 moved to its final position whenever screen update is complete.
1775 `IT_cmgoto' is called from the keyboard reading loop and when the
1776 frame update is complete. This means that we are ready for user
1777 input, so we update the cursor position to show where the point is,
1778 and also make the mouse pointer visible.
1780 Special treatment is required when the cursor is in the echo area,
1781 to put the cursor at the end of the text displayed there. */
1784 IT_cmgoto (FRAME_PTR f
)
1786 /* Only set the cursor to where it should be if the display is
1787 already in sync with the window contents. */
1788 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1790 /* FIXME: This needs to be rewritten for the new redisplay, or
1793 static int previous_pos_X
= -1;
1795 update_cursor_pos
= 1; /* temporary!!! */
1797 /* If the display is in sync, forget any previous knowledge about
1798 cursor position. This is primarily for unexpected events like
1799 C-g in the minibuffer. */
1800 if (update_cursor_pos
&& previous_pos_X
>= 0)
1801 previous_pos_X
= -1;
1802 /* If we are in the echo area, put the cursor at the
1803 end of the echo area message. */
1804 if (!update_cursor_pos
1805 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1807 int tem_X
= current_pos_X
, dummy
;
1809 if (echo_area_glyphs
)
1811 tem_X
= echo_area_glyphs_length
;
1812 /* Save current cursor position, to be restored after the
1813 echo area message is erased. Only remember one level
1814 of previous cursor position. */
1815 if (previous_pos_X
== -1)
1816 ScreenGetCursor (&dummy
, &previous_pos_X
);
1818 else if (previous_pos_X
>= 0)
1820 /* We wind up here after the echo area message is erased.
1821 Restore the cursor position we remembered above. */
1822 tem_X
= previous_pos_X
;
1823 previous_pos_X
= -1;
1826 if (current_pos_X
!= tem_X
)
1829 update_cursor_pos
= 1;
1834 if (update_cursor_pos
1835 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1837 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1839 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1842 /* Maybe cursor is invisible, so make it visible. */
1843 IT_display_cursor (1);
1845 /* Mouse pointer should be always visible if we are waiting for
1852 IT_reassert_line_highlight (int new, int vpos
)
1858 IT_change_line_highlight (int new_highlight
, int y
, int vpos
, int first_unused_hpos
)
1860 highlight
= new_highlight
;
1861 IT_cursor_to (vpos
, 0);
1862 IT_clear_end_of_line (first_unused_hpos
);
1866 IT_update_begin (struct frame
*f
)
1868 struct display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1874 if (f
== display_info
->mouse_face_mouse_frame
)
1876 /* Don't do highlighting for mouse motion during the update. */
1877 display_info
->mouse_face_defer
= 1;
1879 /* If F needs to be redrawn, simply forget about any prior mouse
1881 if (FRAME_GARBAGED_P (f
))
1882 display_info
->mouse_face_window
= Qnil
;
1884 /* Can we tell that this update does not affect the window
1885 where the mouse highlight is? If so, no need to turn off.
1886 Likewise, don't do anything if none of the enabled rows
1887 contains glyphs highlighted in mouse face. */
1888 if (!NILP (display_info
->mouse_face_window
)
1889 && WINDOWP (display_info
->mouse_face_window
))
1891 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1894 /* If the mouse highlight is in the window that was deleted
1895 (e.g., if it was popped by completion), clear highlight
1897 if (NILP (w
->buffer
))
1898 display_info
->mouse_face_window
= Qnil
;
1901 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1902 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1903 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1907 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1908 clear_mouse_face (display_info
);
1911 else if (!FRAME_LIVE_P (display_info
->mouse_face_mouse_frame
))
1913 /* If the frame with mouse highlight was deleted, invalidate the
1915 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1916 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1917 display_info
->mouse_face_window
= Qnil
;
1918 display_info
->mouse_face_deferred_gc
= 0;
1919 display_info
->mouse_face_mouse_frame
= NULL
;
1926 IT_update_end (struct frame
*f
)
1929 FRAME_X_DISPLAY_INFO (f
)->mouse_face_defer
= 0;
1932 Lisp_Object Qcursor_type
;
1935 IT_frame_up_to_date (struct frame
*f
)
1937 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1938 Lisp_Object new_cursor
, frame_desired_cursor
;
1941 if (dpyinfo
->mouse_face_deferred_gc
1942 || f
== dpyinfo
->mouse_face_mouse_frame
)
1945 if (dpyinfo
->mouse_face_mouse_frame
)
1946 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
1947 dpyinfo
->mouse_face_mouse_x
,
1948 dpyinfo
->mouse_face_mouse_y
);
1949 dpyinfo
->mouse_face_deferred_gc
= 0;
1953 /* Set the cursor type to whatever they wanted. In a minibuffer
1954 window, we want the cursor to appear only if we are reading input
1955 from this window, and we want the cursor to be taken from the
1956 frame parameters. For the selected window, we use either its
1957 buffer-local value or the value from the frame parameters if the
1958 buffer doesn't define its local value for the cursor type. */
1959 sw
= XWINDOW (f
->selected_window
);
1960 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1961 if (cursor_in_echo_area
1962 && FRAME_HAS_MINIBUF_P (f
)
1963 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1964 && sw
== XWINDOW (echo_area_window
))
1965 new_cursor
= frame_desired_cursor
;
1968 struct buffer
*b
= XBUFFER (sw
->buffer
);
1970 if (EQ (b
->cursor_type
, Qt
))
1971 new_cursor
= frame_desired_cursor
;
1972 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
1973 new_cursor
= Fcons (Qbar
, make_number (0));
1975 new_cursor
= b
->cursor_type
;
1978 IT_set_cursor_type (f
, new_cursor
);
1980 IT_cmgoto (f
); /* position cursor when update is done */
1983 /* Copy LEN glyphs displayed on a single line whose vertical position
1984 is YPOS, beginning at horizontal position XFROM to horizontal
1985 position XTO, by moving blocks in the video memory. Used by
1986 functions that insert and delete glyphs. */
1988 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1990 /* The offsets of source and destination relative to the
1991 conventional memorty selector. */
1992 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1993 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1995 if (from
== to
|| len
<= 0)
1998 _farsetsel (_dos_ds
);
2000 /* The source and destination might overlap, so we need to move
2001 glyphs non-destructively. */
2004 for ( ; len
; from
+= 2, to
+= 2, len
--)
2005 _farnspokew (to
, _farnspeekw (from
));
2009 from
+= (len
- 1) * 2;
2010 to
+= (len
- 1) * 2;
2011 for ( ; len
; from
-= 2, to
-= 2, len
--)
2012 _farnspokew (to
, _farnspeekw (from
));
2014 if (screen_virtual_segment
)
2015 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
2018 /* Insert and delete glyphs. */
2020 IT_insert_glyphs (start
, len
)
2021 register struct glyph
*start
;
2024 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
2026 /* Shift right the glyphs from the nominal cursor position to the
2027 end of this line. */
2028 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
2030 /* Now write the glyphs to be inserted. */
2031 IT_write_glyphs (start
, len
);
2035 IT_delete_glyphs (n
)
2041 /* set-window-configuration on window.c needs this. */
2043 x_set_menu_bar_lines (f
, value
, oldval
)
2045 Lisp_Object value
, oldval
;
2047 set_menu_bar_lines (f
, value
, oldval
);
2050 /* This was copied from xfns.c */
2052 Lisp_Object Qbackground_color
;
2053 Lisp_Object Qforeground_color
;
2054 Lisp_Object Qreverse
;
2055 extern Lisp_Object Qtitle
;
2057 /* IT_set_terminal_modes is called when emacs is started,
2058 resumed, and whenever the screen is redrawn! */
2061 IT_set_terminal_modes (void)
2064 fprintf (termscript
, "\n<SET_TERM>");
2067 screen_size_X
= ScreenCols ();
2068 screen_size_Y
= ScreenRows ();
2069 screen_size
= screen_size_X
* screen_size_Y
;
2071 new_pos_X
= new_pos_Y
= 0;
2072 current_pos_X
= current_pos_Y
= -1;
2074 if (term_setup_done
)
2076 term_setup_done
= 1;
2078 startup_screen_size_X
= screen_size_X
;
2079 startup_screen_size_Y
= screen_size_Y
;
2080 startup_screen_attrib
= ScreenAttrib
;
2083 /* Is DOS/V (or any other RSIS software which relocates
2084 the screen) installed? */
2086 unsigned short es_value
;
2089 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2090 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2091 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2092 else if (screen_old_address
) /* already switched to Japanese mode once */
2093 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2095 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2097 es_value
= regs
.x
.es
;
2098 __dpmi_int (0x10, ®s
);
2100 if (regs
.x
.es
!= es_value
)
2102 /* screen_old_address is only set if ScreenPrimary does NOT
2103 already point to the relocated buffer address returned by
2104 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2105 ScreenPrimary to that address at startup under DOS/V. */
2106 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2107 screen_old_address
= ScreenPrimary
;
2108 screen_virtual_segment
= regs
.x
.es
;
2109 screen_virtual_offset
= regs
.x
.di
;
2110 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2113 #endif /* __DJGPP__ > 1 */
2115 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2116 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2119 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2120 screen_size_X
, screen_size_Y
);
2125 /* IT_reset_terminal_modes is called when emacs is
2126 suspended or killed. */
2129 IT_reset_terminal_modes (void)
2131 int display_row_start
= (int) ScreenPrimary
;
2132 int saved_row_len
= startup_screen_size_X
* 2;
2133 int update_row_len
= ScreenCols () * 2;
2134 int current_rows
= ScreenRows ();
2135 int to_next_row
= update_row_len
;
2136 unsigned char *saved_row
= startup_screen_buffer
;
2137 int cursor_pos_X
= ScreenCols () - 1;
2138 int cursor_pos_Y
= ScreenRows () - 1;
2141 fprintf (termscript
, "\n<RESET_TERM>");
2145 if (!term_setup_done
)
2150 /* Leave the video system in the same state as we found it,
2151 as far as the blink/bright-background bit is concerned. */
2152 maybe_enable_blinking ();
2154 /* We have a situation here.
2155 We cannot just do ScreenUpdate(startup_screen_buffer) because
2156 the luser could have changed screen dimensions inside Emacs
2157 and failed (or didn't want) to restore them before killing
2158 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2159 thus will happily use memory outside what was allocated for
2160 `startup_screen_buffer'.
2161 Thus we only restore as much as the current screen dimensions
2162 can hold, and clear the rest (if the saved screen is smaller than
2163 the current) with the color attribute saved at startup. The cursor
2164 is also restored within the visible dimensions. */
2166 ScreenAttrib
= startup_screen_attrib
;
2168 /* Don't restore the screen if we are exiting less than 2 seconds
2169 after startup: we might be crashing, and the screen might show
2170 some vital clues to what's wrong. */
2171 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2174 if (screen_virtual_segment
)
2175 dosv_refresh_virtual_screen (0, screen_size
);
2177 if (update_row_len
> saved_row_len
)
2178 update_row_len
= saved_row_len
;
2179 if (current_rows
> startup_screen_size_Y
)
2180 current_rows
= startup_screen_size_Y
;
2183 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2184 update_row_len
/ 2, current_rows
);
2186 while (current_rows
--)
2188 dosmemput (saved_row
, update_row_len
, display_row_start
);
2189 if (screen_virtual_segment
)
2190 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2191 update_row_len
/ 2);
2192 saved_row
+= saved_row_len
;
2193 display_row_start
+= to_next_row
;
2196 if (startup_pos_X
< cursor_pos_X
)
2197 cursor_pos_X
= startup_pos_X
;
2198 if (startup_pos_Y
< cursor_pos_Y
)
2199 cursor_pos_Y
= startup_pos_Y
;
2201 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2202 xfree (startup_screen_buffer
);
2204 term_setup_done
= 0;
2208 IT_set_terminal_window (int foo
)
2212 /* Remember the screen colors of the curent frame, to serve as the
2213 default colors for newly-created frames. */
2215 static int initial_screen_colors
[2];
2217 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2218 Smsdos_remember_default_colors
, 1, 1, 0,
2219 "Remember the screen colors of the current frame.")
2226 CHECK_FRAME (frame
, 0);
2228 reverse
= EQ (Fcdr (Fassq (intern ("reverse"), f
->param_alist
)), Qt
);
2230 initial_screen_colors
[0]
2231 = reverse
? FRAME_BACKGROUND_PIXEL (f
) : FRAME_FOREGROUND_PIXEL (f
);
2232 initial_screen_colors
[1]
2233 = reverse
? FRAME_FOREGROUND_PIXEL (f
) : FRAME_BACKGROUND_PIXEL (f
);
2237 IT_set_frame_parameters (f
, alist
)
2242 int length
= XINT (Flength (alist
));
2245 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2247 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2248 /* Do we have to reverse the foreground and background colors? */
2249 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2250 int was_reverse
= reverse
;
2251 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2252 unsigned long orig_fg
;
2253 unsigned long orig_bg
;
2255 /* If we are creating a new frame, begin with the original screen colors
2256 used for the initial frame. */
2257 if (alist
== Vdefault_frame_alist
2258 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2260 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2261 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2263 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2264 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2266 /* Extract parm names and values into those vectors. */
2268 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2273 parms
[i
] = Fcar (elt
);
2274 CHECK_SYMBOL (parms
[i
], 1);
2275 values
[i
] = Fcdr (elt
);
2281 for (i
= 0; i
< j
; i
++)
2283 Lisp_Object prop
= parms
[i
];
2284 Lisp_Object val
= values
[i
];
2286 if (EQ (prop
, Qreverse
))
2287 reverse
= EQ (val
, Qt
);
2290 if (termscript
&& reverse
&& !was_reverse
)
2291 fprintf (termscript
, "<INVERSE-VIDEO>\n");
2293 /* Now process the alist elements in reverse of specified order. */
2294 for (i
--; i
>= 0; i
--)
2296 Lisp_Object prop
= parms
[i
];
2297 Lisp_Object val
= values
[i
];
2299 if (EQ (prop
, Qforeground_color
))
2301 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
2302 ? LFACE_BACKGROUND_INDEX
2303 : LFACE_FOREGROUND_INDEX
);
2304 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2305 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2306 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2309 /* FIXME: should the fore-/background of the default
2310 face change here as well? */
2311 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2313 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2317 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
2320 else if (EQ (prop
, Qbackground_color
))
2322 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
2323 ? LFACE_FOREGROUND_INDEX
2324 : LFACE_BACKGROUND_INDEX
);
2325 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2326 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2327 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2330 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2332 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2336 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
2339 else if (EQ (prop
, Qtitle
))
2341 x_set_title (f
, val
);
2343 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
2345 else if (EQ (prop
, Qcursor_type
))
2347 IT_set_cursor_type (f
, val
);
2349 fprintf (termscript
, "<CTYPE: %s>\n",
2350 EQ (val
, Qbar
) || CONSP (val
) && EQ (XCAR (val
), Qbar
)
2353 store_frame_param (f
, prop
, val
);
2356 /* If they specified "reverse", but not the colors, we need to swap
2357 the current frame colors. */
2358 if (reverse
&& !was_reverse
)
2362 FRAME_BACKGROUND_PIXEL (f
) = orig_fg
;
2367 FRAME_FOREGROUND_PIXEL (f
) = orig_bg
;
2374 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2375 if (f
== SELECTED_FRAME())
2380 extern void init_frame_faces (FRAME_PTR
);
2382 #endif /* !HAVE_X_WINDOWS */
2385 /* Do we need the internal terminal? */
2388 internal_terminal_init ()
2390 char *term
= getenv ("TERM");
2392 struct frame
*sf
= SELECTED_FRAME();
2394 #ifdef HAVE_X_WINDOWS
2395 if (!inhibit_window_system
)
2400 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2402 if (getenv ("EMACSTEST"))
2403 termscript
= fopen (getenv ("EMACSTEST"), "wt");
2405 #ifndef HAVE_X_WINDOWS
2406 if (!internal_terminal
|| inhibit_window_system
)
2408 sf
->output_method
= output_termcap
;
2412 Vwindow_system
= intern ("pc");
2413 Vwindow_system_version
= make_number (1);
2414 sf
->output_method
= output_msdos_raw
;
2416 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2417 screen_old_address
= 0;
2419 /* Forget the stale screen colors as well. */
2420 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2422 bzero (&the_only_x_display
, sizeof the_only_x_display
);
2423 the_only_x_display
.background_pixel
= 7; /* White */
2424 the_only_x_display
.foreground_pixel
= 0; /* Black */
2426 colors
= getenv ("EMACSCOLORS");
2427 if (colors
&& strlen (colors
) >= 2)
2429 /* The colors use 4 bits each (we enable bright background). */
2430 if (isdigit (colors
[0]))
2432 else if (isxdigit (colors
[0]))
2433 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2434 if (colors
[0] >= 0 && colors
[0] < 16)
2435 the_only_x_display
.foreground_pixel
= colors
[0];
2436 if (isdigit (colors
[1]))
2438 else if (isxdigit (colors
[1]))
2439 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2440 if (colors
[1] >= 0 && colors
[1] < 16)
2441 the_only_x_display
.background_pixel
= colors
[1];
2443 the_only_x_display
.line_height
= 1;
2444 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
2445 the_only_x_display
.display_info
.mouse_face_mouse_frame
= NULL
;
2446 the_only_x_display
.display_info
.mouse_face_deferred_gc
= 0;
2447 the_only_x_display
.display_info
.mouse_face_beg_row
=
2448 the_only_x_display
.display_info
.mouse_face_beg_col
= -1;
2449 the_only_x_display
.display_info
.mouse_face_end_row
=
2450 the_only_x_display
.display_info
.mouse_face_end_col
= -1;
2451 the_only_x_display
.display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2452 the_only_x_display
.display_info
.mouse_face_window
= Qnil
;
2453 the_only_x_display
.display_info
.mouse_face_mouse_x
=
2454 the_only_x_display
.display_info
.mouse_face_mouse_y
= 0;
2455 the_only_x_display
.display_info
.mouse_face_defer
= 0;
2457 init_frame_faces (sf
);
2459 ring_bell_hook
= IT_ring_bell
;
2460 insert_glyphs_hook
= IT_insert_glyphs
;
2461 delete_glyphs_hook
= IT_delete_glyphs
;
2462 write_glyphs_hook
= IT_write_glyphs
;
2463 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
2464 clear_to_end_hook
= IT_clear_to_end
;
2465 clear_end_of_line_hook
= IT_clear_end_of_line
;
2466 clear_frame_hook
= IT_clear_screen
;
2467 change_line_highlight_hook
= IT_change_line_highlight
;
2468 update_begin_hook
= IT_update_begin
;
2469 update_end_hook
= IT_update_end
;
2470 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
2471 frame_up_to_date_hook
= IT_frame_up_to_date
;
2473 /* These hooks are called by term.c without being checked. */
2474 set_terminal_modes_hook
= IT_set_terminal_modes
;
2475 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2476 set_terminal_window_hook
= IT_set_terminal_window
;
2477 char_ins_del_ok
= 0;
2481 dos_get_saved_screen (screen
, rows
, cols
)
2486 #ifndef HAVE_X_WINDOWS
2487 *screen
= startup_screen_buffer
;
2488 *cols
= startup_screen_size_X
;
2489 *rows
= startup_screen_size_Y
;
2490 return *screen
!= (char *)0;
2496 #ifndef HAVE_X_WINDOWS
2498 /* We are not X, but we can emulate it well enough for our needs... */
2502 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2503 error ("Not running under a window system");
2509 /* ----------------------- Keyboard control ----------------------
2511 * Keymaps reflect the following keyboard layout:
2513 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2514 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2515 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2516 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2520 #define Ignore 0x0000
2521 #define Normal 0x0000 /* normal key - alt changes scan-code */
2522 #define FctKey 0x1000 /* func key if c == 0, else c */
2523 #define Special 0x2000 /* func key even if c != 0 */
2524 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2525 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2526 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2527 #define Grey 0x6000 /* Grey keypad key */
2529 #define Alt 0x0100 /* alt scan-code */
2530 #define Ctrl 0x0200 /* ctrl scan-code */
2531 #define Shift 0x0400 /* shift scan-code */
2533 static int extended_kbd
; /* 101 (102) keyboard present. */
2535 struct kbd_translate
{
2538 unsigned short code
;
2541 struct dos_keyboard_map
2546 struct kbd_translate
*translate_table
;
2550 static struct dos_keyboard_map us_keyboard
= {
2552 /* 01234567890123456789012345678901234567890 12345678901234 */
2553 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2554 /* 0123456789012345678901234567890123456789 012345678901234 */
2555 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2556 0, /* no Alt-Gr key */
2557 0 /* no translate table */
2560 static struct dos_keyboard_map fr_keyboard
= {
2562 /* 012 3456789012345678901234567890123456789012345678901234 */
2563 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2564 /* 0123456789012345678901234567890123456789012345678901234 */
2565 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2566 /* 01234567 89012345678901234567890123456789012345678901234 */
2568 0 /* no translate table */
2572 * Italian keyboard support, country code 39.
2575 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2576 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2579 static struct kbd_translate it_kbd_translate_table
[] = {
2580 { 0x56, 0x3c, Normal
| 13 },
2581 { 0x56, 0x3e, Normal
| 27 },
2584 static struct dos_keyboard_map it_keyboard
= {
2586 /* 0 123456789012345678901234567890123456789012345678901234 */
2587 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2588 /* 01 23456789012345678901234567890123456789012345678901234 */
2589 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2590 /* 0123456789012345678901234567890123456789012345678901234 */
2592 it_kbd_translate_table
2595 static struct dos_keyboard_map dk_keyboard
= {
2597 /* 0123456789012345678901234567890123456789012345678901234 */
2598 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2599 /* 01 23456789012345678901234567890123456789012345678901234 */
2600 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2601 /* 0123456789012345678901234567890123456789012345678901234 */
2603 0 /* no translate table */
2606 static struct kbd_translate jp_kbd_translate_table
[] = {
2607 { 0x73, 0x5c, Normal
| 0 },
2608 { 0x73, 0x5f, Normal
| 0 },
2609 { 0x73, 0x1c, Map
| 0 },
2610 { 0x7d, 0x5c, Normal
| 13 },
2611 { 0x7d, 0x7c, Normal
| 13 },
2612 { 0x7d, 0x1c, Map
| 13 },
2615 static struct dos_keyboard_map jp_keyboard
= {
2617 /* 0123456789012 345678901234567890123456789012345678901234 */
2618 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2619 /* 01 23456789012345678901234567890123456789012345678901234 */
2620 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2621 0, /* no Alt-Gr key */
2622 jp_kbd_translate_table
2625 static struct keyboard_layout_list
2628 struct dos_keyboard_map
*keyboard_map
;
2629 } keyboard_layout_list
[] =
2638 static struct dos_keyboard_map
*keyboard
;
2639 static int keyboard_map_all
;
2640 static int international_keyboard
;
2643 dos_set_keyboard (code
, always
)
2648 _go32_dpmi_registers regs
;
2650 /* See if Keyb.Com is installed (for international keyboard support).
2651 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2652 of Windows 9X! So don't do that! */
2654 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2655 _go32_dpmi_simulate_int (0x2f, ®s
);
2656 if (regs
.h
.al
== 0xff)
2657 international_keyboard
= 1;
2659 /* Initialize to US settings, for countries that don't have their own. */
2660 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2661 keyboard_map_all
= always
;
2662 dos_keyboard_layout
= 1;
2664 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2665 if (code
== keyboard_layout_list
[i
].country_code
)
2667 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2668 keyboard_map_all
= always
;
2669 dos_keyboard_layout
= code
;
2677 unsigned char char_code
; /* normal code */
2678 unsigned char meta_code
; /* M- code */
2679 unsigned char keypad_code
; /* keypad code */
2680 unsigned char editkey_code
; /* edit key */
2681 } keypad_translate_map
[] = {
2682 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2683 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2684 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2685 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2686 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2687 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2688 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2689 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2690 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2691 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2692 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2697 unsigned char char_code
; /* normal code */
2698 unsigned char keypad_code
; /* keypad code */
2699 } grey_key_translate_map
[] = {
2700 '/', 0xaf, /* kp-decimal */
2701 '*', 0xaa, /* kp-multiply */
2702 '-', 0xad, /* kp-subtract */
2703 '+', 0xab, /* kp-add */
2704 '\r', 0x8d /* kp-enter */
2707 static unsigned short
2708 ibmpc_translate_map
[] =
2710 /* --------------- 00 to 0f --------------- */
2711 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2712 Alt
| ModFct
| 0x1b, /* Escape */
2713 Normal
| 1, /* '1' */
2714 Normal
| 2, /* '2' */
2715 Normal
| 3, /* '3' */
2716 Normal
| 4, /* '4' */
2717 Normal
| 5, /* '5' */
2718 Normal
| 6, /* '6' */
2719 Normal
| 7, /* '7' */
2720 Normal
| 8, /* '8' */
2721 Normal
| 9, /* '9' */
2722 Normal
| 10, /* '0' */
2723 Normal
| 11, /* '-' */
2724 Normal
| 12, /* '=' */
2725 Special
| 0x08, /* Backspace */
2726 ModFct
| 0x74, /* Tab/Backtab */
2728 /* --------------- 10 to 1f --------------- */
2741 ModFct
| 0x0d, /* Return */
2746 /* --------------- 20 to 2f --------------- */
2755 Map
| 40, /* '\'' */
2757 Ignore
, /* Left shift */
2758 Map
| 41, /* '\\' */
2764 /* --------------- 30 to 3f --------------- */
2771 Ignore
, /* Right shift */
2772 Grey
| 1, /* Grey * */
2774 Normal
| 55, /* ' ' */
2775 Ignore
, /* Caps Lock */
2776 FctKey
| 0xbe, /* F1 */
2777 FctKey
| 0xbf, /* F2 */
2778 FctKey
| 0xc0, /* F3 */
2779 FctKey
| 0xc1, /* F4 */
2780 FctKey
| 0xc2, /* F5 */
2782 /* --------------- 40 to 4f --------------- */
2783 FctKey
| 0xc3, /* F6 */
2784 FctKey
| 0xc4, /* F7 */
2785 FctKey
| 0xc5, /* F8 */
2786 FctKey
| 0xc6, /* F9 */
2787 FctKey
| 0xc7, /* F10 */
2788 Ignore
, /* Num Lock */
2789 Ignore
, /* Scroll Lock */
2790 KeyPad
| 7, /* Home */
2791 KeyPad
| 8, /* Up */
2792 KeyPad
| 9, /* Page Up */
2793 Grey
| 2, /* Grey - */
2794 KeyPad
| 4, /* Left */
2795 KeyPad
| 5, /* Keypad 5 */
2796 KeyPad
| 6, /* Right */
2797 Grey
| 3, /* Grey + */
2798 KeyPad
| 1, /* End */
2800 /* --------------- 50 to 5f --------------- */
2801 KeyPad
| 2, /* Down */
2802 KeyPad
| 3, /* Page Down */
2803 KeyPad
| 0, /* Insert */
2804 KeyPad
| 10, /* Delete */
2805 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2806 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2807 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2808 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2809 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2810 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2811 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2812 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2813 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2814 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2815 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2816 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2818 /* --------------- 60 to 6f --------------- */
2819 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2820 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2821 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2822 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2823 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2824 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2825 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2826 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2827 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2828 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2829 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2830 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2831 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2832 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2833 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2834 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2836 /* --------------- 70 to 7f --------------- */
2837 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2838 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2839 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2840 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2841 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2842 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2843 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2844 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2845 Alt
| Map
| 1, /* '1' */
2846 Alt
| Map
| 2, /* '2' */
2847 Alt
| Map
| 3, /* '3' */
2848 Alt
| Map
| 4, /* '4' */
2849 Alt
| Map
| 5, /* '5' */
2850 Alt
| Map
| 6, /* '6' */
2851 Alt
| Map
| 7, /* '7' */
2852 Alt
| Map
| 8, /* '8' */
2854 /* --------------- 80 to 8f --------------- */
2855 Alt
| Map
| 9, /* '9' */
2856 Alt
| Map
| 10, /* '0' */
2857 Alt
| Map
| 11, /* '-' */
2858 Alt
| Map
| 12, /* '=' */
2859 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2860 FctKey
| 0xc8, /* F11 */
2861 FctKey
| 0xc9, /* F12 */
2862 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2863 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2864 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2865 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2866 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2867 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2868 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2869 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2870 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2872 /* --------------- 90 to 9f --------------- */
2873 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2874 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2875 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2876 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2877 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2878 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2879 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2880 Alt
| FctKey
| 0x50, /* (Alt) Home */
2881 Alt
| FctKey
| 0x52, /* (Alt) Up */
2882 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2883 Ignore
, /* NO KEY */
2884 Alt
| FctKey
| 0x51, /* (Alt) Left */
2885 Ignore
, /* NO KEY */
2886 Alt
| FctKey
| 0x53, /* (Alt) Right */
2887 Ignore
, /* NO KEY */
2888 Alt
| FctKey
| 0x57, /* (Alt) End */
2890 /* --------------- a0 to af --------------- */
2891 Alt
| KeyPad
| 2, /* (Alt) Down */
2892 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2893 Alt
| KeyPad
| 0, /* (Alt) Insert */
2894 Alt
| KeyPad
| 10, /* (Alt) Delete */
2895 Alt
| Grey
| 0, /* (Alt) Grey / */
2896 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2897 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2900 /* These bit-positions corresponds to values returned by BIOS */
2901 #define SHIFT_P 0x0003 /* two bits! */
2902 #define CTRL_P 0x0004
2903 #define ALT_P 0x0008
2904 #define SCRLOCK_P 0x0010
2905 #define NUMLOCK_P 0x0020
2906 #define CAPSLOCK_P 0x0040
2907 #define ALT_GR_P 0x0800
2908 #define SUPER_P 0x4000 /* pseudo */
2909 #define HYPER_P 0x8000 /* pseudo */
2912 dos_get_modifiers (keymask
)
2919 /* Calculate modifier bits */
2920 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2921 int86 (0x16, ®s
, ®s
);
2925 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2926 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2930 mask
= regs
.h
.al
& (SHIFT_P
|
2931 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2933 /* Do not break international keyboard support. */
2934 /* When Keyb.Com is loaded, the right Alt key is */
2935 /* used for accessing characters like { and } */
2936 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2939 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2942 if (dos_hyper_key
== 1)
2945 modifiers
|= hyper_modifier
;
2947 else if (dos_super_key
== 1)
2950 modifiers
|= super_modifier
;
2952 else if (!international_keyboard
)
2954 /* If Keyb.Com is NOT installed, let Right Alt behave
2955 like the Left Alt. */
2961 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2964 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2966 if (dos_hyper_key
== 2)
2969 modifiers
|= hyper_modifier
;
2971 else if (dos_super_key
== 2)
2974 modifiers
|= super_modifier
;
2982 modifiers
|= shift_modifier
;
2984 modifiers
|= ctrl_modifier
;
2986 modifiers
|= meta_modifier
;
2993 #define NUM_RECENT_DOSKEYS (100)
2994 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2995 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
2996 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
2998 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
2999 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
3000 Each input key receives two values in this vector: first the ASCII code,\n\
3001 and then the scan code.")
3004 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
3007 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
3008 return Fvector (total_doskeys
, keys
);
3011 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
3012 bcopy (keys
+ recent_doskeys_index
,
3013 XVECTOR (val
)->contents
,
3014 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
3016 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
3017 recent_doskeys_index
* sizeof (Lisp_Object
));
3022 /* Get a char from keyboard. Function keys are put into the event queue. */
3024 extern void kbd_buffer_store_event (struct input_event
*);
3029 struct input_event event
;
3032 #ifndef HAVE_X_WINDOWS
3033 /* Maybe put the cursor where it should be. */
3034 IT_cmgoto (SELECTED_FRAME());
3037 /* The following condition is equivalent to `kbhit ()', except that
3038 it uses the bios to do its job. This pleases DESQview/X. */
3039 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
3040 int86 (0x16, ®s
, ®s
),
3041 (regs
.x
.flags
& 0x40) == 0)
3044 register unsigned char c
;
3045 int sc
, code
= -1, mask
, kp_mode
;
3048 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
3049 int86 (0x16, ®s
, ®s
);
3054 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3056 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3057 recent_doskeys_index
= 0;
3058 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3060 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3061 recent_doskeys_index
= 0;
3063 modifiers
= dos_get_modifiers (&mask
);
3065 #ifndef HAVE_X_WINDOWS
3066 if (!NILP (Vdos_display_scancodes
))
3069 sprintf (buf
, "%02x:%02x*%04x",
3070 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3071 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3079 case 10: /* Ctrl Grey Enter */
3080 code
= Ctrl
| Grey
| 4;
3082 case 13: /* Grey Enter */
3085 case '/': /* Grey / */
3095 /* Try the keyboard-private translation table first. */
3096 if (keyboard
->translate_table
)
3098 struct kbd_translate
*p
= keyboard
->translate_table
;
3102 if (p
->sc
== sc
&& p
->ch
== c
)
3110 /* If the private table didn't translate it, use the general
3114 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3116 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3123 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3124 Emacs is ready to read a key. Therefore, if they press
3125 `Alt-x' when Emacs is busy, by the time we get to
3126 `dos_get_modifiers', they might have already released the
3127 Alt key, and Emacs gets just `x', which is BAD.
3128 However, for keys with the `Map' property set, the ASCII
3129 code returns zero iff Alt is pressed. So, when we DON'T
3130 have to support international_keyboard, we don't have to
3131 distinguish between the left and right Alt keys, and we
3132 can set the META modifier for any keys with the `Map'
3133 property if they return zero ASCII code (c = 0). */
3135 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3136 modifiers
|= meta_modifier
;
3138 modifiers
|= ctrl_modifier
;
3140 modifiers
|= shift_modifier
;
3143 switch (code
& 0xf000)
3146 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3148 c
= 0; /* Special */
3161 if (c
== 0) /* ctrl-break */
3163 return c
; /* ALT-nnn */
3165 if (!keyboard_map_all
)
3174 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3175 if (!keyboard_map_all
)
3179 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3180 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3184 code
= keyboard
->shifted
[code
];
3186 modifiers
&= ~shift_modifier
;
3189 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3190 code
= keyboard
->alt_gr
[code
];
3192 code
= keyboard
->unshifted
[code
];
3197 if (c
== 0xe0) /* edit key */
3200 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3201 kp_mode
= dos_keypad_mode
& 0x03;
3203 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3208 if (code
== 10 && dos_decimal_point
)
3209 return dos_decimal_point
;
3210 return keypad_translate_map
[code
].char_code
;
3213 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3217 code
= keypad_translate_map
[code
].meta_code
;
3218 modifiers
= meta_modifier
;
3222 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3229 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3230 if (dos_keypad_mode
& kp_mode
)
3231 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3233 code
= grey_key_translate_map
[code
].char_code
;
3242 event
.kind
= non_ascii_keystroke
;
3244 event
.kind
= ascii_keystroke
;
3246 event
.modifiers
= modifiers
;
3247 event
.frame_or_window
= selected_frame
;
3249 event
.timestamp
= event_timestamp ();
3250 kbd_buffer_store_event (&event
);
3253 if (have_mouse
> 0 && !mouse_preempted
)
3255 int but
, press
, x
, y
, ok
;
3256 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3258 /* Check for mouse movement *before* buttons. */
3259 mouse_check_moved ();
3261 /* If the mouse moved from the spot of its last sighting, we
3262 might need to update mouse highlight. */
3263 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3265 previous_help_echo
= help_echo
;
3266 help_echo
= help_echo_object
= help_echo_window
= Qnil
;
3268 IT_note_mouse_highlight (SELECTED_FRAME(),
3269 mouse_last_x
, mouse_last_y
);
3270 /* If the contents of the global variable help_echo has
3271 changed, generate a HELP_EVENT. */
3272 if (!NILP (help_echo
) || !NILP (previous_help_echo
))
3274 /* HELP_EVENT takes 2 events in the event loop. */
3275 event
.kind
= HELP_EVENT
;
3276 event
.frame_or_window
= selected_frame
;
3277 event
.arg
= help_echo_object
;
3278 event
.x
= make_number (help_echo_pos
);
3279 event
.timestamp
= event_timestamp ();
3281 kbd_buffer_store_event (&event
);
3282 if (WINDOWP (help_echo_window
))
3283 event
.frame_or_window
= help_echo_window
;
3284 event
.arg
= help_echo
;
3286 kbd_buffer_store_event (&event
);
3290 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3291 for (press
= 0; press
< 2; press
++)
3293 int button_num
= but
;
3296 ok
= mouse_pressed (but
, &x
, &y
);
3298 ok
= mouse_released (but
, &x
, &y
);
3301 /* Allow a simultaneous press/release of Mouse-1 and
3302 Mouse-2 to simulate Mouse-3 on two-button mice. */
3303 if (mouse_button_count
== 2 && but
< 2)
3305 int x2
, y2
; /* don't clobber original coordinates */
3307 /* If only one button is pressed, wait 100 msec and
3308 check again. This way, Speedy Gonzales isn't
3309 punished, while the slow get their chance. */
3310 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3311 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3316 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3317 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3322 event
.kind
= mouse_click
;
3323 event
.code
= button_num
;
3324 event
.modifiers
= dos_get_modifiers (0)
3325 | (press
? down_modifier
: up_modifier
);
3328 event
.frame_or_window
= selected_frame
;
3330 event
.timestamp
= event_timestamp ();
3331 kbd_buffer_store_event (&event
);
3339 static int prev_get_char
= -1;
3341 /* Return 1 if a key is ready to be read without suspending execution. */
3345 if (prev_get_char
!= -1)
3348 return ((prev_get_char
= dos_rawgetc ()) != -1);
3351 /* Read a key. Return -1 if no key is ready. */
3355 if (prev_get_char
!= -1)
3357 int c
= prev_get_char
;
3362 return dos_rawgetc ();
3365 #ifndef HAVE_X_WINDOWS
3366 /* See xterm.c for more info. */
3368 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
3370 register int pix_x
, pix_y
;
3371 register int *x
, *y
;
3375 if (bounds
) abort ();
3377 /* Ignore clipping. */
3384 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
3387 register int *pix_x
, *pix_y
;
3393 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3396 Actually, I don't know the meaning of all the parameters of the functions
3397 here -- I only know how they are called by xmenu.c. I could of course
3398 grab the nearest Xlib manual (down the hall, second-to-last door on the
3399 left), but I don't think it's worth the effort. */
3401 /* These hold text of the current and the previous menu help messages. */
3402 static char *menu_help_message
, *prev_menu_help_message
;
3403 /* Pane number and item number of the menu item which generated the
3404 last menu help message. */
3405 static int menu_help_paneno
, menu_help_itemno
;
3412 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3413 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3417 /* Allocate some (more) memory for MENU ensuring that there is room for one
3421 IT_menu_make_room (XMenu
*menu
)
3423 if (menu
->allocated
== 0)
3425 int count
= menu
->allocated
= 10;
3426 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3427 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3428 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3429 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3431 else if (menu
->allocated
== menu
->count
)
3433 int count
= menu
->allocated
= menu
->allocated
+ 10;
3435 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3437 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3439 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3441 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3445 /* Search the given menu structure for a given pane number. */
3448 IT_menu_search_pane (XMenu
*menu
, int pane
)
3453 for (i
= 0; i
< menu
->count
; i
++)
3454 if (menu
->submenu
[i
])
3456 if (pane
== menu
->panenumber
[i
])
3457 return menu
->submenu
[i
];
3458 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3464 /* Determine how much screen space a given menu needs. */
3467 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3469 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3472 maxheight
= menu
->count
;
3473 for (i
= 0; i
< menu
->count
; i
++)
3475 if (menu
->submenu
[i
])
3477 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3478 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3479 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3482 *width
= menu
->width
+ maxsubwidth
;
3483 *height
= maxheight
;
3486 /* Display MENU at (X,Y) using FACES. */
3489 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3491 int i
, j
, face
, width
;
3492 struct glyph
*text
, *p
;
3495 int enabled
, mousehere
;
3497 struct frame
*sf
= SELECTED_FRAME();
3499 menu_help_message
= NULL
;
3501 width
= menu
->width
;
3502 text
= (struct glyph
*) xmalloc ((width
+ 2) * sizeof (struct glyph
));
3503 ScreenGetCursor (&row
, &col
);
3504 mouse_get_xy (&mx
, &my
);
3505 IT_update_begin (sf
);
3506 for (i
= 0; i
< menu
->count
; i
++)
3508 int max_width
= width
+ 2;
3510 IT_cursor_to (y
+ i
, x
);
3512 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3513 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
3514 face
= faces
[enabled
+ mousehere
* 2];
3515 /* The following if clause means that we display the menu help
3516 strings even if the menu item is currently disabled. */
3517 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3519 menu_help_message
= menu
->help_text
[i
];
3520 menu_help_paneno
= pn
- 1;
3521 menu_help_itemno
= i
;
3524 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3526 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3530 SET_CHAR_GLYPH (*p
, *q
++, face
, 0);
3533 else /* make '^x' */
3535 SET_CHAR_GLYPH (*p
, '^', face
, 0);
3538 SET_CHAR_GLYPH (*p
, *q
++ + 64, face
, 0);
3542 /* Don't let the menu text overflow into the next screen row. */
3543 if (x
+ max_width
> screen_size_X
)
3545 max_width
= screen_size_X
- x
;
3546 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3548 for (; j
< max_width
- 2; j
++, p
++)
3549 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3551 SET_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3553 IT_write_glyphs (text
, max_width
);
3556 IT_cursor_to (row
, col
);
3560 /* --------------------------- X Menu emulation ---------------------- */
3562 /* Report availability of menus. */
3570 /* Create a brand new menu structure. */
3573 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3575 return IT_menu_create ();
3578 /* Create a new pane and place it on the outer-most level. It is not
3579 clear that it should be placed out there, but I don't know what else
3583 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3591 IT_menu_make_room (menu
);
3592 menu
->submenu
[menu
->count
] = IT_menu_create ();
3593 menu
->text
[menu
->count
] = txt
;
3594 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3595 menu
->help_text
[menu
->count
] = NULL
;
3598 /* Adjust length for possible control characters (which will
3599 be written as ^x). */
3600 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3604 if (len
> menu
->width
)
3607 return menu
->panecount
;
3610 /* Create a new item in a menu pane. */
3613 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3614 int foo
, char *txt
, int enable
, char *help_text
)
3620 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3622 IT_menu_make_room (menu
);
3623 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3624 menu
->text
[menu
->count
] = txt
;
3625 menu
->panenumber
[menu
->count
] = enable
;
3626 menu
->help_text
[menu
->count
] = help_text
;
3629 /* Adjust length for possible control characters (which will
3630 be written as ^x). */
3631 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3635 if (len
> menu
->width
)
3641 /* Decide where the menu would be placed if requested at (X,Y). */
3644 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3645 int *ulx
, int *uly
, int *width
, int *height
)
3647 IT_menu_calc_size (menu
, width
, height
);
3653 struct IT_menu_state
3655 void *screen_behind
;
3662 /* Display menu, wait for user's response, and return that response. */
3665 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3666 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3667 void (*help_callback
)(char *, int, int))
3669 struct IT_menu_state
*state
;
3674 Lisp_Object selectface
;
3675 int leave
, result
, onepane
;
3676 int title_faces
[4]; /* face to display the menu title */
3677 int buffers_num_deleted
= 0;
3678 struct frame
*sf
= SELECTED_FRAME();
3679 Lisp_Object saved_echo_area_message
;
3681 /* Just in case we got here without a mouse present... */
3682 if (have_mouse
<= 0)
3683 return XM_IA_SELECT
;
3684 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3685 around the display. */
3691 /* We will process all the mouse events directly, so we had
3692 better prevent dos_rawgetc from stealing them from us. */
3695 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3696 screensize
= screen_size
* 2;
3698 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3699 0, DEFAULT_FACE_ID
);
3701 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3702 0, DEFAULT_FACE_ID
);
3703 selectface
= intern ("msdos-menu-select-face");
3704 faces
[2] = lookup_derived_face (sf
, selectface
,
3706 faces
[3] = lookup_derived_face (sf
, selectface
,
3709 /* Make sure the menu title is always displayed with
3710 `msdos-menu-active-face', no matter where the mouse pointer is. */
3711 for (i
= 0; i
< 4; i
++)
3712 title_faces
[i
] = faces
[3];
3716 /* Don't let the title for the "Buffers" popup menu include a
3717 digit (which is ugly).
3719 This is a terrible kludge, but I think the "Buffers" case is
3720 the only one where the title includes a number, so it doesn't
3721 seem to be necessary to make this more general. */
3722 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3724 menu
->text
[0][7] = '\0';
3725 buffers_num_deleted
= 1;
3728 /* We need to save the current echo area message, so that we could
3729 restore it below, before we exit. See the commentary below,
3730 before the call to message_with_string. */
3731 saved_echo_area_message
= Fcurrent_message ();
3732 state
[0].menu
= menu
;
3734 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3736 /* Turn off the cursor. Otherwise it shows through the menu
3737 panes, which is ugly. */
3738 IT_display_cursor (0);
3740 /* Display the menu title. */
3741 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3742 if (buffers_num_deleted
)
3743 menu
->text
[0][7] = ' ';
3744 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3746 menu
->width
= menu
->submenu
[0]->width
;
3747 state
[0].menu
= menu
->submenu
[0];
3751 state
[0].menu
= menu
;
3753 state
[0].x
= x0
- 1;
3755 state
[0].pane
= onepane
;
3757 mouse_last_x
= -1; /* A hack that forces display. */
3761 if (!mouse_visible
) mouse_on ();
3762 mouse_check_moved ();
3763 if (sf
->mouse_moved
)
3765 sf
->mouse_moved
= 0;
3766 result
= XM_IA_SELECT
;
3767 mouse_get_xy (&x
, &y
);
3768 for (i
= 0; i
< statecount
; i
++)
3769 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3771 int dy
= y
- state
[i
].y
;
3772 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3774 if (!state
[i
].menu
->submenu
[dy
])
3775 if (state
[i
].menu
->panenumber
[dy
])
3776 result
= XM_SUCCESS
;
3778 result
= XM_IA_SELECT
;
3779 *pane
= state
[i
].pane
- 1;
3781 /* We hit some part of a menu, so drop extra menus that
3782 have been opened. That does not include an open and
3784 if (i
!= statecount
- 2
3785 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3786 while (i
!= statecount
- 1)
3790 ScreenUpdate (state
[statecount
].screen_behind
);
3791 if (screen_virtual_segment
)
3792 dosv_refresh_virtual_screen (0, screen_size
);
3793 xfree (state
[statecount
].screen_behind
);
3795 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3797 IT_menu_display (state
[i
].menu
,
3802 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3803 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3805 ScreenRetrieve (state
[statecount
].screen_behind
3806 = xmalloc (screensize
));
3808 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3809 state
[statecount
].y
= y
;
3814 IT_menu_display (state
[statecount
- 1].menu
,
3815 state
[statecount
- 1].y
,
3816 state
[statecount
- 1].x
,
3817 state
[statecount
- 1].pane
,
3822 if ((menu_help_message
|| prev_menu_help_message
)
3823 && menu_help_message
!= prev_menu_help_message
)
3825 help_callback (menu_help_message
,
3826 menu_help_paneno
, menu_help_itemno
);
3827 IT_display_cursor (0);
3828 prev_menu_help_message
= menu_help_message
;
3830 /* We are busy-waiting for the mouse to move, so let's be nice
3831 to other Windows applications by releasing our time slice. */
3834 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3836 /* Only leave if user both pressed and released the mouse, and in
3837 that order. This avoids popping down the menu pane unless
3838 the user is really done with it. */
3839 if (mouse_pressed (b
, &x
, &y
))
3841 while (mouse_button_depressed (b
, &x
, &y
))
3845 (void) mouse_released (b
, &x
, &y
);
3850 ScreenUpdate (state
[0].screen_behind
);
3851 if (screen_virtual_segment
)
3852 dosv_refresh_virtual_screen (0, screen_size
);
3854 /* We have a situation here. ScreenUpdate has just restored the
3855 screen contents as it was before we started drawing this menu.
3856 That includes any echo area message that could have been
3857 displayed back then. (In reality, that echo area message will
3858 almost always be the ``keystroke echo'' that echoes the sequence
3859 of menu items chosen by the user.) However, if the menu had some
3860 help messages, then displaying those messages caused Emacs to
3861 forget about the original echo area message. So when
3862 ScreenUpdate restored it, it created a discrepancy between the
3863 actual screen contents and what Emacs internal data structures
3866 To avoid this conflict, we force Emacs to restore the original
3867 echo area message as we found it when we entered this function.
3868 The irony of this is that we then erase the restored message
3869 right away, so the only purpose of restoring it is so that
3870 erasing it works correctly... */
3871 if (! NILP (saved_echo_area_message
))
3872 message_with_string ("%s", saved_echo_area_message
, 0);
3874 while (statecount
--)
3875 xfree (state
[statecount
].screen_behind
);
3876 IT_display_cursor (1); /* turn cursor back on */
3877 /* Clean up any mouse events that are waiting inside Emacs event queue.
3878 These events are likely to be generated before the menu was even
3879 displayed, probably because the user pressed and released the button
3880 (which invoked the menu) too quickly. If we don't remove these events,
3881 Emacs will process them after we return and surprise the user. */
3882 discard_mouse_events ();
3883 /* Allow mouse events generation by dos_rawgetc. */
3888 /* Dispose of a menu. */
3891 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3894 if (menu
->allocated
)
3896 for (i
= 0; i
< menu
->count
; i
++)
3897 if (menu
->submenu
[i
])
3898 XMenuDestroy (foo
, menu
->submenu
[i
]);
3900 xfree (menu
->submenu
);
3901 xfree (menu
->panenumber
);
3902 xfree (menu
->help_text
);
3905 menu_help_message
= prev_menu_help_message
= NULL
;
3909 x_pixel_width (struct frame
*f
)
3911 return FRAME_WIDTH (f
);
3915 x_pixel_height (struct frame
*f
)
3917 return FRAME_HEIGHT (f
);
3919 #endif /* !HAVE_X_WINDOWS */
3921 /* ----------------------- DOS / UNIX conversion --------------------- */
3923 void msdos_downcase_filename (unsigned char *);
3925 /* Destructively turn backslashes into slashes. */
3928 dostounix_filename (p
)
3931 msdos_downcase_filename (p
);
3941 /* Destructively turn slashes into backslashes. */
3944 unixtodos_filename (p
)
3947 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3961 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3964 getdefdir (drive
, dst
)
3968 char in_path
[4], *p
= in_path
;
3971 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3974 *p
++ = drive
+ 'A' - 1;
3981 _fixpath (in_path
, dst
);
3982 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3983 it queries the LFN support, so ignore that error. */
3984 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
3987 msdos_downcase_filename (dst
);
3993 /* Remove all CR's that are followed by a LF. */
3998 register unsigned char *buf
;
4000 unsigned char *np
= buf
;
4001 unsigned char *startp
= buf
;
4002 unsigned char *endp
= buf
+ n
;
4006 while (buf
< endp
- 1)
4010 if (*(++buf
) != 0x0a)
4021 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4023 /* In DJGPP v2.0, library `write' can call `malloc', which might
4024 cause relocation of the buffer whose address we get in ADDR.
4025 Here is a version of `write' that avoids calling `malloc',
4026 to serve us until such time as the library is fixed.
4027 Actually, what we define here is called `__write', because
4028 `write' is a stub that just jmp's to `__write' (to be
4029 POSIXLY-correct with respect to the global name-space). */
4031 #include <io.h> /* for _write */
4032 #include <libc/dosio.h> /* for __file_handle_modes[] */
4034 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
4036 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4039 __write (int handle
, const void *buffer
, size_t count
)
4044 if(__file_handle_modes
[handle
] & O_BINARY
)
4045 return _write (handle
, buffer
, count
);
4049 const char *bp
= buffer
;
4050 int total_written
= 0;
4051 int nmoved
= 0, ncr
= 0;
4055 /* The next test makes sure there's space for at least 2 more
4056 characters in xbuf[], so both CR and LF can be put there. */
4068 if (xbp
>= XBUF_END
|| !count
)
4070 size_t to_write
= nmoved
+ ncr
;
4071 int written
= _write (handle
, xbuf
, to_write
);
4076 total_written
+= nmoved
; /* CRs aren't counted in ret value */
4078 /* If some, but not all were written (disk full?), return
4079 an estimate of the total written bytes not counting CRs. */
4080 if (written
< to_write
)
4081 return total_written
- (to_write
- written
) * nmoved
/to_write
;
4088 return total_written
;
4092 /* A low-level file-renaming function which works around Windows 95 bug.
4093 This is pulled directly out of DJGPP v2.01 library sources, and only
4094 used when you compile with DJGPP v2.0. */
4098 int _rename(const char *old
, const char *new)
4101 int olen
= strlen(old
) + 1;
4103 int use_lfn
= _USE_LFN
;
4104 char tempfile
[FILENAME_MAX
];
4105 const char *orig
= old
;
4108 r
.x
.dx
= __tb_offset
;
4109 r
.x
.di
= __tb_offset
+ olen
;
4110 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4114 /* Windows 95 bug: for some filenames, when you rename
4115 file -> file~ (as in Emacs, to leave a backup), the
4116 short 8+3 alias doesn't change, which effectively
4117 makes OLD and NEW the same file. We must rename
4118 through a temporary file to work around this. */
4120 char *pbase
= 0, *p
;
4121 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4122 int idx
= sizeof(try_char
) - 1;
4124 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4125 might point to another drive, which will fail the DOS call. */
4126 strcpy(tempfile
, old
);
4127 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4128 if (*p
== '/' || *p
== '\\' || *p
== ':')
4134 strcpy(pbase
, "X$$djren$$.$$temp$$");
4140 *pbase
= try_char
[--idx
];
4141 } while (_chmod(tempfile
, 0) != -1);
4144 _put_path2(tempfile
, olen
);
4146 __dpmi_int(0x21, &r
);
4149 errno
= __doserr_to_errno(r
.x
.ax
);
4153 /* Now create a file with the original name. This will
4154 ensure that NEW will always have a 8+3 alias
4155 different from that of OLD. (Seems to be required
4156 when NameNumericTail in the Registry is set to 0.) */
4157 lfn_fd
= _creat(old
, 0);
4159 olen
= strlen(tempfile
) + 1;
4161 r
.x
.di
= __tb_offset
+ olen
;
4170 _put_path2(new, olen
);
4172 __dpmi_int(0x21, &r
);
4175 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4176 remove(new); /* and try again */
4179 errno
= __doserr_to_errno(r
.x
.ax
);
4181 /* Restore to original name if we renamed it to temporary. */
4189 _put_path2(orig
, olen
);
4190 _put_path(tempfile
);
4192 __dpmi_int(0x21, &r
);
4201 /* Success. Delete the file possibly created to work
4202 around the Windows 95 bug. */
4204 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4208 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4210 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4212 "Return non-nil if long file names are supported on MSDOS.")
4215 return (_USE_LFN
? Qt
: Qnil
);
4218 /* Convert alphabetic characters in a filename to lower-case. */
4221 msdos_downcase_filename (p
)
4222 register unsigned char *p
;
4224 /* Always lower-case drive letters a-z, even if the filesystem
4225 preserves case in filenames.
4226 This is so MSDOS filenames could be compared by string comparison
4227 functions that are case-sensitive. Even case-preserving filesystems
4228 do not distinguish case in drive letters. */
4229 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4235 /* Under LFN we expect to get pathnames in their true case. */
4236 if (NILP (Fmsdos_long_file_names ()))
4238 if (*p
>= 'A' && *p
<= 'Z')
4242 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4244 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
4245 When long filenames are supported, doesn't change FILENAME.\n\
4246 If FILENAME is not a string, returns nil.\n\
4247 The argument object is never altered--the value is a copy.")
4249 Lisp_Object filename
;
4253 if (! STRINGP (filename
))
4256 tem
= Fcopy_sequence (filename
);
4257 msdos_downcase_filename (XSTRING (tem
)->data
);
4261 /* The Emacs root directory as determined by init_environment. */
4263 static char emacsroot
[MAXPATHLEN
];
4266 rootrelativepath (rel
)
4269 static char result
[MAXPATHLEN
+ 10];
4271 strcpy (result
, emacsroot
);
4272 strcat (result
, "/");
4273 strcat (result
, rel
);
4277 /* Define a lot of environment variables if not already defined. Don't
4278 remove anything unless you know what you're doing -- lots of code will
4279 break if one or more of these are missing. */
4282 init_environment (argc
, argv
, skip_args
)
4289 static const char * const tempdirs
[] = {
4290 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4293 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4295 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4296 temporary files and assume "/tmp" if $TMPDIR is unset, which
4297 will break on DOS/Windows. Refuse to work if we cannot find
4298 a directory, not even "c:/", usable for that purpose. */
4299 for (i
= 0; i
< imax
; i
++)
4301 const char *tmp
= tempdirs
[i
];
4304 tmp
= getenv (tmp
+ 1);
4305 /* Note that `access' can lie to us if the directory resides on a
4306 read-only filesystem, like CD-ROM or a write-protected floppy.
4307 The only way to be really sure is to actually create a file and
4308 see if it succeeds. But I think that's too much to ask. */
4309 if (tmp
&& access (tmp
, D_OK
) == 0)
4311 setenv ("TMPDIR", tmp
, 1);
4318 Fcons (build_string ("no usable temporary directories found!!"),
4320 "While setting TMPDIR: ");
4322 /* Note the startup time, so we know not to clear the screen if we
4323 exit immediately; see IT_reset_terminal_modes.
4324 (Yes, I know `clock' returns zero the first time it's called, but
4325 I do this anyway, in case some wiseguy changes that at some point.) */
4326 startup_time
= clock ();
4328 /* Find our root from argv[0]. Assuming argv[0] is, say,
4329 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4330 root
= alloca (MAXPATHLEN
+ 20);
4331 _fixpath (argv
[0], root
);
4332 msdos_downcase_filename (root
);
4333 len
= strlen (root
);
4334 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4338 && (strcmp (root
+ len
- 4, "/bin") == 0
4339 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4340 root
[len
- 4] = '\0';
4342 strcpy (root
, "c:/emacs"); /* let's be defensive */
4343 len
= strlen (root
);
4344 strcpy (emacsroot
, root
);
4346 /* We default HOME to our root. */
4347 setenv ("HOME", root
, 0);
4349 /* We default EMACSPATH to root + "/bin". */
4350 strcpy (root
+ len
, "/bin");
4351 setenv ("EMACSPATH", root
, 0);
4353 /* I don't expect anybody to ever use other terminals so the internal
4354 terminal is the default. */
4355 setenv ("TERM", "internal", 0);
4357 #ifdef HAVE_X_WINDOWS
4358 /* Emacs expects DISPLAY to be set. */
4359 setenv ("DISPLAY", "unix:0.0", 0);
4362 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4363 downcase it and mirror the backslashes. */
4364 s
= getenv ("COMSPEC");
4365 if (!s
) s
= "c:/command.com";
4366 t
= alloca (strlen (s
) + 1);
4368 dostounix_filename (t
);
4369 setenv ("SHELL", t
, 0);
4371 /* PATH is also downcased and backslashes mirrored. */
4372 s
= getenv ("PATH");
4374 t
= alloca (strlen (s
) + 3);
4375 /* Current directory is always considered part of MsDos's path but it is
4376 not normally mentioned. Now it is. */
4377 strcat (strcpy (t
, ".;"), s
);
4378 dostounix_filename (t
); /* Not a single file name, but this should work. */
4379 setenv ("PATH", t
, 1);
4381 /* In some sense all dos users have root privileges, so... */
4382 setenv ("USER", "root", 0);
4383 setenv ("NAME", getenv ("USER"), 0);
4385 /* Time zone determined from country code. To make this possible, the
4386 country code may not span more than one time zone. In other words,
4387 in the USA, you lose. */
4389 switch (dos_country_code
)
4391 case 31: /* Belgium */
4392 case 32: /* The Netherlands */
4393 case 33: /* France */
4394 case 34: /* Spain */
4395 case 36: /* Hungary */
4396 case 38: /* Yugoslavia (or what's left of it?) */
4397 case 39: /* Italy */
4398 case 41: /* Switzerland */
4399 case 42: /* Tjekia */
4400 case 45: /* Denmark */
4401 case 46: /* Sweden */
4402 case 47: /* Norway */
4403 case 48: /* Poland */
4404 case 49: /* Germany */
4405 /* Daylight saving from last Sunday in March to last Sunday in
4406 September, both at 2AM. */
4407 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4409 case 44: /* United Kingdom */
4410 case 351: /* Portugal */
4411 case 354: /* Iceland */
4412 setenv ("TZ", "GMT+00", 0);
4414 case 81: /* Japan */
4415 case 82: /* Korea */
4416 setenv ("TZ", "JST-09", 0);
4418 case 90: /* Turkey */
4419 case 358: /* Finland */
4420 setenv ("TZ", "EET-02", 0);
4422 case 972: /* Israel */
4423 /* This is an approximation. (For exact rules, use the
4424 `zoneinfo/israel' file which comes with DJGPP, but you need
4425 to install it in `/usr/share/zoneinfo/' directory first.) */
4426 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4434 static int break_stat
; /* BREAK check mode status. */
4435 static int stdin_stat
; /* stdin IOCTL status. */
4439 /* These must be global. */
4440 static _go32_dpmi_seginfo ctrl_break_vector
;
4441 static _go32_dpmi_registers ctrl_break_regs
;
4442 static int ctrlbreakinstalled
= 0;
4444 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4447 ctrl_break_func (regs
)
4448 _go32_dpmi_registers
*regs
;
4454 install_ctrl_break_check ()
4456 if (!ctrlbreakinstalled
)
4458 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4459 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4460 ctrlbreakinstalled
= 1;
4461 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4462 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4464 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4468 #endif /* __DJGPP__ < 2 */
4470 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4471 control chars by DOS. Determine the keyboard type. */
4476 union REGS inregs
, outregs
;
4477 static int first_time
= 1;
4479 break_stat
= getcbrk ();
4482 install_ctrl_break_check ();
4488 int86 (0x15, &inregs
, &outregs
);
4489 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4493 if (internal_terminal
4494 #ifdef HAVE_X_WINDOWS
4495 && inhibit_window_system
4499 inregs
.x
.ax
= 0x0021;
4500 int86 (0x33, &inregs
, &outregs
);
4501 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4504 /* Reportedly, the above doesn't work for some mouse drivers. There
4505 is an additional detection method that should work, but might be
4506 a little slower. Use that as an alternative. */
4507 inregs
.x
.ax
= 0x0000;
4508 int86 (0x33, &inregs
, &outregs
);
4509 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4514 have_mouse
= 1; /* enable mouse */
4517 if (outregs
.x
.bx
== 3)
4519 mouse_button_count
= 3;
4520 mouse_button_translate
[0] = 0; /* Left */
4521 mouse_button_translate
[1] = 2; /* Middle */
4522 mouse_button_translate
[2] = 1; /* Right */
4526 mouse_button_count
= 2;
4527 mouse_button_translate
[0] = 0;
4528 mouse_button_translate
[1] = 1;
4530 mouse_position_hook
= &mouse_get_pos
;
4534 #ifndef HAVE_X_WINDOWS
4536 /* Save the cursor shape used outside Emacs. */
4537 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4546 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4547 return (stdin_stat
!= -1);
4550 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4552 #else /* __DJGPP__ < 2 */
4556 /* I think it is wrong to overwrite `stdin_stat' every time
4557 but the first one this function is called, but I don't
4558 want to change the way it used to work in v1.x.--EZ */
4560 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4561 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4562 intdos (&inregs
, &outregs
);
4563 stdin_stat
= outregs
.h
.dl
;
4565 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4566 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4567 intdos (&inregs
, &outregs
);
4568 return !outregs
.x
.cflag
;
4570 #endif /* __DJGPP__ < 2 */
4573 /* Restore status of standard input and Ctrl-C checking. */
4578 union REGS inregs
, outregs
;
4580 setcbrk (break_stat
);
4585 #ifndef HAVE_X_WINDOWS
4586 /* Restore the cursor shape we found on startup. */
4590 inregs
.x
.cx
= outside_cursor
;
4591 int86 (0x10, &inregs
, &outregs
);
4595 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4597 #else /* not __DJGPP__ >= 2 */
4599 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4600 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4601 inregs
.x
.dx
= stdin_stat
;
4602 intdos (&inregs
, &outregs
);
4603 return !outregs
.x
.cflag
;
4605 #endif /* not __DJGPP__ >= 2 */
4609 /* Run command as specified by ARGV in directory DIR.
4610 The command is run with input from TEMPIN, output to
4611 file TEMPOUT and stderr to TEMPERR. */
4614 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4615 unsigned char **argv
;
4616 const char *working_dir
;
4617 int tempin
, tempout
, temperr
;
4620 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4621 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4622 int msshell
, result
= -1;
4623 int inbak
, outbak
, errbak
;
4627 /* Get current directory as MSDOS cwd is not per-process. */
4630 /* If argv[0] is the shell, it might come in any lettercase.
4631 Since `Fmember' is case-sensitive, we need to downcase
4632 argv[0], even if we are on case-preserving filesystems. */
4633 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4634 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4637 if (*pl
>= 'A' && *pl
<= 'Z')
4642 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4643 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4644 && !strcmp ("-c", argv
[1]);
4647 saveargv1
= argv
[1];
4648 saveargv2
= argv
[2];
4652 char *p
= alloca (strlen (argv
[2]) + 1);
4654 strcpy (argv
[2] = p
, saveargv2
);
4655 while (*p
&& isspace (*p
))
4657 while (*p
&& !isspace (*p
))
4665 chdir (working_dir
);
4669 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4670 goto done
; /* Allocation might fail due to lack of descriptors. */
4673 mouse_get_xy (&x
, &y
);
4675 dos_ttcooked (); /* do it here while 0 = stdin */
4683 if (msshell
&& !argv
[3])
4685 /* MS-DOS native shells are too restrictive. For starters, they
4686 cannot grok commands longer than 126 characters. In DJGPP v2
4687 and later, `system' is much smarter, so we'll call it instead. */
4691 /* A shell gets a single argument--its full command
4692 line--whose original was saved in `saveargv2'. */
4694 /* Don't let them pass empty command lines to `system', since
4695 with some shells it will try to invoke an interactive shell,
4696 which will hang Emacs. */
4697 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4701 extern char **environ
;
4702 int save_system_flags
= __system_flags
;
4704 /* Request the most powerful version of `system'. We need
4705 all the help we can get to avoid calling stock DOS shells. */
4706 __system_flags
= (__system_redirect
4707 | __system_use_shell
4708 | __system_allow_multiple_cmds
4709 | __system_allow_long_cmds
4710 | __system_handle_null_commands
4711 | __system_emulate_chdir
);
4714 result
= system (cmnd
);
4715 __system_flags
= save_system_flags
;
4718 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4722 #endif /* __DJGPP__ > 1 */
4724 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4729 emacs_close (inbak
);
4730 emacs_close (outbak
);
4731 emacs_close (errbak
);
4737 mouse_moveto (x
, y
);
4740 /* Some programs might change the meaning of the highest bit of the
4741 text attribute byte, so we get blinking characters instead of the
4742 bright background colors. Restore that. */
4749 argv
[1] = saveargv1
;
4750 argv
[2] = saveargv2
;
4758 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4765 /* ------------------------- Compatibility functions -------------------
4770 /* Hostnames for a pc are not really funny,
4771 but they are used in change log so we emulate the best we can. */
4773 gethostname (p
, size
)
4777 char *q
= egetenv ("HOSTNAME");
4784 /* When time zones are set from Ms-Dos too many C-libraries are playing
4785 tricks with time values. We solve this by defining our own version
4786 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4787 once and after each call to `tzset' with TZ changed. That is
4788 accomplished by aliasing tzset to init_gettimeofday. */
4790 static struct tm time_rec
;
4793 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4801 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4805 time_rec
.tm_year
= d
.da_year
- 1900;
4806 time_rec
.tm_mon
= d
.da_mon
- 1;
4807 time_rec
.tm_mday
= d
.da_day
;
4810 time_rec
.tm_hour
= t
.ti_hour
;
4811 time_rec
.tm_min
= t
.ti_min
;
4812 time_rec
.tm_sec
= t
.ti_sec
;
4815 tm
.tm_gmtoff
= dos_timezone_offset
;
4817 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4818 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4820 /* Ignore tzp; it's obsolescent. */
4824 #endif /* __DJGPP__ < 2 */
4827 * A list of unimplemented functions that we silently ignore.
4831 unsigned alarm (s
) unsigned s
; {}
4832 fork () { return 0; }
4833 int kill (x
, y
) int x
, y
; { return -1; }
4835 void volatile pause () {}
4836 sigsetmask (x
) int x
; { return 0; }
4837 sigblock (mask
) int mask
; { return 0; }
4840 void request_sigio (void) {}
4841 setpgrp () {return 0; }
4842 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4843 void unrequest_sigio (void) {}
4847 #ifdef POSIX_SIGNALS
4849 /* Augment DJGPP library POSIX signal functions. This is needed
4850 as of DJGPP v2.01, but might be in the library in later releases. */
4852 #include <libc/bss.h>
4854 /* A counter to know when to re-initialize the static sets. */
4855 static int sigprocmask_count
= -1;
4857 /* Which signals are currently blocked (initially none). */
4858 static sigset_t current_mask
;
4860 /* Which signals are pending (initially none). */
4861 static sigset_t pending_signals
;
4863 /* Previous handlers to restore when the blocked signals are unblocked. */
4864 typedef void (*sighandler_t
)(int);
4865 static sighandler_t prev_handlers
[320];
4867 /* A signal handler which just records that a signal occured
4868 (it will be raised later, if and when the signal is unblocked). */
4870 sig_suspender (signo
)
4873 sigaddset (&pending_signals
, signo
);
4877 sigprocmask (how
, new_set
, old_set
)
4879 const sigset_t
*new_set
;
4885 /* If called for the first time, initialize. */
4886 if (sigprocmask_count
!= __bss_count
)
4888 sigprocmask_count
= __bss_count
;
4889 sigemptyset (&pending_signals
);
4890 sigemptyset (¤t_mask
);
4891 for (signo
= 0; signo
< 320; signo
++)
4892 prev_handlers
[signo
] = SIG_ERR
;
4896 *old_set
= current_mask
;
4901 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4907 sigemptyset (&new_mask
);
4909 /* DJGPP supports upto 320 signals. */
4910 for (signo
= 0; signo
< 320; signo
++)
4912 if (sigismember (¤t_mask
, signo
))
4913 sigaddset (&new_mask
, signo
);
4914 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4916 sigaddset (&new_mask
, signo
);
4918 /* SIGKILL is silently ignored, as on other platforms. */
4919 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4920 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4922 if (( how
== SIG_UNBLOCK
4923 && sigismember (&new_mask
, signo
)
4924 && sigismember (new_set
, signo
))
4925 || (how
== SIG_SETMASK
4926 && sigismember (&new_mask
, signo
)
4927 && !sigismember (new_set
, signo
)))
4929 sigdelset (&new_mask
, signo
);
4930 if (prev_handlers
[signo
] != SIG_ERR
)
4932 signal (signo
, prev_handlers
[signo
]);
4933 prev_handlers
[signo
] = SIG_ERR
;
4935 if (sigismember (&pending_signals
, signo
))
4937 sigdelset (&pending_signals
, signo
);
4942 current_mask
= new_mask
;
4946 #else /* not POSIX_SIGNALS */
4948 sigsetmask (x
) int x
; { return 0; }
4949 sigblock (mask
) int mask
; { return 0; }
4951 #endif /* not POSIX_SIGNALS */
4952 #endif /* __DJGPP__ > 1 */
4955 #include "sysselect.h"
4957 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4958 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4959 ((long)(time).tv_sec < 0 \
4960 || ((time).tv_sec == 0 \
4961 && (long)(time).tv_usec <= 0))
4964 /* This yields the rest of the current time slice to the task manager.
4965 It should be called by any code which knows that it has nothing
4966 useful to do except idle.
4968 I don't use __dpmi_yield here, since versions of library before 2.02
4969 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4970 on some versions of Windows 9X. */
4973 dos_yield_time_slice (void)
4975 _go32_dpmi_registers r
;
4978 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
4979 _go32_dpmi_simulate_int (0x2f, &r
);
4984 /* Only event queue is checked. */
4985 /* We don't have to call timer_check here
4986 because wait_reading_process_input takes care of that. */
4988 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
4990 SELECT_TYPE
*rfds
, *wfds
, *efds
;
4991 EMACS_TIME
*timeout
;
4999 check_input
= FD_ISSET (0, rfds
);
5010 /* If we are looking only for the terminal, with no timeout,
5011 just read it and wait -- that's more efficient. */
5014 while (!detect_input_pending ())
5016 dos_yield_time_slice ();
5021 EMACS_TIME clnow
, cllast
, cldiff
;
5024 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
5026 while (!check_input
|| !detect_input_pending ())
5029 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
5030 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
5032 /* When seconds wrap around, we assume that no more than
5033 1 minute passed since last `gettime'. */
5034 if (EMACS_TIME_NEG_P (cldiff
))
5035 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
5036 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
5038 /* Stop when timeout value crosses zero. */
5039 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
5042 dos_yield_time_slice ();
5052 * Define overlaid functions:
5054 * chdir -> sys_chdir
5055 * tzset -> init_gettimeofday
5056 * abort -> dos_abort
5061 extern int chdir ();
5067 int len
= strlen (path
);
5068 char *tmp
= (char *)path
;
5070 if (*tmp
&& tmp
[1] == ':')
5072 if (getdisk () != tolower (tmp
[0]) - 'a')
5073 setdisk (tolower (tmp
[0]) - 'a');
5074 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
5078 if (len
> 1 && (tmp
[len
- 1] == '/'))
5080 char *tmp1
= (char *) alloca (len
+ 1);
5091 extern void tzset (void);
5094 init_gettimeofday ()
5100 ltm
= gtm
= time (NULL
);
5101 ltm
= mktime (lstm
= localtime (<m
));
5102 gtm
= mktime (gmtime (>m
));
5103 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
5104 time_rec
.tm_isdst
= lstm
->tm_isdst
;
5105 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
5112 dos_abort (file
, line
)
5116 char buffer1
[200], buffer2
[400];
5119 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5120 for (i
= j
= 0; buffer1
[i
]; i
++) {
5121 buffer2
[j
++] = buffer1
[i
];
5122 buffer2
[j
++] = 0x70;
5124 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5125 ScreenSetCursor (2, 0);
5133 ScreenSetCursor (10, 0);
5134 cputs ("\r\n\nEmacs aborted!\r\n");
5136 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5137 if (screen_virtual_segment
)
5138 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5139 /* Generate traceback, so we could tell whodunit. */
5140 signal (SIGINT
, SIG_DFL
);
5141 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5142 #else /* __DJGPP_MINOR__ >= 2 */
5144 #endif /* __DJGPP_MINOR__ >= 2 */
5150 /* The following variables are required so that cus-start.el won't
5151 complain about unbound variables. */
5152 #ifndef HAVE_X_WINDOWS
5153 /* Search path for bitmap files (xfns.c). */
5154 Lisp_Object Vx_bitmap_file_path
;
5155 int x_stretch_cursor_p
;
5157 #ifndef subprocesses
5158 /* Nonzero means delete a process right away if it exits (process.c). */
5159 static int delete_exited_processes
;
5164 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5165 staticpro (&recent_doskeys
);
5166 #ifndef HAVE_X_WINDOWS
5168 staticpro (&help_echo
);
5169 help_echo_object
= Qnil
;
5170 staticpro (&help_echo_object
);
5171 help_echo_window
= Qnil
;
5172 staticpro (&help_echo_window
);
5173 previous_help_echo
= Qnil
;
5174 staticpro (&previous_help_echo
);
5177 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
5178 "List of directories to search for bitmap files for X.");
5179 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
5181 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p
,
5182 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
5183 For example, if a block cursor is over a tab, it will be drawn as\n\
5184 wide as that tab on the display. (No effect on MS-DOS.)");
5185 x_stretch_cursor_p
= 0;
5187 /* The following three are from xfns.c: */
5188 Qbackground_color
= intern ("background-color");
5189 staticpro (&Qbackground_color
);
5190 Qforeground_color
= intern ("foreground-color");
5191 staticpro (&Qforeground_color
);
5192 Qbar
= intern ("bar");
5194 Qcursor_type
= intern ("cursor-type");
5195 staticpro (&Qcursor_type
);
5196 Qreverse
= intern ("reverse");
5197 staticpro (&Qreverse
);
5199 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5200 "*Glyph to display instead of chars not supported by current codepage.\n\
5202 This variable is used only by MSDOS terminals.");
5203 Vdos_unsupported_char_glyph
= '\177';
5205 #ifndef subprocesses
5206 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5207 "*Non-nil means delete processes immediately when they exit.\n\
5208 nil means don't delete them until `list-processes' is run.");
5209 delete_exited_processes
= 0;
5212 defsubr (&Srecent_doskeys
);
5213 defsubr (&Smsdos_long_file_names
);
5214 defsubr (&Smsdos_downcase_filename
);
5215 defsubr (&Smsdos_remember_default_colors
);