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 /* Sort overlays into increasing priority order. */
1541 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1543 /* Check mouse-face highlighting. */
1544 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1545 && y
>= dpyinfo
->mouse_face_beg_row
1546 && y
<= dpyinfo
->mouse_face_end_row
1547 && (y
> dpyinfo
->mouse_face_beg_row
1548 || x
>= dpyinfo
->mouse_face_beg_col
)
1549 && (y
< dpyinfo
->mouse_face_end_row
1550 || x
< dpyinfo
->mouse_face_end_col
1551 || dpyinfo
->mouse_face_past_end
)))
1553 /* Clear the display of the old active region, if any. */
1554 clear_mouse_face (dpyinfo
);
1556 /* Find highest priority overlay that has a mouse-face prop. */
1558 for (i
= noverlays
- 1; i
>= 0; --i
)
1560 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1561 if (!NILP (mouse_face
))
1563 overlay
= overlay_vec
[i
];
1568 /* If no overlay applies, get a text property. */
1570 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1573 /* Handle the overlay case. */
1574 if (! NILP (overlay
))
1576 /* Find the range of text around this char that
1577 should be active. */
1578 Lisp_Object before
, after
;
1581 before
= Foverlay_start (overlay
);
1582 after
= Foverlay_end (overlay
);
1583 /* Record this as the current active region. */
1584 fast_find_position (w
, XFASTINT (before
),
1585 &dpyinfo
->mouse_face_beg_col
,
1586 &dpyinfo
->mouse_face_beg_row
);
1587 dpyinfo
->mouse_face_past_end
1588 = !fast_find_position (w
, XFASTINT (after
),
1589 &dpyinfo
->mouse_face_end_col
,
1590 &dpyinfo
->mouse_face_end_row
);
1591 dpyinfo
->mouse_face_window
= window
;
1592 dpyinfo
->mouse_face_face_id
1593 = face_at_buffer_position (w
, pos
, 0, 0,
1594 &ignore
, pos
+ 1, 1);
1596 /* Display it as active. */
1597 show_mouse_face (dpyinfo
, 1);
1599 /* Handle the text property case. */
1600 else if (! NILP (mouse_face
))
1602 /* Find the range of text around this char that
1603 should be active. */
1604 Lisp_Object before
, after
, beginning
, end
;
1607 beginning
= Fmarker_position (w
->start
);
1608 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1609 - XFASTINT (w
->window_end_pos
)));
1611 = Fprevious_single_property_change (make_number (pos
+ 1),
1613 w
->buffer
, beginning
);
1615 = Fnext_single_property_change (position
, Qmouse_face
,
1617 /* Record this as the current active region. */
1618 fast_find_position (w
, XFASTINT (before
),
1619 &dpyinfo
->mouse_face_beg_col
,
1620 &dpyinfo
->mouse_face_beg_row
);
1621 dpyinfo
->mouse_face_past_end
1622 = !fast_find_position (w
, XFASTINT (after
),
1623 &dpyinfo
->mouse_face_end_col
,
1624 &dpyinfo
->mouse_face_end_row
);
1625 dpyinfo
->mouse_face_window
= window
;
1626 dpyinfo
->mouse_face_face_id
1627 = face_at_buffer_position (w
, pos
, 0, 0,
1628 &ignore
, pos
+ 1, 1);
1630 /* Display it as active. */
1631 show_mouse_face (dpyinfo
, 1);
1635 /* Look for a `help-echo' property. */
1638 extern Lisp_Object Qhelp_echo
;
1640 /* Check overlays first. */
1642 for (i
= noverlays
- 1; i
>= 0 && NILP (help
); --i
)
1644 overlay
= overlay_vec
[i
];
1645 help
= Foverlay_get (overlay
, Qhelp_echo
);
1651 help_echo_window
= window
;
1652 help_echo_object
= overlay
;
1653 help_echo_pos
= pos
;
1655 /* Try text properties. */
1656 else if (NILP (help
)
1657 && ((STRINGP (glyph
->object
)
1658 && glyph
->charpos
>= 0
1659 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1660 || (BUFFERP (glyph
->object
)
1661 && glyph
->charpos
>= BEGV
1662 && glyph
->charpos
< ZV
)))
1664 help
= Fget_text_property (make_number (glyph
->charpos
),
1665 Qhelp_echo
, glyph
->object
);
1669 help_echo_window
= window
;
1670 help_echo_object
= glyph
->object
;
1671 help_echo_pos
= glyph
->charpos
;
1678 current_buffer
= obuf
;
1684 IT_clear_end_of_line (int first_unused
)
1688 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1689 extern int fatal_error_in_progress
;
1691 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1695 i
= (j
= first_unused
- new_pos_X
) * 2;
1697 fprintf (termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1698 spaces
= sp
= alloca (i
);
1703 *sp
++ = ScreenAttrib
;
1707 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1708 if (screen_virtual_segment
)
1709 dosv_refresh_virtual_screen (offset
, i
/ 2);
1711 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1712 Let's follow their lead, in case someone relies on this. */
1713 new_pos_X
= first_unused
;
1717 IT_clear_screen (void)
1720 fprintf (termscript
, "<CLR:SCR>");
1724 if (screen_virtual_segment
)
1725 dosv_refresh_virtual_screen (0, screen_size
);
1726 new_pos_X
= new_pos_Y
= 0;
1730 IT_clear_to_end (void)
1733 fprintf (termscript
, "<CLR:EOS>");
1735 while (new_pos_Y
< screen_size_Y
) {
1737 IT_clear_end_of_line (screen_size_X
);
1743 IT_cursor_to (int y
, int x
)
1746 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
1751 static int cursor_cleared
;
1754 IT_display_cursor (int on
)
1756 if (on
&& cursor_cleared
)
1758 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1761 else if (!on
&& !cursor_cleared
)
1763 ScreenSetCursor (-1, -1);
1768 /* Emacs calls cursor-movement functions a lot when it updates the
1769 display (probably a legacy of old terminals where you cannot
1770 update a screen line without first moving the cursor there).
1771 However, cursor movement is expensive on MSDOS (it calls a slow
1772 BIOS function and requires 2 mode switches), while actual screen
1773 updates access the video memory directly and don't depend on
1774 cursor position. To avoid slowing down the redisplay, we cheat:
1775 all functions that move the cursor only set internal variables
1776 which record the cursor position, whereas the cursor is only
1777 moved to its final position whenever screen update is complete.
1779 `IT_cmgoto' is called from the keyboard reading loop and when the
1780 frame update is complete. This means that we are ready for user
1781 input, so we update the cursor position to show where the point is,
1782 and also make the mouse pointer visible.
1784 Special treatment is required when the cursor is in the echo area,
1785 to put the cursor at the end of the text displayed there. */
1788 IT_cmgoto (FRAME_PTR f
)
1790 /* Only set the cursor to where it should be if the display is
1791 already in sync with the window contents. */
1792 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1794 /* FIXME: This needs to be rewritten for the new redisplay, or
1797 static int previous_pos_X
= -1;
1799 update_cursor_pos
= 1; /* temporary!!! */
1801 /* If the display is in sync, forget any previous knowledge about
1802 cursor position. This is primarily for unexpected events like
1803 C-g in the minibuffer. */
1804 if (update_cursor_pos
&& previous_pos_X
>= 0)
1805 previous_pos_X
= -1;
1806 /* If we are in the echo area, put the cursor at the
1807 end of the echo area message. */
1808 if (!update_cursor_pos
1809 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1811 int tem_X
= current_pos_X
, dummy
;
1813 if (echo_area_glyphs
)
1815 tem_X
= echo_area_glyphs_length
;
1816 /* Save current cursor position, to be restored after the
1817 echo area message is erased. Only remember one level
1818 of previous cursor position. */
1819 if (previous_pos_X
== -1)
1820 ScreenGetCursor (&dummy
, &previous_pos_X
);
1822 else if (previous_pos_X
>= 0)
1824 /* We wind up here after the echo area message is erased.
1825 Restore the cursor position we remembered above. */
1826 tem_X
= previous_pos_X
;
1827 previous_pos_X
= -1;
1830 if (current_pos_X
!= tem_X
)
1833 update_cursor_pos
= 1;
1838 if (update_cursor_pos
1839 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1841 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1843 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1846 /* Maybe cursor is invisible, so make it visible. */
1847 IT_display_cursor (1);
1849 /* Mouse pointer should be always visible if we are waiting for
1856 IT_reassert_line_highlight (int new, int vpos
)
1862 IT_change_line_highlight (int new_highlight
, int y
, int vpos
, int first_unused_hpos
)
1864 highlight
= new_highlight
;
1865 IT_cursor_to (vpos
, 0);
1866 IT_clear_end_of_line (first_unused_hpos
);
1870 IT_update_begin (struct frame
*f
)
1872 struct display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1878 if (f
== display_info
->mouse_face_mouse_frame
)
1880 /* Don't do highlighting for mouse motion during the update. */
1881 display_info
->mouse_face_defer
= 1;
1883 /* If F needs to be redrawn, simply forget about any prior mouse
1885 if (FRAME_GARBAGED_P (f
))
1886 display_info
->mouse_face_window
= Qnil
;
1888 /* Can we tell that this update does not affect the window
1889 where the mouse highlight is? If so, no need to turn off.
1890 Likewise, don't do anything if none of the enabled rows
1891 contains glyphs highlighted in mouse face. */
1892 if (!NILP (display_info
->mouse_face_window
)
1893 && WINDOWP (display_info
->mouse_face_window
))
1895 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1898 /* If the mouse highlight is in the window that was deleted
1899 (e.g., if it was popped by completion), clear highlight
1901 if (NILP (w
->buffer
))
1902 display_info
->mouse_face_window
= Qnil
;
1905 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1906 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1907 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1911 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1912 clear_mouse_face (display_info
);
1915 else if (!FRAME_LIVE_P (display_info
->mouse_face_mouse_frame
))
1917 /* If the frame with mouse highlight was deleted, invalidate the
1919 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1920 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1921 display_info
->mouse_face_window
= Qnil
;
1922 display_info
->mouse_face_deferred_gc
= 0;
1923 display_info
->mouse_face_mouse_frame
= NULL
;
1930 IT_update_end (struct frame
*f
)
1933 FRAME_X_DISPLAY_INFO (f
)->mouse_face_defer
= 0;
1936 Lisp_Object Qcursor_type
;
1939 IT_frame_up_to_date (struct frame
*f
)
1941 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1942 Lisp_Object new_cursor
, frame_desired_cursor
;
1945 if (dpyinfo
->mouse_face_deferred_gc
1946 || f
== dpyinfo
->mouse_face_mouse_frame
)
1949 if (dpyinfo
->mouse_face_mouse_frame
)
1950 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
1951 dpyinfo
->mouse_face_mouse_x
,
1952 dpyinfo
->mouse_face_mouse_y
);
1953 dpyinfo
->mouse_face_deferred_gc
= 0;
1957 /* Set the cursor type to whatever they wanted. In a minibuffer
1958 window, we want the cursor to appear only if we are reading input
1959 from this window, and we want the cursor to be taken from the
1960 frame parameters. For the selected window, we use either its
1961 buffer-local value or the value from the frame parameters if the
1962 buffer doesn't define its local value for the cursor type. */
1963 sw
= XWINDOW (f
->selected_window
);
1964 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1965 if (cursor_in_echo_area
1966 && FRAME_HAS_MINIBUF_P (f
)
1967 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1968 && sw
== XWINDOW (echo_area_window
))
1969 new_cursor
= frame_desired_cursor
;
1972 struct buffer
*b
= XBUFFER (sw
->buffer
);
1974 if (EQ (b
->cursor_type
, Qt
))
1975 new_cursor
= frame_desired_cursor
;
1976 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
1977 new_cursor
= Fcons (Qbar
, make_number (0));
1979 new_cursor
= b
->cursor_type
;
1982 IT_set_cursor_type (f
, new_cursor
);
1984 IT_cmgoto (f
); /* position cursor when update is done */
1987 /* Copy LEN glyphs displayed on a single line whose vertical position
1988 is YPOS, beginning at horizontal position XFROM to horizontal
1989 position XTO, by moving blocks in the video memory. Used by
1990 functions that insert and delete glyphs. */
1992 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1994 /* The offsets of source and destination relative to the
1995 conventional memorty selector. */
1996 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1997 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1999 if (from
== to
|| len
<= 0)
2002 _farsetsel (_dos_ds
);
2004 /* The source and destination might overlap, so we need to move
2005 glyphs non-destructively. */
2008 for ( ; len
; from
+= 2, to
+= 2, len
--)
2009 _farnspokew (to
, _farnspeekw (from
));
2013 from
+= (len
- 1) * 2;
2014 to
+= (len
- 1) * 2;
2015 for ( ; len
; from
-= 2, to
-= 2, len
--)
2016 _farnspokew (to
, _farnspeekw (from
));
2018 if (screen_virtual_segment
)
2019 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
2022 /* Insert and delete glyphs. */
2024 IT_insert_glyphs (start
, len
)
2025 register struct glyph
*start
;
2028 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
2030 /* Shift right the glyphs from the nominal cursor position to the
2031 end of this line. */
2032 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
2034 /* Now write the glyphs to be inserted. */
2035 IT_write_glyphs (start
, len
);
2039 IT_delete_glyphs (n
)
2045 /* set-window-configuration on window.c needs this. */
2047 x_set_menu_bar_lines (f
, value
, oldval
)
2049 Lisp_Object value
, oldval
;
2051 set_menu_bar_lines (f
, value
, oldval
);
2054 /* This was copied from xfns.c */
2056 Lisp_Object Qbackground_color
;
2057 Lisp_Object Qforeground_color
;
2058 Lisp_Object Qreverse
;
2059 extern Lisp_Object Qtitle
;
2061 /* IT_set_terminal_modes is called when emacs is started,
2062 resumed, and whenever the screen is redrawn! */
2065 IT_set_terminal_modes (void)
2068 fprintf (termscript
, "\n<SET_TERM>");
2071 screen_size_X
= ScreenCols ();
2072 screen_size_Y
= ScreenRows ();
2073 screen_size
= screen_size_X
* screen_size_Y
;
2075 new_pos_X
= new_pos_Y
= 0;
2076 current_pos_X
= current_pos_Y
= -1;
2078 if (term_setup_done
)
2080 term_setup_done
= 1;
2082 startup_screen_size_X
= screen_size_X
;
2083 startup_screen_size_Y
= screen_size_Y
;
2084 startup_screen_attrib
= ScreenAttrib
;
2087 /* Is DOS/V (or any other RSIS software which relocates
2088 the screen) installed? */
2090 unsigned short es_value
;
2093 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2094 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2095 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2096 else if (screen_old_address
) /* already switched to Japanese mode once */
2097 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2099 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2101 es_value
= regs
.x
.es
;
2102 __dpmi_int (0x10, ®s
);
2104 if (regs
.x
.es
!= es_value
)
2106 /* screen_old_address is only set if ScreenPrimary does NOT
2107 already point to the relocated buffer address returned by
2108 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2109 ScreenPrimary to that address at startup under DOS/V. */
2110 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2111 screen_old_address
= ScreenPrimary
;
2112 screen_virtual_segment
= regs
.x
.es
;
2113 screen_virtual_offset
= regs
.x
.di
;
2114 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2117 #endif /* __DJGPP__ > 1 */
2119 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2120 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2123 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2124 screen_size_X
, screen_size_Y
);
2129 /* IT_reset_terminal_modes is called when emacs is
2130 suspended or killed. */
2133 IT_reset_terminal_modes (void)
2135 int display_row_start
= (int) ScreenPrimary
;
2136 int saved_row_len
= startup_screen_size_X
* 2;
2137 int update_row_len
= ScreenCols () * 2;
2138 int current_rows
= ScreenRows ();
2139 int to_next_row
= update_row_len
;
2140 unsigned char *saved_row
= startup_screen_buffer
;
2141 int cursor_pos_X
= ScreenCols () - 1;
2142 int cursor_pos_Y
= ScreenRows () - 1;
2145 fprintf (termscript
, "\n<RESET_TERM>");
2149 if (!term_setup_done
)
2154 /* Leave the video system in the same state as we found it,
2155 as far as the blink/bright-background bit is concerned. */
2156 maybe_enable_blinking ();
2158 /* We have a situation here.
2159 We cannot just do ScreenUpdate(startup_screen_buffer) because
2160 the luser could have changed screen dimensions inside Emacs
2161 and failed (or didn't want) to restore them before killing
2162 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2163 thus will happily use memory outside what was allocated for
2164 `startup_screen_buffer'.
2165 Thus we only restore as much as the current screen dimensions
2166 can hold, and clear the rest (if the saved screen is smaller than
2167 the current) with the color attribute saved at startup. The cursor
2168 is also restored within the visible dimensions. */
2170 ScreenAttrib
= startup_screen_attrib
;
2172 /* Don't restore the screen if we are exiting less than 2 seconds
2173 after startup: we might be crashing, and the screen might show
2174 some vital clues to what's wrong. */
2175 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2178 if (screen_virtual_segment
)
2179 dosv_refresh_virtual_screen (0, screen_size
);
2181 if (update_row_len
> saved_row_len
)
2182 update_row_len
= saved_row_len
;
2183 if (current_rows
> startup_screen_size_Y
)
2184 current_rows
= startup_screen_size_Y
;
2187 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2188 update_row_len
/ 2, current_rows
);
2190 while (current_rows
--)
2192 dosmemput (saved_row
, update_row_len
, display_row_start
);
2193 if (screen_virtual_segment
)
2194 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2195 update_row_len
/ 2);
2196 saved_row
+= saved_row_len
;
2197 display_row_start
+= to_next_row
;
2200 if (startup_pos_X
< cursor_pos_X
)
2201 cursor_pos_X
= startup_pos_X
;
2202 if (startup_pos_Y
< cursor_pos_Y
)
2203 cursor_pos_Y
= startup_pos_Y
;
2205 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2206 xfree (startup_screen_buffer
);
2208 term_setup_done
= 0;
2212 IT_set_terminal_window (int foo
)
2216 /* Remember the screen colors of the curent frame, to serve as the
2217 default colors for newly-created frames. */
2219 static int initial_screen_colors
[2];
2221 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2222 Smsdos_remember_default_colors
, 1, 1, 0,
2223 "Remember the screen colors of the current frame.")
2230 CHECK_FRAME (frame
, 0);
2232 reverse
= EQ (Fcdr (Fassq (intern ("reverse"), f
->param_alist
)), Qt
);
2234 initial_screen_colors
[0]
2235 = reverse
? FRAME_BACKGROUND_PIXEL (f
) : FRAME_FOREGROUND_PIXEL (f
);
2236 initial_screen_colors
[1]
2237 = reverse
? FRAME_FOREGROUND_PIXEL (f
) : FRAME_BACKGROUND_PIXEL (f
);
2241 IT_set_frame_parameters (f
, alist
)
2246 int length
= XINT (Flength (alist
));
2249 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2251 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2252 /* Do we have to reverse the foreground and background colors? */
2253 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2254 int was_reverse
= reverse
;
2255 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2256 unsigned long orig_fg
;
2257 unsigned long orig_bg
;
2259 /* If we are creating a new frame, begin with the original screen colors
2260 used for the initial frame. */
2261 if (alist
== Vdefault_frame_alist
2262 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2264 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2265 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2267 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2268 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2270 /* Extract parm names and values into those vectors. */
2272 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2277 parms
[i
] = Fcar (elt
);
2278 CHECK_SYMBOL (parms
[i
], 1);
2279 values
[i
] = Fcdr (elt
);
2285 for (i
= 0; i
< j
; i
++)
2287 Lisp_Object prop
= parms
[i
];
2288 Lisp_Object val
= values
[i
];
2290 if (EQ (prop
, Qreverse
))
2291 reverse
= EQ (val
, Qt
);
2294 if (termscript
&& reverse
&& !was_reverse
)
2295 fprintf (termscript
, "<INVERSE-VIDEO>\n");
2297 /* Now process the alist elements in reverse of specified order. */
2298 for (i
--; i
>= 0; i
--)
2300 Lisp_Object prop
= parms
[i
];
2301 Lisp_Object val
= values
[i
];
2303 if (EQ (prop
, Qforeground_color
))
2305 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
2306 ? LFACE_BACKGROUND_INDEX
2307 : LFACE_FOREGROUND_INDEX
);
2308 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2309 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2310 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2313 /* FIXME: should the fore-/background of the default
2314 face change here as well? */
2315 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2317 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2321 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
2324 else if (EQ (prop
, Qbackground_color
))
2326 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
2327 ? LFACE_FOREGROUND_INDEX
2328 : LFACE_BACKGROUND_INDEX
);
2329 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2330 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2331 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2334 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2336 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2340 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
2343 else if (EQ (prop
, Qtitle
))
2345 x_set_title (f
, val
);
2347 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
2349 else if (EQ (prop
, Qcursor_type
))
2351 IT_set_cursor_type (f
, val
);
2353 fprintf (termscript
, "<CTYPE: %s>\n",
2354 EQ (val
, Qbar
) || CONSP (val
) && EQ (XCAR (val
), Qbar
)
2357 store_frame_param (f
, prop
, val
);
2360 /* If they specified "reverse", but not the colors, we need to swap
2361 the current frame colors. */
2362 if (reverse
&& !was_reverse
)
2366 FRAME_BACKGROUND_PIXEL (f
) = orig_fg
;
2371 FRAME_FOREGROUND_PIXEL (f
) = orig_bg
;
2378 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2379 if (f
== SELECTED_FRAME())
2384 extern void init_frame_faces (FRAME_PTR
);
2386 #endif /* !HAVE_X_WINDOWS */
2389 /* Do we need the internal terminal? */
2392 internal_terminal_init ()
2394 char *term
= getenv ("TERM");
2396 struct frame
*sf
= SELECTED_FRAME();
2398 #ifdef HAVE_X_WINDOWS
2399 if (!inhibit_window_system
)
2404 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2406 if (getenv ("EMACSTEST"))
2407 termscript
= fopen (getenv ("EMACSTEST"), "wt");
2409 #ifndef HAVE_X_WINDOWS
2410 if (!internal_terminal
|| inhibit_window_system
)
2412 sf
->output_method
= output_termcap
;
2416 Vwindow_system
= intern ("pc");
2417 Vwindow_system_version
= make_number (1);
2418 sf
->output_method
= output_msdos_raw
;
2420 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2421 screen_old_address
= 0;
2423 /* Forget the stale screen colors as well. */
2424 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2426 bzero (&the_only_x_display
, sizeof the_only_x_display
);
2427 the_only_x_display
.background_pixel
= 7; /* White */
2428 the_only_x_display
.foreground_pixel
= 0; /* Black */
2430 colors
= getenv ("EMACSCOLORS");
2431 if (colors
&& strlen (colors
) >= 2)
2433 /* The colors use 4 bits each (we enable bright background). */
2434 if (isdigit (colors
[0]))
2436 else if (isxdigit (colors
[0]))
2437 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2438 if (colors
[0] >= 0 && colors
[0] < 16)
2439 the_only_x_display
.foreground_pixel
= colors
[0];
2440 if (isdigit (colors
[1]))
2442 else if (isxdigit (colors
[1]))
2443 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2444 if (colors
[1] >= 0 && colors
[1] < 16)
2445 the_only_x_display
.background_pixel
= colors
[1];
2447 the_only_x_display
.line_height
= 1;
2448 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
2449 the_only_x_display
.display_info
.mouse_face_mouse_frame
= NULL
;
2450 the_only_x_display
.display_info
.mouse_face_deferred_gc
= 0;
2451 the_only_x_display
.display_info
.mouse_face_beg_row
=
2452 the_only_x_display
.display_info
.mouse_face_beg_col
= -1;
2453 the_only_x_display
.display_info
.mouse_face_end_row
=
2454 the_only_x_display
.display_info
.mouse_face_end_col
= -1;
2455 the_only_x_display
.display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2456 the_only_x_display
.display_info
.mouse_face_window
= Qnil
;
2457 the_only_x_display
.display_info
.mouse_face_mouse_x
=
2458 the_only_x_display
.display_info
.mouse_face_mouse_y
= 0;
2459 the_only_x_display
.display_info
.mouse_face_defer
= 0;
2461 init_frame_faces (sf
);
2463 ring_bell_hook
= IT_ring_bell
;
2464 insert_glyphs_hook
= IT_insert_glyphs
;
2465 delete_glyphs_hook
= IT_delete_glyphs
;
2466 write_glyphs_hook
= IT_write_glyphs
;
2467 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
2468 clear_to_end_hook
= IT_clear_to_end
;
2469 clear_end_of_line_hook
= IT_clear_end_of_line
;
2470 clear_frame_hook
= IT_clear_screen
;
2471 change_line_highlight_hook
= IT_change_line_highlight
;
2472 update_begin_hook
= IT_update_begin
;
2473 update_end_hook
= IT_update_end
;
2474 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
2475 frame_up_to_date_hook
= IT_frame_up_to_date
;
2477 /* These hooks are called by term.c without being checked. */
2478 set_terminal_modes_hook
= IT_set_terminal_modes
;
2479 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2480 set_terminal_window_hook
= IT_set_terminal_window
;
2481 char_ins_del_ok
= 0;
2485 dos_get_saved_screen (screen
, rows
, cols
)
2490 #ifndef HAVE_X_WINDOWS
2491 *screen
= startup_screen_buffer
;
2492 *cols
= startup_screen_size_X
;
2493 *rows
= startup_screen_size_Y
;
2494 return *screen
!= (char *)0;
2500 #ifndef HAVE_X_WINDOWS
2502 /* We are not X, but we can emulate it well enough for our needs... */
2506 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2507 error ("Not running under a window system");
2513 /* ----------------------- Keyboard control ----------------------
2515 * Keymaps reflect the following keyboard layout:
2517 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2518 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2519 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2520 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2524 #define Ignore 0x0000
2525 #define Normal 0x0000 /* normal key - alt changes scan-code */
2526 #define FctKey 0x1000 /* func key if c == 0, else c */
2527 #define Special 0x2000 /* func key even if c != 0 */
2528 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2529 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2530 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2531 #define Grey 0x6000 /* Grey keypad key */
2533 #define Alt 0x0100 /* alt scan-code */
2534 #define Ctrl 0x0200 /* ctrl scan-code */
2535 #define Shift 0x0400 /* shift scan-code */
2537 static int extended_kbd
; /* 101 (102) keyboard present. */
2539 struct kbd_translate
{
2542 unsigned short code
;
2545 struct dos_keyboard_map
2550 struct kbd_translate
*translate_table
;
2554 static struct dos_keyboard_map us_keyboard
= {
2556 /* 01234567890123456789012345678901234567890 12345678901234 */
2557 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2558 /* 0123456789012345678901234567890123456789 012345678901234 */
2559 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2560 0, /* no Alt-Gr key */
2561 0 /* no translate table */
2564 static struct dos_keyboard_map fr_keyboard
= {
2566 /* 012 3456789012345678901234567890123456789012345678901234 */
2567 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
2568 /* 0123456789012345678901234567890123456789012345678901234 */
2569 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
2570 /* 01234567 89012345678901234567890123456789012345678901234 */
2572 0 /* no translate table */
2576 * Italian keyboard support, country code 39.
2579 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2580 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2583 static struct kbd_translate it_kbd_translate_table
[] = {
2584 { 0x56, 0x3c, Normal
| 13 },
2585 { 0x56, 0x3e, Normal
| 27 },
2588 static struct dos_keyboard_map it_keyboard
= {
2590 /* 0 123456789012345678901234567890123456789012345678901234 */
2591 "\\1234567890'\8d< qwertyuiop\8a+> asdfghjkl\95\85\97 zxcvbnm,.- ",
2592 /* 01 23456789012345678901234567890123456789012345678901234 */
2593 "|!\"\9c$%&/()=?^> QWERTYUIOP\82* ASDFGHJKL\87øõ ZXCVBNM;:_ ",
2594 /* 0123456789012345678901234567890123456789012345678901234 */
2596 it_kbd_translate_table
2599 static struct dos_keyboard_map dk_keyboard
= {
2601 /* 0123456789012345678901234567890123456789012345678901234 */
2602 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
2603 /* 01 23456789012345678901234567890123456789012345678901234 */
2604 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
2605 /* 0123456789012345678901234567890123456789012345678901234 */
2607 0 /* no translate table */
2610 static struct kbd_translate jp_kbd_translate_table
[] = {
2611 { 0x73, 0x5c, Normal
| 0 },
2612 { 0x73, 0x5f, Normal
| 0 },
2613 { 0x73, 0x1c, Map
| 0 },
2614 { 0x7d, 0x5c, Normal
| 13 },
2615 { 0x7d, 0x7c, Normal
| 13 },
2616 { 0x7d, 0x1c, Map
| 13 },
2619 static struct dos_keyboard_map jp_keyboard
= {
2621 /* 0123456789012 345678901234567890123456789012345678901234 */
2622 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2623 /* 01 23456789012345678901234567890123456789012345678901234 */
2624 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2625 0, /* no Alt-Gr key */
2626 jp_kbd_translate_table
2629 static struct keyboard_layout_list
2632 struct dos_keyboard_map
*keyboard_map
;
2633 } keyboard_layout_list
[] =
2642 static struct dos_keyboard_map
*keyboard
;
2643 static int keyboard_map_all
;
2644 static int international_keyboard
;
2647 dos_set_keyboard (code
, always
)
2652 _go32_dpmi_registers regs
;
2654 /* See if Keyb.Com is installed (for international keyboard support).
2655 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2656 of Windows 9X! So don't do that! */
2658 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2659 _go32_dpmi_simulate_int (0x2f, ®s
);
2660 if (regs
.h
.al
== 0xff)
2661 international_keyboard
= 1;
2663 /* Initialize to US settings, for countries that don't have their own. */
2664 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2665 keyboard_map_all
= always
;
2666 dos_keyboard_layout
= 1;
2668 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2669 if (code
== keyboard_layout_list
[i
].country_code
)
2671 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2672 keyboard_map_all
= always
;
2673 dos_keyboard_layout
= code
;
2681 unsigned char char_code
; /* normal code */
2682 unsigned char meta_code
; /* M- code */
2683 unsigned char keypad_code
; /* keypad code */
2684 unsigned char editkey_code
; /* edit key */
2685 } keypad_translate_map
[] = {
2686 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2687 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2688 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2689 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2690 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2691 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2692 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2693 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2694 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2695 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2696 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2701 unsigned char char_code
; /* normal code */
2702 unsigned char keypad_code
; /* keypad code */
2703 } grey_key_translate_map
[] = {
2704 '/', 0xaf, /* kp-decimal */
2705 '*', 0xaa, /* kp-multiply */
2706 '-', 0xad, /* kp-subtract */
2707 '+', 0xab, /* kp-add */
2708 '\r', 0x8d /* kp-enter */
2711 static unsigned short
2712 ibmpc_translate_map
[] =
2714 /* --------------- 00 to 0f --------------- */
2715 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2716 Alt
| ModFct
| 0x1b, /* Escape */
2717 Normal
| 1, /* '1' */
2718 Normal
| 2, /* '2' */
2719 Normal
| 3, /* '3' */
2720 Normal
| 4, /* '4' */
2721 Normal
| 5, /* '5' */
2722 Normal
| 6, /* '6' */
2723 Normal
| 7, /* '7' */
2724 Normal
| 8, /* '8' */
2725 Normal
| 9, /* '9' */
2726 Normal
| 10, /* '0' */
2727 Normal
| 11, /* '-' */
2728 Normal
| 12, /* '=' */
2729 Special
| 0x08, /* Backspace */
2730 ModFct
| 0x74, /* Tab/Backtab */
2732 /* --------------- 10 to 1f --------------- */
2745 ModFct
| 0x0d, /* Return */
2750 /* --------------- 20 to 2f --------------- */
2759 Map
| 40, /* '\'' */
2761 Ignore
, /* Left shift */
2762 Map
| 41, /* '\\' */
2768 /* --------------- 30 to 3f --------------- */
2775 Ignore
, /* Right shift */
2776 Grey
| 1, /* Grey * */
2778 Normal
| 55, /* ' ' */
2779 Ignore
, /* Caps Lock */
2780 FctKey
| 0xbe, /* F1 */
2781 FctKey
| 0xbf, /* F2 */
2782 FctKey
| 0xc0, /* F3 */
2783 FctKey
| 0xc1, /* F4 */
2784 FctKey
| 0xc2, /* F5 */
2786 /* --------------- 40 to 4f --------------- */
2787 FctKey
| 0xc3, /* F6 */
2788 FctKey
| 0xc4, /* F7 */
2789 FctKey
| 0xc5, /* F8 */
2790 FctKey
| 0xc6, /* F9 */
2791 FctKey
| 0xc7, /* F10 */
2792 Ignore
, /* Num Lock */
2793 Ignore
, /* Scroll Lock */
2794 KeyPad
| 7, /* Home */
2795 KeyPad
| 8, /* Up */
2796 KeyPad
| 9, /* Page Up */
2797 Grey
| 2, /* Grey - */
2798 KeyPad
| 4, /* Left */
2799 KeyPad
| 5, /* Keypad 5 */
2800 KeyPad
| 6, /* Right */
2801 Grey
| 3, /* Grey + */
2802 KeyPad
| 1, /* End */
2804 /* --------------- 50 to 5f --------------- */
2805 KeyPad
| 2, /* Down */
2806 KeyPad
| 3, /* Page Down */
2807 KeyPad
| 0, /* Insert */
2808 KeyPad
| 10, /* Delete */
2809 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2810 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2811 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2812 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2813 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2814 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2815 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2816 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2817 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2818 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2819 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2820 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2822 /* --------------- 60 to 6f --------------- */
2823 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2824 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2825 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2826 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2827 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2828 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2829 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2830 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2831 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2832 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2833 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2834 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2835 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2836 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2837 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2838 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2840 /* --------------- 70 to 7f --------------- */
2841 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2842 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2843 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2844 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2845 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2846 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2847 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2848 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2849 Alt
| Map
| 1, /* '1' */
2850 Alt
| Map
| 2, /* '2' */
2851 Alt
| Map
| 3, /* '3' */
2852 Alt
| Map
| 4, /* '4' */
2853 Alt
| Map
| 5, /* '5' */
2854 Alt
| Map
| 6, /* '6' */
2855 Alt
| Map
| 7, /* '7' */
2856 Alt
| Map
| 8, /* '8' */
2858 /* --------------- 80 to 8f --------------- */
2859 Alt
| Map
| 9, /* '9' */
2860 Alt
| Map
| 10, /* '0' */
2861 Alt
| Map
| 11, /* '-' */
2862 Alt
| Map
| 12, /* '=' */
2863 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2864 FctKey
| 0xc8, /* F11 */
2865 FctKey
| 0xc9, /* F12 */
2866 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2867 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2868 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2869 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2870 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2871 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2872 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2873 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2874 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2876 /* --------------- 90 to 9f --------------- */
2877 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2878 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2879 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2880 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2881 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2882 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2883 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2884 Alt
| FctKey
| 0x50, /* (Alt) Home */
2885 Alt
| FctKey
| 0x52, /* (Alt) Up */
2886 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2887 Ignore
, /* NO KEY */
2888 Alt
| FctKey
| 0x51, /* (Alt) Left */
2889 Ignore
, /* NO KEY */
2890 Alt
| FctKey
| 0x53, /* (Alt) Right */
2891 Ignore
, /* NO KEY */
2892 Alt
| FctKey
| 0x57, /* (Alt) End */
2894 /* --------------- a0 to af --------------- */
2895 Alt
| KeyPad
| 2, /* (Alt) Down */
2896 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2897 Alt
| KeyPad
| 0, /* (Alt) Insert */
2898 Alt
| KeyPad
| 10, /* (Alt) Delete */
2899 Alt
| Grey
| 0, /* (Alt) Grey / */
2900 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2901 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2904 /* These bit-positions corresponds to values returned by BIOS */
2905 #define SHIFT_P 0x0003 /* two bits! */
2906 #define CTRL_P 0x0004
2907 #define ALT_P 0x0008
2908 #define SCRLOCK_P 0x0010
2909 #define NUMLOCK_P 0x0020
2910 #define CAPSLOCK_P 0x0040
2911 #define ALT_GR_P 0x0800
2912 #define SUPER_P 0x4000 /* pseudo */
2913 #define HYPER_P 0x8000 /* pseudo */
2916 dos_get_modifiers (keymask
)
2923 /* Calculate modifier bits */
2924 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2925 int86 (0x16, ®s
, ®s
);
2929 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2930 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2934 mask
= regs
.h
.al
& (SHIFT_P
|
2935 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2937 /* Do not break international keyboard support. */
2938 /* When Keyb.Com is loaded, the right Alt key is */
2939 /* used for accessing characters like { and } */
2940 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2943 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2946 if (dos_hyper_key
== 1)
2949 modifiers
|= hyper_modifier
;
2951 else if (dos_super_key
== 1)
2954 modifiers
|= super_modifier
;
2956 else if (!international_keyboard
)
2958 /* If Keyb.Com is NOT installed, let Right Alt behave
2959 like the Left Alt. */
2965 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2968 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2970 if (dos_hyper_key
== 2)
2973 modifiers
|= hyper_modifier
;
2975 else if (dos_super_key
== 2)
2978 modifiers
|= super_modifier
;
2986 modifiers
|= shift_modifier
;
2988 modifiers
|= ctrl_modifier
;
2990 modifiers
|= meta_modifier
;
2997 #define NUM_RECENT_DOSKEYS (100)
2998 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2999 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
3000 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
3002 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
3003 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
3004 Each input key receives two values in this vector: first the ASCII code,\n\
3005 and then the scan code.")
3008 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
3011 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
3012 return Fvector (total_doskeys
, keys
);
3015 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
3016 bcopy (keys
+ recent_doskeys_index
,
3017 XVECTOR (val
)->contents
,
3018 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
3020 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
3021 recent_doskeys_index
* sizeof (Lisp_Object
));
3026 /* Get a char from keyboard. Function keys are put into the event queue. */
3028 extern void kbd_buffer_store_event (struct input_event
*);
3033 struct input_event event
;
3036 #ifndef HAVE_X_WINDOWS
3037 /* Maybe put the cursor where it should be. */
3038 IT_cmgoto (SELECTED_FRAME());
3041 /* The following condition is equivalent to `kbhit ()', except that
3042 it uses the bios to do its job. This pleases DESQview/X. */
3043 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
3044 int86 (0x16, ®s
, ®s
),
3045 (regs
.x
.flags
& 0x40) == 0)
3048 register unsigned char c
;
3049 int sc
, code
= -1, mask
, kp_mode
;
3052 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
3053 int86 (0x16, ®s
, ®s
);
3058 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3060 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3061 recent_doskeys_index
= 0;
3062 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3064 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3065 recent_doskeys_index
= 0;
3067 modifiers
= dos_get_modifiers (&mask
);
3069 #ifndef HAVE_X_WINDOWS
3070 if (!NILP (Vdos_display_scancodes
))
3073 sprintf (buf
, "%02x:%02x*%04x",
3074 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3075 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3083 case 10: /* Ctrl Grey Enter */
3084 code
= Ctrl
| Grey
| 4;
3086 case 13: /* Grey Enter */
3089 case '/': /* Grey / */
3099 /* Try the keyboard-private translation table first. */
3100 if (keyboard
->translate_table
)
3102 struct kbd_translate
*p
= keyboard
->translate_table
;
3106 if (p
->sc
== sc
&& p
->ch
== c
)
3114 /* If the private table didn't translate it, use the general
3118 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3120 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3127 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3128 Emacs is ready to read a key. Therefore, if they press
3129 `Alt-x' when Emacs is busy, by the time we get to
3130 `dos_get_modifiers', they might have already released the
3131 Alt key, and Emacs gets just `x', which is BAD.
3132 However, for keys with the `Map' property set, the ASCII
3133 code returns zero iff Alt is pressed. So, when we DON'T
3134 have to support international_keyboard, we don't have to
3135 distinguish between the left and right Alt keys, and we
3136 can set the META modifier for any keys with the `Map'
3137 property if they return zero ASCII code (c = 0). */
3139 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3140 modifiers
|= meta_modifier
;
3142 modifiers
|= ctrl_modifier
;
3144 modifiers
|= shift_modifier
;
3147 switch (code
& 0xf000)
3150 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3152 c
= 0; /* Special */
3165 if (c
== 0) /* ctrl-break */
3167 return c
; /* ALT-nnn */
3169 if (!keyboard_map_all
)
3178 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3179 if (!keyboard_map_all
)
3183 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3184 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3188 code
= keyboard
->shifted
[code
];
3190 modifiers
&= ~shift_modifier
;
3193 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3194 code
= keyboard
->alt_gr
[code
];
3196 code
= keyboard
->unshifted
[code
];
3201 if (c
== 0xe0) /* edit key */
3204 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3205 kp_mode
= dos_keypad_mode
& 0x03;
3207 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3212 if (code
== 10 && dos_decimal_point
)
3213 return dos_decimal_point
;
3214 return keypad_translate_map
[code
].char_code
;
3217 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3221 code
= keypad_translate_map
[code
].meta_code
;
3222 modifiers
= meta_modifier
;
3226 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3233 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3234 if (dos_keypad_mode
& kp_mode
)
3235 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3237 code
= grey_key_translate_map
[code
].char_code
;
3246 event
.kind
= non_ascii_keystroke
;
3248 event
.kind
= ascii_keystroke
;
3250 event
.modifiers
= modifiers
;
3251 event
.frame_or_window
= selected_frame
;
3253 event
.timestamp
= event_timestamp ();
3254 kbd_buffer_store_event (&event
);
3257 if (have_mouse
> 0 && !mouse_preempted
)
3259 int but
, press
, x
, y
, ok
;
3260 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3262 /* Check for mouse movement *before* buttons. */
3263 mouse_check_moved ();
3265 /* If the mouse moved from the spot of its last sighting, we
3266 might need to update mouse highlight. */
3267 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3269 previous_help_echo
= help_echo
;
3270 help_echo
= help_echo_object
= help_echo_window
= Qnil
;
3272 IT_note_mouse_highlight (SELECTED_FRAME(),
3273 mouse_last_x
, mouse_last_y
);
3274 /* If the contents of the global variable help_echo has
3275 changed, generate a HELP_EVENT. */
3276 if (!NILP (help_echo
) || !NILP (previous_help_echo
))
3278 /* HELP_EVENT takes 2 events in the event loop. */
3279 event
.kind
= HELP_EVENT
;
3280 event
.frame_or_window
= selected_frame
;
3281 event
.arg
= help_echo_object
;
3282 event
.x
= make_number (help_echo_pos
);
3283 event
.timestamp
= event_timestamp ();
3285 kbd_buffer_store_event (&event
);
3286 if (WINDOWP (help_echo_window
))
3287 event
.frame_or_window
= help_echo_window
;
3288 event
.arg
= help_echo
;
3290 kbd_buffer_store_event (&event
);
3294 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3295 for (press
= 0; press
< 2; press
++)
3297 int button_num
= but
;
3300 ok
= mouse_pressed (but
, &x
, &y
);
3302 ok
= mouse_released (but
, &x
, &y
);
3305 /* Allow a simultaneous press/release of Mouse-1 and
3306 Mouse-2 to simulate Mouse-3 on two-button mice. */
3307 if (mouse_button_count
== 2 && but
< 2)
3309 int x2
, y2
; /* don't clobber original coordinates */
3311 /* If only one button is pressed, wait 100 msec and
3312 check again. This way, Speedy Gonzales isn't
3313 punished, while the slow get their chance. */
3314 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3315 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3320 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3321 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3326 event
.kind
= mouse_click
;
3327 event
.code
= button_num
;
3328 event
.modifiers
= dos_get_modifiers (0)
3329 | (press
? down_modifier
: up_modifier
);
3332 event
.frame_or_window
= selected_frame
;
3334 event
.timestamp
= event_timestamp ();
3335 kbd_buffer_store_event (&event
);
3343 static int prev_get_char
= -1;
3345 /* Return 1 if a key is ready to be read without suspending execution. */
3349 if (prev_get_char
!= -1)
3352 return ((prev_get_char
= dos_rawgetc ()) != -1);
3355 /* Read a key. Return -1 if no key is ready. */
3359 if (prev_get_char
!= -1)
3361 int c
= prev_get_char
;
3366 return dos_rawgetc ();
3369 #ifndef HAVE_X_WINDOWS
3370 /* See xterm.c for more info. */
3372 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
3374 register int pix_x
, pix_y
;
3375 register int *x
, *y
;
3379 if (bounds
) abort ();
3381 /* Ignore clipping. */
3388 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
3391 register int *pix_x
, *pix_y
;
3397 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3400 Actually, I don't know the meaning of all the parameters of the functions
3401 here -- I only know how they are called by xmenu.c. I could of course
3402 grab the nearest Xlib manual (down the hall, second-to-last door on the
3403 left), but I don't think it's worth the effort. */
3405 /* These hold text of the current and the previous menu help messages. */
3406 static char *menu_help_message
, *prev_menu_help_message
;
3407 /* Pane number and item number of the menu item which generated the
3408 last menu help message. */
3409 static int menu_help_paneno
, menu_help_itemno
;
3416 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3417 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3421 /* Allocate some (more) memory for MENU ensuring that there is room for one
3425 IT_menu_make_room (XMenu
*menu
)
3427 if (menu
->allocated
== 0)
3429 int count
= menu
->allocated
= 10;
3430 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3431 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3432 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3433 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3435 else if (menu
->allocated
== menu
->count
)
3437 int count
= menu
->allocated
= menu
->allocated
+ 10;
3439 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3441 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3443 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3445 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3449 /* Search the given menu structure for a given pane number. */
3452 IT_menu_search_pane (XMenu
*menu
, int pane
)
3457 for (i
= 0; i
< menu
->count
; i
++)
3458 if (menu
->submenu
[i
])
3460 if (pane
== menu
->panenumber
[i
])
3461 return menu
->submenu
[i
];
3462 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3468 /* Determine how much screen space a given menu needs. */
3471 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3473 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3476 maxheight
= menu
->count
;
3477 for (i
= 0; i
< menu
->count
; i
++)
3479 if (menu
->submenu
[i
])
3481 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3482 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3483 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3486 *width
= menu
->width
+ maxsubwidth
;
3487 *height
= maxheight
;
3490 /* Display MENU at (X,Y) using FACES. */
3493 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3495 int i
, j
, face
, width
;
3496 struct glyph
*text
, *p
;
3499 int enabled
, mousehere
;
3501 struct frame
*sf
= SELECTED_FRAME();
3503 menu_help_message
= NULL
;
3505 width
= menu
->width
;
3506 text
= (struct glyph
*) xmalloc ((width
+ 2) * sizeof (struct glyph
));
3507 ScreenGetCursor (&row
, &col
);
3508 mouse_get_xy (&mx
, &my
);
3509 IT_update_begin (sf
);
3510 for (i
= 0; i
< menu
->count
; i
++)
3512 int max_width
= width
+ 2;
3514 IT_cursor_to (y
+ i
, x
);
3516 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3517 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
3518 face
= faces
[enabled
+ mousehere
* 2];
3519 /* The following if clause means that we display the menu help
3520 strings even if the menu item is currently disabled. */
3521 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3523 menu_help_message
= menu
->help_text
[i
];
3524 menu_help_paneno
= pn
- 1;
3525 menu_help_itemno
= i
;
3528 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3530 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3534 SET_CHAR_GLYPH (*p
, *q
++, face
, 0);
3537 else /* make '^x' */
3539 SET_CHAR_GLYPH (*p
, '^', face
, 0);
3542 SET_CHAR_GLYPH (*p
, *q
++ + 64, face
, 0);
3546 /* Don't let the menu text overflow into the next screen row. */
3547 if (x
+ max_width
> screen_size_X
)
3549 max_width
= screen_size_X
- x
;
3550 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3552 for (; j
< max_width
- 2; j
++, p
++)
3553 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3555 SET_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3557 IT_write_glyphs (text
, max_width
);
3560 IT_cursor_to (row
, col
);
3564 /* --------------------------- X Menu emulation ---------------------- */
3566 /* Report availability of menus. */
3574 /* Create a brand new menu structure. */
3577 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3579 return IT_menu_create ();
3582 /* Create a new pane and place it on the outer-most level. It is not
3583 clear that it should be placed out there, but I don't know what else
3587 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3595 IT_menu_make_room (menu
);
3596 menu
->submenu
[menu
->count
] = IT_menu_create ();
3597 menu
->text
[menu
->count
] = txt
;
3598 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3599 menu
->help_text
[menu
->count
] = NULL
;
3602 /* Adjust length for possible control characters (which will
3603 be written as ^x). */
3604 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3608 if (len
> menu
->width
)
3611 return menu
->panecount
;
3614 /* Create a new item in a menu pane. */
3617 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3618 int foo
, char *txt
, int enable
, char *help_text
)
3624 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3626 IT_menu_make_room (menu
);
3627 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3628 menu
->text
[menu
->count
] = txt
;
3629 menu
->panenumber
[menu
->count
] = enable
;
3630 menu
->help_text
[menu
->count
] = help_text
;
3633 /* Adjust length for possible control characters (which will
3634 be written as ^x). */
3635 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3639 if (len
> menu
->width
)
3645 /* Decide where the menu would be placed if requested at (X,Y). */
3648 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3649 int *ulx
, int *uly
, int *width
, int *height
)
3651 IT_menu_calc_size (menu
, width
, height
);
3657 struct IT_menu_state
3659 void *screen_behind
;
3666 /* Display menu, wait for user's response, and return that response. */
3669 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3670 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3671 void (*help_callback
)(char *, int, int))
3673 struct IT_menu_state
*state
;
3678 Lisp_Object selectface
;
3679 int leave
, result
, onepane
;
3680 int title_faces
[4]; /* face to display the menu title */
3681 int buffers_num_deleted
= 0;
3682 struct frame
*sf
= SELECTED_FRAME();
3683 Lisp_Object saved_echo_area_message
;
3685 /* Just in case we got here without a mouse present... */
3686 if (have_mouse
<= 0)
3687 return XM_IA_SELECT
;
3688 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3689 around the display. */
3695 /* We will process all the mouse events directly, so we had
3696 better prevent dos_rawgetc from stealing them from us. */
3699 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3700 screensize
= screen_size
* 2;
3702 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3703 0, DEFAULT_FACE_ID
);
3705 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3706 0, DEFAULT_FACE_ID
);
3707 selectface
= intern ("msdos-menu-select-face");
3708 faces
[2] = lookup_derived_face (sf
, selectface
,
3710 faces
[3] = lookup_derived_face (sf
, selectface
,
3713 /* Make sure the menu title is always displayed with
3714 `msdos-menu-active-face', no matter where the mouse pointer is. */
3715 for (i
= 0; i
< 4; i
++)
3716 title_faces
[i
] = faces
[3];
3720 /* Don't let the title for the "Buffers" popup menu include a
3721 digit (which is ugly).
3723 This is a terrible kludge, but I think the "Buffers" case is
3724 the only one where the title includes a number, so it doesn't
3725 seem to be necessary to make this more general. */
3726 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3728 menu
->text
[0][7] = '\0';
3729 buffers_num_deleted
= 1;
3732 /* We need to save the current echo area message, so that we could
3733 restore it below, before we exit. See the commentary below,
3734 before the call to message_with_string. */
3735 saved_echo_area_message
= Fcurrent_message ();
3736 state
[0].menu
= menu
;
3738 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3740 /* Turn off the cursor. Otherwise it shows through the menu
3741 panes, which is ugly. */
3742 IT_display_cursor (0);
3744 /* Display the menu title. */
3745 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3746 if (buffers_num_deleted
)
3747 menu
->text
[0][7] = ' ';
3748 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3750 menu
->width
= menu
->submenu
[0]->width
;
3751 state
[0].menu
= menu
->submenu
[0];
3755 state
[0].menu
= menu
;
3757 state
[0].x
= x0
- 1;
3759 state
[0].pane
= onepane
;
3761 mouse_last_x
= -1; /* A hack that forces display. */
3765 if (!mouse_visible
) mouse_on ();
3766 mouse_check_moved ();
3767 if (sf
->mouse_moved
)
3769 sf
->mouse_moved
= 0;
3770 result
= XM_IA_SELECT
;
3771 mouse_get_xy (&x
, &y
);
3772 for (i
= 0; i
< statecount
; i
++)
3773 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3775 int dy
= y
- state
[i
].y
;
3776 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3778 if (!state
[i
].menu
->submenu
[dy
])
3779 if (state
[i
].menu
->panenumber
[dy
])
3780 result
= XM_SUCCESS
;
3782 result
= XM_IA_SELECT
;
3783 *pane
= state
[i
].pane
- 1;
3785 /* We hit some part of a menu, so drop extra menus that
3786 have been opened. That does not include an open and
3788 if (i
!= statecount
- 2
3789 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3790 while (i
!= statecount
- 1)
3794 ScreenUpdate (state
[statecount
].screen_behind
);
3795 if (screen_virtual_segment
)
3796 dosv_refresh_virtual_screen (0, screen_size
);
3797 xfree (state
[statecount
].screen_behind
);
3799 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3801 IT_menu_display (state
[i
].menu
,
3806 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3807 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3809 ScreenRetrieve (state
[statecount
].screen_behind
3810 = xmalloc (screensize
));
3812 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3813 state
[statecount
].y
= y
;
3818 IT_menu_display (state
[statecount
- 1].menu
,
3819 state
[statecount
- 1].y
,
3820 state
[statecount
- 1].x
,
3821 state
[statecount
- 1].pane
,
3826 if ((menu_help_message
|| prev_menu_help_message
)
3827 && menu_help_message
!= prev_menu_help_message
)
3829 help_callback (menu_help_message
,
3830 menu_help_paneno
, menu_help_itemno
);
3831 IT_display_cursor (0);
3832 prev_menu_help_message
= menu_help_message
;
3834 /* We are busy-waiting for the mouse to move, so let's be nice
3835 to other Windows applications by releasing our time slice. */
3838 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3840 /* Only leave if user both pressed and released the mouse, and in
3841 that order. This avoids popping down the menu pane unless
3842 the user is really done with it. */
3843 if (mouse_pressed (b
, &x
, &y
))
3845 while (mouse_button_depressed (b
, &x
, &y
))
3849 (void) mouse_released (b
, &x
, &y
);
3854 ScreenUpdate (state
[0].screen_behind
);
3855 if (screen_virtual_segment
)
3856 dosv_refresh_virtual_screen (0, screen_size
);
3858 /* We have a situation here. ScreenUpdate has just restored the
3859 screen contents as it was before we started drawing this menu.
3860 That includes any echo area message that could have been
3861 displayed back then. (In reality, that echo area message will
3862 almost always be the ``keystroke echo'' that echoes the sequence
3863 of menu items chosen by the user.) However, if the menu had some
3864 help messages, then displaying those messages caused Emacs to
3865 forget about the original echo area message. So when
3866 ScreenUpdate restored it, it created a discrepancy between the
3867 actual screen contents and what Emacs internal data structures
3870 To avoid this conflict, we force Emacs to restore the original
3871 echo area message as we found it when we entered this function.
3872 The irony of this is that we then erase the restored message
3873 right away, so the only purpose of restoring it is so that
3874 erasing it works correctly... */
3875 if (! NILP (saved_echo_area_message
))
3876 message_with_string ("%s", saved_echo_area_message
, 0);
3878 while (statecount
--)
3879 xfree (state
[statecount
].screen_behind
);
3880 IT_display_cursor (1); /* turn cursor back on */
3881 /* Clean up any mouse events that are waiting inside Emacs event queue.
3882 These events are likely to be generated before the menu was even
3883 displayed, probably because the user pressed and released the button
3884 (which invoked the menu) too quickly. If we don't remove these events,
3885 Emacs will process them after we return and surprise the user. */
3886 discard_mouse_events ();
3887 /* Allow mouse events generation by dos_rawgetc. */
3892 /* Dispose of a menu. */
3895 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3898 if (menu
->allocated
)
3900 for (i
= 0; i
< menu
->count
; i
++)
3901 if (menu
->submenu
[i
])
3902 XMenuDestroy (foo
, menu
->submenu
[i
]);
3904 xfree (menu
->submenu
);
3905 xfree (menu
->panenumber
);
3906 xfree (menu
->help_text
);
3909 menu_help_message
= prev_menu_help_message
= NULL
;
3913 x_pixel_width (struct frame
*f
)
3915 return FRAME_WIDTH (f
);
3919 x_pixel_height (struct frame
*f
)
3921 return FRAME_HEIGHT (f
);
3923 #endif /* !HAVE_X_WINDOWS */
3925 /* ----------------------- DOS / UNIX conversion --------------------- */
3927 void msdos_downcase_filename (unsigned char *);
3929 /* Destructively turn backslashes into slashes. */
3932 dostounix_filename (p
)
3935 msdos_downcase_filename (p
);
3945 /* Destructively turn slashes into backslashes. */
3948 unixtodos_filename (p
)
3951 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3965 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3968 getdefdir (drive
, dst
)
3972 char in_path
[4], *p
= in_path
;
3975 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3978 *p
++ = drive
+ 'A' - 1;
3985 _fixpath (in_path
, dst
);
3986 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3987 it queries the LFN support, so ignore that error. */
3988 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
3991 msdos_downcase_filename (dst
);
3997 /* Remove all CR's that are followed by a LF. */
4002 register unsigned char *buf
;
4004 unsigned char *np
= buf
;
4005 unsigned char *startp
= buf
;
4006 unsigned char *endp
= buf
+ n
;
4010 while (buf
< endp
- 1)
4014 if (*(++buf
) != 0x0a)
4025 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4027 /* In DJGPP v2.0, library `write' can call `malloc', which might
4028 cause relocation of the buffer whose address we get in ADDR.
4029 Here is a version of `write' that avoids calling `malloc',
4030 to serve us until such time as the library is fixed.
4031 Actually, what we define here is called `__write', because
4032 `write' is a stub that just jmp's to `__write' (to be
4033 POSIXLY-correct with respect to the global name-space). */
4035 #include <io.h> /* for _write */
4036 #include <libc/dosio.h> /* for __file_handle_modes[] */
4038 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
4040 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4043 __write (int handle
, const void *buffer
, size_t count
)
4048 if(__file_handle_modes
[handle
] & O_BINARY
)
4049 return _write (handle
, buffer
, count
);
4053 const char *bp
= buffer
;
4054 int total_written
= 0;
4055 int nmoved
= 0, ncr
= 0;
4059 /* The next test makes sure there's space for at least 2 more
4060 characters in xbuf[], so both CR and LF can be put there. */
4072 if (xbp
>= XBUF_END
|| !count
)
4074 size_t to_write
= nmoved
+ ncr
;
4075 int written
= _write (handle
, xbuf
, to_write
);
4080 total_written
+= nmoved
; /* CRs aren't counted in ret value */
4082 /* If some, but not all were written (disk full?), return
4083 an estimate of the total written bytes not counting CRs. */
4084 if (written
< to_write
)
4085 return total_written
- (to_write
- written
) * nmoved
/to_write
;
4092 return total_written
;
4096 /* A low-level file-renaming function which works around Windows 95 bug.
4097 This is pulled directly out of DJGPP v2.01 library sources, and only
4098 used when you compile with DJGPP v2.0. */
4102 int _rename(const char *old
, const char *new)
4105 int olen
= strlen(old
) + 1;
4107 int use_lfn
= _USE_LFN
;
4108 char tempfile
[FILENAME_MAX
];
4109 const char *orig
= old
;
4112 r
.x
.dx
= __tb_offset
;
4113 r
.x
.di
= __tb_offset
+ olen
;
4114 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4118 /* Windows 95 bug: for some filenames, when you rename
4119 file -> file~ (as in Emacs, to leave a backup), the
4120 short 8+3 alias doesn't change, which effectively
4121 makes OLD and NEW the same file. We must rename
4122 through a temporary file to work around this. */
4124 char *pbase
= 0, *p
;
4125 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4126 int idx
= sizeof(try_char
) - 1;
4128 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4129 might point to another drive, which will fail the DOS call. */
4130 strcpy(tempfile
, old
);
4131 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4132 if (*p
== '/' || *p
== '\\' || *p
== ':')
4138 strcpy(pbase
, "X$$djren$$.$$temp$$");
4144 *pbase
= try_char
[--idx
];
4145 } while (_chmod(tempfile
, 0) != -1);
4148 _put_path2(tempfile
, olen
);
4150 __dpmi_int(0x21, &r
);
4153 errno
= __doserr_to_errno(r
.x
.ax
);
4157 /* Now create a file with the original name. This will
4158 ensure that NEW will always have a 8+3 alias
4159 different from that of OLD. (Seems to be required
4160 when NameNumericTail in the Registry is set to 0.) */
4161 lfn_fd
= _creat(old
, 0);
4163 olen
= strlen(tempfile
) + 1;
4165 r
.x
.di
= __tb_offset
+ olen
;
4174 _put_path2(new, olen
);
4176 __dpmi_int(0x21, &r
);
4179 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4180 remove(new); /* and try again */
4183 errno
= __doserr_to_errno(r
.x
.ax
);
4185 /* Restore to original name if we renamed it to temporary. */
4193 _put_path2(orig
, olen
);
4194 _put_path(tempfile
);
4196 __dpmi_int(0x21, &r
);
4205 /* Success. Delete the file possibly created to work
4206 around the Windows 95 bug. */
4208 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4212 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4214 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4216 "Return non-nil if long file names are supported on MSDOS.")
4219 return (_USE_LFN
? Qt
: Qnil
);
4222 /* Convert alphabetic characters in a filename to lower-case. */
4225 msdos_downcase_filename (p
)
4226 register unsigned char *p
;
4228 /* Always lower-case drive letters a-z, even if the filesystem
4229 preserves case in filenames.
4230 This is so MSDOS filenames could be compared by string comparison
4231 functions that are case-sensitive. Even case-preserving filesystems
4232 do not distinguish case in drive letters. */
4233 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4239 /* Under LFN we expect to get pathnames in their true case. */
4240 if (NILP (Fmsdos_long_file_names ()))
4242 if (*p
>= 'A' && *p
<= 'Z')
4246 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4248 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
4249 When long filenames are supported, doesn't change FILENAME.\n\
4250 If FILENAME is not a string, returns nil.\n\
4251 The argument object is never altered--the value is a copy.")
4253 Lisp_Object filename
;
4257 if (! STRINGP (filename
))
4260 tem
= Fcopy_sequence (filename
);
4261 msdos_downcase_filename (XSTRING (tem
)->data
);
4265 /* The Emacs root directory as determined by init_environment. */
4267 static char emacsroot
[MAXPATHLEN
];
4270 rootrelativepath (rel
)
4273 static char result
[MAXPATHLEN
+ 10];
4275 strcpy (result
, emacsroot
);
4276 strcat (result
, "/");
4277 strcat (result
, rel
);
4281 /* Define a lot of environment variables if not already defined. Don't
4282 remove anything unless you know what you're doing -- lots of code will
4283 break if one or more of these are missing. */
4286 init_environment (argc
, argv
, skip_args
)
4293 static const char * const tempdirs
[] = {
4294 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4297 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4299 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4300 temporary files and assume "/tmp" if $TMPDIR is unset, which
4301 will break on DOS/Windows. Refuse to work if we cannot find
4302 a directory, not even "c:/", usable for that purpose. */
4303 for (i
= 0; i
< imax
; i
++)
4305 const char *tmp
= tempdirs
[i
];
4308 tmp
= getenv (tmp
+ 1);
4309 /* Note that `access' can lie to us if the directory resides on a
4310 read-only filesystem, like CD-ROM or a write-protected floppy.
4311 The only way to be really sure is to actually create a file and
4312 see if it succeeds. But I think that's too much to ask. */
4313 if (tmp
&& access (tmp
, D_OK
) == 0)
4315 setenv ("TMPDIR", tmp
, 1);
4322 Fcons (build_string ("no usable temporary directories found!!"),
4324 "While setting TMPDIR: ");
4326 /* Note the startup time, so we know not to clear the screen if we
4327 exit immediately; see IT_reset_terminal_modes.
4328 (Yes, I know `clock' returns zero the first time it's called, but
4329 I do this anyway, in case some wiseguy changes that at some point.) */
4330 startup_time
= clock ();
4332 /* Find our root from argv[0]. Assuming argv[0] is, say,
4333 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4334 root
= alloca (MAXPATHLEN
+ 20);
4335 _fixpath (argv
[0], root
);
4336 msdos_downcase_filename (root
);
4337 len
= strlen (root
);
4338 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4342 && (strcmp (root
+ len
- 4, "/bin") == 0
4343 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4344 root
[len
- 4] = '\0';
4346 strcpy (root
, "c:/emacs"); /* let's be defensive */
4347 len
= strlen (root
);
4348 strcpy (emacsroot
, root
);
4350 /* We default HOME to our root. */
4351 setenv ("HOME", root
, 0);
4353 /* We default EMACSPATH to root + "/bin". */
4354 strcpy (root
+ len
, "/bin");
4355 setenv ("EMACSPATH", root
, 0);
4357 /* I don't expect anybody to ever use other terminals so the internal
4358 terminal is the default. */
4359 setenv ("TERM", "internal", 0);
4361 #ifdef HAVE_X_WINDOWS
4362 /* Emacs expects DISPLAY to be set. */
4363 setenv ("DISPLAY", "unix:0.0", 0);
4366 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4367 downcase it and mirror the backslashes. */
4368 s
= getenv ("COMSPEC");
4369 if (!s
) s
= "c:/command.com";
4370 t
= alloca (strlen (s
) + 1);
4372 dostounix_filename (t
);
4373 setenv ("SHELL", t
, 0);
4375 /* PATH is also downcased and backslashes mirrored. */
4376 s
= getenv ("PATH");
4378 t
= alloca (strlen (s
) + 3);
4379 /* Current directory is always considered part of MsDos's path but it is
4380 not normally mentioned. Now it is. */
4381 strcat (strcpy (t
, ".;"), s
);
4382 dostounix_filename (t
); /* Not a single file name, but this should work. */
4383 setenv ("PATH", t
, 1);
4385 /* In some sense all dos users have root privileges, so... */
4386 setenv ("USER", "root", 0);
4387 setenv ("NAME", getenv ("USER"), 0);
4389 /* Time zone determined from country code. To make this possible, the
4390 country code may not span more than one time zone. In other words,
4391 in the USA, you lose. */
4393 switch (dos_country_code
)
4395 case 31: /* Belgium */
4396 case 32: /* The Netherlands */
4397 case 33: /* France */
4398 case 34: /* Spain */
4399 case 36: /* Hungary */
4400 case 38: /* Yugoslavia (or what's left of it?) */
4401 case 39: /* Italy */
4402 case 41: /* Switzerland */
4403 case 42: /* Tjekia */
4404 case 45: /* Denmark */
4405 case 46: /* Sweden */
4406 case 47: /* Norway */
4407 case 48: /* Poland */
4408 case 49: /* Germany */
4409 /* Daylight saving from last Sunday in March to last Sunday in
4410 September, both at 2AM. */
4411 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4413 case 44: /* United Kingdom */
4414 case 351: /* Portugal */
4415 case 354: /* Iceland */
4416 setenv ("TZ", "GMT+00", 0);
4418 case 81: /* Japan */
4419 case 82: /* Korea */
4420 setenv ("TZ", "JST-09", 0);
4422 case 90: /* Turkey */
4423 case 358: /* Finland */
4424 setenv ("TZ", "EET-02", 0);
4426 case 972: /* Israel */
4427 /* This is an approximation. (For exact rules, use the
4428 `zoneinfo/israel' file which comes with DJGPP, but you need
4429 to install it in `/usr/share/zoneinfo/' directory first.) */
4430 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4438 static int break_stat
; /* BREAK check mode status. */
4439 static int stdin_stat
; /* stdin IOCTL status. */
4443 /* These must be global. */
4444 static _go32_dpmi_seginfo ctrl_break_vector
;
4445 static _go32_dpmi_registers ctrl_break_regs
;
4446 static int ctrlbreakinstalled
= 0;
4448 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4451 ctrl_break_func (regs
)
4452 _go32_dpmi_registers
*regs
;
4458 install_ctrl_break_check ()
4460 if (!ctrlbreakinstalled
)
4462 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4463 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4464 ctrlbreakinstalled
= 1;
4465 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4466 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4468 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4472 #endif /* __DJGPP__ < 2 */
4474 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4475 control chars by DOS. Determine the keyboard type. */
4480 union REGS inregs
, outregs
;
4481 static int first_time
= 1;
4483 break_stat
= getcbrk ();
4486 install_ctrl_break_check ();
4492 int86 (0x15, &inregs
, &outregs
);
4493 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4497 if (internal_terminal
4498 #ifdef HAVE_X_WINDOWS
4499 && inhibit_window_system
4503 inregs
.x
.ax
= 0x0021;
4504 int86 (0x33, &inregs
, &outregs
);
4505 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4508 /* Reportedly, the above doesn't work for some mouse drivers. There
4509 is an additional detection method that should work, but might be
4510 a little slower. Use that as an alternative. */
4511 inregs
.x
.ax
= 0x0000;
4512 int86 (0x33, &inregs
, &outregs
);
4513 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4518 have_mouse
= 1; /* enable mouse */
4521 if (outregs
.x
.bx
== 3)
4523 mouse_button_count
= 3;
4524 mouse_button_translate
[0] = 0; /* Left */
4525 mouse_button_translate
[1] = 2; /* Middle */
4526 mouse_button_translate
[2] = 1; /* Right */
4530 mouse_button_count
= 2;
4531 mouse_button_translate
[0] = 0;
4532 mouse_button_translate
[1] = 1;
4534 mouse_position_hook
= &mouse_get_pos
;
4538 #ifndef HAVE_X_WINDOWS
4540 /* Save the cursor shape used outside Emacs. */
4541 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4550 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4551 return (stdin_stat
!= -1);
4554 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4556 #else /* __DJGPP__ < 2 */
4560 /* I think it is wrong to overwrite `stdin_stat' every time
4561 but the first one this function is called, but I don't
4562 want to change the way it used to work in v1.x.--EZ */
4564 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4565 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4566 intdos (&inregs
, &outregs
);
4567 stdin_stat
= outregs
.h
.dl
;
4569 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4570 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4571 intdos (&inregs
, &outregs
);
4572 return !outregs
.x
.cflag
;
4574 #endif /* __DJGPP__ < 2 */
4577 /* Restore status of standard input and Ctrl-C checking. */
4582 union REGS inregs
, outregs
;
4584 setcbrk (break_stat
);
4589 #ifndef HAVE_X_WINDOWS
4590 /* Restore the cursor shape we found on startup. */
4594 inregs
.x
.cx
= outside_cursor
;
4595 int86 (0x10, &inregs
, &outregs
);
4599 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4601 #else /* not __DJGPP__ >= 2 */
4603 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4604 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4605 inregs
.x
.dx
= stdin_stat
;
4606 intdos (&inregs
, &outregs
);
4607 return !outregs
.x
.cflag
;
4609 #endif /* not __DJGPP__ >= 2 */
4613 /* Run command as specified by ARGV in directory DIR.
4614 The command is run with input from TEMPIN, output to
4615 file TEMPOUT and stderr to TEMPERR. */
4618 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4619 unsigned char **argv
;
4620 const char *working_dir
;
4621 int tempin
, tempout
, temperr
;
4624 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4625 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4626 int msshell
, result
= -1;
4627 int inbak
, outbak
, errbak
;
4631 /* Get current directory as MSDOS cwd is not per-process. */
4634 /* If argv[0] is the shell, it might come in any lettercase.
4635 Since `Fmember' is case-sensitive, we need to downcase
4636 argv[0], even if we are on case-preserving filesystems. */
4637 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4638 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4641 if (*pl
>= 'A' && *pl
<= 'Z')
4646 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4647 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4648 && !strcmp ("-c", argv
[1]);
4651 saveargv1
= argv
[1];
4652 saveargv2
= argv
[2];
4654 /* We only need to mirror slashes if a DOS shell will be invoked
4655 not via `system' (which does the mirroring itself). Yes, that
4656 means DJGPP v1.x will lose here. */
4657 if (argv
[2] && argv
[3])
4659 char *p
= alloca (strlen (argv
[2]) + 1);
4661 strcpy (argv
[2] = p
, saveargv2
);
4662 while (*p
&& isspace (*p
))
4674 chdir (working_dir
);
4678 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4679 goto done
; /* Allocation might fail due to lack of descriptors. */
4682 mouse_get_xy (&x
, &y
);
4684 dos_ttcooked (); /* do it here while 0 = stdin */
4692 if (msshell
&& !argv
[3])
4694 /* MS-DOS native shells are too restrictive. For starters, they
4695 cannot grok commands longer than 126 characters. In DJGPP v2
4696 and later, `system' is much smarter, so we'll call it instead. */
4700 /* A shell gets a single argument--its full command
4701 line--whose original was saved in `saveargv2'. */
4703 /* Don't let them pass empty command lines to `system', since
4704 with some shells it will try to invoke an interactive shell,
4705 which will hang Emacs. */
4706 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4710 extern char **environ
;
4711 char **save_env
= environ
;
4712 int save_system_flags
= __system_flags
;
4714 /* Request the most powerful version of `system'. We need
4715 all the help we can get to avoid calling stock DOS shells. */
4716 __system_flags
= (__system_redirect
4717 | __system_use_shell
4718 | __system_allow_multiple_cmds
4719 | __system_allow_long_cmds
4720 | __system_handle_null_commands
4721 | __system_emulate_chdir
);
4724 result
= system (cmnd
);
4725 __system_flags
= save_system_flags
;
4729 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4733 #endif /* __DJGPP__ > 1 */
4735 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4740 emacs_close (inbak
);
4741 emacs_close (outbak
);
4742 emacs_close (errbak
);
4748 mouse_moveto (x
, y
);
4751 /* Some programs might change the meaning of the highest bit of the
4752 text attribute byte, so we get blinking characters instead of the
4753 bright background colors. Restore that. */
4760 argv
[1] = saveargv1
;
4761 argv
[2] = saveargv2
;
4769 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4776 /* ------------------------- Compatibility functions -------------------
4781 /* Hostnames for a pc are not really funny,
4782 but they are used in change log so we emulate the best we can. */
4784 gethostname (p
, size
)
4788 char *q
= egetenv ("HOSTNAME");
4795 /* When time zones are set from Ms-Dos too many C-libraries are playing
4796 tricks with time values. We solve this by defining our own version
4797 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4798 once and after each call to `tzset' with TZ changed. That is
4799 accomplished by aliasing tzset to init_gettimeofday. */
4801 static struct tm time_rec
;
4804 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4812 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4816 time_rec
.tm_year
= d
.da_year
- 1900;
4817 time_rec
.tm_mon
= d
.da_mon
- 1;
4818 time_rec
.tm_mday
= d
.da_day
;
4821 time_rec
.tm_hour
= t
.ti_hour
;
4822 time_rec
.tm_min
= t
.ti_min
;
4823 time_rec
.tm_sec
= t
.ti_sec
;
4826 tm
.tm_gmtoff
= dos_timezone_offset
;
4828 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4829 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4831 /* Ignore tzp; it's obsolescent. */
4835 #endif /* __DJGPP__ < 2 */
4838 * A list of unimplemented functions that we silently ignore.
4842 unsigned alarm (s
) unsigned s
; {}
4843 fork () { return 0; }
4844 int kill (x
, y
) int x
, y
; { return -1; }
4846 void volatile pause () {}
4847 sigsetmask (x
) int x
; { return 0; }
4848 sigblock (mask
) int mask
; { return 0; }
4851 void request_sigio (void) {}
4852 setpgrp () {return 0; }
4853 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4854 void unrequest_sigio (void) {}
4858 #ifdef POSIX_SIGNALS
4860 /* Augment DJGPP library POSIX signal functions. This is needed
4861 as of DJGPP v2.01, but might be in the library in later releases. */
4863 #include <libc/bss.h>
4865 /* A counter to know when to re-initialize the static sets. */
4866 static int sigprocmask_count
= -1;
4868 /* Which signals are currently blocked (initially none). */
4869 static sigset_t current_mask
;
4871 /* Which signals are pending (initially none). */
4872 static sigset_t pending_signals
;
4874 /* Previous handlers to restore when the blocked signals are unblocked. */
4875 typedef void (*sighandler_t
)(int);
4876 static sighandler_t prev_handlers
[320];
4878 /* A signal handler which just records that a signal occured
4879 (it will be raised later, if and when the signal is unblocked). */
4881 sig_suspender (signo
)
4884 sigaddset (&pending_signals
, signo
);
4888 sigprocmask (how
, new_set
, old_set
)
4890 const sigset_t
*new_set
;
4896 /* If called for the first time, initialize. */
4897 if (sigprocmask_count
!= __bss_count
)
4899 sigprocmask_count
= __bss_count
;
4900 sigemptyset (&pending_signals
);
4901 sigemptyset (¤t_mask
);
4902 for (signo
= 0; signo
< 320; signo
++)
4903 prev_handlers
[signo
] = SIG_ERR
;
4907 *old_set
= current_mask
;
4912 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4918 sigemptyset (&new_mask
);
4920 /* DJGPP supports upto 320 signals. */
4921 for (signo
= 0; signo
< 320; signo
++)
4923 if (sigismember (¤t_mask
, signo
))
4924 sigaddset (&new_mask
, signo
);
4925 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4927 sigaddset (&new_mask
, signo
);
4929 /* SIGKILL is silently ignored, as on other platforms. */
4930 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4931 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4933 if (( how
== SIG_UNBLOCK
4934 && sigismember (&new_mask
, signo
)
4935 && sigismember (new_set
, signo
))
4936 || (how
== SIG_SETMASK
4937 && sigismember (&new_mask
, signo
)
4938 && !sigismember (new_set
, signo
)))
4940 sigdelset (&new_mask
, signo
);
4941 if (prev_handlers
[signo
] != SIG_ERR
)
4943 signal (signo
, prev_handlers
[signo
]);
4944 prev_handlers
[signo
] = SIG_ERR
;
4946 if (sigismember (&pending_signals
, signo
))
4948 sigdelset (&pending_signals
, signo
);
4953 current_mask
= new_mask
;
4957 #else /* not POSIX_SIGNALS */
4959 sigsetmask (x
) int x
; { return 0; }
4960 sigblock (mask
) int mask
; { return 0; }
4962 #endif /* not POSIX_SIGNALS */
4963 #endif /* __DJGPP__ > 1 */
4966 #include "sysselect.h"
4968 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4969 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4970 ((long)(time).tv_sec < 0 \
4971 || ((time).tv_sec == 0 \
4972 && (long)(time).tv_usec <= 0))
4975 /* This yields the rest of the current time slice to the task manager.
4976 It should be called by any code which knows that it has nothing
4977 useful to do except idle.
4979 I don't use __dpmi_yield here, since versions of library before 2.02
4980 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4981 on some versions of Windows 9X. */
4984 dos_yield_time_slice (void)
4986 _go32_dpmi_registers r
;
4989 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
4990 _go32_dpmi_simulate_int (0x2f, &r
);
4995 /* Only event queue is checked. */
4996 /* We don't have to call timer_check here
4997 because wait_reading_process_input takes care of that. */
4999 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5001 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5002 EMACS_TIME
*timeout
;
5010 check_input
= FD_ISSET (0, rfds
);
5021 /* If we are looking only for the terminal, with no timeout,
5022 just read it and wait -- that's more efficient. */
5025 while (!detect_input_pending ())
5027 dos_yield_time_slice ();
5032 EMACS_TIME clnow
, cllast
, cldiff
;
5035 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
5037 while (!check_input
|| !detect_input_pending ())
5040 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
5041 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
5043 /* When seconds wrap around, we assume that no more than
5044 1 minute passed since last `gettime'. */
5045 if (EMACS_TIME_NEG_P (cldiff
))
5046 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
5047 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
5049 /* Stop when timeout value crosses zero. */
5050 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
5053 dos_yield_time_slice ();
5063 * Define overlaid functions:
5065 * chdir -> sys_chdir
5066 * tzset -> init_gettimeofday
5067 * abort -> dos_abort
5072 extern int chdir ();
5078 int len
= strlen (path
);
5079 char *tmp
= (char *)path
;
5081 if (*tmp
&& tmp
[1] == ':')
5083 if (getdisk () != tolower (tmp
[0]) - 'a')
5084 setdisk (tolower (tmp
[0]) - 'a');
5085 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
5089 if (len
> 1 && (tmp
[len
- 1] == '/'))
5091 char *tmp1
= (char *) alloca (len
+ 1);
5102 extern void tzset (void);
5105 init_gettimeofday ()
5111 ltm
= gtm
= time (NULL
);
5112 ltm
= mktime (lstm
= localtime (<m
));
5113 gtm
= mktime (gmtime (>m
));
5114 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
5115 time_rec
.tm_isdst
= lstm
->tm_isdst
;
5116 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
5123 dos_abort (file
, line
)
5127 char buffer1
[200], buffer2
[400];
5130 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5131 for (i
= j
= 0; buffer1
[i
]; i
++) {
5132 buffer2
[j
++] = buffer1
[i
];
5133 buffer2
[j
++] = 0x70;
5135 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5136 ScreenSetCursor (2, 0);
5144 ScreenSetCursor (10, 0);
5145 cputs ("\r\n\nEmacs aborted!\r\n");
5147 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5148 if (screen_virtual_segment
)
5149 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5150 /* Generate traceback, so we could tell whodunit. */
5151 signal (SIGINT
, SIG_DFL
);
5152 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5153 #else /* __DJGPP_MINOR__ >= 2 */
5155 #endif /* __DJGPP_MINOR__ >= 2 */
5161 /* The following variables are required so that cus-start.el won't
5162 complain about unbound variables. */
5163 #ifndef HAVE_X_WINDOWS
5164 /* Search path for bitmap files (xfns.c). */
5165 Lisp_Object Vx_bitmap_file_path
;
5166 int x_stretch_cursor_p
;
5168 #ifndef subprocesses
5169 /* Nonzero means delete a process right away if it exits (process.c). */
5170 static int delete_exited_processes
;
5175 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5176 staticpro (&recent_doskeys
);
5177 #ifndef HAVE_X_WINDOWS
5179 staticpro (&help_echo
);
5180 help_echo_object
= Qnil
;
5181 staticpro (&help_echo_object
);
5182 help_echo_window
= Qnil
;
5183 staticpro (&help_echo_window
);
5184 previous_help_echo
= Qnil
;
5185 staticpro (&previous_help_echo
);
5188 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
5189 "List of directories to search for bitmap files for X.");
5190 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
5192 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p
,
5193 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
5194 For example, if a block cursor is over a tab, it will be drawn as\n\
5195 wide as that tab on the display. (No effect on MS-DOS.)");
5196 x_stretch_cursor_p
= 0;
5198 /* The following three are from xfns.c: */
5199 Qbackground_color
= intern ("background-color");
5200 staticpro (&Qbackground_color
);
5201 Qforeground_color
= intern ("foreground-color");
5202 staticpro (&Qforeground_color
);
5203 Qbar
= intern ("bar");
5205 Qcursor_type
= intern ("cursor-type");
5206 staticpro (&Qcursor_type
);
5207 Qreverse
= intern ("reverse");
5208 staticpro (&Qreverse
);
5210 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5211 "*Glyph to display instead of chars not supported by current codepage.\n\
5213 This variable is used only by MSDOS terminals.");
5214 Vdos_unsupported_char_glyph
= '\177';
5216 #ifndef subprocesses
5217 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5218 "*Non-nil means delete processes immediately when they exit.\n\
5219 nil means don't delete them until `list-processes' is run.");
5220 delete_exited_processes
= 0;
5223 defsubr (&Srecent_doskeys
);
5224 defsubr (&Smsdos_long_file_names
);
5225 defsubr (&Smsdos_downcase_filename
);
5226 defsubr (&Smsdos_remember_default_colors
);