1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
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. */
34 #include <sys/param.h>
38 #include <string.h> /* for memset and string functions */
39 #include <sys/stat.h> /* for _fixpath */
40 #include <unistd.h> /* for chdir, dup, dup2, etc. */
41 #include <dir.h> /* for getdisk */
42 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
44 #include <io.h> /* for setmode */
45 #include <dpmi.h> /* for __dpmi_xxx stuff */
46 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
47 #include <libc/dosio.h> /* for _USE_LFN */
48 #include <conio.h> /* for cputs */
53 #include "termhooks.h"
55 #include "dispextern.h"
58 #include "character.h"
64 #include "blockinput.h"
66 #include "intervals.h"
70 /* #include <process.h> */
71 /* Damn that local process.h! Instead we can define P_WAIT and
74 extern int spawnve (int, const char *, char *const [], char *const []);
81 #define _dos_ds _go32_info_block.selector_for_linear_memory
85 #include "syssignal.h"
91 /* If other `malloc' than ours is used, force our `sbrk' behave like
92 Unix programs expect (resize memory blocks to keep them contiguous).
93 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
94 because that's what `gmalloc' expects to get. */
98 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
99 #else /* not REL_ALLOC */
100 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
101 #endif /* not REL_ALLOC */
102 #endif /* GNU_MALLOC */
104 #endif /* not SYSTEM_MALLOC */
107 event_timestamp (void)
123 /* ------------------------ Mouse control ---------------------------
125 * Coordinates are in screen positions and zero based.
126 * Mouse buttons are numbered from left to right and also zero based.
129 /* This used to be in termhooks.h, but mainstream Emacs code no longer
130 uses it, and it was removed... */
131 #define NUM_MOUSE_BUTTONS (5)
133 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
134 static int mouse_visible
;
136 static int mouse_last_x
;
137 static int mouse_last_y
;
139 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
140 static int mouse_button_count
;
147 if (have_mouse
> 0 && !mouse_visible
)
149 struct tty_display_info
*tty
= CURTTY ();
152 fprintf (tty
->termscript
, "<M_ON>");
154 int86 (0x33, ®s
, ®s
);
164 if (have_mouse
> 0 && mouse_visible
)
166 struct tty_display_info
*tty
= CURTTY ();
169 fprintf (tty
->termscript
, "<M_OFF>");
171 int86 (0x33, ®s
, ®s
);
177 mouse_setup_buttons (int n_buttons
)
181 mouse_button_count
= 3;
182 mouse_button_translate
[0] = 0; /* Left */
183 mouse_button_translate
[1] = 2; /* Middle */
184 mouse_button_translate
[2] = 1; /* Right */
186 else /* two, what else? */
188 mouse_button_count
= 2;
189 mouse_button_translate
[0] = 0;
190 mouse_button_translate
[1] = 1;
194 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons
, Smsdos_set_mouse_buttons
,
195 1, 1, "NSet number of mouse buttons to: ",
196 doc
: /* Set the number of mouse buttons to use by Emacs.
197 This is useful with mice that report the number of buttons inconsistently,
198 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
199 them. This happens with wheeled mice on Windows 9X, for example. */)
200 (Lisp_Object nbuttons
)
204 CHECK_NUMBER (nbuttons
);
207 xsignal2 (Qargs_out_of_range
,
208 build_string ("only 2 or 3 mouse buttons are supported"),
210 mouse_setup_buttons (n
);
215 mouse_get_xy (int *x
, int *y
)
220 int86 (0x33, ®s
, ®s
);
226 mouse_moveto (int x
, int y
)
229 struct tty_display_info
*tty
= CURTTY ();
232 fprintf (tty
->termscript
, "<M_XY=%dx%d>", x
, y
);
234 mouse_last_x
= regs
.x
.cx
= x
* 8;
235 mouse_last_y
= regs
.x
.dx
= y
* 8;
236 int86 (0x33, ®s
, ®s
);
240 mouse_pressed (int b
, int *xp
, int *yp
)
244 if (b
>= mouse_button_count
)
247 regs
.x
.bx
= mouse_button_translate
[b
];
248 int86 (0x33, ®s
, ®s
);
250 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
251 return (regs
.x
.bx
!= 0);
255 mouse_released (int b
, int *xp
, int *yp
)
259 if (b
>= mouse_button_count
)
262 regs
.x
.bx
= mouse_button_translate
[b
];
263 int86 (0x33, ®s
, ®s
);
265 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
266 return (regs
.x
.bx
!= 0);
270 mouse_button_depressed (int b
, int *xp
, int *yp
)
274 if (b
>= mouse_button_count
)
277 int86 (0x33, ®s
, ®s
);
278 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
288 mouse_get_pos (FRAME_PTR
*f
, int insist
, Lisp_Object
*bar_window
,
289 enum scroll_bar_part
*part
, Lisp_Object
*x
, Lisp_Object
*y
,
293 Lisp_Object frame
, tail
;
295 /* Clear the mouse-moved flag for every frame on this display. */
296 FOR_EACH_FRAME (tail
, frame
)
297 XFRAME (frame
)->mouse_moved
= 0;
299 *f
= SELECTED_FRAME();
301 mouse_get_xy (&ix
, &iy
);
302 *time
= event_timestamp ();
303 *x
= make_number (mouse_last_x
= ix
);
304 *y
= make_number (mouse_last_y
= iy
);
308 mouse_check_moved (void)
312 mouse_get_xy (&x
, &y
);
313 SELECTED_FRAME()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
318 /* Force the mouse driver to ``forget'' about any button clicks until
321 mouse_clear_clicks (void)
325 for (b
= 0; b
< mouse_button_count
; b
++)
327 int dummy_x
, dummy_y
;
329 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
330 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
338 struct tty_display_info
*tty
= CURTTY ();
341 fprintf (tty
->termscript
, "<M_INIT>");
344 int86 (0x33, ®s
, ®s
);
346 /* Reset the mouse last press/release info. It seems that Windows
347 doesn't do that automatically when function 21h is called, which
348 causes Emacs to ``remember'' the click that switched focus to the
349 window just before Emacs was started from that window. */
350 mouse_clear_clicks ();
354 regs
.x
.dx
= 8 * (ScreenCols () - 1);
355 int86 (0x33, ®s
, ®s
);
359 regs
.x
.dx
= 8 * (ScreenRows () - 1);
360 int86 (0x33, ®s
, ®s
);
366 /* ------------------------- Screen control ----------------------
370 static int internal_terminal
= 0;
372 #ifndef HAVE_X_WINDOWS
373 extern unsigned char ScreenAttrib
;
374 static int screen_face
;
376 static int screen_size_X
;
377 static int screen_size_Y
;
378 static int screen_size
;
380 static int current_pos_X
;
381 static int current_pos_Y
;
382 static int new_pos_X
;
383 static int new_pos_Y
;
385 static void *startup_screen_buffer
;
386 static int startup_screen_size_X
;
387 static int startup_screen_size_Y
;
388 static int startup_pos_X
;
389 static int startup_pos_Y
;
390 static unsigned char startup_screen_attrib
;
392 static clock_t startup_time
;
394 static int term_setup_done
;
396 static unsigned short outside_cursor
;
398 /* Similar to the_only_frame. */
399 struct tty_display_info the_only_display_info
;
401 /* Support for DOS/V (allows Japanese characters to be displayed on
402 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
404 /* Holds the address of the text-mode screen buffer. */
405 static unsigned long screen_old_address
= 0;
406 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
407 static unsigned short screen_virtual_segment
= 0;
408 static unsigned short screen_virtual_offset
= 0;
409 /* A flag to control how to display unibyte 8-bit characters. */
410 extern int unibyte_display_via_language_environment
;
412 extern Lisp_Object Qcursor_type
;
413 extern Lisp_Object Qbar
, Qhbar
;
415 /* The screen colors of the current frame, which serve as the default
416 colors for newly-created frames. */
417 static int initial_screen_colors
[2];
419 /* Update the screen from a part of relocated DOS/V screen buffer which
420 begins at OFFSET and includes COUNT characters. */
422 dosv_refresh_virtual_screen (int offset
, int count
)
426 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
429 regs
.h
.ah
= 0xff; /* update relocated screen */
430 regs
.x
.es
= screen_virtual_segment
;
431 regs
.x
.di
= screen_virtual_offset
+ offset
;
433 __dpmi_int (0x10, ®s
);
437 dos_direct_output (int y
, int x
, char *buf
, int len
)
439 int t0
= 2 * (x
+ y
* screen_size_X
);
440 int t
= t0
+ (int) ScreenPrimary
;
443 /* This is faster. */
444 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
445 _farnspokeb (t
, *buf
);
447 if (screen_virtual_segment
)
448 dosv_refresh_virtual_screen (t0
, l0
);
452 #ifndef HAVE_X_WINDOWS
454 static int blink_bit
= -1; /* the state of the blink bit at startup */
456 /* Enable bright background colors. */
462 /* Remember the original state of the blink/bright-background bit.
463 It is stored at 0040:0065h in the BIOS data area. */
465 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
469 int86 (0x10, ®s
, ®s
);
472 /* Disable bright background colors (and enable blinking) if we found
473 the video system in that state at startup. */
475 maybe_enable_blinking (void)
483 int86 (0x10, ®s
, ®s
);
487 /* Return non-zero if the system has a VGA adapter. */
494 int86 (0x10, ®s
, ®s
);
495 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
500 /* Set the screen dimensions so that it can show no less than
501 ROWS x COLS frame. */
504 dos_set_window_size (int *rows
, int *cols
)
508 Lisp_Object video_mode
;
509 int video_mode_value
, have_vga
= 0;
510 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
512 if (*rows
== current_rows
&& *cols
== current_cols
)
516 have_vga
= vga_installed ();
518 /* If the user specified a special video mode for these dimensions,
520 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
521 video_mode
= Fsymbol_value (Fintern_soft (build_string (video_name
), Qnil
));
523 if (INTEGERP (video_mode
)
524 && (video_mode_value
= XINT (video_mode
)) > 0)
526 regs
.x
.ax
= video_mode_value
;
527 int86 (0x10, ®s
, ®s
);
531 /* Must hardware-reset the mouse, or else it won't update
532 its notion of screen dimensions for some non-standard
533 video modes. This is *painfully* slow... */
535 int86 (0x33, ®s
, ®s
);
539 /* Find one of the dimensions supported by standard EGA/VGA
540 which gives us at least the required dimensions. */
545 } std_dimension
[] = {
555 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
557 if (std_dimension
[i
].need_vga
<= have_vga
558 && std_dimension
[i
].rows
>= *rows
)
560 if (std_dimension
[i
].rows
!= current_rows
561 || *cols
!= current_cols
)
562 _set_screen_lines (std_dimension
[i
].rows
);
576 /* Tell the caller what dimensions have been REALLY set. */
577 *rows
= ScreenRows ();
578 *cols
= ScreenCols ();
580 /* Update Emacs' notion of screen dimensions. */
581 screen_size_X
= *cols
;
582 screen_size_Y
= *rows
;
583 screen_size
= *cols
* *rows
;
585 /* If the dimensions changed, the mouse highlight info is invalid. */
586 if (current_rows
!= *rows
|| current_cols
!= *cols
)
588 struct frame
*f
= SELECTED_FRAME();
589 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
590 Lisp_Object window
= dpyinfo
->mouse_face_window
;
592 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
594 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
595 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
596 dpyinfo
->mouse_face_window
= Qnil
;
600 /* Enable bright background colors. */
603 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
604 be defensive anyway. */
605 if (screen_virtual_segment
)
606 dosv_refresh_virtual_screen (0, *cols
* *rows
);
609 /* If we write a character in the position where the mouse is,
610 the mouse cursor may need to be refreshed. */
613 mouse_off_maybe (void)
620 mouse_get_xy (&x
, &y
);
621 if (y
!= new_pos_Y
|| x
< new_pos_X
)
627 #define DEFAULT_CURSOR_START (-1)
628 #define DEFAULT_CURSOR_WIDTH (-1)
629 #define BOX_CURSOR_WIDTH (-32)
631 /* Set cursor to begin at scan line START_LINE in the character cell
632 and extend for WIDTH scan lines. Scan lines are counted from top
633 of the character cell, starting from zero. */
635 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
637 unsigned desired_cursor
;
639 int max_line
, top_line
, bot_line
;
640 struct tty_display_info
*tty
= FRAME_TTY (f
);
642 /* Avoid the costly BIOS call if F isn't the currently selected
643 frame. Allow for NULL as unconditionally meaning the selected
645 if (f
&& f
!= SELECTED_FRAME())
649 fprintf (tty
->termscript
, "\nCURSOR SHAPE=(%d,%d)", start_line
, width
);
651 /* The character cell size in scan lines is stored at 40:85 in the
653 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
656 default: /* this relies on CGA cursor emulation being ON! */
673 if (width
== BOX_CURSOR_WIDTH
)
678 else if (start_line
!= DEFAULT_CURSOR_START
)
680 top_line
= start_line
;
681 bot_line
= top_line
- width
- 1;
683 else if (width
!= DEFAULT_CURSOR_WIDTH
)
686 bot_line
= -1 - width
;
689 top_line
= bot_line
+ 1;
693 /* [31, 0] seems to DTRT for all screen sizes. */
697 else /* WIDTH is positive */
699 if (start_line
!= DEFAULT_CURSOR_START
)
700 bot_line
= start_line
;
701 top_line
= bot_line
- (width
- 1);
704 /* If the current cursor shape is already what they want, we are
706 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
707 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
711 regs
.x
.cx
= desired_cursor
;
712 __dpmi_int (0x10, ®s
);
716 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
718 if (EQ (cursor_type
, Qbar
) || EQ (cursor_type
, Qhbar
))
720 /* Just BAR means the normal EGA/VGA cursor. */
721 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
723 else if (CONSP (cursor_type
)
724 && (EQ (XCAR (cursor_type
), Qbar
)
725 || EQ (XCAR (cursor_type
), Qhbar
)))
727 Lisp_Object bar_parms
= XCDR (cursor_type
);
730 if (INTEGERP (bar_parms
))
732 /* Feature: negative WIDTH means cursor at the top
733 of the character cell, zero means invisible cursor. */
734 width
= XINT (bar_parms
);
735 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
738 else if (CONSP (bar_parms
)
739 && INTEGERP (XCAR (bar_parms
))
740 && INTEGERP (XCDR (bar_parms
)))
742 int start_line
= XINT (XCDR (bar_parms
));
744 width
= XINT (XCAR (bar_parms
));
745 msdos_set_cursor_shape (f
, start_line
, width
);
750 /* Treat anything unknown as "box cursor". This includes nil, so
751 that a frame which doesn't specify a cursor type gets a box,
752 which is the default in Emacs. */
753 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
758 IT_ring_bell (struct frame
*f
)
767 union REGS inregs
, outregs
;
770 intdos (&inregs
, &outregs
);
774 /* Given a face id FACE, extract the face parameters to be used for
775 display until the face changes. The face parameters (actually, its
776 color) are used to construct the video attribute byte for each
777 glyph during the construction of the buffer that is then blitted to
780 IT_set_face (int face
)
782 struct frame
*sf
= SELECTED_FRAME();
783 struct face
*fp
= FACE_FROM_ID (sf
, face
);
784 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
785 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
786 struct tty_display_info
*tty
= FRAME_TTY (sf
);
791 /* The default face for the frame should always be realized and
799 dflt_fg
= dfp
->foreground
;
800 dflt_bg
= dfp
->background
;
802 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
803 mean use the colors of the default face. Note that we assume all
804 16 colors to be available for the background, since Emacs switches
805 on this mode (and loses the blinking attribute) at startup. */
806 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
807 fg
= FRAME_FOREGROUND_PIXEL (sf
);
808 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
809 fg
= FRAME_BACKGROUND_PIXEL (sf
);
810 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
811 bg
= FRAME_BACKGROUND_PIXEL (sf
);
812 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
813 bg
= FRAME_FOREGROUND_PIXEL (sf
);
815 /* Make sure highlighted lines really stand out, come what may. */
816 if (fp
->tty_reverse_p
&& (fg
== dflt_fg
&& bg
== dflt_bg
))
818 unsigned long tem
= fg
;
823 /* If the user requested inverse video, obey. */
826 unsigned long tem2
= fg
;
832 fprintf (tty
->termscript
, "<FACE %d: %lu/%lu[FG:%lu/BG:%lu]>", face
,
833 fp
->foreground
, fp
->background
, fg
, bg
);
834 if (fg
>= 0 && fg
< 16)
836 ScreenAttrib
&= 0xf0;
839 if (bg
>= 0 && bg
< 16)
841 ScreenAttrib
&= 0x0f;
842 ScreenAttrib
|= ((bg
& 0x0f) << 4);
846 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
847 width of a DOS display in any known text mode. We multiply by 2 to
848 accomodate the screen attribute byte. */
849 #define MAX_SCREEN_BUF 160*2
851 Lisp_Object Vdos_unsupported_char_glyph
;
852 extern unsigned char *encode_terminal_code (struct glyph
*, int,
853 struct coding_system
*);
855 IT_write_glyphs (struct frame
*f
, struct glyph
*str
, int str_len
)
857 unsigned char screen_buf
[MAX_SCREEN_BUF
], *screen_bp
, *bp
;
858 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
859 register int sl
= str_len
;
860 struct tty_display_info
*tty
= FRAME_TTY (f
);
862 unsigned char *conversion_buffer
;
864 /* If terminal_coding does any conversion, use it, otherwise use
865 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
866 because it always returns 1 if terminal_coding.src_multibyte is 1. */
867 struct coding_system
*coding
= FRAME_TERMINAL_CODING (f
);
869 if (!(coding
->common_flags
& CODING_REQUIRE_ENCODING_MASK
))
870 coding
= &safe_terminal_coding
;
872 if (str_len
<= 0) return;
874 sf
= SELECTED_FRAME();
876 /* Since faces get cached and uncached behind our back, we can't
877 rely on their indices in the cache being consistent across
878 invocations. So always reset the screen face to the default
879 face of the frame, before writing glyphs, and let the glyphs
880 set the right face if it's different from the default. */
881 IT_set_face (DEFAULT_FACE_ID
);
883 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
885 coding
->mode
&= ~CODING_MODE_LAST_BLOCK
;
886 screen_bp
= &screen_buf
[0];
892 /* If the face of this glyph is different from the current
893 screen face, update the screen attribute byte. */
895 if (cf
!= screen_face
)
896 IT_set_face (cf
); /* handles invalid faces gracefully */
898 /* Identify a run of glyphs with the same face. */
899 for (n
= 1; n
< sl
; ++n
)
900 if (str
[n
].face_id
!= cf
)
904 /* This is the last glyph. */
905 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
907 conversion_buffer
= encode_terminal_code (str
, n
, coding
);
908 if (coding
->produced
> 0)
910 /* Copy the encoded bytes to the screen buffer. */
911 for (bp
= conversion_buffer
; coding
->produced
--; bp
++)
913 /* Paranoia: discard bytes that would overrun the end of
914 the screen buffer. */
915 if (screen_bp
- screen_buf
<= MAX_SCREEN_BUF
- 2)
917 *screen_bp
++ = (unsigned char)*bp
;
918 *screen_bp
++ = ScreenAttrib
;
921 fputc (*bp
, tty
->termscript
);
924 /* Update STR and its remaining length. */
929 /* Dump whatever we have in the screen buffer. */
931 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
932 if (screen_virtual_segment
)
933 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
934 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
937 /************************************************************************
938 Mouse Highlight (and friends..)
939 ************************************************************************/
941 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
942 static Lisp_Object last_mouse_window
;
944 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
946 /* Set the mouse pointer shape according to whether it is in the
947 area where the mouse highlight is in effect. */
949 IT_set_mouse_pointer (int mode
)
951 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
952 many possibilities to change its shape, and the available
953 functionality pretty much sucks (e.g., almost every reasonable
954 shape will conceal the character it is on). Since the color of
955 the pointer changes in the highlighted area, it is not clear to
956 me whether anything else is required, anyway. */
959 /* Display the active region described by mouse_face_*
960 in its mouse-face if HL > 0, in its normal face if HL = 0. */
962 show_mouse_face (struct tty_display_info
*dpyinfo
, int hl
)
964 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
965 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
968 struct tty_display_info
*tty
= FRAME_TTY (f
);
971 /* If window is in the process of being destroyed, don't bother
973 if (w
->current_matrix
== NULL
)
974 goto set_cursor_shape
;
976 /* Recognize when we are called to operate on rows that don't exist
977 anymore. This can happen when a window is split. */
978 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
979 goto set_cursor_shape
;
981 /* There's no sense to do anything if the mouse face isn't realized. */
984 if (dpyinfo
->mouse_face_hidden
)
985 goto set_cursor_shape
;
987 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
989 goto set_cursor_shape
;
992 /* Note that mouse_face_beg_row etc. are window relative. */
993 for (i
= dpyinfo
->mouse_face_beg_row
;
994 i
<= dpyinfo
->mouse_face_end_row
;
997 int start_hpos
, end_hpos
;
998 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1000 /* Don't do anything if row doesn't have valid contents. */
1001 if (!row
->enabled_p
)
1004 /* For all but the first row, the highlight starts at column 0. */
1005 if (i
== dpyinfo
->mouse_face_beg_row
)
1006 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1010 if (i
== dpyinfo
->mouse_face_end_row
)
1011 end_hpos
= dpyinfo
->mouse_face_end_col
;
1013 end_hpos
= row
->used
[TEXT_AREA
];
1015 if (end_hpos
<= start_hpos
)
1017 /* Record that some glyphs of this row are displayed in
1019 row
->mouse_face_p
= hl
> 0;
1022 int vpos
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1023 int kstart
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1024 int nglyphs
= end_hpos
- start_hpos
;
1025 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1026 int start_offset
= offset
;
1028 if (tty
->termscript
)
1029 fprintf (tty
->termscript
, "\n<MH+ %d-%d:%d>",
1030 kstart
, kstart
+ nglyphs
- 1, vpos
);
1033 IT_set_face (dpyinfo
->mouse_face_face_id
);
1034 /* Since we are going to change only the _colors_ of the
1035 displayed text, there's no need to go through all the
1036 pain of generating and encoding the text from the glyphs.
1037 Instead, we simply poke the attribute byte of each
1038 affected position in video memory with the colors
1039 computed by IT_set_face! */
1040 _farsetsel (_dos_ds
);
1043 _farnspokeb (offset
, ScreenAttrib
);
1046 if (screen_virtual_segment
)
1047 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1052 /* We are removing a previously-drawn mouse highlight. The
1053 safest way to do so is to redraw the glyphs anew, since
1054 all kinds of faces and display tables could have changed
1056 int nglyphs
= end_hpos
- start_hpos
;
1057 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1059 if (end_hpos
>= row
->used
[TEXT_AREA
])
1060 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1062 /* IT_write_glyphs writes at cursor position, so we need to
1063 temporarily move cursor coordinates to the beginning of
1064 the highlight region. */
1065 new_pos_X
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1066 new_pos_Y
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1068 if (tty
->termscript
)
1069 fprintf (tty
->termscript
, "<MH- %d-%d:%d>",
1070 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1071 IT_write_glyphs (f
, row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1072 if (tty
->termscript
)
1073 fputs ("\n", tty
->termscript
);
1080 /* Change the mouse pointer shape. */
1081 IT_set_mouse_pointer (hl
);
1084 /* Clear out the mouse-highlighted active region.
1085 Redraw it un-highlighted first. */
1087 clear_mouse_face (struct tty_display_info
*dpyinfo
)
1089 if (!dpyinfo
->mouse_face_hidden
&& ! NILP (dpyinfo
->mouse_face_window
))
1090 show_mouse_face (dpyinfo
, 0);
1092 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1093 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1094 dpyinfo
->mouse_face_window
= Qnil
;
1097 /* Find the glyph matrix position of buffer position POS in window W.
1098 *HPOS and *VPOS are set to the positions found. W's current glyphs
1099 must be up to date. If POS is above window start return (0, 0).
1100 If POS is after end of W, return end of last line in W. */
1102 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1104 int i
, lastcol
, line_start_position
, maybe_next_line_p
= 0;
1105 int yb
= window_text_bottom_y (w
);
1106 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0), *best_row
= row
;
1110 if (row
->used
[TEXT_AREA
])
1111 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1113 line_start_position
= 0;
1115 if (line_start_position
> pos
)
1117 /* If the position sought is the end of the buffer,
1118 don't include the blank lines at the bottom of the window. */
1119 else if (line_start_position
== pos
1120 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1122 maybe_next_line_p
= 1;
1125 else if (line_start_position
> 0)
1128 /* Don't overstep the last matrix row, lest we get into the
1129 never-never land... */
1130 if (row
->y
+ 1 >= yb
)
1136 /* Find the right column within BEST_ROW. */
1139 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1141 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1144 charpos
= glyph
->charpos
;
1151 else if (charpos
> pos
)
1153 else if (charpos
> 0)
1157 /* If we're looking for the end of the buffer,
1158 and we didn't find it in the line we scanned,
1159 use the start of the following line. */
1160 if (maybe_next_line_p
)
1167 *hpos
= lastcol
+ 1;
1171 /* Take proper action when mouse has moved to the mode or top line of
1172 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1173 mode line. X is relative to the start of the text display area of
1174 W, so the width of fringes and scroll bars must be subtracted
1175 to get a position relative to the start of the mode line. */
1177 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1179 struct glyph_row
*row
;
1182 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1184 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1188 struct glyph
*glyph
, *end
;
1191 /* Find the glyph under X. */
1192 glyph
= (row
->glyphs
[TEXT_AREA
]
1194 /* in case someone implements scroll bars some day... */
1195 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w
));
1196 end
= glyph
+ row
->used
[TEXT_AREA
];
1198 && STRINGP (glyph
->object
)
1199 && STRING_INTERVALS (glyph
->object
)
1200 && glyph
->charpos
>= 0
1201 && glyph
->charpos
< SCHARS (glyph
->object
))
1203 /* If we're on a string with `help-echo' text property,
1204 arrange for the help to be displayed. This is done by
1205 setting the global variable help_echo to the help string. */
1206 help
= Fget_text_property (make_number (glyph
->charpos
),
1207 Qhelp_echo
, glyph
->object
);
1210 help_echo_string
= help
;
1211 XSETWINDOW (help_echo_window
, w
);
1212 help_echo_object
= glyph
->object
;
1213 help_echo_pos
= glyph
->charpos
;
1219 /* Take proper action when the mouse has moved to position X, Y on
1220 frame F as regards highlighting characters that have mouse-face
1221 properties. Also de-highlighting chars where the mouse was before.
1222 X and Y can be negative or out of range. */
1224 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1226 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1227 enum window_part part
= ON_NOTHING
;
1231 /* When a menu is active, don't highlight because this looks odd. */
1232 if (mouse_preempted
)
1235 if (NILP (Vmouse_highlight
)
1236 || !f
->glyphs_initialized_p
)
1239 dpyinfo
->mouse_face_mouse_x
= x
;
1240 dpyinfo
->mouse_face_mouse_y
= y
;
1241 dpyinfo
->mouse_face_mouse_frame
= f
;
1243 if (dpyinfo
->mouse_face_defer
)
1248 dpyinfo
->mouse_face_deferred_gc
= 1;
1252 /* Which window is that in? */
1253 window
= window_from_coordinates (f
, x
, y
, &part
, &x
, &y
, 0);
1255 /* If we were displaying active text in another window, clear that. */
1256 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1257 clear_mouse_face (dpyinfo
);
1259 /* Not on a window -> return. */
1260 if (!WINDOWP (window
))
1263 /* Convert to window-relative coordinates. */
1264 w
= XWINDOW (window
);
1266 if (part
== ON_MODE_LINE
|| part
== ON_HEADER_LINE
)
1268 /* Mouse is on the mode or top line. */
1269 IT_note_mode_line_highlight (w
, x
, part
== ON_MODE_LINE
);
1273 IT_set_mouse_pointer (0);
1275 /* Are we in a window whose display is up to date?
1276 And verify the buffer's text has not changed. */
1278 && EQ (w
->window_end_valid
, w
->buffer
)
1279 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1280 && (XFASTINT (w
->last_overlay_modified
)
1281 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1283 int pos
, i
, nrows
= w
->current_matrix
->nrows
;
1284 struct glyph_row
*row
;
1285 struct glyph
*glyph
;
1287 /* Find the glyph under X/Y. */
1289 if (y
>= 0 && y
< nrows
)
1291 row
= MATRIX_ROW (w
->current_matrix
, y
);
1292 /* Give up if some row before the one we are looking for is
1294 for (i
= 0; i
<= y
; i
++)
1295 if (!MATRIX_ROW (w
->current_matrix
, i
)->enabled_p
)
1297 if (i
> y
/* all rows upto and including the one at Y are enabled */
1298 && row
->displays_text_p
1299 && x
< window_box_width (w
, TEXT_AREA
))
1301 glyph
= row
->glyphs
[TEXT_AREA
];
1302 if (x
>= row
->used
[TEXT_AREA
])
1307 if (!BUFFERP (glyph
->object
))
1313 /* Clear mouse face if X/Y not over text. */
1316 clear_mouse_face (dpyinfo
);
1320 if (!BUFFERP (glyph
->object
))
1322 pos
= glyph
->charpos
;
1324 /* Check for mouse-face and help-echo. */
1326 Lisp_Object mouse_face
, overlay
, position
, *overlay_vec
;
1327 int noverlays
, obegv
, ozv
;
1328 struct buffer
*obuf
;
1330 /* If we get an out-of-range value, return now; avoid an error. */
1331 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1334 /* Make the window's buffer temporarily current for
1335 overlays_at and compute_char_face. */
1336 obuf
= current_buffer
;
1337 current_buffer
= XBUFFER (w
->buffer
);
1343 /* Is this char mouse-active or does it have help-echo? */
1344 XSETINT (position
, pos
);
1346 /* Put all the overlays we want in a vector in overlay_vec. */
1347 GET_OVERLAYS_AT (pos
, overlay_vec
, noverlays
, NULL
, 0);
1348 /* Sort overlays into increasing priority order. */
1349 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1351 /* Check mouse-face highlighting. */
1352 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1353 && y
>= dpyinfo
->mouse_face_beg_row
1354 && y
<= dpyinfo
->mouse_face_end_row
1355 && (y
> dpyinfo
->mouse_face_beg_row
1356 || x
>= dpyinfo
->mouse_face_beg_col
)
1357 && (y
< dpyinfo
->mouse_face_end_row
1358 || x
< dpyinfo
->mouse_face_end_col
1359 || dpyinfo
->mouse_face_past_end
)))
1361 /* Clear the display of the old active region, if any. */
1362 clear_mouse_face (dpyinfo
);
1364 /* Find highest priority overlay that has a mouse-face prop. */
1366 for (i
= noverlays
- 1; i
>= 0; --i
)
1368 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1369 if (!NILP (mouse_face
))
1371 overlay
= overlay_vec
[i
];
1376 /* If no overlay applies, get a text property. */
1378 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1381 /* Handle the overlay case. */
1382 if (! NILP (overlay
))
1384 /* Find the range of text around this char that
1385 should be active. */
1386 Lisp_Object before
, after
;
1389 before
= Foverlay_start (overlay
);
1390 after
= Foverlay_end (overlay
);
1391 /* Record this as the current active region. */
1392 fast_find_position (w
, XFASTINT (before
),
1393 &dpyinfo
->mouse_face_beg_col
,
1394 &dpyinfo
->mouse_face_beg_row
);
1395 dpyinfo
->mouse_face_past_end
1396 = !fast_find_position (w
, XFASTINT (after
),
1397 &dpyinfo
->mouse_face_end_col
,
1398 &dpyinfo
->mouse_face_end_row
);
1399 dpyinfo
->mouse_face_window
= window
;
1400 dpyinfo
->mouse_face_face_id
1401 = face_at_buffer_position (w
, pos
, 0, 0,
1403 !dpyinfo
->mouse_face_hidden
,
1406 /* Display it as active. */
1407 show_mouse_face (dpyinfo
, 1);
1409 /* Handle the text property case. */
1410 else if (! NILP (mouse_face
))
1412 /* Find the range of text around this char that
1413 should be active. */
1414 Lisp_Object before
, after
, beginning
, end
;
1417 beginning
= Fmarker_position (w
->start
);
1418 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1419 - XFASTINT (w
->window_end_pos
)));
1421 = Fprevious_single_property_change (make_number (pos
+ 1),
1423 w
->buffer
, beginning
);
1425 = Fnext_single_property_change (position
, Qmouse_face
,
1427 /* Record this as the current active region. */
1428 fast_find_position (w
, XFASTINT (before
),
1429 &dpyinfo
->mouse_face_beg_col
,
1430 &dpyinfo
->mouse_face_beg_row
);
1431 dpyinfo
->mouse_face_past_end
1432 = !fast_find_position (w
, XFASTINT (after
),
1433 &dpyinfo
->mouse_face_end_col
,
1434 &dpyinfo
->mouse_face_end_row
);
1435 dpyinfo
->mouse_face_window
= window
;
1436 dpyinfo
->mouse_face_face_id
1437 = face_at_buffer_position (w
, pos
, 0, 0,
1439 !dpyinfo
->mouse_face_hidden
,
1442 /* Display it as active. */
1443 show_mouse_face (dpyinfo
, 1);
1447 /* Look for a `help-echo' property. */
1451 /* Check overlays first. */
1453 for (i
= noverlays
- 1; i
>= 0 && NILP (help
); --i
)
1455 overlay
= overlay_vec
[i
];
1456 help
= Foverlay_get (overlay
, Qhelp_echo
);
1461 help_echo_string
= help
;
1462 help_echo_window
= window
;
1463 help_echo_object
= overlay
;
1464 help_echo_pos
= pos
;
1466 /* Try text properties. */
1467 else if (NILP (help
)
1468 && ((STRINGP (glyph
->object
)
1469 && glyph
->charpos
>= 0
1470 && glyph
->charpos
< SCHARS (glyph
->object
))
1471 || (BUFFERP (glyph
->object
)
1472 && glyph
->charpos
>= BEGV
1473 && glyph
->charpos
< ZV
)))
1475 help
= Fget_text_property (make_number (glyph
->charpos
),
1476 Qhelp_echo
, glyph
->object
);
1479 help_echo_string
= help
;
1480 help_echo_window
= window
;
1481 help_echo_object
= glyph
->object
;
1482 help_echo_pos
= glyph
->charpos
;
1489 current_buffer
= obuf
;
1495 IT_clear_end_of_line (struct frame
*f
, int first_unused
)
1498 int i
, j
, offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1499 extern int fatal_error_in_progress
;
1500 struct tty_display_info
*tty
= FRAME_TTY (f
);
1502 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1506 i
= (j
= first_unused
- new_pos_X
) * 2;
1507 if (tty
->termscript
)
1508 fprintf (tty
->termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1509 spaces
= sp
= alloca (i
);
1514 *sp
++ = ScreenAttrib
;
1518 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1519 if (screen_virtual_segment
)
1520 dosv_refresh_virtual_screen (offset
, i
/ 2);
1522 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1523 Let's follow their lead, in case someone relies on this. */
1524 new_pos_X
= first_unused
;
1528 IT_clear_screen (struct frame
*f
)
1530 struct tty_display_info
*tty
= FRAME_TTY (f
);
1532 if (tty
->termscript
)
1533 fprintf (tty
->termscript
, "<CLR:SCR>");
1534 /* We are sometimes called (from clear_garbaged_frames) when a new
1535 frame is being created, but its faces are not yet realized. In
1536 such a case we cannot call IT_set_face, since it will fail to find
1537 any valid faces and will abort. Instead, use the initial screen
1538 colors; that should mimic what a Unix tty does, which simply clears
1539 the screen with whatever default colors are in use. */
1540 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1541 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1546 if (screen_virtual_segment
)
1547 dosv_refresh_virtual_screen (0, screen_size
);
1548 new_pos_X
= new_pos_Y
= 0;
1552 IT_clear_to_end (struct frame
*f
)
1554 struct tty_display_info
*tty
= FRAME_TTY (f
);
1556 if (tty
->termscript
)
1557 fprintf (tty
->termscript
, "<CLR:EOS>");
1559 while (new_pos_Y
< screen_size_Y
) {
1561 IT_clear_end_of_line (f
, screen_size_X
);
1567 IT_cursor_to (struct frame
*f
, int y
, int x
)
1569 struct tty_display_info
*tty
= FRAME_TTY (f
);
1571 if (tty
->termscript
)
1572 fprintf (tty
->termscript
, "\n<XY=%dx%d>", x
, y
);
1577 static int cursor_cleared
;
1580 IT_display_cursor (int on
)
1582 struct tty_display_info
*tty
= CURTTY ();
1584 if (on
&& cursor_cleared
)
1586 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1588 if (tty
->termscript
)
1589 fprintf (tty
->termscript
, "\nCURSOR ON (%dx%d)",
1590 current_pos_Y
, current_pos_X
);
1592 else if (!on
&& !cursor_cleared
)
1594 ScreenSetCursor (-1, -1);
1596 if (tty
->termscript
)
1597 fprintf (tty
->termscript
, "\nCURSOR OFF (%dx%d)",
1598 current_pos_Y
, current_pos_X
);
1602 /* Emacs calls cursor-movement functions a lot when it updates the
1603 display (probably a legacy of old terminals where you cannot
1604 update a screen line without first moving the cursor there).
1605 However, cursor movement is expensive on MSDOS (it calls a slow
1606 BIOS function and requires 2 mode switches), while actual screen
1607 updates access the video memory directly and don't depend on
1608 cursor position. To avoid slowing down the redisplay, we cheat:
1609 all functions that move the cursor only set internal variables
1610 which record the cursor position, whereas the cursor is only
1611 moved to its final position whenever screen update is complete.
1613 `IT_cmgoto' is called from the keyboard reading loop and when the
1614 frame update is complete. This means that we are ready for user
1615 input, so we update the cursor position to show where the point is,
1616 and also make the mouse pointer visible.
1618 Special treatment is required when the cursor is in the echo area,
1619 to put the cursor at the end of the text displayed there. */
1622 IT_cmgoto (FRAME_PTR f
)
1624 /* Only set the cursor to where it should be if the display is
1625 already in sync with the window contents. */
1626 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1627 struct tty_display_info
*tty
= FRAME_TTY (f
);
1629 /* FIXME: This needs to be rewritten for the new redisplay, or
1632 static int previous_pos_X
= -1;
1634 update_cursor_pos
= 1; /* temporary!!! */
1636 /* If the display is in sync, forget any previous knowledge about
1637 cursor position. This is primarily for unexpected events like
1638 C-g in the minibuffer. */
1639 if (update_cursor_pos
&& previous_pos_X
>= 0)
1640 previous_pos_X
= -1;
1641 /* If we are in the echo area, put the cursor at the
1642 end of the echo area message. */
1643 if (!update_cursor_pos
1644 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f
))) <= new_pos_Y
)
1646 int tem_X
= current_pos_X
, dummy
;
1648 if (echo_area_glyphs
)
1650 tem_X
= echo_area_glyphs_length
;
1651 /* Save current cursor position, to be restored after the
1652 echo area message is erased. Only remember one level
1653 of previous cursor position. */
1654 if (previous_pos_X
== -1)
1655 ScreenGetCursor (&dummy
, &previous_pos_X
);
1657 else if (previous_pos_X
>= 0)
1659 /* We wind up here after the echo area message is erased.
1660 Restore the cursor position we remembered above. */
1661 tem_X
= previous_pos_X
;
1662 previous_pos_X
= -1;
1665 if (current_pos_X
!= tem_X
)
1668 update_cursor_pos
= 1;
1673 if (update_cursor_pos
1674 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1676 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1677 if (tty
->termscript
)
1678 fprintf (tty
->termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1681 /* Maybe cursor is invisible, so make it visible. */
1682 IT_display_cursor (1);
1684 /* Mouse pointer should be always visible if we are waiting for
1691 IT_update_begin (struct frame
*f
)
1693 struct tty_display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1694 struct frame
*mouse_face_frame
= display_info
->mouse_face_mouse_frame
;
1696 if (display_info
->termscript
)
1697 fprintf (display_info
->termscript
, "\n\n<UPDATE_BEGIN");
1701 if (f
&& f
== mouse_face_frame
)
1703 /* Don't do highlighting for mouse motion during the update. */
1704 display_info
->mouse_face_defer
= 1;
1706 /* If F needs to be redrawn, simply forget about any prior mouse
1708 if (FRAME_GARBAGED_P (f
))
1709 display_info
->mouse_face_window
= Qnil
;
1711 /* Can we tell that this update does not affect the window
1712 where the mouse highlight is? If so, no need to turn off.
1713 Likewise, don't do anything if none of the enabled rows
1714 contains glyphs highlighted in mouse face. */
1715 if (!NILP (display_info
->mouse_face_window
)
1716 && WINDOWP (display_info
->mouse_face_window
))
1718 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1721 /* If the mouse highlight is in the window that was deleted
1722 (e.g., if it was popped by completion), clear highlight
1724 if (NILP (w
->buffer
))
1725 display_info
->mouse_face_window
= Qnil
;
1728 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1729 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1730 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1734 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1735 clear_mouse_face (display_info
);
1738 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
1740 /* If the frame with mouse highlight was deleted, invalidate the
1742 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1743 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1744 display_info
->mouse_face_window
= Qnil
;
1745 display_info
->mouse_face_deferred_gc
= 0;
1746 display_info
->mouse_face_mouse_frame
= NULL
;
1753 IT_update_end (struct frame
*f
)
1755 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1757 if (dpyinfo
->termscript
)
1758 fprintf (dpyinfo
->termscript
, "\n<UPDATE_END\n");
1759 dpyinfo
->mouse_face_defer
= 0;
1763 IT_frame_up_to_date (struct frame
*f
)
1765 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1766 Lisp_Object new_cursor
, frame_desired_cursor
;
1769 if (dpyinfo
->mouse_face_deferred_gc
1770 || (f
&& f
== dpyinfo
->mouse_face_mouse_frame
))
1773 if (dpyinfo
->mouse_face_mouse_frame
)
1774 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
1775 dpyinfo
->mouse_face_mouse_x
,
1776 dpyinfo
->mouse_face_mouse_y
);
1777 dpyinfo
->mouse_face_deferred_gc
= 0;
1781 /* Set the cursor type to whatever they wanted. In a minibuffer
1782 window, we want the cursor to appear only if we are reading input
1783 from this window, and we want the cursor to be taken from the
1784 frame parameters. For the selected window, we use either its
1785 buffer-local value or the value from the frame parameters if the
1786 buffer doesn't define its local value for the cursor type. */
1787 sw
= XWINDOW (f
->selected_window
);
1788 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1789 if (cursor_in_echo_area
1790 && FRAME_HAS_MINIBUF_P (f
)
1791 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1792 && sw
== XWINDOW (echo_area_window
))
1793 new_cursor
= frame_desired_cursor
;
1796 struct buffer
*b
= XBUFFER (sw
->buffer
);
1798 if (EQ (b
->cursor_type
, Qt
))
1799 new_cursor
= frame_desired_cursor
;
1800 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
1801 new_cursor
= Fcons (Qbar
, make_number (0));
1803 new_cursor
= b
->cursor_type
;
1806 IT_set_cursor_type (f
, new_cursor
);
1808 IT_cmgoto (f
); /* position cursor when update is done */
1811 /* Copy LEN glyphs displayed on a single line whose vertical position
1812 is YPOS, beginning at horizontal position XFROM to horizontal
1813 position XTO, by moving blocks in the video memory. Used by
1814 functions that insert and delete glyphs. */
1816 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1818 /* The offsets of source and destination relative to the
1819 conventional memorty selector. */
1820 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1821 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1823 if (from
== to
|| len
<= 0)
1826 _farsetsel (_dos_ds
);
1828 /* The source and destination might overlap, so we need to move
1829 glyphs non-destructively. */
1832 for ( ; len
; from
+= 2, to
+= 2, len
--)
1833 _farnspokew (to
, _farnspeekw (from
));
1837 from
+= (len
- 1) * 2;
1838 to
+= (len
- 1) * 2;
1839 for ( ; len
; from
-= 2, to
-= 2, len
--)
1840 _farnspokew (to
, _farnspeekw (from
));
1842 if (screen_virtual_segment
)
1843 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1846 /* Insert and delete glyphs. */
1848 IT_insert_glyphs (struct frame
*f
, struct glyph
*start
, int len
)
1850 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1852 /* Shift right the glyphs from the nominal cursor position to the
1853 end of this line. */
1854 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
1856 /* Now write the glyphs to be inserted. */
1857 IT_write_glyphs (f
, start
, len
);
1861 IT_delete_glyphs (struct frame
*f
, int n
)
1866 /* set-window-configuration on window.c needs this. */
1868 x_set_menu_bar_lines (struct frame
*f
, Lisp_Object value
, Lisp_Object oldval
)
1870 extern void set_menu_bar_lines (struct frame
*, Lisp_Object
, Lisp_Object
);
1872 set_menu_bar_lines (f
, value
, oldval
);
1875 /* This was copied from xfaces.c */
1877 extern Lisp_Object Qbackground_color
;
1878 extern Lisp_Object Qforeground_color
;
1879 Lisp_Object Qreverse
;
1880 extern Lisp_Object Qtitle
;
1882 /* IT_set_terminal_modes is called when emacs is started,
1883 resumed, and whenever the screen is redrawn! */
1886 IT_set_terminal_modes (struct terminal
*term
)
1888 struct tty_display_info
*tty
;
1890 /* If called with initial terminal, it's too early to do anything
1892 if (term
->type
== output_initial
)
1895 tty
= term
->display_info
.tty
;
1897 if (tty
->termscript
)
1898 fprintf (tty
->termscript
, "\n<SET_TERM>");
1900 screen_size_X
= ScreenCols ();
1901 screen_size_Y
= ScreenRows ();
1902 screen_size
= screen_size_X
* screen_size_Y
;
1904 new_pos_X
= new_pos_Y
= 0;
1905 current_pos_X
= current_pos_Y
= -1;
1907 if (term_setup_done
)
1909 term_setup_done
= 1;
1911 startup_screen_size_X
= screen_size_X
;
1912 startup_screen_size_Y
= screen_size_Y
;
1913 startup_screen_attrib
= ScreenAttrib
;
1915 /* Is DOS/V (or any other RSIS software which relocates
1916 the screen) installed? */
1918 unsigned short es_value
;
1921 regs
.h
.ah
= 0xfe; /* get relocated screen address */
1922 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
1923 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
1924 else if (screen_old_address
) /* already switched to Japanese mode once */
1925 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
1927 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
1929 es_value
= regs
.x
.es
;
1930 __dpmi_int (0x10, ®s
);
1932 if (regs
.x
.es
!= es_value
)
1934 /* screen_old_address is only set if ScreenPrimary does NOT
1935 already point to the relocated buffer address returned by
1936 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1937 ScreenPrimary to that address at startup under DOS/V. */
1938 if (regs
.x
.es
!= ((ScreenPrimary
>> 4) & 0xffff))
1939 screen_old_address
= ScreenPrimary
;
1940 screen_virtual_segment
= regs
.x
.es
;
1941 screen_virtual_offset
= regs
.x
.di
;
1942 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
1946 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
1947 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
1952 /* IT_reset_terminal_modes is called when emacs is
1953 suspended or killed. */
1956 IT_reset_terminal_modes (struct terminal
*term
)
1958 int display_row_start
= (int) ScreenPrimary
;
1959 int saved_row_len
= startup_screen_size_X
* 2;
1960 int update_row_len
= ScreenCols () * 2, current_rows
= ScreenRows ();
1961 int to_next_row
= update_row_len
;
1962 unsigned char *saved_row
= startup_screen_buffer
;
1963 int cursor_pos_X
= ScreenCols () - 1, cursor_pos_Y
= ScreenRows () - 1;
1964 struct tty_display_info
*tty
= term
->display_info
.tty
;
1966 if (tty
->termscript
)
1967 fprintf (tty
->termscript
, "\n<RESET_TERM>");
1969 if (!term_setup_done
)
1974 /* Leave the video system in the same state as we found it,
1975 as far as the blink/bright-background bit is concerned. */
1976 maybe_enable_blinking ();
1978 /* We have a situation here.
1979 We cannot just do ScreenUpdate(startup_screen_buffer) because
1980 the luser could have changed screen dimensions inside Emacs
1981 and failed (or didn't want) to restore them before killing
1982 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1983 thus will happily use memory outside what was allocated for
1984 `startup_screen_buffer'.
1985 Thus we only restore as much as the current screen dimensions
1986 can hold, and clear the rest (if the saved screen is smaller than
1987 the current) with the color attribute saved at startup. The cursor
1988 is also restored within the visible dimensions. */
1990 ScreenAttrib
= startup_screen_attrib
;
1992 /* Don't restore the screen if we are exiting less than 2 seconds
1993 after startup: we might be crashing, and the screen might show
1994 some vital clues to what's wrong. */
1995 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
1998 if (screen_virtual_segment
)
1999 dosv_refresh_virtual_screen (0, screen_size
);
2001 if (update_row_len
> saved_row_len
)
2002 update_row_len
= saved_row_len
;
2003 if (current_rows
> startup_screen_size_Y
)
2004 current_rows
= startup_screen_size_Y
;
2006 if (tty
->termscript
)
2007 fprintf (tty
->termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2008 update_row_len
/ 2, current_rows
);
2010 while (current_rows
--)
2012 dosmemput (saved_row
, update_row_len
, display_row_start
);
2013 if (screen_virtual_segment
)
2014 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2015 update_row_len
/ 2);
2016 saved_row
+= saved_row_len
;
2017 display_row_start
+= to_next_row
;
2020 if (startup_pos_X
< cursor_pos_X
)
2021 cursor_pos_X
= startup_pos_X
;
2022 if (startup_pos_Y
< cursor_pos_Y
)
2023 cursor_pos_Y
= startup_pos_Y
;
2025 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2026 xfree (startup_screen_buffer
);
2027 startup_screen_buffer
= NULL
;
2029 term_setup_done
= 0;
2033 IT_set_terminal_window (struct frame
*f
, int foo
)
2037 /* Remember the screen colors of the curent frame, to serve as the
2038 default colors for newly-created frames. */
2039 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2040 Smsdos_remember_default_colors
, 1, 1, 0,
2041 doc
: /* Remember the screen colors of the current frame. */)
2046 CHECK_FRAME (frame
);
2049 /* This function is called after applying default-frame-alist to the
2050 initial frame. At that time, if reverse-colors option was
2051 specified in default-frame-alist, it was already applied, and
2052 frame colors are reversed. */
2053 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
2054 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
2060 IT_set_frame_parameters (struct frame
*f
, Lisp_Object alist
)
2063 int i
, j
, length
= XINT (Flength (alist
));
2065 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2067 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2068 /* Do we have to reverse the foreground and background colors? */
2069 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2070 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2071 unsigned long orig_fg
, orig_bg
;
2072 struct tty_display_info
*tty
= FRAME_TTY (f
);
2074 /* If we are creating a new frame, begin with the original screen colors
2075 used for the initial frame. */
2076 if (!f
->default_face_done_p
2077 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2079 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2080 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2081 init_frame_faces (f
);
2082 f
->default_face_done_p
= 1;
2084 orig_fg
= reverse
? FRAME_BACKGROUND_PIXEL (f
) : FRAME_FOREGROUND_PIXEL (f
);
2085 orig_bg
= reverse
? FRAME_FOREGROUND_PIXEL (f
) : FRAME_BACKGROUND_PIXEL (f
);
2087 /* Extract parm names and values into those vectors. */
2089 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2094 parms
[i
] = Fcar (elt
);
2095 CHECK_SYMBOL (parms
[i
]);
2096 values
[i
] = Fcdr (elt
);
2102 for (i
= 0; i
< j
; i
++)
2104 Lisp_Object prop
, val
;
2109 if (EQ (prop
, Qreverse
))
2110 reverse
= EQ (val
, Qt
);
2113 if (tty
->termscript
&& reverse
)
2114 fprintf (tty
->termscript
, "<INVERSE-VIDEO>\n");
2116 /* Now process the alist elements in reverse of specified order. */
2117 for (i
--; i
>= 0; i
--)
2119 Lisp_Object prop
, val
;
2124 if (EQ (prop
, Qforeground_color
))
2126 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
2127 ? LFACE_BACKGROUND_INDEX
2128 : LFACE_FOREGROUND_INDEX
);
2129 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2130 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2131 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2135 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2136 /* Make sure the foreground of the default face for
2137 this frame is changed as well. */
2138 update_face_from_frame_parameter (f
, Qforeground_color
, val
);
2140 if (tty
->termscript
)
2141 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
2145 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2146 update_face_from_frame_parameter (f
, Qbackground_color
, val
);
2148 if (tty
->termscript
)
2149 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
2154 else if (EQ (prop
, Qbackground_color
))
2156 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
2157 ? LFACE_FOREGROUND_INDEX
2158 : LFACE_BACKGROUND_INDEX
);
2159 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2160 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2161 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2165 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2166 /* Make sure the background of the default face for
2167 this frame is changed as well. */
2169 update_face_from_frame_parameter (f
, Qbackground_color
, val
);
2170 if (tty
->termscript
)
2171 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
2175 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2177 update_face_from_frame_parameter (f
, Qforeground_color
, val
);
2178 if (tty
->termscript
)
2179 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
2184 else if (EQ (prop
, Qtitle
))
2186 x_set_title (f
, val
);
2187 if (tty
->termscript
)
2188 fprintf (tty
->termscript
, "<TITLE: %s>\n", SDATA (val
));
2190 else if (EQ (prop
, Qcursor_type
))
2192 IT_set_cursor_type (f
, val
);
2193 if (tty
->termscript
)
2194 fprintf (tty
->termscript
, "<CTYPE: %s>\n",
2197 || (CONSP (val
) && (EQ (XCAR (val
), Qbar
)
2198 || EQ (XCAR (val
), Qhbar
)))
2201 else if (EQ (prop
, Qtty_type
))
2203 internal_terminal_init ();
2204 if (tty
->termscript
)
2205 fprintf (tty
->termscript
, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2206 SBYTES (val
), SDATA (val
));
2208 store_frame_param (f
, prop
, val
);
2211 /* If they specified "reverse", but not the colors, we need to swap
2212 the current frame colors. */
2217 FRAME_FOREGROUND_PIXEL (f
) = orig_bg
;
2218 update_face_from_frame_parameter (f
, Qforeground_color
,
2219 tty_color_name (f
, orig_bg
));
2224 FRAME_BACKGROUND_PIXEL (f
) = orig_fg
;
2225 update_face_from_frame_parameter (f
, Qbackground_color
,
2226 tty_color_name (f
, orig_fg
));
2233 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2234 if (f
== SELECTED_FRAME())
2239 extern void init_frame_faces (FRAME_PTR
);
2241 #endif /* !HAVE_X_WINDOWS */
2244 /* Do we need the internal terminal? */
2247 internal_terminal_init (void)
2249 static int init_needed
= 1;
2250 char *term
= getenv ("TERM"), *colors
;
2251 struct frame
*sf
= SELECTED_FRAME();
2252 struct tty_display_info
*tty
;
2254 #ifdef HAVE_X_WINDOWS
2255 if (!inhibit_window_system
)
2259 /* If this is the initial terminal, we are done here. */
2260 if (sf
->output_method
== output_initial
)
2264 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2266 #ifndef HAVE_X_WINDOWS
2267 if (!internal_terminal
|| inhibit_window_system
)
2269 sf
->output_method
= output_termcap
;
2273 tty
= FRAME_TTY (sf
);
2274 current_kboard
->Vwindow_system
= Qpc
;
2275 sf
->output_method
= output_msdos_raw
;
2278 if (!tty
->termscript
&& getenv ("EMACSTEST"))
2279 tty
->termscript
= fopen (getenv ("EMACSTEST"), "wt");
2280 if (tty
->termscript
)
2282 time_t now
= time (NULL
);
2283 struct tm
*tnow
= localtime (&now
);
2286 strftime (tbuf
, sizeof (tbuf
) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow
);
2287 fprintf (tty
->termscript
, "\nEmacs session started at %s\n", tbuf
);
2288 fprintf (tty
->termscript
, "=====================\n\n");
2291 Vinitial_window_system
= Qpc
;
2292 Vwindow_system_version
= make_number (23); /* RE Emacs version */
2293 tty
->terminal
->type
= output_msdos_raw
;
2295 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2297 screen_old_address
= 0;
2299 /* Forget the stale screen colors as well. */
2300 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2302 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2303 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2305 colors
= getenv ("EMACSCOLORS");
2306 if (colors
&& strlen (colors
) >= 2)
2308 /* The colors use 4 bits each (we enable bright background). */
2309 if (isdigit (colors
[0]))
2311 else if (isxdigit (colors
[0]))
2312 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2313 if (colors
[0] >= 0 && colors
[0] < 16)
2314 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors
[0];
2315 if (isdigit (colors
[1]))
2317 else if (isxdigit (colors
[1]))
2318 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2319 if (colors
[1] >= 0 && colors
[1] < 16)
2320 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors
[1];
2322 the_only_display_info
.mouse_face_mouse_frame
= NULL
;
2323 the_only_display_info
.mouse_face_deferred_gc
= 0;
2324 the_only_display_info
.mouse_face_beg_row
=
2325 the_only_display_info
.mouse_face_beg_col
= -1;
2326 the_only_display_info
.mouse_face_end_row
=
2327 the_only_display_info
.mouse_face_end_col
= -1;
2328 the_only_display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2329 the_only_display_info
.mouse_face_window
= Qnil
;
2330 the_only_display_info
.mouse_face_mouse_x
=
2331 the_only_display_info
.mouse_face_mouse_y
= 0;
2332 the_only_display_info
.mouse_face_defer
= 0;
2333 the_only_display_info
.mouse_face_hidden
= 0;
2335 if (have_mouse
) /* detected in dos_ttraw, which see */
2337 have_mouse
= 1; /* enable mouse */
2339 mouse_setup_buttons (mouse_button_count
);
2340 tty
->terminal
->mouse_position_hook
= &mouse_get_pos
;
2344 if (tty
->termscript
&& screen_size
)
2345 fprintf (tty
->termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2346 screen_size_X
, screen_size_Y
);
2348 init_frame_faces (sf
);
2355 initialize_msdos_display (struct terminal
*term
)
2357 term
->rif
= 0; /* we don't support window-based display */
2358 term
->cursor_to_hook
= term
->raw_cursor_to_hook
= IT_cursor_to
;
2359 term
->clear_to_end_hook
= IT_clear_to_end
;
2360 term
->clear_frame_hook
= IT_clear_screen
;
2361 term
->clear_end_of_line_hook
= IT_clear_end_of_line
;
2362 term
->ins_del_lines_hook
= 0;
2363 term
->insert_glyphs_hook
= IT_insert_glyphs
;
2364 term
->write_glyphs_hook
= IT_write_glyphs
;
2365 term
->delete_glyphs_hook
= IT_delete_glyphs
;
2366 term
->ring_bell_hook
= IT_ring_bell
;
2367 term
->reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2368 term
->set_terminal_modes_hook
= IT_set_terminal_modes
;
2369 term
->set_terminal_window_hook
= IT_set_terminal_window
;
2370 term
->update_begin_hook
= IT_update_begin
;
2371 term
->update_end_hook
= IT_update_end
;
2372 term
->frame_up_to_date_hook
= IT_frame_up_to_date
;
2373 term
->mouse_position_hook
= 0; /* set later by dos_ttraw */
2374 term
->frame_rehighlight_hook
= 0;
2375 term
->frame_raise_lower_hook
= 0;
2376 term
->set_vertical_scroll_bar_hook
= 0;
2377 term
->condemn_scroll_bars_hook
= 0;
2378 term
->redeem_scroll_bar_hook
= 0;
2379 term
->judge_scroll_bars_hook
= 0;
2380 term
->read_socket_hook
= &tty_read_avail_input
; /* from keyboard.c */
2384 dos_get_saved_screen (char **screen
, int *rows
, int *cols
)
2386 #ifndef HAVE_X_WINDOWS
2387 *screen
= startup_screen_buffer
;
2388 *cols
= startup_screen_size_X
;
2389 *rows
= startup_screen_size_Y
;
2390 return *screen
!= (char *)0;
2396 #ifndef HAVE_X_WINDOWS
2398 /* We are not X, but we can emulate it well enough for our needs... */
2402 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2403 error ("Not running under a window system");
2409 /* ----------------------- Keyboard control ----------------------
2411 * Keymaps reflect the following keyboard layout:
2413 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2414 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2415 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2416 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2420 #define Ignore 0x0000
2421 #define Normal 0x0000 /* normal key - alt changes scan-code */
2422 #define FctKey 0x1000 /* func key if c == 0, else c */
2423 #define Special 0x2000 /* func key even if c != 0 */
2424 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2425 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2426 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2427 #define Grey 0x6000 /* Grey keypad key */
2429 #define Alt 0x0100 /* alt scan-code */
2430 #define Ctrl 0x0200 /* ctrl scan-code */
2431 #define Shift 0x0400 /* shift scan-code */
2433 static int extended_kbd
; /* 101 (102) keyboard present. */
2435 struct kbd_translate
{
2438 unsigned short code
;
2441 struct dos_keyboard_map
2446 struct kbd_translate
*translate_table
;
2450 static struct dos_keyboard_map us_keyboard
= {
2452 /* 01234567890123456789012345678901234567890 12345678901234 */
2453 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2454 /* 0123456789012345678901234567890123456789 012345678901234 */
2455 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2456 0, /* no Alt-Gr key */
2457 0 /* no translate table */
2460 static struct dos_keyboard_map fr_keyboard
= {
2462 /* 012 3456789012345678901234567890123456789012345678901234 */
2463 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2464 /* 0123456789012345678901234567890123456789012345678901234 */
2465 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2466 /* 01234567 89012345678901234567890123456789012345678901234 */
2468 0 /* no translate table */
2472 * Italian keyboard support, country code 39.
2475 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2476 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2479 static struct kbd_translate it_kbd_translate_table
[] = {
2480 { 0x56, 0x3c, Normal
| 13 },
2481 { 0x56, 0x3e, Normal
| 27 },
2484 static struct dos_keyboard_map it_keyboard
= {
2486 /* 0 123456789012345678901234567890123456789012345678901234 */
2487 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2488 /* 01 23456789012345678901234567890123456789012345678901234 */
2489 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2490 /* 0123456789012345678901234567890123456789012345678901234 */
2492 it_kbd_translate_table
2495 static struct dos_keyboard_map dk_keyboard
= {
2497 /* 0123456789012345678901234567890123456789012345678901234 */
2498 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2499 /* 01 23456789012345678901234567890123456789012345678901234 */
2500 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2501 /* 0123456789012345678901234567890123456789012345678901234 */
2503 0 /* no translate table */
2506 static struct kbd_translate jp_kbd_translate_table
[] = {
2507 { 0x73, 0x5c, Normal
| 0 },
2508 { 0x73, 0x5f, Normal
| 0 },
2509 { 0x73, 0x1c, Map
| 0 },
2510 { 0x7d, 0x5c, Normal
| 13 },
2511 { 0x7d, 0x7c, Normal
| 13 },
2512 { 0x7d, 0x1c, Map
| 13 },
2515 static struct dos_keyboard_map jp_keyboard
= {
2517 /* 0123456789012 345678901234567890123456789012345678901234 */
2518 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2519 /* 01 23456789012345678901234567890123456789012345678901234 */
2520 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2521 0, /* no Alt-Gr key */
2522 jp_kbd_translate_table
2525 static struct keyboard_layout_list
2528 struct dos_keyboard_map
*keyboard_map
;
2529 } keyboard_layout_list
[] =
2531 { 1, &us_keyboard
},
2532 { 33, &fr_keyboard
},
2533 { 39, &it_keyboard
},
2534 { 45, &dk_keyboard
},
2535 { 81, &jp_keyboard
}
2538 static struct dos_keyboard_map
*keyboard
;
2539 static int keyboard_map_all
;
2540 static int international_keyboard
;
2543 dos_set_keyboard (int code
, int always
)
2546 _go32_dpmi_registers regs
;
2548 /* See if Keyb.Com is installed (for international keyboard support).
2549 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2550 of Windows 9X! So don't do that! */
2552 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2553 _go32_dpmi_simulate_int (0x2f, ®s
);
2554 if (regs
.h
.al
== 0xff)
2555 international_keyboard
= 1;
2557 /* Initialize to US settings, for countries that don't have their own. */
2558 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2559 keyboard_map_all
= always
;
2560 dos_keyboard_layout
= 1;
2562 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2563 if (code
== keyboard_layout_list
[i
].country_code
)
2565 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2566 keyboard_map_all
= always
;
2567 dos_keyboard_layout
= code
;
2575 unsigned char char_code
; /* normal code */
2576 unsigned char meta_code
; /* M- code */
2577 unsigned char keypad_code
; /* keypad code */
2578 unsigned char editkey_code
; /* edit key */
2579 } keypad_translate_map
[] = {
2580 { '0', '0', 0xb0, /* kp-0 */ 0x63 /* insert */ },
2581 { '1', '1', 0xb1, /* kp-1 */ 0x57 /* end */ },
2582 { '2', '2', 0xb2, /* kp-2 */ 0x54 /* down */ },
2583 { '3', '3', 0xb3, /* kp-3 */ 0x56 /* next */ },
2584 { '4', '4', 0xb4, /* kp-4 */ 0x51 /* left */ },
2585 { '5', '5', 0xb5, /* kp-5 */ 0xb5 /* kp-5 */ },
2586 { '6', '6', 0xb6, /* kp-6 */ 0x53 /* right */ },
2587 { '7', '7', 0xb7, /* kp-7 */ 0x50 /* home */ },
2588 { '8', '8', 0xb8, /* kp-8 */ 0x52 /* up */ },
2589 { '9', '9', 0xb9, /* kp-9 */ 0x55 /* prior */ },
2590 { '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */}
2595 unsigned char char_code
; /* normal code */
2596 unsigned char keypad_code
; /* keypad code */
2597 } grey_key_translate_map
[] = {
2598 { '/', 0xaf /* kp-decimal */ },
2599 { '*', 0xaa /* kp-multiply */ },
2600 { '-', 0xad /* kp-subtract */ },
2601 { '+', 0xab /* kp-add */ },
2602 { '\r', 0x8d /* kp-enter */ }
2605 static unsigned short
2606 ibmpc_translate_map
[] =
2608 /* --------------- 00 to 0f --------------- */
2609 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2610 Alt
| ModFct
| 0x1b, /* Escape */
2611 Normal
| 1, /* '1' */
2612 Normal
| 2, /* '2' */
2613 Normal
| 3, /* '3' */
2614 Normal
| 4, /* '4' */
2615 Normal
| 5, /* '5' */
2616 Normal
| 6, /* '6' */
2617 Normal
| 7, /* '7' */
2618 Normal
| 8, /* '8' */
2619 Normal
| 9, /* '9' */
2620 Normal
| 10, /* '0' */
2621 Normal
| 11, /* '-' */
2622 Normal
| 12, /* '=' */
2623 Special
| 0x08, /* Backspace */
2624 ModFct
| 0x74, /* Tab/Backtab */
2626 /* --------------- 10 to 1f --------------- */
2639 ModFct
| 0x0d, /* Return */
2644 /* --------------- 20 to 2f --------------- */
2653 Map
| 40, /* '\'' */
2655 Ignore
, /* Left shift */
2656 Map
| 41, /* '\\' */
2662 /* --------------- 30 to 3f --------------- */
2669 Ignore
, /* Right shift */
2670 Grey
| 1, /* Grey * */
2672 Normal
| 55, /* ' ' */
2673 Ignore
, /* Caps Lock */
2674 FctKey
| 0xbe, /* F1 */
2675 FctKey
| 0xbf, /* F2 */
2676 FctKey
| 0xc0, /* F3 */
2677 FctKey
| 0xc1, /* F4 */
2678 FctKey
| 0xc2, /* F5 */
2680 /* --------------- 40 to 4f --------------- */
2681 FctKey
| 0xc3, /* F6 */
2682 FctKey
| 0xc4, /* F7 */
2683 FctKey
| 0xc5, /* F8 */
2684 FctKey
| 0xc6, /* F9 */
2685 FctKey
| 0xc7, /* F10 */
2686 Ignore
, /* Num Lock */
2687 Ignore
, /* Scroll Lock */
2688 KeyPad
| 7, /* Home */
2689 KeyPad
| 8, /* Up */
2690 KeyPad
| 9, /* Page Up */
2691 Grey
| 2, /* Grey - */
2692 KeyPad
| 4, /* Left */
2693 KeyPad
| 5, /* Keypad 5 */
2694 KeyPad
| 6, /* Right */
2695 Grey
| 3, /* Grey + */
2696 KeyPad
| 1, /* End */
2698 /* --------------- 50 to 5f --------------- */
2699 KeyPad
| 2, /* Down */
2700 KeyPad
| 3, /* Page Down */
2701 KeyPad
| 0, /* Insert */
2702 KeyPad
| 10, /* Delete */
2703 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2704 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2705 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2706 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2707 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2708 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2709 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2710 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2711 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2712 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2713 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2714 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2716 /* --------------- 60 to 6f --------------- */
2717 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2718 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2719 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2720 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2721 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2722 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2723 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2724 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2725 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2726 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2727 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2728 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2729 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2730 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2731 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2732 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2734 /* --------------- 70 to 7f --------------- */
2735 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2736 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2737 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2738 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2739 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2740 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2741 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2742 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2743 Alt
| Map
| 1, /* '1' */
2744 Alt
| Map
| 2, /* '2' */
2745 Alt
| Map
| 3, /* '3' */
2746 Alt
| Map
| 4, /* '4' */
2747 Alt
| Map
| 5, /* '5' */
2748 Alt
| Map
| 6, /* '6' */
2749 Alt
| Map
| 7, /* '7' */
2750 Alt
| Map
| 8, /* '8' */
2752 /* --------------- 80 to 8f --------------- */
2753 Alt
| Map
| 9, /* '9' */
2754 Alt
| Map
| 10, /* '0' */
2755 Alt
| Map
| 11, /* '-' */
2756 Alt
| Map
| 12, /* '=' */
2757 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2758 FctKey
| 0xc8, /* F11 */
2759 FctKey
| 0xc9, /* F12 */
2760 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2761 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2762 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2763 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2764 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2765 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2766 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2767 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2768 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2770 /* --------------- 90 to 9f --------------- */
2771 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2772 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2773 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2774 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2775 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2776 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2777 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2778 Alt
| FctKey
| 0x50, /* (Alt) Home */
2779 Alt
| FctKey
| 0x52, /* (Alt) Up */
2780 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2781 Ignore
, /* NO KEY */
2782 Alt
| FctKey
| 0x51, /* (Alt) Left */
2783 Ignore
, /* NO KEY */
2784 Alt
| FctKey
| 0x53, /* (Alt) Right */
2785 Ignore
, /* NO KEY */
2786 Alt
| FctKey
| 0x57, /* (Alt) End */
2788 /* --------------- a0 to af --------------- */
2789 Alt
| KeyPad
| 2, /* (Alt) Down */
2790 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2791 Alt
| KeyPad
| 0, /* (Alt) Insert */
2792 Alt
| KeyPad
| 10, /* (Alt) Delete */
2793 Alt
| Grey
| 0, /* (Alt) Grey / */
2794 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2795 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2798 /* These bit-positions corresponds to values returned by BIOS */
2799 #define SHIFT_P 0x0003 /* two bits! */
2800 #define CTRL_P 0x0004
2801 #define ALT_P 0x0008
2802 #define SCRLOCK_P 0x0010
2803 #define NUMLOCK_P 0x0020
2804 #define CAPSLOCK_P 0x0040
2805 #define ALT_GR_P 0x0800
2806 #define SUPER_P 0x4000 /* pseudo */
2807 #define HYPER_P 0x8000 /* pseudo */
2810 dos_get_modifiers (int *keymask
)
2813 int mask
, modifiers
= 0;
2815 /* Calculate modifier bits */
2816 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2817 int86 (0x16, ®s
, ®s
);
2821 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2822 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2826 mask
= regs
.h
.al
& (SHIFT_P
|
2827 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2829 /* Do not break international keyboard support. */
2830 /* When Keyb.Com is loaded, the right Alt key is */
2831 /* used for accessing characters like { and } */
2832 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2835 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2838 if (dos_hyper_key
== 1)
2841 modifiers
|= hyper_modifier
;
2843 else if (dos_super_key
== 1)
2846 modifiers
|= super_modifier
;
2848 else if (!international_keyboard
)
2850 /* If Keyb.Com is NOT installed, let Right Alt behave
2851 like the Left Alt. */
2857 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2860 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2862 if (dos_hyper_key
== 2)
2865 modifiers
|= hyper_modifier
;
2867 else if (dos_super_key
== 2)
2870 modifiers
|= super_modifier
;
2878 modifiers
|= shift_modifier
;
2880 modifiers
|= ctrl_modifier
;
2882 modifiers
|= meta_modifier
;
2889 #define NUM_RECENT_DOSKEYS (100)
2890 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2891 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
2892 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
2894 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
2895 doc
: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2896 Each input key receives two values in this vector: first the ASCII code,
2897 and then the scan code. */)
2900 Lisp_Object val
, *keys
= XVECTOR (recent_doskeys
)->contents
;
2902 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
2903 return Fvector (total_doskeys
, keys
);
2906 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
2907 memcpy (XVECTOR (val
)->contents
, keys
+ recent_doskeys_index
,
2908 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
2909 memcpy (XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
2910 keys
, recent_doskeys_index
* sizeof (Lisp_Object
));
2915 /* Get a char from keyboard. Function keys are put into the event queue. */
2919 struct input_event event
;
2921 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
2924 #ifndef HAVE_X_WINDOWS
2925 /* Maybe put the cursor where it should be. */
2926 IT_cmgoto (SELECTED_FRAME());
2929 /* The following condition is equivalent to `kbhit ()', except that
2930 it uses the bios to do its job. This pleases DESQview/X. */
2931 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
2932 int86 (0x16, ®s
, ®s
),
2933 (regs
.x
.flags
& 0x40) == 0)
2936 register unsigned char c
;
2937 int modifiers
, sc
, code
= -1, mask
, kp_mode
;
2939 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
2940 int86 (0x16, ®s
, ®s
);
2945 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2947 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2948 recent_doskeys_index
= 0;
2949 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2951 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2952 recent_doskeys_index
= 0;
2954 modifiers
= dos_get_modifiers (&mask
);
2956 #ifndef HAVE_X_WINDOWS
2957 if (!NILP (Vdos_display_scancodes
))
2960 sprintf (buf
, "%02x:%02x*%04x",
2961 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
2962 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
2970 case 10: /* Ctrl Grey Enter */
2971 code
= Ctrl
| Grey
| 4;
2973 case 13: /* Grey Enter */
2976 case '/': /* Grey / */
2986 /* Try the keyboard-private translation table first. */
2987 if (keyboard
->translate_table
)
2989 struct kbd_translate
*p
= keyboard
->translate_table
;
2993 if (p
->sc
== sc
&& p
->ch
== c
)
3001 /* If the private table didn't translate it, use the general
3005 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3007 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3014 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3015 Emacs is ready to read a key. Therefore, if they press
3016 `Alt-x' when Emacs is busy, by the time we get to
3017 `dos_get_modifiers', they might have already released the
3018 Alt key, and Emacs gets just `x', which is BAD.
3019 However, for keys with the `Map' property set, the ASCII
3020 code returns zero only if Alt is pressed. So, when we DON'T
3021 have to support international_keyboard, we don't have to
3022 distinguish between the left and right Alt keys, and we
3023 can set the META modifier for any keys with the `Map'
3024 property if they return zero ASCII code (c = 0). */
3026 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3027 modifiers
|= meta_modifier
;
3029 modifiers
|= ctrl_modifier
;
3031 modifiers
|= shift_modifier
;
3034 switch (code
& 0xf000)
3037 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3039 c
= 0; /* Special */
3052 if (c
== 0) /* ctrl-break */
3054 return c
; /* ALT-nnn */
3056 if (!keyboard_map_all
)
3065 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3066 if (!keyboard_map_all
)
3070 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3071 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3075 code
= keyboard
->shifted
[code
];
3077 modifiers
&= ~shift_modifier
;
3080 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3081 code
= keyboard
->alt_gr
[code
];
3083 code
= keyboard
->unshifted
[code
];
3088 if (c
== 0xe0) /* edit key */
3091 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3092 kp_mode
= dos_keypad_mode
& 0x03;
3094 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3099 if (code
== 10 && dos_decimal_point
)
3100 return dos_decimal_point
;
3101 return keypad_translate_map
[code
].char_code
;
3104 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3108 code
= keypad_translate_map
[code
].meta_code
;
3109 modifiers
= meta_modifier
;
3113 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3120 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3121 if (dos_keypad_mode
& kp_mode
)
3122 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3124 code
= grey_key_translate_map
[code
].char_code
;
3131 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
))
3133 clear_mouse_face (dpyinfo
);
3134 dpyinfo
->mouse_face_hidden
= 1;
3138 event
.kind
= NON_ASCII_KEYSTROKE_EVENT
;
3140 event
.kind
= ASCII_KEYSTROKE_EVENT
;
3142 event
.modifiers
= modifiers
;
3143 event
.frame_or_window
= selected_frame
;
3145 event
.timestamp
= event_timestamp ();
3146 kbd_buffer_store_event (&event
);
3149 if (have_mouse
> 0 && !mouse_preempted
)
3151 int but
, press
, x
, y
, ok
;
3152 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3153 Lisp_Object mouse_window
= Qnil
;
3155 /* Check for mouse movement *before* buttons. */
3156 mouse_check_moved ();
3158 /* If the mouse moved from the spot of its last sighting, we
3159 might need to update mouse highlight. */
3160 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3162 if (dpyinfo
->mouse_face_hidden
)
3164 dpyinfo
->mouse_face_hidden
= 0;
3165 clear_mouse_face (dpyinfo
);
3168 /* Generate SELECT_WINDOW_EVENTs when needed. */
3169 if (!NILP (Vmouse_autoselect_window
))
3171 mouse_window
= window_from_coordinates (SELECTED_FRAME(),
3175 /* A window will be selected only when it is not
3176 selected now, and the last mouse movement event was
3177 not in it. A minibuffer window will be selected iff
3179 if (WINDOWP (mouse_window
)
3180 && !EQ (mouse_window
, last_mouse_window
)
3181 && !EQ (mouse_window
, selected_window
))
3183 event
.kind
= SELECT_WINDOW_EVENT
;
3184 event
.frame_or_window
= mouse_window
;
3186 event
.timestamp
= event_timestamp ();
3187 kbd_buffer_store_event (&event
);
3189 last_mouse_window
= mouse_window
;
3192 last_mouse_window
= Qnil
;
3194 previous_help_echo_string
= help_echo_string
;
3195 help_echo_string
= help_echo_object
= help_echo_window
= Qnil
;
3197 IT_note_mouse_highlight (SELECTED_FRAME(),
3198 mouse_last_x
, mouse_last_y
);
3199 /* If the contents of the global variable help_echo has
3200 changed, generate a HELP_EVENT. */
3201 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
3203 event
.kind
= HELP_EVENT
;
3204 event
.frame_or_window
= selected_frame
;
3205 event
.arg
= help_echo_object
;
3206 event
.x
= WINDOWP (help_echo_window
)
3207 ? help_echo_window
: selected_frame
;
3208 event
.y
= help_echo_string
;
3209 event
.timestamp
= event_timestamp ();
3210 event
.code
= help_echo_pos
;
3211 kbd_buffer_store_event (&event
);
3215 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3216 for (press
= 0; press
< 2; press
++)
3218 int button_num
= but
;
3221 ok
= mouse_pressed (but
, &x
, &y
);
3223 ok
= mouse_released (but
, &x
, &y
);
3226 /* Allow a simultaneous press/release of Mouse-1 and
3227 Mouse-2 to simulate Mouse-3 on two-button mice. */
3228 if (mouse_button_count
== 2 && but
< 2)
3230 int x2
, y2
; /* don't clobber original coordinates */
3232 /* If only one button is pressed, wait 100 msec and
3233 check again. This way, Speedy Gonzales isn't
3234 punished, while the slow get their chance. */
3235 if ((press
&& mouse_pressed (1-but
, &x2
, &y2
))
3236 || (!press
&& mouse_released (1-but
, &x2
, &y2
)))
3241 if ((press
&& mouse_pressed (1-but
, &x2
, &y2
))
3242 || (!press
&& mouse_released (1-but
, &x2
, &y2
)))
3247 event
.kind
= MOUSE_CLICK_EVENT
;
3248 event
.code
= button_num
;
3249 event
.modifiers
= dos_get_modifiers (0)
3250 | (press
? down_modifier
: up_modifier
);
3251 event
.x
= make_number (x
);
3252 event
.y
= make_number (y
);
3253 event
.frame_or_window
= selected_frame
;
3255 event
.timestamp
= event_timestamp ();
3256 kbd_buffer_store_event (&event
);
3264 static int prev_get_char
= -1;
3266 /* Return 1 if a key is ready to be read without suspending execution. */
3270 if (prev_get_char
!= -1)
3273 return ((prev_get_char
= dos_rawgetc ()) != -1);
3276 /* Read a key. Return -1 if no key is ready. */
3280 if (prev_get_char
!= -1)
3282 int c
= prev_get_char
;
3287 return dos_rawgetc ();
3290 #ifndef HAVE_X_WINDOWS
3292 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3295 Actually, I don't know the meaning of all the parameters of the functions
3296 here -- I only know how they are called by xmenu.c. I could of course
3297 grab the nearest Xlib manual (down the hall, second-to-last door on the
3298 left), but I don't think it's worth the effort. */
3300 /* These hold text of the current and the previous menu help messages. */
3301 static char *menu_help_message
, *prev_menu_help_message
;
3302 /* Pane number and item number of the menu item which generated the
3303 last menu help message. */
3304 static int menu_help_paneno
, menu_help_itemno
;
3307 IT_menu_create (void)
3311 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3312 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3316 /* Allocate some (more) memory for MENU ensuring that there is room for one
3320 IT_menu_make_room (XMenu
*menu
)
3322 if (menu
->allocated
== 0)
3324 int count
= menu
->allocated
= 10;
3325 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3326 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3327 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3328 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3330 else if (menu
->allocated
== menu
->count
)
3332 int count
= menu
->allocated
= menu
->allocated
+ 10;
3334 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3336 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3338 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3340 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3344 /* Search the given menu structure for a given pane number. */
3347 IT_menu_search_pane (XMenu
*menu
, int pane
)
3352 for (i
= 0; i
< menu
->count
; i
++)
3353 if (menu
->submenu
[i
])
3355 if (pane
== menu
->panenumber
[i
])
3356 return menu
->submenu
[i
];
3357 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3363 /* Determine how much screen space a given menu needs. */
3366 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3368 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3371 maxheight
= menu
->count
;
3372 for (i
= 0; i
< menu
->count
; i
++)
3374 if (menu
->submenu
[i
])
3376 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3377 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3378 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3381 *width
= menu
->width
+ maxsubwidth
;
3382 *height
= maxheight
;
3385 /* Display MENU at (X,Y) using FACES. */
3387 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3390 (GLYPH).type = CHAR_GLYPH; \
3391 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3392 (GLYPH).charpos = -1; \
3397 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3399 int i
, j
, face
, width
, mx
, my
, enabled
, mousehere
, row
, col
;
3400 struct glyph
*text
, *p
;
3401 const unsigned char *q
;
3402 struct frame
*sf
= SELECTED_FRAME();
3404 menu_help_message
= NULL
;
3406 width
= menu
->width
;
3407 /* We multiply width by 2 to account for possible control characters.
3408 FIXME: cater to non-ASCII characters in menus. */
3409 text
= (struct glyph
*) xmalloc ((width
* 2 + 2) * sizeof (struct glyph
));
3410 ScreenGetCursor (&row
, &col
);
3411 mouse_get_xy (&mx
, &my
);
3412 IT_update_begin (sf
);
3413 for (i
= 0; i
< menu
->count
; i
++)
3415 int max_width
= width
+ 2;
3417 IT_cursor_to (sf
, y
+ i
, x
);
3419 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3420 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ max_width
);
3421 face
= faces
[enabled
+ mousehere
* 2];
3422 /* The following if clause means that we display the menu help
3423 strings even if the menu item is currently disabled. */
3424 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3426 menu_help_message
= menu
->help_text
[i
];
3427 menu_help_paneno
= pn
- 1;
3428 menu_help_itemno
= i
;
3431 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
3433 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3435 unsigned c
= STRING_CHAR_ADVANCE (q
);
3439 BUILD_CHAR_GLYPH (*p
, c
, face
, 0);
3442 else /* make '^x' */
3444 BUILD_CHAR_GLYPH (*p
, '^', face
, 0);
3447 BUILD_CHAR_GLYPH (*p
, c
+ 64, face
, 0);
3451 /* Don't let the menu text overflow into the next screen row. */
3452 if (x
+ max_width
> screen_size_X
)
3454 max_width
= screen_size_X
- x
;
3455 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3457 for (; j
< max_width
- 2; j
++, p
++)
3458 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
3460 /* 16 is the character code of a character that on DOS terminal
3461 produces a nice-looking right-pointing arrow glyph. */
3462 BUILD_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3464 IT_write_glyphs (sf
, text
, max_width
);
3467 IT_cursor_to (sf
, row
, col
);
3471 /* --------------------------- X Menu emulation ---------------------- */
3473 /* Report availability of menus. */
3476 have_menus_p (void) { return 1; }
3478 /* Create a brand new menu structure. */
3481 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3483 return IT_menu_create ();
3486 /* Create a new pane and place it on the outer-most level. It is not
3487 clear that it should be placed out there, but I don't know what else
3491 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3499 IT_menu_make_room (menu
);
3500 menu
->submenu
[menu
->count
] = IT_menu_create ();
3501 menu
->text
[menu
->count
] = txt
;
3502 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3503 menu
->help_text
[menu
->count
] = NULL
;
3506 /* Adjust length for possible control characters (which will
3507 be written as ^x). */
3508 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3512 if (len
> menu
->width
)
3515 return menu
->panecount
;
3518 /* Create a new item in a menu pane. */
3521 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3522 int foo
, char *txt
, int enable
, char *help_text
)
3528 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3530 IT_menu_make_room (menu
);
3531 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3532 menu
->text
[menu
->count
] = txt
;
3533 menu
->panenumber
[menu
->count
] = enable
;
3534 menu
->help_text
[menu
->count
] = help_text
;
3537 /* Adjust length for possible control characters (which will
3538 be written as ^x). */
3539 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3543 if (len
> menu
->width
)
3549 /* Decide where the menu would be placed if requested at (X,Y). */
3552 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3553 int *ulx
, int *uly
, int *width
, int *height
)
3555 IT_menu_calc_size (menu
, width
, height
);
3561 struct IT_menu_state
3563 void *screen_behind
;
3570 /* Display menu, wait for user's response, and return that response. */
3573 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3574 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3575 void (*help_callback
)(char *, int, int))
3577 struct IT_menu_state
*state
;
3578 int statecount
, x
, y
, i
, b
, screensize
, leave
, result
, onepane
;
3579 int title_faces
[4]; /* face to display the menu title */
3580 int faces
[4], buffers_num_deleted
= 0;
3581 struct frame
*sf
= SELECTED_FRAME();
3582 Lisp_Object saved_echo_area_message
, selectface
;
3584 /* Just in case we got here without a mouse present... */
3585 if (have_mouse
<= 0)
3586 return XM_IA_SELECT
;
3587 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3588 around the display. */
3594 /* We will process all the mouse events directly, so we had
3595 better prevent dos_rawgetc from stealing them from us. */
3598 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3599 screensize
= screen_size
* 2;
3601 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3602 DEFAULT_FACE_ID
, 1);
3604 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3605 DEFAULT_FACE_ID
, 1);
3606 selectface
= intern ("msdos-menu-select-face");
3607 faces
[2] = lookup_derived_face (sf
, selectface
,
3609 faces
[3] = lookup_derived_face (sf
, selectface
,
3612 /* Make sure the menu title is always displayed with
3613 `msdos-menu-active-face', no matter where the mouse pointer is. */
3614 for (i
= 0; i
< 4; i
++)
3615 title_faces
[i
] = faces
[3];
3619 /* Don't let the title for the "Buffers" popup menu include a
3620 digit (which is ugly).
3622 This is a terrible kludge, but I think the "Buffers" case is
3623 the only one where the title includes a number, so it doesn't
3624 seem to be necessary to make this more general. */
3625 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3627 menu
->text
[0][7] = '\0';
3628 buffers_num_deleted
= 1;
3631 /* We need to save the current echo area message, so that we could
3632 restore it below, before we exit. See the commentary below,
3633 before the call to message_with_string. */
3634 saved_echo_area_message
= Fcurrent_message ();
3635 state
[0].menu
= menu
;
3637 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3639 /* Turn off the cursor. Otherwise it shows through the menu
3640 panes, which is ugly. */
3641 IT_display_cursor (0);
3643 /* Display the menu title. */
3644 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3645 if (buffers_num_deleted
)
3646 menu
->text
[0][7] = ' ';
3647 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3649 menu
->width
= menu
->submenu
[0]->width
;
3650 state
[0].menu
= menu
->submenu
[0];
3654 state
[0].menu
= menu
;
3656 state
[0].x
= x0
- 1;
3658 state
[0].pane
= onepane
;
3660 mouse_last_x
= -1; /* A hack that forces display. */
3664 if (!mouse_visible
) mouse_on ();
3665 mouse_check_moved ();
3666 if (sf
->mouse_moved
)
3668 sf
->mouse_moved
= 0;
3669 result
= XM_IA_SELECT
;
3670 mouse_get_xy (&x
, &y
);
3671 for (i
= 0; i
< statecount
; i
++)
3672 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3674 int dy
= y
- state
[i
].y
;
3675 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3677 if (!state
[i
].menu
->submenu
[dy
])
3679 if (state
[i
].menu
->panenumber
[dy
])
3680 result
= XM_SUCCESS
;
3682 result
= XM_IA_SELECT
;
3684 *pane
= state
[i
].pane
- 1;
3686 /* We hit some part of a menu, so drop extra menus that
3687 have been opened. That does not include an open and
3689 if (i
!= statecount
- 2
3690 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3691 while (i
!= statecount
- 1)
3695 ScreenUpdate (state
[statecount
].screen_behind
);
3696 if (screen_virtual_segment
)
3697 dosv_refresh_virtual_screen (0, screen_size
);
3698 xfree (state
[statecount
].screen_behind
);
3700 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3702 IT_menu_display (state
[i
].menu
,
3707 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3708 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3710 ScreenRetrieve (state
[statecount
].screen_behind
3711 = xmalloc (screensize
));
3713 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3714 state
[statecount
].y
= y
;
3719 IT_menu_display (state
[statecount
- 1].menu
,
3720 state
[statecount
- 1].y
,
3721 state
[statecount
- 1].x
,
3722 state
[statecount
- 1].pane
,
3727 if ((menu_help_message
|| prev_menu_help_message
)
3728 && menu_help_message
!= prev_menu_help_message
)
3730 help_callback (menu_help_message
,
3731 menu_help_paneno
, menu_help_itemno
);
3732 IT_display_cursor (0);
3733 prev_menu_help_message
= menu_help_message
;
3735 /* We are busy-waiting for the mouse to move, so let's be nice
3736 to other Windows applications by releasing our time slice. */
3739 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3741 /* Only leave if user both pressed and released the mouse, and in
3742 that order. This avoids popping down the menu pane unless
3743 the user is really done with it. */
3744 if (mouse_pressed (b
, &x
, &y
))
3746 while (mouse_button_depressed (b
, &x
, &y
))
3750 (void) mouse_released (b
, &x
, &y
);
3755 ScreenUpdate (state
[0].screen_behind
);
3756 if (screen_virtual_segment
)
3757 dosv_refresh_virtual_screen (0, screen_size
);
3759 /* We have a situation here. ScreenUpdate has just restored the
3760 screen contents as it was before we started drawing this menu.
3761 That includes any echo area message that could have been
3762 displayed back then. (In reality, that echo area message will
3763 almost always be the ``keystroke echo'' that echoes the sequence
3764 of menu items chosen by the user.) However, if the menu had some
3765 help messages, then displaying those messages caused Emacs to
3766 forget about the original echo area message. So when
3767 ScreenUpdate restored it, it created a discrepancy between the
3768 actual screen contents and what Emacs internal data structures
3771 To avoid this conflict, we force Emacs to restore the original
3772 echo area message as we found it when we entered this function.
3773 The irony of this is that we then erase the restored message
3774 right away, so the only purpose of restoring it is so that
3775 erasing it works correctly... */
3776 if (! NILP (saved_echo_area_message
))
3777 message_with_string ("%s", saved_echo_area_message
, 0);
3779 while (statecount
--)
3780 xfree (state
[statecount
].screen_behind
);
3781 IT_display_cursor (1); /* turn cursor back on */
3782 /* Clean up any mouse events that are waiting inside Emacs event queue.
3783 These events are likely to be generated before the menu was even
3784 displayed, probably because the user pressed and released the button
3785 (which invoked the menu) too quickly. If we don't remove these events,
3786 Emacs will process them after we return and surprise the user. */
3787 discard_mouse_events ();
3788 mouse_clear_clicks ();
3789 if (!kbd_buffer_events_waiting (1))
3790 clear_input_pending ();
3791 /* Allow mouse events generation by dos_rawgetc. */
3796 /* Dispose of a menu. */
3799 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3802 if (menu
->allocated
)
3804 for (i
= 0; i
< menu
->count
; i
++)
3805 if (menu
->submenu
[i
])
3806 XMenuDestroy (foo
, menu
->submenu
[i
]);
3808 xfree (menu
->submenu
);
3809 xfree (menu
->panenumber
);
3810 xfree (menu
->help_text
);
3813 menu_help_message
= prev_menu_help_message
= NULL
;
3817 x_pixel_width (struct frame
*f
)
3819 return FRAME_COLS (f
);
3823 x_pixel_height (struct frame
*f
)
3825 return FRAME_LINES (f
);
3827 #endif /* !HAVE_X_WINDOWS */
3829 /* ----------------------- DOS / UNIX conversion --------------------- */
3831 void msdos_downcase_filename (unsigned char *);
3833 /* Destructively turn backslashes into slashes. */
3836 dostounix_filename (char *p
)
3838 msdos_downcase_filename (p
);
3848 /* Destructively turn slashes into backslashes. */
3851 unixtodos_filename (char *p
)
3853 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3867 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3870 getdefdir (int drive
, char *dst
)
3872 char in_path
[4], *p
= in_path
, e
= errno
;
3874 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3877 *p
++ = drive
+ 'A' - 1;
3884 _fixpath (in_path
, dst
);
3885 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3886 it queries the LFN support, so ignore that error. */
3887 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
3890 msdos_downcase_filename (dst
);
3897 emacs_root_dir (void)
3899 static char root_dir
[4];
3901 sprintf (root_dir
, "%c:/", 'A' + getdisk ());
3902 root_dir
[0] = tolower (root_dir
[0]);
3906 /* Remove all CR's that are followed by a LF. */
3909 crlf_to_lf (int n
, unsigned char *buf
)
3911 unsigned char *np
= buf
, *startp
= buf
, *endp
= buf
+ n
;
3915 while (buf
< endp
- 1)
3919 if (*(++buf
) != 0x0a)
3930 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
3932 doc
: /* Return non-nil if long file names are supported on MS-DOS. */)
3935 return (_USE_LFN
? Qt
: Qnil
);
3938 /* Convert alphabetic characters in a filename to lower-case. */
3941 msdos_downcase_filename (unsigned char *p
)
3943 /* Always lower-case drive letters a-z, even if the filesystem
3944 preserves case in filenames.
3945 This is so MSDOS filenames could be compared by string comparison
3946 functions that are case-sensitive. Even case-preserving filesystems
3947 do not distinguish case in drive letters. */
3948 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3954 /* Under LFN we expect to get pathnames in their true case. */
3955 if (NILP (Fmsdos_long_file_names ()))
3957 if (*p
>= 'A' && *p
<= 'Z')
3961 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
3963 doc
: /* Convert alphabetic characters in FILENAME to lower case and return that.
3964 When long filenames are supported, doesn't change FILENAME.
3965 If FILENAME is not a string, returns nil.
3966 The argument object is never altered--the value is a copy. */)
3967 (Lisp_Object filename
)
3971 if (! STRINGP (filename
))
3974 tem
= Fcopy_sequence (filename
);
3975 msdos_downcase_filename (SDATA (tem
));
3979 /* The Emacs root directory as determined by init_environment. */
3981 static char emacsroot
[MAXPATHLEN
];
3984 rootrelativepath (char *rel
)
3986 static char result
[MAXPATHLEN
+ 10];
3988 strcpy (result
, emacsroot
);
3989 strcat (result
, "/");
3990 strcat (result
, rel
);
3994 /* Define a lot of environment variables if not already defined. Don't
3995 remove anything unless you know what you're doing -- lots of code will
3996 break if one or more of these are missing. */
3999 init_environment (int argc
, char **argv
, int skip_args
)
4003 static const char * const tempdirs
[] = {
4004 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4006 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4008 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4009 temporary files and assume "/tmp" if $TMPDIR is unset, which
4010 will break on DOS/Windows. Refuse to work if we cannot find
4011 a directory, not even "c:/", usable for that purpose. */
4012 for (i
= 0; i
< imax
; i
++)
4014 const char *tmp
= tempdirs
[i
];
4015 char buf
[FILENAME_MAX
];
4021 tmp
= getenv (tmp
+ 1);
4025 /* Some lusers set TMPDIR=e:, probably because some losing
4026 programs cannot handle multiple slashes if they use e:/.
4027 e: fails in `access' below, so we interpret e: as e:/. */
4028 tmp_len
= strlen(tmp
);
4029 if (tmp
[tmp_len
- 1] != '/' && tmp
[tmp_len
- 1] != '\\')
4032 buf
[tmp_len
++] = '/', buf
[tmp_len
] = 0;
4037 /* Note that `access' can lie to us if the directory resides on a
4038 read-only filesystem, like CD-ROM or a write-protected floppy.
4039 The only way to be really sure is to actually create a file and
4040 see if it succeeds. But I think that's too much to ask. */
4041 if (tmp
&& access (tmp
, D_OK
) == 0)
4043 setenv ("TMPDIR", tmp
, 1);
4050 Fcons (build_string ("no usable temporary directories found!!"),
4052 "While setting TMPDIR: ");
4054 /* Note the startup time, so we know not to clear the screen if we
4055 exit immediately; see IT_reset_terminal_modes.
4056 (Yes, I know `clock' returns zero the first time it's called, but
4057 I do this anyway, in case some wiseguy changes that at some point.) */
4058 startup_time
= clock ();
4060 /* Find our root from argv[0]. Assuming argv[0] is, say,
4061 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4062 root
= alloca (MAXPATHLEN
+ 20);
4063 _fixpath (argv
[0], root
);
4064 msdos_downcase_filename (root
);
4065 len
= strlen (root
);
4066 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4070 && (strcmp (root
+ len
- 4, "/bin") == 0
4071 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4072 root
[len
- 4] = '\0';
4074 strcpy (root
, "c:/emacs"); /* let's be defensive */
4075 len
= strlen (root
);
4076 strcpy (emacsroot
, root
);
4078 /* We default HOME to our root. */
4079 setenv ("HOME", root
, 0);
4081 /* We default EMACSPATH to root + "/bin". */
4082 strcpy (root
+ len
, "/bin");
4083 setenv ("EMACSPATH", root
, 0);
4085 /* I don't expect anybody to ever use other terminals so the internal
4086 terminal is the default. */
4087 setenv ("TERM", "internal", 0);
4089 #ifdef HAVE_X_WINDOWS
4090 /* Emacs expects DISPLAY to be set. */
4091 setenv ("DISPLAY", "unix:0.0", 0);
4094 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4095 downcase it and mirror the backslashes. */
4096 s
= getenv ("COMSPEC");
4097 if (!s
) s
= "c:/command.com";
4098 t
= alloca (strlen (s
) + 1);
4100 dostounix_filename (t
);
4101 setenv ("SHELL", t
, 0);
4103 /* PATH is also downcased and backslashes mirrored. */
4104 s
= getenv ("PATH");
4106 t
= alloca (strlen (s
) + 3);
4107 /* Current directory is always considered part of MsDos's path but it is
4108 not normally mentioned. Now it is. */
4109 strcat (strcpy (t
, ".;"), s
);
4110 dostounix_filename (t
); /* Not a single file name, but this should work. */
4111 setenv ("PATH", t
, 1);
4113 /* In some sense all dos users have root privileges, so... */
4114 setenv ("USER", "root", 0);
4115 setenv ("NAME", getenv ("USER"), 0);
4117 /* Time zone determined from country code. To make this possible, the
4118 country code may not span more than one time zone. In other words,
4119 in the USA, you lose. */
4121 switch (dos_country_code
)
4123 case 31: /* Belgium */
4124 case 32: /* The Netherlands */
4125 case 33: /* France */
4126 case 34: /* Spain */
4127 case 36: /* Hungary */
4128 case 38: /* Yugoslavia (or what's left of it?) */
4129 case 39: /* Italy */
4130 case 41: /* Switzerland */
4131 case 42: /* Tjekia */
4132 case 45: /* Denmark */
4133 case 46: /* Sweden */
4134 case 47: /* Norway */
4135 case 48: /* Poland */
4136 case 49: /* Germany */
4137 /* Daylight saving from last Sunday in March to last Sunday in
4138 September, both at 2AM. */
4139 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4141 case 44: /* United Kingdom */
4142 case 351: /* Portugal */
4143 case 354: /* Iceland */
4144 setenv ("TZ", "GMT+00", 0);
4146 case 81: /* Japan */
4147 case 82: /* Korea */
4148 setenv ("TZ", "JST-09", 0);
4150 case 90: /* Turkey */
4151 case 358: /* Finland */
4152 setenv ("TZ", "EET-02", 0);
4154 case 972: /* Israel */
4155 /* This is an approximation. (For exact rules, use the
4156 `zoneinfo/israel' file which comes with DJGPP, but you need
4157 to install it in `/usr/share/zoneinfo/' directory first.) */
4158 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4166 static int break_stat
; /* BREAK check mode status. */
4167 static int stdin_stat
; /* stdin IOCTL status. */
4169 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4170 control chars by DOS. Determine the keyboard type. */
4173 dos_ttraw (struct tty_display_info
*tty
)
4175 union REGS inregs
, outregs
;
4176 static int first_time
= 1;
4178 /* If we are called for the initial terminal, it's too early to do
4179 anything, and termscript isn't set up. */
4180 if (tty
->terminal
->type
== output_initial
)
4183 break_stat
= getcbrk ();
4189 int86 (0x15, &inregs
, &outregs
);
4190 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4195 #ifdef HAVE_X_WINDOWS
4196 && inhibit_window_system
4200 inregs
.x
.ax
= 0x0021;
4201 int86 (0x33, &inregs
, &outregs
);
4202 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4205 /* Reportedly, the above doesn't work for some mouse drivers. There
4206 is an additional detection method that should work, but might be
4207 a little slower. Use that as an alternative. */
4208 inregs
.x
.ax
= 0x0000;
4209 int86 (0x33, &inregs
, &outregs
);
4210 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4213 mouse_button_count
= outregs
.x
.bx
;
4215 #ifndef HAVE_X_WINDOWS
4216 /* Save the cursor shape used outside Emacs. */
4217 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4223 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4224 return (stdin_stat
!= -1);
4227 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4230 /* Restore status of standard input and Ctrl-C checking. */
4235 union REGS inregs
, outregs
;
4237 setcbrk (break_stat
);
4240 #ifndef HAVE_X_WINDOWS
4241 /* Restore the cursor shape we found on startup. */
4245 inregs
.x
.cx
= outside_cursor
;
4246 int86 (0x10, &inregs
, &outregs
);
4250 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4254 /* Run command as specified by ARGV in directory DIR.
4255 The command is run with input from TEMPIN, output to
4256 file TEMPOUT and stderr to TEMPERR. */
4259 run_msdos_command (unsigned char **argv
, const char *working_dir
,
4260 int tempin
, int tempout
, int temperr
, char **envv
)
4262 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4263 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4264 int msshell
, result
= -1, inbak
, outbak
, errbak
, x
, y
;
4267 /* Get current directory as MSDOS cwd is not per-process. */
4270 /* If argv[0] is the shell, it might come in any lettercase.
4271 Since `Fmember' is case-sensitive, we need to downcase
4272 argv[0], even if we are on case-preserving filesystems. */
4273 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4274 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4277 if (*pl
>= 'A' && *pl
<= 'Z')
4282 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4283 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4284 && !strcmp ("-c", argv
[1]);
4287 saveargv1
= argv
[1];
4288 saveargv2
= argv
[2];
4290 /* We only need to mirror slashes if a DOS shell will be invoked
4291 not via `system' (which does the mirroring itself). Yes, that
4292 means DJGPP v1.x will lose here. */
4293 if (argv
[2] && argv
[3])
4295 char *p
= alloca (strlen (argv
[2]) + 1);
4297 strcpy (argv
[2] = p
, saveargv2
);
4298 while (*p
&& isspace (*p
))
4310 chdir (working_dir
);
4314 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4315 goto done
; /* Allocation might fail due to lack of descriptors. */
4318 mouse_get_xy (&x
, &y
);
4320 if (!noninteractive
)
4321 dos_ttcooked (); /* do it here while 0 = stdin */
4327 if (msshell
&& !argv
[3])
4329 /* MS-DOS native shells are too restrictive. For starters, they
4330 cannot grok commands longer than 126 characters. In DJGPP v2
4331 and later, `system' is much smarter, so we'll call it instead. */
4335 /* A shell gets a single argument--its full command
4336 line--whose original was saved in `saveargv2'. */
4338 /* Don't let them pass empty command lines to `system', since
4339 with some shells it will try to invoke an interactive shell,
4340 which will hang Emacs. */
4341 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4345 extern char **environ
;
4346 char **save_env
= environ
;
4347 int save_system_flags
= __system_flags
;
4349 /* Request the most powerful version of `system'. We need
4350 all the help we can get to avoid calling stock DOS shells. */
4351 __system_flags
= (__system_redirect
4352 | __system_use_shell
4353 | __system_allow_multiple_cmds
4354 | __system_allow_long_cmds
4355 | __system_handle_null_commands
4356 | __system_emulate_chdir
);
4359 result
= system (cmnd
);
4360 __system_flags
= save_system_flags
;
4364 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4367 result
= spawnve (P_WAIT
, argv
[0], (char **)argv
, envv
);
4372 emacs_close (inbak
);
4373 emacs_close (outbak
);
4374 emacs_close (errbak
);
4376 if (!noninteractive
)
4377 dos_ttraw (CURTTY ());
4381 mouse_moveto (x
, y
);
4384 /* Some programs might change the meaning of the highest bit of the
4385 text attribute byte, so we get blinking characters instead of the
4386 bright background colors. Restore that. */
4387 if (!noninteractive
)
4394 argv
[1] = saveargv1
;
4395 argv
[2] = saveargv2
;
4401 croak (char *badfunc
)
4403 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4404 reset_all_sys_modes ();
4409 * A few unimplemented functions that we silently ignore.
4411 int setpgrp (void) {return 0; }
4412 int setpriority (int x
, int y
, int z
) { return 0; }
4414 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4416 /* Augment DJGPP library POSIX signal functions. This is needed
4417 as of DJGPP v2.01, but might be in the library in later releases. */
4419 #include <libc/bss.h>
4421 /* A counter to know when to re-initialize the static sets. */
4422 static int sigprocmask_count
= -1;
4424 /* Which signals are currently blocked (initially none). */
4425 static sigset_t current_mask
;
4427 /* Which signals are pending (initially none). */
4428 static sigset_t msdos_pending_signals
;
4430 /* Previous handlers to restore when the blocked signals are unblocked. */
4431 typedef void (*sighandler_t
)(int);
4432 static sighandler_t prev_handlers
[320];
4434 /* A signal handler which just records that a signal occurred
4435 (it will be raised later, if and when the signal is unblocked). */
4437 sig_suspender (int signo
)
4439 sigaddset (&msdos_pending_signals
, signo
);
4443 sigprocmask (int how
, const sigset_t
*new_set
, sigset_t
*old_set
)
4448 /* If called for the first time, initialize. */
4449 if (sigprocmask_count
!= __bss_count
)
4451 sigprocmask_count
= __bss_count
;
4452 sigemptyset (&msdos_pending_signals
);
4453 sigemptyset (¤t_mask
);
4454 for (signo
= 0; signo
< 320; signo
++)
4455 prev_handlers
[signo
] = SIG_ERR
;
4459 *old_set
= current_mask
;
4464 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4470 sigemptyset (&new_mask
);
4472 /* DJGPP supports upto 320 signals. */
4473 for (signo
= 0; signo
< 320; signo
++)
4475 if (sigismember (¤t_mask
, signo
))
4476 sigaddset (&new_mask
, signo
);
4477 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4479 sigaddset (&new_mask
, signo
);
4481 /* SIGKILL is silently ignored, as on other platforms. */
4482 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4483 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4485 if (( how
== SIG_UNBLOCK
4486 && sigismember (&new_mask
, signo
)
4487 && sigismember (new_set
, signo
))
4488 || (how
== SIG_SETMASK
4489 && sigismember (&new_mask
, signo
)
4490 && !sigismember (new_set
, signo
)))
4492 sigdelset (&new_mask
, signo
);
4493 if (prev_handlers
[signo
] != SIG_ERR
)
4495 signal (signo
, prev_handlers
[signo
]);
4496 prev_handlers
[signo
] = SIG_ERR
;
4498 if (sigismember (&msdos_pending_signals
, signo
))
4500 sigdelset (&msdos_pending_signals
, signo
);
4505 current_mask
= new_mask
;
4509 #endif /* not __DJGPP_MINOR__ < 2 */
4512 #include "sysselect.h"
4514 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4515 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4516 ((long)(time).tv_sec < 0 \
4517 || ((time).tv_sec == 0 \
4518 && (long)(time).tv_usec <= 0))
4521 /* This yields the rest of the current time slice to the task manager.
4522 It should be called by any code which knows that it has nothing
4523 useful to do except idle.
4525 I don't use __dpmi_yield here, since versions of library before 2.02
4526 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4527 on some versions of Windows 9X. */
4530 dos_yield_time_slice (void)
4532 _go32_dpmi_registers r
;
4535 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
4536 _go32_dpmi_simulate_int (0x2f, &r
);
4541 /* Only event queue is checked. */
4542 /* We don't have to call timer_check here
4543 because wait_reading_process_output takes care of that. */
4545 sys_select (int nfds
, SELECT_TYPE
*rfds
, SELECT_TYPE
*wfds
, SELECT_TYPE
*efds
,
4546 EMACS_TIME
*timeout
)
4554 check_input
= FD_ISSET (0, rfds
);
4565 /* If we are looking only for the terminal, with no timeout,
4566 just read it and wait -- that's more efficient. */
4569 while (!detect_input_pending ())
4571 dos_yield_time_slice ();
4576 EMACS_TIME clnow
, cllast
, cldiff
;
4579 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
4581 while (!check_input
|| !detect_input_pending ())
4584 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
4585 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
4587 /* When seconds wrap around, we assume that no more than
4588 1 minute passed since last `gettime'. */
4589 if (EMACS_TIME_NEG_P (cldiff
))
4590 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
4591 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
4593 /* Stop when timeout value crosses zero. */
4594 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
4597 dos_yield_time_slice ();
4607 * Define overlaid functions:
4609 * chdir -> sys_chdir
4610 * tzset -> init_gettimeofday
4611 * abort -> dos_abort
4616 extern int chdir (const char *);
4619 sys_chdir (const char *path
)
4621 int len
= strlen (path
);
4622 char *tmp
= (char *)path
;
4624 if (*tmp
&& tmp
[1] == ':')
4626 if (getdisk () != tolower (tmp
[0]) - 'a')
4627 setdisk (tolower (tmp
[0]) - 'a');
4628 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
4632 if (len
> 1 && (tmp
[len
- 1] == '/'))
4634 char *tmp1
= (char *) alloca (len
+ 1);
4645 extern void tzset (void);
4648 init_gettimeofday (void)
4654 ltm
= gtm
= time (NULL
);
4655 ltm
= mktime (lstm
= localtime (<m
));
4656 gtm
= mktime (gmtime (>m
));
4657 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
4658 time_rec
.tm_isdst
= lstm
->tm_isdst
;
4659 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
4666 dos_abort (char *file
, int line
)
4668 char buffer1
[200], buffer2
[400];
4671 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
4672 for (i
= j
= 0; buffer1
[i
]; i
++) {
4673 buffer2
[j
++] = buffer1
[i
];
4674 buffer2
[j
++] = 0x70;
4676 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
4677 ScreenSetCursor (2, 0);
4685 ScreenSetCursor (10, 0);
4686 cputs ("\r\n\nEmacs aborted!\r\n");
4687 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4688 if (screen_virtual_segment
)
4689 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
4690 /* Generate traceback, so we could tell whodunit. */
4691 signal (SIGINT
, SIG_DFL
);
4692 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4693 #else /* __DJGPP_MINOR__ >= 2 */
4695 #endif /* __DJGPP_MINOR__ >= 2 */
4701 syms_of_msdos (void)
4703 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
4704 staticpro (&recent_doskeys
);
4706 #ifndef HAVE_X_WINDOWS
4708 /* The following two are from xfns.c: */
4709 Qreverse
= intern ("reverse");
4710 staticpro (&Qreverse
);
4712 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
4713 doc
: /* *Glyph to display instead of chars not supported by current codepage.
4714 This variable is used only by MS-DOS terminals. */);
4715 Vdos_unsupported_char_glyph
= make_number ('\177');
4719 defsubr (&Srecent_doskeys
);
4720 defsubr (&Smsdos_long_file_names
);
4721 defsubr (&Smsdos_downcase_filename
);
4722 defsubr (&Smsdos_remember_default_colors
);
4723 defsubr (&Smsdos_set_mouse_buttons
);
4728 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
4729 (do not change this comment) */