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 bzero 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 ourselves. */
79 #define _dos_ds _go32_info_block.selector_for_linear_memory
83 #include "syssignal.h"
89 /* If other `malloc' than ours is used, force our `sbrk' behave like
90 Unix programs expect (resize memory blocks to keep them contiguous).
91 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
92 because that's what `gmalloc' expects to get. */
96 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
97 #else /* not REL_ALLOC */
98 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
99 #endif /* not REL_ALLOC */
100 #endif /* GNU_MALLOC */
102 #endif /* not SYSTEM_MALLOC */
121 /* ------------------------ Mouse control ---------------------------
123 * Coordinates are in screen positions and zero based.
124 * Mouse buttons are numbered from left to right and also zero based.
127 /* This used to be in termhooks.h, but mainstream Emacs code no longer
128 uses it, and it was removed... */
129 #define NUM_MOUSE_BUTTONS (5)
131 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
132 static int mouse_visible
;
134 static int mouse_last_x
;
135 static int mouse_last_y
;
137 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
138 static int mouse_button_count
;
145 if (have_mouse
> 0 && !mouse_visible
)
147 struct tty_display_info
*tty
= CURTTY ();
150 fprintf (tty
->termscript
, "<M_ON>");
152 int86 (0x33, ®s
, ®s
);
162 if (have_mouse
> 0 && mouse_visible
)
164 struct tty_display_info
*tty
= CURTTY ();
167 fprintf (tty
->termscript
, "<M_OFF>");
169 int86 (0x33, ®s
, ®s
);
175 mouse_setup_buttons (int n_buttons
)
179 mouse_button_count
= 3;
180 mouse_button_translate
[0] = 0; /* Left */
181 mouse_button_translate
[1] = 2; /* Middle */
182 mouse_button_translate
[2] = 1; /* Right */
184 else /* two, what else? */
186 mouse_button_count
= 2;
187 mouse_button_translate
[0] = 0;
188 mouse_button_translate
[1] = 1;
192 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons
, Smsdos_set_mouse_buttons
,
193 1, 1, "NSet number of mouse buttons to: ",
194 doc
: /* Set the number of mouse buttons to use by Emacs.
195 This is useful with mice that report the number of buttons inconsistently,
196 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
197 them. This happens with wheeled mice on Windows 9X, for example. */)
199 Lisp_Object nbuttons
;
203 CHECK_NUMBER (nbuttons
);
206 xsignal2 (Qargs_out_of_range
,
207 build_string ("only 2 or 3 mouse buttons are supported"),
209 mouse_setup_buttons (n
);
214 mouse_get_xy (int *x
, int *y
)
219 int86 (0x33, ®s
, ®s
);
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 (b
, xp
, yp
)
245 if (b
>= mouse_button_count
)
248 regs
.x
.bx
= mouse_button_translate
[b
];
249 int86 (0x33, ®s
, ®s
);
251 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
252 return (regs
.x
.bx
!= 0);
256 mouse_released (b
, xp
, yp
)
261 if (b
>= mouse_button_count
)
264 regs
.x
.bx
= mouse_button_translate
[b
];
265 int86 (0x33, ®s
, ®s
);
267 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
268 return (regs
.x
.bx
!= 0);
272 mouse_button_depressed (b
, xp
, yp
)
277 if (b
>= mouse_button_count
)
280 int86 (0x33, ®s
, ®s
);
281 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
291 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
294 Lisp_Object
*bar_window
, *x
, *y
;
295 enum scroll_bar_part
*part
;
299 Lisp_Object frame
, tail
;
301 /* Clear the mouse-moved flag for every frame on this display. */
302 FOR_EACH_FRAME (tail
, frame
)
303 XFRAME (frame
)->mouse_moved
= 0;
305 *f
= SELECTED_FRAME();
307 mouse_get_xy (&ix
, &iy
);
308 *time
= event_timestamp ();
309 *x
= make_number (mouse_last_x
= ix
);
310 *y
= make_number (mouse_last_y
= iy
);
318 mouse_get_xy (&x
, &y
);
319 SELECTED_FRAME()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
324 /* Force the mouse driver to ``forget'' about any button clicks until
327 mouse_clear_clicks (void)
331 for (b
= 0; b
< mouse_button_count
; b
++)
333 int dummy_x
, dummy_y
;
335 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
336 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
344 struct tty_display_info
*tty
= CURTTY ();
347 fprintf (tty
->termscript
, "<M_INIT>");
350 int86 (0x33, ®s
, ®s
);
352 /* Reset the mouse last press/release info. It seems that Windows
353 doesn't do that automatically when function 21h is called, which
354 causes Emacs to ``remember'' the click that switched focus to the
355 window just before Emacs was started from that window. */
356 mouse_clear_clicks ();
360 regs
.x
.dx
= 8 * (ScreenCols () - 1);
361 int86 (0x33, ®s
, ®s
);
365 regs
.x
.dx
= 8 * (ScreenRows () - 1);
366 int86 (0x33, ®s
, ®s
);
372 /* ------------------------- Screen control ----------------------
376 static int internal_terminal
= 0;
378 #ifndef HAVE_X_WINDOWS
379 extern unsigned char ScreenAttrib
;
380 static int screen_face
;
382 static int screen_size_X
;
383 static int screen_size_Y
;
384 static int screen_size
;
386 static int current_pos_X
;
387 static int current_pos_Y
;
388 static int new_pos_X
;
389 static int new_pos_Y
;
391 static void *startup_screen_buffer
;
392 static int startup_screen_size_X
;
393 static int startup_screen_size_Y
;
394 static int startup_pos_X
;
395 static int startup_pos_Y
;
396 static unsigned char startup_screen_attrib
;
398 static clock_t startup_time
;
400 static int term_setup_done
;
402 static unsigned short outside_cursor
;
404 /* Similar to the_only_frame. */
405 struct tty_display_info the_only_display_info
;
407 /* Support for DOS/V (allows Japanese characters to be displayed on
408 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
410 /* Holds the address of the text-mode screen buffer. */
411 static unsigned long screen_old_address
= 0;
412 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
413 static unsigned short screen_virtual_segment
= 0;
414 static unsigned short screen_virtual_offset
= 0;
415 /* A flag to control how to display unibyte 8-bit characters. */
416 extern int unibyte_display_via_language_environment
;
418 extern Lisp_Object Qcursor_type
;
419 extern Lisp_Object Qbar
, Qhbar
;
421 /* The screen colors of the current frame, which serve as the default
422 colors for newly-created frames. */
423 static int initial_screen_colors
[2];
425 /* Update the screen from a part of relocated DOS/V screen buffer which
426 begins at OFFSET and includes COUNT characters. */
428 dosv_refresh_virtual_screen (int offset
, int count
)
432 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
435 regs
.h
.ah
= 0xff; /* update relocated screen */
436 regs
.x
.es
= screen_virtual_segment
;
437 regs
.x
.di
= screen_virtual_offset
+ offset
;
439 __dpmi_int (0x10, ®s
);
443 dos_direct_output (y
, x
, buf
, len
)
448 int t0
= 2 * (x
+ y
* screen_size_X
);
449 int t
= t0
+ (int) ScreenPrimary
;
452 /* This is faster. */
453 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
454 _farnspokeb (t
, *buf
);
456 if (screen_virtual_segment
)
457 dosv_refresh_virtual_screen (t0
, l0
);
461 #ifndef HAVE_X_WINDOWS
463 static int blink_bit
= -1; /* the state of the blink bit at startup */
465 /* Enable bright background colors. */
471 /* Remember the original state of the blink/bright-background bit.
472 It is stored at 0040:0065h in the BIOS data area. */
474 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
478 int86 (0x10, ®s
, ®s
);
481 /* Disable bright background colors (and enable blinking) if we found
482 the video system in that state at startup. */
484 maybe_enable_blinking (void)
492 int86 (0x10, ®s
, ®s
);
496 /* Return non-zero if the system has a VGA adapter. */
503 int86 (0x10, ®s
, ®s
);
504 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
509 /* Set the screen dimensions so that it can show no less than
510 ROWS x COLS frame. */
513 dos_set_window_size (rows
, cols
)
518 Lisp_Object video_mode
;
519 int video_mode_value
, have_vga
= 0;
520 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
522 if (*rows
== current_rows
&& *cols
== current_cols
)
526 have_vga
= vga_installed ();
528 /* If the user specified a special video mode for these dimensions,
530 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
531 video_mode
= Fsymbol_value (Fintern_soft (build_string (video_name
), Qnil
));
533 if (INTEGERP (video_mode
)
534 && (video_mode_value
= XINT (video_mode
)) > 0)
536 regs
.x
.ax
= video_mode_value
;
537 int86 (0x10, ®s
, ®s
);
541 /* Must hardware-reset the mouse, or else it won't update
542 its notion of screen dimensions for some non-standard
543 video modes. This is *painfully* slow... */
545 int86 (0x33, ®s
, ®s
);
549 /* Find one of the dimensions supported by standard EGA/VGA
550 which gives us at least the required dimensions. */
555 } std_dimension
[] = {
565 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
567 if (std_dimension
[i
].need_vga
<= have_vga
568 && std_dimension
[i
].rows
>= *rows
)
570 if (std_dimension
[i
].rows
!= current_rows
571 || *cols
!= current_cols
)
572 _set_screen_lines (std_dimension
[i
].rows
);
586 /* Tell the caller what dimensions have been REALLY set. */
587 *rows
= ScreenRows ();
588 *cols
= ScreenCols ();
590 /* Update Emacs' notion of screen dimensions. */
591 screen_size_X
= *cols
;
592 screen_size_Y
= *rows
;
593 screen_size
= *cols
* *rows
;
595 /* If the dimensions changed, the mouse highlight info is invalid. */
596 if (current_rows
!= *rows
|| current_cols
!= *cols
)
598 struct frame
*f
= SELECTED_FRAME();
599 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
600 Lisp_Object window
= dpyinfo
->mouse_face_window
;
602 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
604 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
605 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
606 dpyinfo
->mouse_face_window
= Qnil
;
610 /* Enable bright background colors. */
613 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
614 be defensive anyway. */
615 if (screen_virtual_segment
)
616 dosv_refresh_virtual_screen (0, *cols
* *rows
);
619 /* If we write a character in the position where the mouse is,
620 the mouse cursor may need to be refreshed. */
630 mouse_get_xy (&x
, &y
);
631 if (y
!= new_pos_Y
|| x
< new_pos_X
)
637 #define DEFAULT_CURSOR_START (-1)
638 #define DEFAULT_CURSOR_WIDTH (-1)
639 #define BOX_CURSOR_WIDTH (-32)
641 /* Set cursor to begin at scan line START_LINE in the character cell
642 and extend for WIDTH scan lines. Scan lines are counted from top
643 of the character cell, starting from zero. */
645 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
647 unsigned desired_cursor
;
649 int max_line
, top_line
, bot_line
;
650 struct tty_display_info
*tty
= FRAME_TTY (f
);
652 /* Avoid the costly BIOS call if F isn't the currently selected
653 frame. Allow for NULL as unconditionally meaning the selected
655 if (f
&& f
!= SELECTED_FRAME())
659 fprintf (tty
->termscript
, "\nCURSOR SHAPE=(%d,%d)", start_line
, width
);
661 /* The character cell size in scan lines is stored at 40:85 in the
663 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
666 default: /* this relies on CGA cursor emulation being ON! */
683 if (width
== BOX_CURSOR_WIDTH
)
688 else if (start_line
!= DEFAULT_CURSOR_START
)
690 top_line
= start_line
;
691 bot_line
= top_line
- width
- 1;
693 else if (width
!= DEFAULT_CURSOR_WIDTH
)
696 bot_line
= -1 - width
;
699 top_line
= bot_line
+ 1;
703 /* [31, 0] seems to DTRT for all screen sizes. */
707 else /* WIDTH is positive */
709 if (start_line
!= DEFAULT_CURSOR_START
)
710 bot_line
= start_line
;
711 top_line
= bot_line
- (width
- 1);
714 /* If the current cursor shape is already what they want, we are
716 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
717 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
721 regs
.x
.cx
= desired_cursor
;
722 __dpmi_int (0x10, ®s
);
726 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
728 if (EQ (cursor_type
, Qbar
) || EQ (cursor_type
, Qhbar
))
730 /* Just BAR means the normal EGA/VGA cursor. */
731 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
733 else if (CONSP (cursor_type
)
734 && (EQ (XCAR (cursor_type
), Qbar
)
735 || EQ (XCAR (cursor_type
), Qhbar
)))
737 Lisp_Object bar_parms
= XCDR (cursor_type
);
740 if (INTEGERP (bar_parms
))
742 /* Feature: negative WIDTH means cursor at the top
743 of the character cell, zero means invisible cursor. */
744 width
= XINT (bar_parms
);
745 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
748 else if (CONSP (bar_parms
)
749 && INTEGERP (XCAR (bar_parms
))
750 && INTEGERP (XCDR (bar_parms
)))
752 int start_line
= XINT (XCDR (bar_parms
));
754 width
= XINT (XCAR (bar_parms
));
755 msdos_set_cursor_shape (f
, start_line
, width
);
760 /* Treat anything unknown as "box cursor". This includes nil, so
761 that a frame which doesn't specify a cursor type gets a box,
762 which is the default in Emacs. */
763 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
768 IT_ring_bell (struct frame
*f
)
777 union REGS inregs
, outregs
;
780 intdos (&inregs
, &outregs
);
784 /* Given a face id FACE, extract the face parameters to be used for
785 display until the face changes. The face parameters (actually, its
786 color) are used to construct the video attribute byte for each
787 glyph during the construction of the buffer that is then blitted to
790 IT_set_face (int face
)
792 struct frame
*sf
= SELECTED_FRAME();
793 struct face
*fp
= FACE_FROM_ID (sf
, face
);
794 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
795 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
796 struct tty_display_info
*tty
= FRAME_TTY (sf
);
801 /* The default face for the frame should always be realized and
809 dflt_fg
= dfp
->foreground
;
810 dflt_bg
= dfp
->background
;
812 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
813 mean use the colors of the default face. Note that we assume all
814 16 colors to be available for the background, since Emacs switches
815 on this mode (and loses the blinking attribute) at startup. */
816 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
817 fg
= FRAME_FOREGROUND_PIXEL (sf
);
818 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
819 fg
= FRAME_BACKGROUND_PIXEL (sf
);
820 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
821 bg
= FRAME_BACKGROUND_PIXEL (sf
);
822 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
823 bg
= FRAME_FOREGROUND_PIXEL (sf
);
825 /* Make sure highlighted lines really stand out, come what may. */
826 if (fp
->tty_reverse_p
&& (fg
== dflt_fg
&& bg
== dflt_bg
))
828 unsigned long tem
= fg
;
833 /* If the user requested inverse video, obey. */
836 unsigned long tem2
= fg
;
842 fprintf (tty
->termscript
, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face
,
843 fp
->foreground
, fp
->background
, fg
, bg
);
844 if (fg
>= 0 && fg
< 16)
846 ScreenAttrib
&= 0xf0;
849 if (bg
>= 0 && bg
< 16)
851 ScreenAttrib
&= 0x0f;
852 ScreenAttrib
|= ((bg
& 0x0f) << 4);
856 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
857 width of a DOS display in any known text mode. We multiply by 2 to
858 accomodate the screen attribute byte. */
859 #define MAX_SCREEN_BUF 160*2
861 Lisp_Object Vdos_unsupported_char_glyph
;
862 extern unsigned char *encode_terminal_code (struct glyph
*, int,
863 struct coding_system
*);
865 IT_write_glyphs (struct frame
*f
, struct glyph
*str
, int str_len
)
867 unsigned char screen_buf
[MAX_SCREEN_BUF
], *screen_bp
, *bp
;
868 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
869 register int sl
= str_len
;
870 struct tty_display_info
*tty
= FRAME_TTY (f
);
872 unsigned char *conversion_buffer
;
874 /* Do we need to consider conversion of unibyte characters to
876 int convert_unibyte_characters
877 = (NILP (current_buffer
->enable_multibyte_characters
)
878 && unibyte_display_via_language_environment
);
880 /* If terminal_coding does any conversion, use it, otherwise use
881 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
882 because it always returns 1 if terminal_coding.src_multibyte is 1. */
883 struct coding_system
*coding
= FRAME_TERMINAL_CODING (f
);
885 if (!(coding
->common_flags
& CODING_REQUIRE_ENCODING_MASK
))
886 coding
= &safe_terminal_coding
;
888 if (str_len
<= 0) return;
890 sf
= SELECTED_FRAME();
892 /* Since faces get cached and uncached behind our back, we can't
893 rely on their indices in the cache being consistent across
894 invocations. So always reset the screen face to the default
895 face of the frame, before writing glyphs, and let the glyphs
896 set the right face if it's different from the default. */
897 IT_set_face (DEFAULT_FACE_ID
);
899 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
901 coding
->mode
&= ~CODING_MODE_LAST_BLOCK
;
902 screen_bp
= &screen_buf
[0];
908 /* If the face of this glyph is different from the current
909 screen face, update the screen attribute byte. */
911 if (cf
!= screen_face
)
912 IT_set_face (cf
); /* handles invalid faces gracefully */
914 /* Identify a run of glyphs with the same face. */
915 for (n
= 1; n
< sl
; ++n
)
916 if (str
[n
].face_id
!= cf
)
920 /* This is the last glyph. */
921 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
923 conversion_buffer
= encode_terminal_code (str
, n
, coding
);
924 if (coding
->produced
> 0)
926 /* Copy the encoded bytes to the screen buffer. */
927 for (bp
= conversion_buffer
; coding
->produced
--; bp
++)
929 /* Paranoia: discard bytes that would overrun the end of
930 the screen buffer. */
931 if (screen_bp
- screen_buf
<= MAX_SCREEN_BUF
- 2)
933 *screen_bp
++ = (unsigned char)*bp
;
934 *screen_bp
++ = ScreenAttrib
;
937 fputc (*bp
, tty
->termscript
);
940 /* Update STR and its remaining length. */
945 /* Dump whatever we have in the screen buffer. */
947 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
948 if (screen_virtual_segment
)
949 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
950 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
953 /************************************************************************
954 Mouse Highlight (and friends..)
955 ************************************************************************/
957 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
958 static Lisp_Object last_mouse_window
;
960 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
962 /* Set the mouse pointer shape according to whether it is in the
963 area where the mouse highlight is in effect. */
965 IT_set_mouse_pointer (int mode
)
967 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
968 many possibilities to change its shape, and the available
969 functionality pretty much sucks (e.g., almost every reasonable
970 shape will conceal the character it is on). Since the color of
971 the pointer changes in the highlighted area, it is not clear to
972 me whether anything else is required, anyway. */
975 /* Display the active region described by mouse_face_*
976 in its mouse-face if HL > 0, in its normal face if HL = 0. */
978 show_mouse_face (struct tty_display_info
*dpyinfo
, int hl
)
980 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
981 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
984 struct tty_display_info
*tty
= FRAME_TTY (f
);
987 /* If window is in the process of being destroyed, don't bother
989 if (w
->current_matrix
== NULL
)
990 goto set_cursor_shape
;
992 /* Recognize when we are called to operate on rows that don't exist
993 anymore. This can happen when a window is split. */
994 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
995 goto set_cursor_shape
;
997 /* There's no sense to do anything if the mouse face isn't realized. */
1000 if (dpyinfo
->mouse_face_hidden
)
1001 goto set_cursor_shape
;
1003 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1005 goto set_cursor_shape
;
1008 /* Note that mouse_face_beg_row etc. are window relative. */
1009 for (i
= dpyinfo
->mouse_face_beg_row
;
1010 i
<= dpyinfo
->mouse_face_end_row
;
1013 int start_hpos
, end_hpos
;
1014 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1016 /* Don't do anything if row doesn't have valid contents. */
1017 if (!row
->enabled_p
)
1020 /* For all but the first row, the highlight starts at column 0. */
1021 if (i
== dpyinfo
->mouse_face_beg_row
)
1022 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1026 if (i
== dpyinfo
->mouse_face_end_row
)
1027 end_hpos
= dpyinfo
->mouse_face_end_col
;
1029 end_hpos
= row
->used
[TEXT_AREA
];
1031 if (end_hpos
<= start_hpos
)
1033 /* Record that some glyphs of this row are displayed in
1035 row
->mouse_face_p
= hl
> 0;
1038 int vpos
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1039 int kstart
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1040 int nglyphs
= end_hpos
- start_hpos
;
1041 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1042 int start_offset
= offset
;
1044 if (tty
->termscript
)
1045 fprintf (tty
->termscript
, "\n<MH+ %d-%d:%d>",
1046 kstart
, kstart
+ nglyphs
- 1, vpos
);
1049 IT_set_face (dpyinfo
->mouse_face_face_id
);
1050 /* Since we are going to change only the _colors_ of the
1051 displayed text, there's no need to go through all the
1052 pain of generating and encoding the text from the glyphs.
1053 Instead, we simply poke the attribute byte of each
1054 affected position in video memory with the colors
1055 computed by IT_set_face! */
1056 _farsetsel (_dos_ds
);
1059 _farnspokeb (offset
, ScreenAttrib
);
1062 if (screen_virtual_segment
)
1063 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1068 /* We are removing a previously-drawn mouse highlight. The
1069 safest way to do so is to redraw the glyphs anew, since
1070 all kinds of faces and display tables could have changed
1072 int nglyphs
= end_hpos
- start_hpos
;
1073 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1075 if (end_hpos
>= row
->used
[TEXT_AREA
])
1076 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1078 /* IT_write_glyphs writes at cursor position, so we need to
1079 temporarily move cursor coordinates to the beginning of
1080 the highlight region. */
1081 new_pos_X
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1082 new_pos_Y
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1084 if (tty
->termscript
)
1085 fprintf (tty
->termscript
, "<MH- %d-%d:%d>",
1086 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1087 IT_write_glyphs (f
, row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1088 if (tty
->termscript
)
1089 fputs ("\n", tty
->termscript
);
1096 /* Change the mouse pointer shape. */
1097 IT_set_mouse_pointer (hl
);
1100 /* Clear out the mouse-highlighted active region.
1101 Redraw it un-highlighted first. */
1103 clear_mouse_face (struct tty_display_info
*dpyinfo
)
1105 if (!dpyinfo
->mouse_face_hidden
&& ! NILP (dpyinfo
->mouse_face_window
))
1106 show_mouse_face (dpyinfo
, 0);
1108 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1109 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1110 dpyinfo
->mouse_face_window
= Qnil
;
1113 /* Find the glyph matrix position of buffer position POS in window W.
1114 *HPOS and *VPOS are set to the positions found. W's current glyphs
1115 must be up to date. If POS is above window start return (0, 0).
1116 If POS is after end of W, return end of last line in W. */
1118 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1120 int i
, lastcol
, line_start_position
, maybe_next_line_p
= 0;
1121 int yb
= window_text_bottom_y (w
);
1122 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0), *best_row
= row
;
1126 if (row
->used
[TEXT_AREA
])
1127 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1129 line_start_position
= 0;
1131 if (line_start_position
> pos
)
1133 /* If the position sought is the end of the buffer,
1134 don't include the blank lines at the bottom of the window. */
1135 else if (line_start_position
== pos
1136 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1138 maybe_next_line_p
= 1;
1141 else if (line_start_position
> 0)
1144 /* Don't overstep the last matrix row, lest we get into the
1145 never-never land... */
1146 if (row
->y
+ 1 >= yb
)
1152 /* Find the right column within BEST_ROW. */
1155 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1157 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1160 charpos
= glyph
->charpos
;
1167 else if (charpos
> pos
)
1169 else if (charpos
> 0)
1173 /* If we're looking for the end of the buffer,
1174 and we didn't find it in the line we scanned,
1175 use the start of the following line. */
1176 if (maybe_next_line_p
)
1183 *hpos
= lastcol
+ 1;
1187 /* Take proper action when mouse has moved to the mode or top line of
1188 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1189 mode line. X is relative to the start of the text display area of
1190 W, so the width of fringes and scroll bars must be subtracted
1191 to get a position relative to the start of the mode line. */
1193 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1195 struct frame
*f
= XFRAME (w
->frame
);
1196 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1197 struct glyph_row
*row
;
1200 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1202 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1206 extern Lisp_Object Qhelp_echo
;
1207 struct glyph
*glyph
, *end
;
1208 Lisp_Object help
, map
;
1210 /* Find the glyph under X. */
1211 glyph
= (row
->glyphs
[TEXT_AREA
]
1213 /* in case someone implements scroll bars some day... */
1214 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w
));
1215 end
= glyph
+ row
->used
[TEXT_AREA
];
1217 && STRINGP (glyph
->object
)
1218 && STRING_INTERVALS (glyph
->object
)
1219 && glyph
->charpos
>= 0
1220 && glyph
->charpos
< SCHARS (glyph
->object
))
1222 /* If we're on a string with `help-echo' text property,
1223 arrange for the help to be displayed. This is done by
1224 setting the global variable help_echo to the help string. */
1225 help
= Fget_text_property (make_number (glyph
->charpos
),
1226 Qhelp_echo
, glyph
->object
);
1229 help_echo_string
= help
;
1230 XSETWINDOW (help_echo_window
, w
);
1231 help_echo_object
= glyph
->object
;
1232 help_echo_pos
= glyph
->charpos
;
1238 /* Take proper action when the mouse has moved to position X, Y on
1239 frame F as regards highlighting characters that have mouse-face
1240 properties. Also de-highlighting chars where the mouse was before.
1241 X and Y can be negative or out of range. */
1243 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1245 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1246 enum window_part part
= ON_NOTHING
;
1250 /* When a menu is active, don't highlight because this looks odd. */
1251 if (mouse_preempted
)
1254 if (NILP (Vmouse_highlight
)
1255 || !f
->glyphs_initialized_p
)
1258 dpyinfo
->mouse_face_mouse_x
= x
;
1259 dpyinfo
->mouse_face_mouse_y
= y
;
1260 dpyinfo
->mouse_face_mouse_frame
= f
;
1262 if (dpyinfo
->mouse_face_defer
)
1267 dpyinfo
->mouse_face_deferred_gc
= 1;
1271 /* Which window is that in? */
1272 window
= window_from_coordinates (f
, x
, y
, &part
, &x
, &y
, 0);
1274 /* If we were displaying active text in another window, clear that. */
1275 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1276 clear_mouse_face (dpyinfo
);
1278 /* Not on a window -> return. */
1279 if (!WINDOWP (window
))
1282 /* Convert to window-relative coordinates. */
1283 w
= XWINDOW (window
);
1285 if (part
== ON_MODE_LINE
|| part
== ON_HEADER_LINE
)
1287 /* Mouse is on the mode or top line. */
1288 IT_note_mode_line_highlight (w
, x
, part
== ON_MODE_LINE
);
1292 IT_set_mouse_pointer (0);
1294 /* Are we in a window whose display is up to date?
1295 And verify the buffer's text has not changed. */
1297 && EQ (w
->window_end_valid
, w
->buffer
)
1298 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1299 && (XFASTINT (w
->last_overlay_modified
)
1300 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1302 int pos
, i
, nrows
= w
->current_matrix
->nrows
;
1303 struct glyph_row
*row
;
1304 struct glyph
*glyph
;
1306 /* Find the glyph under X/Y. */
1308 if (y
>= 0 && y
< nrows
)
1310 row
= MATRIX_ROW (w
->current_matrix
, y
);
1311 /* Give up if some row before the one we are looking for is
1313 for (i
= 0; i
<= y
; i
++)
1314 if (!MATRIX_ROW (w
->current_matrix
, i
)->enabled_p
)
1316 if (i
> y
/* all rows upto and including the one at Y are enabled */
1317 && row
->displays_text_p
1318 && x
< window_box_width (w
, TEXT_AREA
))
1320 glyph
= row
->glyphs
[TEXT_AREA
];
1321 if (x
>= row
->used
[TEXT_AREA
])
1326 if (!BUFFERP (glyph
->object
))
1332 /* Clear mouse face if X/Y not over text. */
1335 clear_mouse_face (dpyinfo
);
1339 if (!BUFFERP (glyph
->object
))
1341 pos
= glyph
->charpos
;
1343 /* Check for mouse-face and help-echo. */
1345 extern Lisp_Object Qmouse_face
;
1346 Lisp_Object mouse_face
, overlay
, position
, *overlay_vec
;
1347 int noverlays
, obegv
, ozv
;
1348 struct buffer
*obuf
;
1350 /* If we get an out-of-range value, return now; avoid an error. */
1351 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1354 /* Make the window's buffer temporarily current for
1355 overlays_at and compute_char_face. */
1356 obuf
= current_buffer
;
1357 current_buffer
= XBUFFER (w
->buffer
);
1363 /* Is this char mouse-active or does it have help-echo? */
1364 XSETINT (position
, pos
);
1366 /* Put all the overlays we want in a vector in overlay_vec. */
1367 GET_OVERLAYS_AT (pos
, overlay_vec
, noverlays
, NULL
, 0);
1368 /* Sort overlays into increasing priority order. */
1369 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1371 /* Check mouse-face highlighting. */
1372 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1373 && y
>= dpyinfo
->mouse_face_beg_row
1374 && y
<= dpyinfo
->mouse_face_end_row
1375 && (y
> dpyinfo
->mouse_face_beg_row
1376 || x
>= dpyinfo
->mouse_face_beg_col
)
1377 && (y
< dpyinfo
->mouse_face_end_row
1378 || x
< dpyinfo
->mouse_face_end_col
1379 || dpyinfo
->mouse_face_past_end
)))
1381 /* Clear the display of the old active region, if any. */
1382 clear_mouse_face (dpyinfo
);
1384 /* Find highest priority overlay that has a mouse-face prop. */
1386 for (i
= noverlays
- 1; i
>= 0; --i
)
1388 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1389 if (!NILP (mouse_face
))
1391 overlay
= overlay_vec
[i
];
1396 /* If no overlay applies, get a text property. */
1398 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1401 /* Handle the overlay case. */
1402 if (! NILP (overlay
))
1404 /* Find the range of text around this char that
1405 should be active. */
1406 Lisp_Object before
, after
;
1409 before
= Foverlay_start (overlay
);
1410 after
= Foverlay_end (overlay
);
1411 /* Record this as the current active region. */
1412 fast_find_position (w
, XFASTINT (before
),
1413 &dpyinfo
->mouse_face_beg_col
,
1414 &dpyinfo
->mouse_face_beg_row
);
1415 dpyinfo
->mouse_face_past_end
1416 = !fast_find_position (w
, XFASTINT (after
),
1417 &dpyinfo
->mouse_face_end_col
,
1418 &dpyinfo
->mouse_face_end_row
);
1419 dpyinfo
->mouse_face_window
= window
;
1420 dpyinfo
->mouse_face_face_id
1421 = face_at_buffer_position (w
, pos
, 0, 0,
1423 !dpyinfo
->mouse_face_hidden
,
1426 /* Display it as active. */
1427 show_mouse_face (dpyinfo
, 1);
1429 /* Handle the text property case. */
1430 else if (! NILP (mouse_face
))
1432 /* Find the range of text around this char that
1433 should be active. */
1434 Lisp_Object before
, after
, beginning
, end
;
1437 beginning
= Fmarker_position (w
->start
);
1438 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1439 - XFASTINT (w
->window_end_pos
)));
1441 = Fprevious_single_property_change (make_number (pos
+ 1),
1443 w
->buffer
, beginning
);
1445 = Fnext_single_property_change (position
, Qmouse_face
,
1447 /* Record this as the current active region. */
1448 fast_find_position (w
, XFASTINT (before
),
1449 &dpyinfo
->mouse_face_beg_col
,
1450 &dpyinfo
->mouse_face_beg_row
);
1451 dpyinfo
->mouse_face_past_end
1452 = !fast_find_position (w
, XFASTINT (after
),
1453 &dpyinfo
->mouse_face_end_col
,
1454 &dpyinfo
->mouse_face_end_row
);
1455 dpyinfo
->mouse_face_window
= window
;
1456 dpyinfo
->mouse_face_face_id
1457 = face_at_buffer_position (w
, pos
, 0, 0,
1459 !dpyinfo
->mouse_face_hidden
,
1462 /* Display it as active. */
1463 show_mouse_face (dpyinfo
, 1);
1467 /* Look for a `help-echo' property. */
1470 extern Lisp_Object Qhelp_echo
;
1472 /* Check overlays first. */
1474 for (i
= noverlays
- 1; i
>= 0 && NILP (help
); --i
)
1476 overlay
= overlay_vec
[i
];
1477 help
= Foverlay_get (overlay
, Qhelp_echo
);
1482 help_echo_string
= help
;
1483 help_echo_window
= window
;
1484 help_echo_object
= overlay
;
1485 help_echo_pos
= pos
;
1487 /* Try text properties. */
1488 else if (NILP (help
)
1489 && ((STRINGP (glyph
->object
)
1490 && glyph
->charpos
>= 0
1491 && glyph
->charpos
< SCHARS (glyph
->object
))
1492 || (BUFFERP (glyph
->object
)
1493 && glyph
->charpos
>= BEGV
1494 && glyph
->charpos
< ZV
)))
1496 help
= Fget_text_property (make_number (glyph
->charpos
),
1497 Qhelp_echo
, glyph
->object
);
1500 help_echo_string
= help
;
1501 help_echo_window
= window
;
1502 help_echo_object
= glyph
->object
;
1503 help_echo_pos
= glyph
->charpos
;
1510 current_buffer
= obuf
;
1516 IT_clear_end_of_line (struct frame
*f
, int first_unused
)
1519 int i
, j
, offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1520 extern int fatal_error_in_progress
;
1521 struct tty_display_info
*tty
= FRAME_TTY (f
);
1523 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1527 i
= (j
= first_unused
- new_pos_X
) * 2;
1528 if (tty
->termscript
)
1529 fprintf (tty
->termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1530 spaces
= sp
= alloca (i
);
1535 *sp
++ = ScreenAttrib
;
1539 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1540 if (screen_virtual_segment
)
1541 dosv_refresh_virtual_screen (offset
, i
/ 2);
1543 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1544 Let's follow their lead, in case someone relies on this. */
1545 new_pos_X
= first_unused
;
1549 IT_clear_screen (struct frame
*f
)
1551 struct tty_display_info
*tty
= FRAME_TTY (f
);
1553 if (tty
->termscript
)
1554 fprintf (tty
->termscript
, "<CLR:SCR>");
1555 /* We are sometimes called (from clear_garbaged_frames) when a new
1556 frame is being created, but its faces are not yet realized. In
1557 such a case we cannot call IT_set_face, since it will fail to find
1558 any valid faces and will abort. Instead, use the initial screen
1559 colors; that should mimic what a Unix tty does, which simply clears
1560 the screen with whatever default colors are in use. */
1561 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1562 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1567 if (screen_virtual_segment
)
1568 dosv_refresh_virtual_screen (0, screen_size
);
1569 new_pos_X
= new_pos_Y
= 0;
1573 IT_clear_to_end (struct frame
*f
)
1575 struct tty_display_info
*tty
= FRAME_TTY (f
);
1577 if (tty
->termscript
)
1578 fprintf (tty
->termscript
, "<CLR:EOS>");
1580 while (new_pos_Y
< screen_size_Y
) {
1582 IT_clear_end_of_line (f
, screen_size_X
);
1588 IT_cursor_to (struct frame
*f
, int y
, int x
)
1590 struct tty_display_info
*tty
= FRAME_TTY (f
);
1592 if (tty
->termscript
)
1593 fprintf (tty
->termscript
, "\n<XY=%dx%d>", x
, y
);
1598 static int cursor_cleared
;
1601 IT_display_cursor (int on
)
1603 struct tty_display_info
*tty
= CURTTY ();
1605 if (on
&& cursor_cleared
)
1607 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1609 if (tty
->termscript
)
1610 fprintf (tty
->termscript
, "\nCURSOR ON");
1612 else if (!on
&& !cursor_cleared
)
1614 ScreenSetCursor (-1, -1);
1616 if (tty
->termscript
)
1617 fprintf (tty
->termscript
, "\nCURSOR OFF");
1621 /* Emacs calls cursor-movement functions a lot when it updates the
1622 display (probably a legacy of old terminals where you cannot
1623 update a screen line without first moving the cursor there).
1624 However, cursor movement is expensive on MSDOS (it calls a slow
1625 BIOS function and requires 2 mode switches), while actual screen
1626 updates access the video memory directly and don't depend on
1627 cursor position. To avoid slowing down the redisplay, we cheat:
1628 all functions that move the cursor only set internal variables
1629 which record the cursor position, whereas the cursor is only
1630 moved to its final position whenever screen update is complete.
1632 `IT_cmgoto' is called from the keyboard reading loop and when the
1633 frame update is complete. This means that we are ready for user
1634 input, so we update the cursor position to show where the point is,
1635 and also make the mouse pointer visible.
1637 Special treatment is required when the cursor is in the echo area,
1638 to put the cursor at the end of the text displayed there. */
1641 IT_cmgoto (FRAME_PTR f
)
1643 /* Only set the cursor to where it should be if the display is
1644 already in sync with the window contents. */
1645 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1646 struct tty_display_info
*tty
= FRAME_TTY (f
);
1648 /* FIXME: This needs to be rewritten for the new redisplay, or
1651 static int previous_pos_X
= -1;
1653 update_cursor_pos
= 1; /* temporary!!! */
1655 /* If the display is in sync, forget any previous knowledge about
1656 cursor position. This is primarily for unexpected events like
1657 C-g in the minibuffer. */
1658 if (update_cursor_pos
&& previous_pos_X
>= 0)
1659 previous_pos_X
= -1;
1660 /* If we are in the echo area, put the cursor at the
1661 end of the echo area message. */
1662 if (!update_cursor_pos
1663 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f
))) <= new_pos_Y
)
1665 int tem_X
= current_pos_X
, dummy
;
1667 if (echo_area_glyphs
)
1669 tem_X
= echo_area_glyphs_length
;
1670 /* Save current cursor position, to be restored after the
1671 echo area message is erased. Only remember one level
1672 of previous cursor position. */
1673 if (previous_pos_X
== -1)
1674 ScreenGetCursor (&dummy
, &previous_pos_X
);
1676 else if (previous_pos_X
>= 0)
1678 /* We wind up here after the echo area message is erased.
1679 Restore the cursor position we remembered above. */
1680 tem_X
= previous_pos_X
;
1681 previous_pos_X
= -1;
1684 if (current_pos_X
!= tem_X
)
1687 update_cursor_pos
= 1;
1692 if (update_cursor_pos
1693 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1695 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1696 if (tty
->termscript
)
1697 fprintf (tty
->termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1700 /* Maybe cursor is invisible, so make it visible. */
1701 IT_display_cursor (1);
1703 /* Mouse pointer should be always visible if we are waiting for
1710 IT_update_begin (struct frame
*f
)
1712 struct tty_display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1713 struct frame
*mouse_face_frame
= display_info
->mouse_face_mouse_frame
;
1715 if (display_info
->termscript
)
1716 fprintf (display_info
->termscript
, "\n\n<UPDATE_BEGIN");
1720 if (f
&& f
== mouse_face_frame
)
1722 /* Don't do highlighting for mouse motion during the update. */
1723 display_info
->mouse_face_defer
= 1;
1725 /* If F needs to be redrawn, simply forget about any prior mouse
1727 if (FRAME_GARBAGED_P (f
))
1728 display_info
->mouse_face_window
= Qnil
;
1730 /* Can we tell that this update does not affect the window
1731 where the mouse highlight is? If so, no need to turn off.
1732 Likewise, don't do anything if none of the enabled rows
1733 contains glyphs highlighted in mouse face. */
1734 if (!NILP (display_info
->mouse_face_window
)
1735 && WINDOWP (display_info
->mouse_face_window
))
1737 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1740 /* If the mouse highlight is in the window that was deleted
1741 (e.g., if it was popped by completion), clear highlight
1743 if (NILP (w
->buffer
))
1744 display_info
->mouse_face_window
= Qnil
;
1747 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1748 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1749 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1753 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1754 clear_mouse_face (display_info
);
1757 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
1759 /* If the frame with mouse highlight was deleted, invalidate the
1761 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1762 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1763 display_info
->mouse_face_window
= Qnil
;
1764 display_info
->mouse_face_deferred_gc
= 0;
1765 display_info
->mouse_face_mouse_frame
= NULL
;
1772 IT_update_end (struct frame
*f
)
1774 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1776 if (dpyinfo
->termscript
)
1777 fprintf (dpyinfo
->termscript
, "\n<UPDATE_END\n");
1778 dpyinfo
->mouse_face_defer
= 0;
1782 IT_frame_up_to_date (struct frame
*f
)
1784 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1785 Lisp_Object new_cursor
, frame_desired_cursor
;
1788 if (dpyinfo
->mouse_face_deferred_gc
1789 || (f
&& f
== dpyinfo
->mouse_face_mouse_frame
))
1792 if (dpyinfo
->mouse_face_mouse_frame
)
1793 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
1794 dpyinfo
->mouse_face_mouse_x
,
1795 dpyinfo
->mouse_face_mouse_y
);
1796 dpyinfo
->mouse_face_deferred_gc
= 0;
1800 /* Set the cursor type to whatever they wanted. In a minibuffer
1801 window, we want the cursor to appear only if we are reading input
1802 from this window, and we want the cursor to be taken from the
1803 frame parameters. For the selected window, we use either its
1804 buffer-local value or the value from the frame parameters if the
1805 buffer doesn't define its local value for the cursor type. */
1806 sw
= XWINDOW (f
->selected_window
);
1807 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1808 if (cursor_in_echo_area
1809 && FRAME_HAS_MINIBUF_P (f
)
1810 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1811 && sw
== XWINDOW (echo_area_window
))
1812 new_cursor
= frame_desired_cursor
;
1815 struct buffer
*b
= XBUFFER (sw
->buffer
);
1817 if (EQ (b
->cursor_type
, Qt
))
1818 new_cursor
= frame_desired_cursor
;
1819 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
1820 new_cursor
= Fcons (Qbar
, make_number (0));
1822 new_cursor
= b
->cursor_type
;
1825 IT_set_cursor_type (f
, new_cursor
);
1827 IT_cmgoto (f
); /* position cursor when update is done */
1830 /* Copy LEN glyphs displayed on a single line whose vertical position
1831 is YPOS, beginning at horizontal position XFROM to horizontal
1832 position XTO, by moving blocks in the video memory. Used by
1833 functions that insert and delete glyphs. */
1835 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1837 /* The offsets of source and destination relative to the
1838 conventional memorty selector. */
1839 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1840 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1842 if (from
== to
|| len
<= 0)
1845 _farsetsel (_dos_ds
);
1847 /* The source and destination might overlap, so we need to move
1848 glyphs non-destructively. */
1851 for ( ; len
; from
+= 2, to
+= 2, len
--)
1852 _farnspokew (to
, _farnspeekw (from
));
1856 from
+= (len
- 1) * 2;
1857 to
+= (len
- 1) * 2;
1858 for ( ; len
; from
-= 2, to
-= 2, len
--)
1859 _farnspokew (to
, _farnspeekw (from
));
1861 if (screen_virtual_segment
)
1862 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1865 /* Insert and delete glyphs. */
1867 IT_insert_glyphs (f
, start
, len
)
1869 register struct glyph
*start
;
1872 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1874 /* Shift right the glyphs from the nominal cursor position to the
1875 end of this line. */
1876 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
1878 /* Now write the glyphs to be inserted. */
1879 IT_write_glyphs (f
, start
, len
);
1883 IT_delete_glyphs (f
, n
)
1890 /* set-window-configuration on window.c needs this. */
1892 x_set_menu_bar_lines (f
, value
, oldval
)
1894 Lisp_Object value
, oldval
;
1896 set_menu_bar_lines (f
, value
, oldval
);
1899 /* This was copied from xfaces.c */
1901 extern Lisp_Object Qbackground_color
;
1902 extern Lisp_Object Qforeground_color
;
1903 Lisp_Object Qreverse
;
1904 extern Lisp_Object Qtitle
;
1906 /* IT_set_terminal_modes is called when emacs is started,
1907 resumed, and whenever the screen is redrawn! */
1910 IT_set_terminal_modes (struct terminal
*term
)
1912 struct tty_display_info
*tty
;
1914 /* If called with initial terminal, it's too early to do anything
1916 if (term
->type
== output_initial
)
1919 tty
= term
->display_info
.tty
;
1921 if (tty
->termscript
)
1922 fprintf (tty
->termscript
, "\n<SET_TERM>");
1924 screen_size_X
= ScreenCols ();
1925 screen_size_Y
= ScreenRows ();
1926 screen_size
= screen_size_X
* screen_size_Y
;
1928 new_pos_X
= new_pos_Y
= 0;
1929 current_pos_X
= current_pos_Y
= -1;
1931 if (term_setup_done
)
1933 term_setup_done
= 1;
1935 startup_screen_size_X
= screen_size_X
;
1936 startup_screen_size_Y
= screen_size_Y
;
1937 startup_screen_attrib
= ScreenAttrib
;
1939 /* Is DOS/V (or any other RSIS software which relocates
1940 the screen) installed? */
1942 unsigned short es_value
;
1945 regs
.h
.ah
= 0xfe; /* get relocated screen address */
1946 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
1947 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
1948 else if (screen_old_address
) /* already switched to Japanese mode once */
1949 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
1951 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
1953 es_value
= regs
.x
.es
;
1954 __dpmi_int (0x10, ®s
);
1956 if (regs
.x
.es
!= es_value
)
1958 /* screen_old_address is only set if ScreenPrimary does NOT
1959 already point to the relocated buffer address returned by
1960 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1961 ScreenPrimary to that address at startup under DOS/V. */
1962 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
1963 screen_old_address
= ScreenPrimary
;
1964 screen_virtual_segment
= regs
.x
.es
;
1965 screen_virtual_offset
= regs
.x
.di
;
1966 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
1970 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
1971 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
1976 /* IT_reset_terminal_modes is called when emacs is
1977 suspended or killed. */
1980 IT_reset_terminal_modes (struct terminal
*term
)
1982 int display_row_start
= (int) ScreenPrimary
;
1983 int saved_row_len
= startup_screen_size_X
* 2;
1984 int update_row_len
= ScreenCols () * 2, current_rows
= ScreenRows ();
1985 int to_next_row
= update_row_len
;
1986 unsigned char *saved_row
= startup_screen_buffer
;
1987 int cursor_pos_X
= ScreenCols () - 1, cursor_pos_Y
= ScreenRows () - 1;
1988 struct tty_display_info
*tty
= term
->display_info
.tty
;
1990 if (tty
->termscript
)
1991 fprintf (tty
->termscript
, "\n<RESET_TERM>");
1993 if (!term_setup_done
)
1998 /* Leave the video system in the same state as we found it,
1999 as far as the blink/bright-background bit is concerned. */
2000 maybe_enable_blinking ();
2002 /* We have a situation here.
2003 We cannot just do ScreenUpdate(startup_screen_buffer) because
2004 the luser could have changed screen dimensions inside Emacs
2005 and failed (or didn't want) to restore them before killing
2006 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2007 thus will happily use memory outside what was allocated for
2008 `startup_screen_buffer'.
2009 Thus we only restore as much as the current screen dimensions
2010 can hold, and clear the rest (if the saved screen is smaller than
2011 the current) with the color attribute saved at startup. The cursor
2012 is also restored within the visible dimensions. */
2014 ScreenAttrib
= startup_screen_attrib
;
2016 /* Don't restore the screen if we are exiting less than 2 seconds
2017 after startup: we might be crashing, and the screen might show
2018 some vital clues to what's wrong. */
2019 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2022 if (screen_virtual_segment
)
2023 dosv_refresh_virtual_screen (0, screen_size
);
2025 if (update_row_len
> saved_row_len
)
2026 update_row_len
= saved_row_len
;
2027 if (current_rows
> startup_screen_size_Y
)
2028 current_rows
= startup_screen_size_Y
;
2030 if (tty
->termscript
)
2031 fprintf (tty
->termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2032 update_row_len
/ 2, current_rows
);
2034 while (current_rows
--)
2036 dosmemput (saved_row
, update_row_len
, display_row_start
);
2037 if (screen_virtual_segment
)
2038 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2039 update_row_len
/ 2);
2040 saved_row
+= saved_row_len
;
2041 display_row_start
+= to_next_row
;
2044 if (startup_pos_X
< cursor_pos_X
)
2045 cursor_pos_X
= startup_pos_X
;
2046 if (startup_pos_Y
< cursor_pos_Y
)
2047 cursor_pos_Y
= startup_pos_Y
;
2049 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2050 xfree (startup_screen_buffer
);
2051 startup_screen_buffer
= NULL
;
2053 term_setup_done
= 0;
2057 IT_set_terminal_window (struct frame
*f
, int foo
)
2061 /* Remember the screen colors of the curent frame, to serve as the
2062 default colors for newly-created frames. */
2063 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2064 Smsdos_remember_default_colors
, 1, 1, 0,
2065 doc
: /* Remember the screen colors of the current frame. */)
2071 CHECK_FRAME (frame
);
2074 /* This function is called after applying default-frame-alist to the
2075 initial frame. At that time, if reverse-colors option was
2076 specified in default-frame-alist, it was already applied, and
2077 frame colors are reversed. */
2078 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
2079 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
2083 IT_set_frame_parameters (f
, alist
)
2088 int i
, j
, length
= XINT (Flength (alist
));
2090 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2092 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2093 /* Do we have to reverse the foreground and background colors? */
2094 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2095 int need_to_reverse
, was_reverse
= reverse
;
2096 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2097 unsigned long orig_fg
, orig_bg
;
2098 Lisp_Object frame_bg
, frame_fg
;
2099 extern Lisp_Object Qdefault
, QCforeground
, QCbackground
;
2100 struct tty_display_info
*tty
= FRAME_TTY (f
);
2102 /* If we are creating a new frame, begin with the original screen colors
2103 used for the initial frame. */
2104 if (EQ (alist
, Vdefault_frame_alist
)
2105 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2107 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2108 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2109 init_frame_faces (f
);
2111 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2112 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2113 frame_fg
= Fcdr (Fassq (Qforeground_color
, f
->param_alist
));
2114 frame_bg
= Fcdr (Fassq (Qbackground_color
, f
->param_alist
));
2115 /* frame_fg and frame_bg could be nil if, for example,
2116 f->param_alist is nil, e.g. if we are called from
2117 Fmake_terminal_frame. */
2118 if (NILP (frame_fg
))
2119 frame_fg
= build_string (unspecified_fg
);
2120 if (NILP (frame_bg
))
2121 frame_bg
= build_string (unspecified_bg
);
2123 /* Extract parm names and values into those vectors. */
2125 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2130 parms
[i
] = Fcar (elt
);
2131 CHECK_SYMBOL (parms
[i
]);
2132 values
[i
] = Fcdr (elt
);
2138 for (i
= 0; i
< j
; i
++)
2140 Lisp_Object prop
, val
;
2145 if (EQ (prop
, Qreverse
))
2146 reverse
= EQ (val
, Qt
);
2149 need_to_reverse
= reverse
&& !was_reverse
;
2150 if (tty
->termscript
&& need_to_reverse
)
2151 fprintf (tty
->termscript
, "<INVERSE-VIDEO>\n");
2153 /* Now process the alist elements in reverse of specified order. */
2154 for (i
--; i
>= 0; i
--)
2156 Lisp_Object prop
, val
, frame
;
2161 if (EQ (prop
, Qforeground_color
))
2163 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2164 ? LFACE_BACKGROUND_INDEX
2165 : LFACE_FOREGROUND_INDEX
);
2166 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2167 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2168 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2170 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2171 /* Make sure the foreground of the default face for this
2172 frame is changed as well. */
2173 XSETFRAME (frame
, f
);
2174 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2178 if (tty
->termscript
)
2179 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
2182 else if (EQ (prop
, Qbackground_color
))
2184 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2185 ? LFACE_FOREGROUND_INDEX
2186 : LFACE_BACKGROUND_INDEX
);
2187 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2188 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2189 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2191 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2192 /* Make sure the background of the default face for this
2193 frame is changed as well. */
2194 XSETFRAME (frame
, f
);
2195 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2199 if (tty
->termscript
)
2200 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
2203 else if (EQ (prop
, Qtitle
))
2205 x_set_title (f
, val
);
2206 if (tty
->termscript
)
2207 fprintf (tty
->termscript
, "<TITLE: %s>\n", SDATA (val
));
2209 else if (EQ (prop
, Qcursor_type
))
2211 IT_set_cursor_type (f
, val
);
2212 if (tty
->termscript
)
2213 fprintf (tty
->termscript
, "<CTYPE: %s>\n",
2214 EQ (val
, Qbar
) || EQ (val
, Qhbar
)
2215 || CONSP (val
) && (EQ (XCAR (val
), Qbar
)
2216 || EQ (XCAR (val
), Qhbar
))
2219 else if (EQ (prop
, Qtty_type
))
2221 internal_terminal_init ();
2222 if (tty
->termscript
)
2223 fprintf (tty
->termscript
, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2224 SBYTES (val
), SDATA (val
));
2226 store_frame_param (f
, prop
, val
);
2229 /* If they specified "reverse", but not the colors, we need to swap
2230 the current frame colors. */
2231 if (need_to_reverse
)
2237 XSETFRAME (frame
, f
);
2238 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2239 tty_color_name (f
, orig_bg
),
2245 XSETFRAME (frame
, f
);
2246 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2247 tty_color_name (f
, orig_fg
),
2255 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2256 if (f
== SELECTED_FRAME())
2261 extern void init_frame_faces (FRAME_PTR
);
2263 #endif /* !HAVE_X_WINDOWS */
2266 /* Do we need the internal terminal? */
2269 internal_terminal_init ()
2271 static int init_needed
= 1;
2272 char *term
= getenv ("TERM"), *colors
;
2273 struct frame
*sf
= SELECTED_FRAME();
2274 struct tty_display_info
*tty
;
2276 #ifdef HAVE_X_WINDOWS
2277 if (!inhibit_window_system
)
2281 /* If this is the initial terminal, we are done here. */
2282 if (sf
->output_method
== output_initial
)
2286 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2288 #ifndef HAVE_X_WINDOWS
2289 if (!internal_terminal
|| inhibit_window_system
)
2291 sf
->output_method
= output_termcap
;
2295 tty
= FRAME_TTY (sf
);
2296 current_kboard
->Vwindow_system
= Qpc
;
2297 sf
->output_method
= output_msdos_raw
;
2300 if (!tty
->termscript
&& getenv ("EMACSTEST"))
2301 tty
->termscript
= fopen (getenv ("EMACSTEST"), "wt");
2302 if (tty
->termscript
)
2304 time_t now
= time (NULL
);
2305 struct tm
*tnow
= localtime (&now
);
2308 strftime (tbuf
, sizeof (tbuf
) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow
);
2309 fprintf (tty
->termscript
, "\nEmacs session started at %s\n", tbuf
);
2310 fprintf (tty
->termscript
, "=====================\n\n");
2313 Vinitial_window_system
= Qpc
;
2314 Vwindow_system_version
= make_number (23); /* RE Emacs version */
2315 tty
->terminal
->type
= output_msdos_raw
;
2317 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2319 screen_old_address
= 0;
2321 /* Forget the stale screen colors as well. */
2322 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2324 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2325 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2327 colors
= getenv ("EMACSCOLORS");
2328 if (colors
&& strlen (colors
) >= 2)
2330 /* The colors use 4 bits each (we enable bright background). */
2331 if (isdigit (colors
[0]))
2333 else if (isxdigit (colors
[0]))
2334 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2335 if (colors
[0] >= 0 && colors
[0] < 16)
2336 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors
[0];
2337 if (isdigit (colors
[1]))
2339 else if (isxdigit (colors
[1]))
2340 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2341 if (colors
[1] >= 0 && colors
[1] < 16)
2342 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors
[1];
2344 the_only_display_info
.mouse_face_mouse_frame
= NULL
;
2345 the_only_display_info
.mouse_face_deferred_gc
= 0;
2346 the_only_display_info
.mouse_face_beg_row
=
2347 the_only_display_info
.mouse_face_beg_col
= -1;
2348 the_only_display_info
.mouse_face_end_row
=
2349 the_only_display_info
.mouse_face_end_col
= -1;
2350 the_only_display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2351 the_only_display_info
.mouse_face_window
= Qnil
;
2352 the_only_display_info
.mouse_face_mouse_x
=
2353 the_only_display_info
.mouse_face_mouse_y
= 0;
2354 the_only_display_info
.mouse_face_defer
= 0;
2355 the_only_display_info
.mouse_face_hidden
= 0;
2357 if (have_mouse
) /* detected in dos_ttraw, which see */
2359 have_mouse
= 1; /* enable mouse */
2361 mouse_setup_buttons (mouse_button_count
);
2362 tty
->terminal
->mouse_position_hook
= &mouse_get_pos
;
2366 if (tty
->termscript
&& screen_size
)
2367 fprintf (tty
->termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2368 screen_size_X
, screen_size_Y
);
2370 init_frame_faces (sf
);
2377 initialize_msdos_display (struct terminal
*term
)
2379 term
->rif
= 0; /* we don't support window-based display */
2380 term
->cursor_to_hook
= term
->raw_cursor_to_hook
= IT_cursor_to
;
2381 term
->clear_to_end_hook
= IT_clear_to_end
;
2382 term
->clear_frame_hook
= IT_clear_screen
;
2383 term
->clear_end_of_line_hook
= IT_clear_end_of_line
;
2384 term
->ins_del_lines_hook
= 0;
2385 term
->insert_glyphs_hook
= IT_insert_glyphs
;
2386 term
->write_glyphs_hook
= IT_write_glyphs
;
2387 term
->delete_glyphs_hook
= IT_delete_glyphs
;
2388 term
->ring_bell_hook
= IT_ring_bell
;
2389 term
->reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2390 term
->set_terminal_modes_hook
= IT_set_terminal_modes
;
2391 term
->set_terminal_window_hook
= IT_set_terminal_window
;
2392 term
->update_begin_hook
= IT_update_begin
;
2393 term
->update_end_hook
= IT_update_end
;
2394 term
->frame_up_to_date_hook
= IT_frame_up_to_date
;
2395 term
->mouse_position_hook
= 0; /* set later by dos_ttraw */
2396 term
->frame_rehighlight_hook
= 0;
2397 term
->frame_raise_lower_hook
= 0;
2398 term
->set_vertical_scroll_bar_hook
= 0;
2399 term
->condemn_scroll_bars_hook
= 0;
2400 term
->redeem_scroll_bar_hook
= 0;
2401 term
->judge_scroll_bars_hook
= 0;
2402 term
->read_socket_hook
= &tty_read_avail_input
; /* from keyboard.c */
2405 dos_get_saved_screen (screen
, rows
, cols
)
2410 #ifndef HAVE_X_WINDOWS
2411 *screen
= startup_screen_buffer
;
2412 *cols
= startup_screen_size_X
;
2413 *rows
= startup_screen_size_Y
;
2414 return *screen
!= (char *)0;
2420 #ifndef HAVE_X_WINDOWS
2422 /* We are not X, but we can emulate it well enough for our needs... */
2426 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2427 error ("Not running under a window system");
2433 /* ----------------------- Keyboard control ----------------------
2435 * Keymaps reflect the following keyboard layout:
2437 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2438 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2439 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2440 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2444 #define Ignore 0x0000
2445 #define Normal 0x0000 /* normal key - alt changes scan-code */
2446 #define FctKey 0x1000 /* func key if c == 0, else c */
2447 #define Special 0x2000 /* func key even if c != 0 */
2448 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2449 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2450 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2451 #define Grey 0x6000 /* Grey keypad key */
2453 #define Alt 0x0100 /* alt scan-code */
2454 #define Ctrl 0x0200 /* ctrl scan-code */
2455 #define Shift 0x0400 /* shift scan-code */
2457 static int extended_kbd
; /* 101 (102) keyboard present. */
2459 struct kbd_translate
{
2462 unsigned short code
;
2465 struct dos_keyboard_map
2470 struct kbd_translate
*translate_table
;
2474 static struct dos_keyboard_map us_keyboard
= {
2476 /* 01234567890123456789012345678901234567890 12345678901234 */
2477 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2478 /* 0123456789012345678901234567890123456789 012345678901234 */
2479 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2480 0, /* no Alt-Gr key */
2481 0 /* no translate table */
2484 static struct dos_keyboard_map fr_keyboard
= {
2486 /* 012 3456789012345678901234567890123456789012345678901234 */
2487 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2488 /* 0123456789012345678901234567890123456789012345678901234 */
2489 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2490 /* 01234567 89012345678901234567890123456789012345678901234 */
2492 0 /* no translate table */
2496 * Italian keyboard support, country code 39.
2499 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2500 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2503 static struct kbd_translate it_kbd_translate_table
[] = {
2504 { 0x56, 0x3c, Normal
| 13 },
2505 { 0x56, 0x3e, Normal
| 27 },
2508 static struct dos_keyboard_map it_keyboard
= {
2510 /* 0 123456789012345678901234567890123456789012345678901234 */
2511 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2512 /* 01 23456789012345678901234567890123456789012345678901234 */
2513 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2514 /* 0123456789012345678901234567890123456789012345678901234 */
2516 it_kbd_translate_table
2519 static struct dos_keyboard_map dk_keyboard
= {
2521 /* 0123456789012345678901234567890123456789012345678901234 */
2522 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2523 /* 01 23456789012345678901234567890123456789012345678901234 */
2524 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2525 /* 0123456789012345678901234567890123456789012345678901234 */
2527 0 /* no translate table */
2530 static struct kbd_translate jp_kbd_translate_table
[] = {
2531 { 0x73, 0x5c, Normal
| 0 },
2532 { 0x73, 0x5f, Normal
| 0 },
2533 { 0x73, 0x1c, Map
| 0 },
2534 { 0x7d, 0x5c, Normal
| 13 },
2535 { 0x7d, 0x7c, Normal
| 13 },
2536 { 0x7d, 0x1c, Map
| 13 },
2539 static struct dos_keyboard_map jp_keyboard
= {
2541 /* 0123456789012 345678901234567890123456789012345678901234 */
2542 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2543 /* 01 23456789012345678901234567890123456789012345678901234 */
2544 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2545 0, /* no Alt-Gr key */
2546 jp_kbd_translate_table
2549 static struct keyboard_layout_list
2552 struct dos_keyboard_map
*keyboard_map
;
2553 } keyboard_layout_list
[] =
2562 static struct dos_keyboard_map
*keyboard
;
2563 static int keyboard_map_all
;
2564 static int international_keyboard
;
2567 dos_set_keyboard (code
, always
)
2572 _go32_dpmi_registers regs
;
2574 /* See if Keyb.Com is installed (for international keyboard support).
2575 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2576 of Windows 9X! So don't do that! */
2578 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2579 _go32_dpmi_simulate_int (0x2f, ®s
);
2580 if (regs
.h
.al
== 0xff)
2581 international_keyboard
= 1;
2583 /* Initialize to US settings, for countries that don't have their own. */
2584 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2585 keyboard_map_all
= always
;
2586 dos_keyboard_layout
= 1;
2588 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2589 if (code
== keyboard_layout_list
[i
].country_code
)
2591 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2592 keyboard_map_all
= always
;
2593 dos_keyboard_layout
= code
;
2601 unsigned char char_code
; /* normal code */
2602 unsigned char meta_code
; /* M- code */
2603 unsigned char keypad_code
; /* keypad code */
2604 unsigned char editkey_code
; /* edit key */
2605 } keypad_translate_map
[] = {
2606 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2607 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2608 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2609 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2610 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2611 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2612 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2613 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2614 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2615 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2616 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2621 unsigned char char_code
; /* normal code */
2622 unsigned char keypad_code
; /* keypad code */
2623 } grey_key_translate_map
[] = {
2624 '/', 0xaf, /* kp-decimal */
2625 '*', 0xaa, /* kp-multiply */
2626 '-', 0xad, /* kp-subtract */
2627 '+', 0xab, /* kp-add */
2628 '\r', 0x8d /* kp-enter */
2631 static unsigned short
2632 ibmpc_translate_map
[] =
2634 /* --------------- 00 to 0f --------------- */
2635 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2636 Alt
| ModFct
| 0x1b, /* Escape */
2637 Normal
| 1, /* '1' */
2638 Normal
| 2, /* '2' */
2639 Normal
| 3, /* '3' */
2640 Normal
| 4, /* '4' */
2641 Normal
| 5, /* '5' */
2642 Normal
| 6, /* '6' */
2643 Normal
| 7, /* '7' */
2644 Normal
| 8, /* '8' */
2645 Normal
| 9, /* '9' */
2646 Normal
| 10, /* '0' */
2647 Normal
| 11, /* '-' */
2648 Normal
| 12, /* '=' */
2649 Special
| 0x08, /* Backspace */
2650 ModFct
| 0x74, /* Tab/Backtab */
2652 /* --------------- 10 to 1f --------------- */
2665 ModFct
| 0x0d, /* Return */
2670 /* --------------- 20 to 2f --------------- */
2679 Map
| 40, /* '\'' */
2681 Ignore
, /* Left shift */
2682 Map
| 41, /* '\\' */
2688 /* --------------- 30 to 3f --------------- */
2695 Ignore
, /* Right shift */
2696 Grey
| 1, /* Grey * */
2698 Normal
| 55, /* ' ' */
2699 Ignore
, /* Caps Lock */
2700 FctKey
| 0xbe, /* F1 */
2701 FctKey
| 0xbf, /* F2 */
2702 FctKey
| 0xc0, /* F3 */
2703 FctKey
| 0xc1, /* F4 */
2704 FctKey
| 0xc2, /* F5 */
2706 /* --------------- 40 to 4f --------------- */
2707 FctKey
| 0xc3, /* F6 */
2708 FctKey
| 0xc4, /* F7 */
2709 FctKey
| 0xc5, /* F8 */
2710 FctKey
| 0xc6, /* F9 */
2711 FctKey
| 0xc7, /* F10 */
2712 Ignore
, /* Num Lock */
2713 Ignore
, /* Scroll Lock */
2714 KeyPad
| 7, /* Home */
2715 KeyPad
| 8, /* Up */
2716 KeyPad
| 9, /* Page Up */
2717 Grey
| 2, /* Grey - */
2718 KeyPad
| 4, /* Left */
2719 KeyPad
| 5, /* Keypad 5 */
2720 KeyPad
| 6, /* Right */
2721 Grey
| 3, /* Grey + */
2722 KeyPad
| 1, /* End */
2724 /* --------------- 50 to 5f --------------- */
2725 KeyPad
| 2, /* Down */
2726 KeyPad
| 3, /* Page Down */
2727 KeyPad
| 0, /* Insert */
2728 KeyPad
| 10, /* Delete */
2729 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2730 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2731 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2732 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2733 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2734 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2735 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2736 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2737 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2738 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2739 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2740 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2742 /* --------------- 60 to 6f --------------- */
2743 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2744 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2745 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2746 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2747 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2748 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2749 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2750 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2751 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2752 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2753 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2754 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2755 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2756 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2757 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2758 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2760 /* --------------- 70 to 7f --------------- */
2761 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2762 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2763 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2764 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2765 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2766 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2767 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2768 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2769 Alt
| Map
| 1, /* '1' */
2770 Alt
| Map
| 2, /* '2' */
2771 Alt
| Map
| 3, /* '3' */
2772 Alt
| Map
| 4, /* '4' */
2773 Alt
| Map
| 5, /* '5' */
2774 Alt
| Map
| 6, /* '6' */
2775 Alt
| Map
| 7, /* '7' */
2776 Alt
| Map
| 8, /* '8' */
2778 /* --------------- 80 to 8f --------------- */
2779 Alt
| Map
| 9, /* '9' */
2780 Alt
| Map
| 10, /* '0' */
2781 Alt
| Map
| 11, /* '-' */
2782 Alt
| Map
| 12, /* '=' */
2783 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2784 FctKey
| 0xc8, /* F11 */
2785 FctKey
| 0xc9, /* F12 */
2786 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2787 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2788 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2789 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2790 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2791 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2792 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2793 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2794 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2796 /* --------------- 90 to 9f --------------- */
2797 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2798 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2799 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2800 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2801 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2802 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2803 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2804 Alt
| FctKey
| 0x50, /* (Alt) Home */
2805 Alt
| FctKey
| 0x52, /* (Alt) Up */
2806 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2807 Ignore
, /* NO KEY */
2808 Alt
| FctKey
| 0x51, /* (Alt) Left */
2809 Ignore
, /* NO KEY */
2810 Alt
| FctKey
| 0x53, /* (Alt) Right */
2811 Ignore
, /* NO KEY */
2812 Alt
| FctKey
| 0x57, /* (Alt) End */
2814 /* --------------- a0 to af --------------- */
2815 Alt
| KeyPad
| 2, /* (Alt) Down */
2816 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2817 Alt
| KeyPad
| 0, /* (Alt) Insert */
2818 Alt
| KeyPad
| 10, /* (Alt) Delete */
2819 Alt
| Grey
| 0, /* (Alt) Grey / */
2820 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2821 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2824 /* These bit-positions corresponds to values returned by BIOS */
2825 #define SHIFT_P 0x0003 /* two bits! */
2826 #define CTRL_P 0x0004
2827 #define ALT_P 0x0008
2828 #define SCRLOCK_P 0x0010
2829 #define NUMLOCK_P 0x0020
2830 #define CAPSLOCK_P 0x0040
2831 #define ALT_GR_P 0x0800
2832 #define SUPER_P 0x4000 /* pseudo */
2833 #define HYPER_P 0x8000 /* pseudo */
2836 dos_get_modifiers (keymask
)
2840 int mask
, modifiers
= 0;
2842 /* Calculate modifier bits */
2843 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2844 int86 (0x16, ®s
, ®s
);
2848 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2849 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2853 mask
= regs
.h
.al
& (SHIFT_P
|
2854 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2856 /* Do not break international keyboard support. */
2857 /* When Keyb.Com is loaded, the right Alt key is */
2858 /* used for accessing characters like { and } */
2859 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2862 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2865 if (dos_hyper_key
== 1)
2868 modifiers
|= hyper_modifier
;
2870 else if (dos_super_key
== 1)
2873 modifiers
|= super_modifier
;
2875 else if (!international_keyboard
)
2877 /* If Keyb.Com is NOT installed, let Right Alt behave
2878 like the Left Alt. */
2884 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2887 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2889 if (dos_hyper_key
== 2)
2892 modifiers
|= hyper_modifier
;
2894 else if (dos_super_key
== 2)
2897 modifiers
|= super_modifier
;
2905 modifiers
|= shift_modifier
;
2907 modifiers
|= ctrl_modifier
;
2909 modifiers
|= meta_modifier
;
2916 #define NUM_RECENT_DOSKEYS (100)
2917 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2918 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
2919 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
2921 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
2922 doc
: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2923 Each input key receives two values in this vector: first the ASCII code,
2924 and then the scan code. */)
2927 Lisp_Object val
, *keys
= XVECTOR (recent_doskeys
)->contents
;
2929 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
2930 return Fvector (total_doskeys
, keys
);
2933 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
2934 bcopy (keys
+ recent_doskeys_index
,
2935 XVECTOR (val
)->contents
,
2936 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
2938 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
2939 recent_doskeys_index
* sizeof (Lisp_Object
));
2944 /* Get a char from keyboard. Function keys are put into the event queue. */
2948 struct input_event event
;
2950 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
2953 #ifndef HAVE_X_WINDOWS
2954 /* Maybe put the cursor where it should be. */
2955 IT_cmgoto (SELECTED_FRAME());
2958 /* The following condition is equivalent to `kbhit ()', except that
2959 it uses the bios to do its job. This pleases DESQview/X. */
2960 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
2961 int86 (0x16, ®s
, ®s
),
2962 (regs
.x
.flags
& 0x40) == 0)
2965 register unsigned char c
;
2966 int modifiers
, sc
, code
= -1, mask
, kp_mode
;
2968 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
2969 int86 (0x16, ®s
, ®s
);
2974 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2976 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2977 recent_doskeys_index
= 0;
2978 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2980 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2981 recent_doskeys_index
= 0;
2983 modifiers
= dos_get_modifiers (&mask
);
2985 #ifndef HAVE_X_WINDOWS
2986 if (!NILP (Vdos_display_scancodes
))
2989 sprintf (buf
, "%02x:%02x*%04x",
2990 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
2991 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
2999 case 10: /* Ctrl Grey Enter */
3000 code
= Ctrl
| Grey
| 4;
3002 case 13: /* Grey Enter */
3005 case '/': /* Grey / */
3015 /* Try the keyboard-private translation table first. */
3016 if (keyboard
->translate_table
)
3018 struct kbd_translate
*p
= keyboard
->translate_table
;
3022 if (p
->sc
== sc
&& p
->ch
== c
)
3030 /* If the private table didn't translate it, use the general
3034 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3036 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3043 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3044 Emacs is ready to read a key. Therefore, if they press
3045 `Alt-x' when Emacs is busy, by the time we get to
3046 `dos_get_modifiers', they might have already released the
3047 Alt key, and Emacs gets just `x', which is BAD.
3048 However, for keys with the `Map' property set, the ASCII
3049 code returns zero only if Alt is pressed. So, when we DON'T
3050 have to support international_keyboard, we don't have to
3051 distinguish between the left and right Alt keys, and we
3052 can set the META modifier for any keys with the `Map'
3053 property if they return zero ASCII code (c = 0). */
3055 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3056 modifiers
|= meta_modifier
;
3058 modifiers
|= ctrl_modifier
;
3060 modifiers
|= shift_modifier
;
3063 switch (code
& 0xf000)
3066 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3068 c
= 0; /* Special */
3081 if (c
== 0) /* ctrl-break */
3083 return c
; /* ALT-nnn */
3085 if (!keyboard_map_all
)
3094 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3095 if (!keyboard_map_all
)
3099 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3100 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3104 code
= keyboard
->shifted
[code
];
3106 modifiers
&= ~shift_modifier
;
3109 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3110 code
= keyboard
->alt_gr
[code
];
3112 code
= keyboard
->unshifted
[code
];
3117 if (c
== 0xe0) /* edit key */
3120 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3121 kp_mode
= dos_keypad_mode
& 0x03;
3123 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3128 if (code
== 10 && dos_decimal_point
)
3129 return dos_decimal_point
;
3130 return keypad_translate_map
[code
].char_code
;
3133 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3137 code
= keypad_translate_map
[code
].meta_code
;
3138 modifiers
= meta_modifier
;
3142 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3149 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3150 if (dos_keypad_mode
& kp_mode
)
3151 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3153 code
= grey_key_translate_map
[code
].char_code
;
3161 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
))
3163 clear_mouse_face (dpyinfo
);
3164 dpyinfo
->mouse_face_hidden
= 1;
3168 event
.kind
= NON_ASCII_KEYSTROKE_EVENT
;
3170 event
.kind
= ASCII_KEYSTROKE_EVENT
;
3172 event
.modifiers
= modifiers
;
3173 event
.frame_or_window
= selected_frame
;
3175 event
.timestamp
= event_timestamp ();
3176 kbd_buffer_store_event (&event
);
3179 if (have_mouse
> 0 && !mouse_preempted
)
3181 int but
, press
, x
, y
, ok
;
3182 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3183 Lisp_Object mouse_window
= Qnil
;
3185 /* Check for mouse movement *before* buttons. */
3186 mouse_check_moved ();
3188 /* If the mouse moved from the spot of its last sighting, we
3189 might need to update mouse highlight. */
3190 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3192 if (dpyinfo
->mouse_face_hidden
)
3194 dpyinfo
->mouse_face_hidden
= 0;
3195 clear_mouse_face (dpyinfo
);
3198 /* Generate SELECT_WINDOW_EVENTs when needed. */
3199 if (!NILP (Vmouse_autoselect_window
))
3201 mouse_window
= window_from_coordinates (SELECTED_FRAME(),
3205 /* A window will be selected only when it is not
3206 selected now, and the last mouse movement event was
3207 not in it. A minibuffer window will be selected iff
3209 if (WINDOWP (mouse_window
)
3210 && !EQ (mouse_window
, last_mouse_window
)
3211 && !EQ (mouse_window
, selected_window
))
3213 event
.kind
= SELECT_WINDOW_EVENT
;
3214 event
.frame_or_window
= mouse_window
;
3216 event
.timestamp
= event_timestamp ();
3217 kbd_buffer_store_event (&event
);
3219 last_mouse_window
= mouse_window
;
3222 last_mouse_window
= Qnil
;
3224 previous_help_echo_string
= help_echo_string
;
3225 help_echo_string
= help_echo_object
= help_echo_window
= Qnil
;
3227 IT_note_mouse_highlight (SELECTED_FRAME(),
3228 mouse_last_x
, mouse_last_y
);
3229 /* If the contents of the global variable help_echo has
3230 changed, generate a HELP_EVENT. */
3231 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
3233 event
.kind
= HELP_EVENT
;
3234 event
.frame_or_window
= selected_frame
;
3235 event
.arg
= help_echo_object
;
3236 event
.x
= WINDOWP (help_echo_window
)
3237 ? help_echo_window
: selected_frame
;
3238 event
.y
= help_echo_string
;
3239 event
.timestamp
= event_timestamp ();
3240 event
.code
= help_echo_pos
;
3241 kbd_buffer_store_event (&event
);
3245 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3246 for (press
= 0; press
< 2; press
++)
3248 int button_num
= but
;
3251 ok
= mouse_pressed (but
, &x
, &y
);
3253 ok
= mouse_released (but
, &x
, &y
);
3256 /* Allow a simultaneous press/release of Mouse-1 and
3257 Mouse-2 to simulate Mouse-3 on two-button mice. */
3258 if (mouse_button_count
== 2 && but
< 2)
3260 int x2
, y2
; /* don't clobber original coordinates */
3262 /* If only one button is pressed, wait 100 msec and
3263 check again. This way, Speedy Gonzales isn't
3264 punished, while the slow get their chance. */
3265 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3266 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3271 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3272 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3277 event
.kind
= MOUSE_CLICK_EVENT
;
3278 event
.code
= button_num
;
3279 event
.modifiers
= dos_get_modifiers (0)
3280 | (press
? down_modifier
: up_modifier
);
3281 event
.x
= make_number (x
);
3282 event
.y
= make_number (y
);
3283 event
.frame_or_window
= selected_frame
;
3285 event
.timestamp
= event_timestamp ();
3286 kbd_buffer_store_event (&event
);
3294 static int prev_get_char
= -1;
3296 /* Return 1 if a key is ready to be read without suspending execution. */
3300 if (prev_get_char
!= -1)
3303 return ((prev_get_char
= dos_rawgetc ()) != -1);
3306 /* Read a key. Return -1 if no key is ready. */
3310 if (prev_get_char
!= -1)
3312 int c
= prev_get_char
;
3317 return dos_rawgetc ();
3320 #ifndef HAVE_X_WINDOWS
3322 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3325 Actually, I don't know the meaning of all the parameters of the functions
3326 here -- I only know how they are called by xmenu.c. I could of course
3327 grab the nearest Xlib manual (down the hall, second-to-last door on the
3328 left), but I don't think it's worth the effort. */
3330 /* These hold text of the current and the previous menu help messages. */
3331 static char *menu_help_message
, *prev_menu_help_message
;
3332 /* Pane number and item number of the menu item which generated the
3333 last menu help message. */
3334 static int menu_help_paneno
, menu_help_itemno
;
3341 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3342 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3346 /* Allocate some (more) memory for MENU ensuring that there is room for one
3350 IT_menu_make_room (XMenu
*menu
)
3352 if (menu
->allocated
== 0)
3354 int count
= menu
->allocated
= 10;
3355 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3356 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3357 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3358 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3360 else if (menu
->allocated
== menu
->count
)
3362 int count
= menu
->allocated
= menu
->allocated
+ 10;
3364 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3366 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3368 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3370 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3374 /* Search the given menu structure for a given pane number. */
3377 IT_menu_search_pane (XMenu
*menu
, int pane
)
3382 for (i
= 0; i
< menu
->count
; i
++)
3383 if (menu
->submenu
[i
])
3385 if (pane
== menu
->panenumber
[i
])
3386 return menu
->submenu
[i
];
3387 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3393 /* Determine how much screen space a given menu needs. */
3396 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3398 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3401 maxheight
= menu
->count
;
3402 for (i
= 0; i
< menu
->count
; i
++)
3404 if (menu
->submenu
[i
])
3406 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3407 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3408 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3411 *width
= menu
->width
+ maxsubwidth
;
3412 *height
= maxheight
;
3415 /* Display MENU at (X,Y) using FACES. */
3417 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3420 (GLYPH).type = CHAR_GLYPH; \
3421 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3422 (GLYPH).charpos = -1; \
3427 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3429 int i
, j
, face
, width
, mx
, my
, enabled
, mousehere
, row
, col
;
3430 struct glyph
*text
, *p
;
3431 const unsigned char *q
;
3432 struct frame
*sf
= SELECTED_FRAME();
3434 menu_help_message
= NULL
;
3436 width
= menu
->width
;
3437 /* We multiply width by 2 to account for possible control characters.
3438 FIXME: cater to non-ASCII characters in menus. */
3439 text
= (struct glyph
*) xmalloc ((width
* 2 + 2) * sizeof (struct glyph
));
3440 ScreenGetCursor (&row
, &col
);
3441 mouse_get_xy (&mx
, &my
);
3442 IT_update_begin (sf
);
3443 for (i
= 0; i
< menu
->count
; i
++)
3445 int max_width
= width
+ 2;
3447 IT_cursor_to (sf
, y
+ i
, x
);
3449 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3450 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ max_width
);
3451 face
= faces
[enabled
+ mousehere
* 2];
3452 /* The following if clause means that we display the menu help
3453 strings even if the menu item is currently disabled. */
3454 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3456 menu_help_message
= menu
->help_text
[i
];
3457 menu_help_paneno
= pn
- 1;
3458 menu_help_itemno
= i
;
3461 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
3463 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3465 unsigned c
= STRING_CHAR_ADVANCE (q
);
3469 BUILD_CHAR_GLYPH (*p
, c
, face
, 0);
3472 else /* make '^x' */
3474 BUILD_CHAR_GLYPH (*p
, '^', face
, 0);
3477 BUILD_CHAR_GLYPH (*p
, c
+ 64, face
, 0);
3481 /* Don't let the menu text overflow into the next screen row. */
3482 if (x
+ max_width
> screen_size_X
)
3484 max_width
= screen_size_X
- x
;
3485 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3487 for (; j
< max_width
- 2; j
++, p
++)
3488 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
3490 /* 16 is the character code of a character that on DOS terminal
3491 produces a nice-looking right-pointing arrow glyph. */
3492 BUILD_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3494 IT_write_glyphs (sf
, text
, max_width
);
3497 IT_cursor_to (sf
, row
, col
);
3501 /* --------------------------- X Menu emulation ---------------------- */
3503 /* Report availability of menus. */
3506 have_menus_p () { return 1; }
3508 /* Create a brand new menu structure. */
3511 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3513 return IT_menu_create ();
3516 /* Create a new pane and place it on the outer-most level. It is not
3517 clear that it should be placed out there, but I don't know what else
3521 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3529 IT_menu_make_room (menu
);
3530 menu
->submenu
[menu
->count
] = IT_menu_create ();
3531 menu
->text
[menu
->count
] = txt
;
3532 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3533 menu
->help_text
[menu
->count
] = NULL
;
3536 /* Adjust length for possible control characters (which will
3537 be written as ^x). */
3538 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3542 if (len
> menu
->width
)
3545 return menu
->panecount
;
3548 /* Create a new item in a menu pane. */
3551 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3552 int foo
, char *txt
, int enable
, char *help_text
)
3558 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3560 IT_menu_make_room (menu
);
3561 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3562 menu
->text
[menu
->count
] = txt
;
3563 menu
->panenumber
[menu
->count
] = enable
;
3564 menu
->help_text
[menu
->count
] = help_text
;
3567 /* Adjust length for possible control characters (which will
3568 be written as ^x). */
3569 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3573 if (len
> menu
->width
)
3579 /* Decide where the menu would be placed if requested at (X,Y). */
3582 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3583 int *ulx
, int *uly
, int *width
, int *height
)
3585 IT_menu_calc_size (menu
, width
, height
);
3591 struct IT_menu_state
3593 void *screen_behind
;
3600 /* Display menu, wait for user's response, and return that response. */
3603 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3604 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3605 void (*help_callback
)(char *, int, int))
3607 struct IT_menu_state
*state
;
3608 int statecount
, x
, y
, i
, b
, screensize
, leave
, result
, onepane
;
3609 int title_faces
[4]; /* face to display the menu title */
3610 int faces
[4], buffers_num_deleted
= 0;
3611 struct frame
*sf
= SELECTED_FRAME();
3612 Lisp_Object saved_echo_area_message
, selectface
;
3614 /* Just in case we got here without a mouse present... */
3615 if (have_mouse
<= 0)
3616 return XM_IA_SELECT
;
3617 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3618 around the display. */
3624 /* We will process all the mouse events directly, so we had
3625 better prevent dos_rawgetc from stealing them from us. */
3628 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3629 screensize
= screen_size
* 2;
3631 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3632 DEFAULT_FACE_ID
, 1);
3634 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3635 DEFAULT_FACE_ID
, 1);
3636 selectface
= intern ("msdos-menu-select-face");
3637 faces
[2] = lookup_derived_face (sf
, selectface
,
3639 faces
[3] = lookup_derived_face (sf
, selectface
,
3642 /* Make sure the menu title is always displayed with
3643 `msdos-menu-active-face', no matter where the mouse pointer is. */
3644 for (i
= 0; i
< 4; i
++)
3645 title_faces
[i
] = faces
[3];
3649 /* Don't let the title for the "Buffers" popup menu include a
3650 digit (which is ugly).
3652 This is a terrible kludge, but I think the "Buffers" case is
3653 the only one where the title includes a number, so it doesn't
3654 seem to be necessary to make this more general. */
3655 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3657 menu
->text
[0][7] = '\0';
3658 buffers_num_deleted
= 1;
3661 /* We need to save the current echo area message, so that we could
3662 restore it below, before we exit. See the commentary below,
3663 before the call to message_with_string. */
3664 saved_echo_area_message
= Fcurrent_message ();
3665 state
[0].menu
= menu
;
3667 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3669 /* Turn off the cursor. Otherwise it shows through the menu
3670 panes, which is ugly. */
3671 IT_display_cursor (0);
3673 /* Display the menu title. */
3674 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3675 if (buffers_num_deleted
)
3676 menu
->text
[0][7] = ' ';
3677 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3679 menu
->width
= menu
->submenu
[0]->width
;
3680 state
[0].menu
= menu
->submenu
[0];
3684 state
[0].menu
= menu
;
3686 state
[0].x
= x0
- 1;
3688 state
[0].pane
= onepane
;
3690 mouse_last_x
= -1; /* A hack that forces display. */
3694 if (!mouse_visible
) mouse_on ();
3695 mouse_check_moved ();
3696 if (sf
->mouse_moved
)
3698 sf
->mouse_moved
= 0;
3699 result
= XM_IA_SELECT
;
3700 mouse_get_xy (&x
, &y
);
3701 for (i
= 0; i
< statecount
; i
++)
3702 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3704 int dy
= y
- state
[i
].y
;
3705 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3707 if (!state
[i
].menu
->submenu
[dy
])
3708 if (state
[i
].menu
->panenumber
[dy
])
3709 result
= XM_SUCCESS
;
3711 result
= XM_IA_SELECT
;
3712 *pane
= state
[i
].pane
- 1;
3714 /* We hit some part of a menu, so drop extra menus that
3715 have been opened. That does not include an open and
3717 if (i
!= statecount
- 2
3718 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3719 while (i
!= statecount
- 1)
3723 ScreenUpdate (state
[statecount
].screen_behind
);
3724 if (screen_virtual_segment
)
3725 dosv_refresh_virtual_screen (0, screen_size
);
3726 xfree (state
[statecount
].screen_behind
);
3728 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3730 IT_menu_display (state
[i
].menu
,
3735 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3736 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3738 ScreenRetrieve (state
[statecount
].screen_behind
3739 = xmalloc (screensize
));
3741 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3742 state
[statecount
].y
= y
;
3747 IT_menu_display (state
[statecount
- 1].menu
,
3748 state
[statecount
- 1].y
,
3749 state
[statecount
- 1].x
,
3750 state
[statecount
- 1].pane
,
3755 if ((menu_help_message
|| prev_menu_help_message
)
3756 && menu_help_message
!= prev_menu_help_message
)
3758 help_callback (menu_help_message
,
3759 menu_help_paneno
, menu_help_itemno
);
3760 IT_display_cursor (0);
3761 prev_menu_help_message
= menu_help_message
;
3763 /* We are busy-waiting for the mouse to move, so let's be nice
3764 to other Windows applications by releasing our time slice. */
3767 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3769 /* Only leave if user both pressed and released the mouse, and in
3770 that order. This avoids popping down the menu pane unless
3771 the user is really done with it. */
3772 if (mouse_pressed (b
, &x
, &y
))
3774 while (mouse_button_depressed (b
, &x
, &y
))
3778 (void) mouse_released (b
, &x
, &y
);
3783 ScreenUpdate (state
[0].screen_behind
);
3784 if (screen_virtual_segment
)
3785 dosv_refresh_virtual_screen (0, screen_size
);
3787 /* We have a situation here. ScreenUpdate has just restored the
3788 screen contents as it was before we started drawing this menu.
3789 That includes any echo area message that could have been
3790 displayed back then. (In reality, that echo area message will
3791 almost always be the ``keystroke echo'' that echoes the sequence
3792 of menu items chosen by the user.) However, if the menu had some
3793 help messages, then displaying those messages caused Emacs to
3794 forget about the original echo area message. So when
3795 ScreenUpdate restored it, it created a discrepancy between the
3796 actual screen contents and what Emacs internal data structures
3799 To avoid this conflict, we force Emacs to restore the original
3800 echo area message as we found it when we entered this function.
3801 The irony of this is that we then erase the restored message
3802 right away, so the only purpose of restoring it is so that
3803 erasing it works correctly... */
3804 if (! NILP (saved_echo_area_message
))
3805 message_with_string ("%s", saved_echo_area_message
, 0);
3807 while (statecount
--)
3808 xfree (state
[statecount
].screen_behind
);
3809 IT_display_cursor (1); /* turn cursor back on */
3810 /* Clean up any mouse events that are waiting inside Emacs event queue.
3811 These events are likely to be generated before the menu was even
3812 displayed, probably because the user pressed and released the button
3813 (which invoked the menu) too quickly. If we don't remove these events,
3814 Emacs will process them after we return and surprise the user. */
3815 discard_mouse_events ();
3816 mouse_clear_clicks ();
3817 if (!kbd_buffer_events_waiting (1))
3818 clear_input_pending ();
3819 /* Allow mouse events generation by dos_rawgetc. */
3824 /* Dispose of a menu. */
3827 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3830 if (menu
->allocated
)
3832 for (i
= 0; i
< menu
->count
; i
++)
3833 if (menu
->submenu
[i
])
3834 XMenuDestroy (foo
, menu
->submenu
[i
]);
3836 xfree (menu
->submenu
);
3837 xfree (menu
->panenumber
);
3838 xfree (menu
->help_text
);
3841 menu_help_message
= prev_menu_help_message
= NULL
;
3845 x_pixel_width (struct frame
*f
)
3847 return FRAME_COLS (f
);
3851 x_pixel_height (struct frame
*f
)
3853 return FRAME_LINES (f
);
3855 #endif /* !HAVE_X_WINDOWS */
3857 /* ----------------------- DOS / UNIX conversion --------------------- */
3859 void msdos_downcase_filename (unsigned char *);
3861 /* Destructively turn backslashes into slashes. */
3864 dostounix_filename (p
)
3867 msdos_downcase_filename (p
);
3877 /* Destructively turn slashes into backslashes. */
3880 unixtodos_filename (p
)
3883 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3897 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3900 getdefdir (drive
, dst
)
3904 char in_path
[4], *p
= in_path
, e
= errno
;
3906 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3909 *p
++ = drive
+ 'A' - 1;
3916 _fixpath (in_path
, dst
);
3917 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3918 it queries the LFN support, so ignore that error. */
3919 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
3922 msdos_downcase_filename (dst
);
3929 emacs_root_dir (void)
3931 static char root_dir
[4];
3933 sprintf (root_dir
, "%c:/", 'A' + getdisk ());
3934 root_dir
[0] = tolower (root_dir
[0]);
3938 /* Remove all CR's that are followed by a LF. */
3943 register unsigned char *buf
;
3945 unsigned char *np
= buf
, *startp
= buf
, *endp
= buf
+ n
;
3949 while (buf
< endp
- 1)
3953 if (*(++buf
) != 0x0a)
3964 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
3966 doc
: /* Return non-nil if long file names are supported on MS-DOS. */)
3969 return (_USE_LFN
? Qt
: Qnil
);
3972 /* Convert alphabetic characters in a filename to lower-case. */
3975 msdos_downcase_filename (p
)
3976 register unsigned char *p
;
3978 /* Always lower-case drive letters a-z, even if the filesystem
3979 preserves case in filenames.
3980 This is so MSDOS filenames could be compared by string comparison
3981 functions that are case-sensitive. Even case-preserving filesystems
3982 do not distinguish case in drive letters. */
3983 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3989 /* Under LFN we expect to get pathnames in their true case. */
3990 if (NILP (Fmsdos_long_file_names ()))
3992 if (*p
>= 'A' && *p
<= 'Z')
3996 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
3998 doc
: /* Convert alphabetic characters in FILENAME to lower case and return that.
3999 When long filenames are supported, doesn't change FILENAME.
4000 If FILENAME is not a string, returns nil.
4001 The argument object is never altered--the value is a copy. */)
4003 Lisp_Object filename
;
4007 if (! STRINGP (filename
))
4010 tem
= Fcopy_sequence (filename
);
4011 msdos_downcase_filename (SDATA (tem
));
4015 /* The Emacs root directory as determined by init_environment. */
4017 static char emacsroot
[MAXPATHLEN
];
4020 rootrelativepath (rel
)
4023 static char result
[MAXPATHLEN
+ 10];
4025 strcpy (result
, emacsroot
);
4026 strcat (result
, "/");
4027 strcat (result
, rel
);
4031 /* Define a lot of environment variables if not already defined. Don't
4032 remove anything unless you know what you're doing -- lots of code will
4033 break if one or more of these are missing. */
4036 init_environment (argc
, argv
, skip_args
)
4043 static const char * const tempdirs
[] = {
4044 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4046 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4048 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4049 temporary files and assume "/tmp" if $TMPDIR is unset, which
4050 will break on DOS/Windows. Refuse to work if we cannot find
4051 a directory, not even "c:/", usable for that purpose. */
4052 for (i
= 0; i
< imax
; i
++)
4054 const char *tmp
= tempdirs
[i
];
4055 char buf
[FILENAME_MAX
];
4061 tmp
= getenv (tmp
+ 1);
4065 /* Some lusers set TMPDIR=e:, probably because some losing
4066 programs cannot handle multiple slashes if they use e:/.
4067 e: fails in `access' below, so we interpret e: as e:/. */
4068 tmp_len
= strlen(tmp
);
4069 if (tmp
[tmp_len
- 1] != '/' && tmp
[tmp_len
- 1] != '\\')
4072 buf
[tmp_len
++] = '/', buf
[tmp_len
] = 0;
4077 /* Note that `access' can lie to us if the directory resides on a
4078 read-only filesystem, like CD-ROM or a write-protected floppy.
4079 The only way to be really sure is to actually create a file and
4080 see if it succeeds. But I think that's too much to ask. */
4081 if (tmp
&& access (tmp
, D_OK
) == 0)
4083 setenv ("TMPDIR", tmp
, 1);
4090 Fcons (build_string ("no usable temporary directories found!!"),
4092 "While setting TMPDIR: ");
4094 /* Note the startup time, so we know not to clear the screen if we
4095 exit immediately; see IT_reset_terminal_modes.
4096 (Yes, I know `clock' returns zero the first time it's called, but
4097 I do this anyway, in case some wiseguy changes that at some point.) */
4098 startup_time
= clock ();
4100 /* Find our root from argv[0]. Assuming argv[0] is, say,
4101 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4102 root
= alloca (MAXPATHLEN
+ 20);
4103 _fixpath (argv
[0], root
);
4104 msdos_downcase_filename (root
);
4105 len
= strlen (root
);
4106 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4110 && (strcmp (root
+ len
- 4, "/bin") == 0
4111 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4112 root
[len
- 4] = '\0';
4114 strcpy (root
, "c:/emacs"); /* let's be defensive */
4115 len
= strlen (root
);
4116 strcpy (emacsroot
, root
);
4118 /* We default HOME to our root. */
4119 setenv ("HOME", root
, 0);
4121 /* We default EMACSPATH to root + "/bin". */
4122 strcpy (root
+ len
, "/bin");
4123 setenv ("EMACSPATH", root
, 0);
4125 /* I don't expect anybody to ever use other terminals so the internal
4126 terminal is the default. */
4127 setenv ("TERM", "internal", 0);
4129 #ifdef HAVE_X_WINDOWS
4130 /* Emacs expects DISPLAY to be set. */
4131 setenv ("DISPLAY", "unix:0.0", 0);
4134 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4135 downcase it and mirror the backslashes. */
4136 s
= getenv ("COMSPEC");
4137 if (!s
) s
= "c:/command.com";
4138 t
= alloca (strlen (s
) + 1);
4140 dostounix_filename (t
);
4141 setenv ("SHELL", t
, 0);
4143 /* PATH is also downcased and backslashes mirrored. */
4144 s
= getenv ("PATH");
4146 t
= alloca (strlen (s
) + 3);
4147 /* Current directory is always considered part of MsDos's path but it is
4148 not normally mentioned. Now it is. */
4149 strcat (strcpy (t
, ".;"), s
);
4150 dostounix_filename (t
); /* Not a single file name, but this should work. */
4151 setenv ("PATH", t
, 1);
4153 /* In some sense all dos users have root privileges, so... */
4154 setenv ("USER", "root", 0);
4155 setenv ("NAME", getenv ("USER"), 0);
4157 /* Time zone determined from country code. To make this possible, the
4158 country code may not span more than one time zone. In other words,
4159 in the USA, you lose. */
4161 switch (dos_country_code
)
4163 case 31: /* Belgium */
4164 case 32: /* The Netherlands */
4165 case 33: /* France */
4166 case 34: /* Spain */
4167 case 36: /* Hungary */
4168 case 38: /* Yugoslavia (or what's left of it?) */
4169 case 39: /* Italy */
4170 case 41: /* Switzerland */
4171 case 42: /* Tjekia */
4172 case 45: /* Denmark */
4173 case 46: /* Sweden */
4174 case 47: /* Norway */
4175 case 48: /* Poland */
4176 case 49: /* Germany */
4177 /* Daylight saving from last Sunday in March to last Sunday in
4178 September, both at 2AM. */
4179 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4181 case 44: /* United Kingdom */
4182 case 351: /* Portugal */
4183 case 354: /* Iceland */
4184 setenv ("TZ", "GMT+00", 0);
4186 case 81: /* Japan */
4187 case 82: /* Korea */
4188 setenv ("TZ", "JST-09", 0);
4190 case 90: /* Turkey */
4191 case 358: /* Finland */
4192 setenv ("TZ", "EET-02", 0);
4194 case 972: /* Israel */
4195 /* This is an approximation. (For exact rules, use the
4196 `zoneinfo/israel' file which comes with DJGPP, but you need
4197 to install it in `/usr/share/zoneinfo/' directory first.) */
4198 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4206 static int break_stat
; /* BREAK check mode status. */
4207 static int stdin_stat
; /* stdin IOCTL status. */
4209 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4210 control chars by DOS. Determine the keyboard type. */
4213 dos_ttraw (struct tty_display_info
*tty
)
4215 union REGS inregs
, outregs
;
4216 static int first_time
= 1;
4218 /* If we are called for the initial terminal, it's too early to do
4219 anything, and termscript isn't set up. */
4220 if (tty
->terminal
->type
== output_initial
)
4223 break_stat
= getcbrk ();
4229 int86 (0x15, &inregs
, &outregs
);
4230 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4235 #ifdef HAVE_X_WINDOWS
4236 && inhibit_window_system
4240 inregs
.x
.ax
= 0x0021;
4241 int86 (0x33, &inregs
, &outregs
);
4242 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4245 /* Reportedly, the above doesn't work for some mouse drivers. There
4246 is an additional detection method that should work, but might be
4247 a little slower. Use that as an alternative. */
4248 inregs
.x
.ax
= 0x0000;
4249 int86 (0x33, &inregs
, &outregs
);
4250 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4253 mouse_button_count
= outregs
.x
.bx
;
4255 #ifndef HAVE_X_WINDOWS
4256 /* Save the cursor shape used outside Emacs. */
4257 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4263 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4264 return (stdin_stat
!= -1);
4267 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4270 /* Restore status of standard input and Ctrl-C checking. */
4275 union REGS inregs
, outregs
;
4277 setcbrk (break_stat
);
4280 #ifndef HAVE_X_WINDOWS
4281 /* Restore the cursor shape we found on startup. */
4285 inregs
.x
.cx
= outside_cursor
;
4286 int86 (0x10, &inregs
, &outregs
);
4290 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4294 /* Run command as specified by ARGV in directory DIR.
4295 The command is run with input from TEMPIN, output to
4296 file TEMPOUT and stderr to TEMPERR. */
4299 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4300 unsigned char **argv
;
4301 const char *working_dir
;
4302 int tempin
, tempout
, temperr
;
4305 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4306 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4307 int msshell
, result
= -1, inbak
, outbak
, errbak
, x
, y
;
4310 /* Get current directory as MSDOS cwd is not per-process. */
4313 /* If argv[0] is the shell, it might come in any lettercase.
4314 Since `Fmember' is case-sensitive, we need to downcase
4315 argv[0], even if we are on case-preserving filesystems. */
4316 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4317 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4320 if (*pl
>= 'A' && *pl
<= 'Z')
4325 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4326 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4327 && !strcmp ("-c", argv
[1]);
4330 saveargv1
= argv
[1];
4331 saveargv2
= argv
[2];
4333 /* We only need to mirror slashes if a DOS shell will be invoked
4334 not via `system' (which does the mirroring itself). Yes, that
4335 means DJGPP v1.x will lose here. */
4336 if (argv
[2] && argv
[3])
4338 char *p
= alloca (strlen (argv
[2]) + 1);
4340 strcpy (argv
[2] = p
, saveargv2
);
4341 while (*p
&& isspace (*p
))
4353 chdir (working_dir
);
4357 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4358 goto done
; /* Allocation might fail due to lack of descriptors. */
4361 mouse_get_xy (&x
, &y
);
4363 if (!noninteractive
)
4364 dos_ttcooked (); /* do it here while 0 = stdin */
4370 if (msshell
&& !argv
[3])
4372 /* MS-DOS native shells are too restrictive. For starters, they
4373 cannot grok commands longer than 126 characters. In DJGPP v2
4374 and later, `system' is much smarter, so we'll call it instead. */
4378 /* A shell gets a single argument--its full command
4379 line--whose original was saved in `saveargv2'. */
4381 /* Don't let them pass empty command lines to `system', since
4382 with some shells it will try to invoke an interactive shell,
4383 which will hang Emacs. */
4384 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4388 extern char **environ
;
4389 char **save_env
= environ
;
4390 int save_system_flags
= __system_flags
;
4392 /* Request the most powerful version of `system'. We need
4393 all the help we can get to avoid calling stock DOS shells. */
4394 __system_flags
= (__system_redirect
4395 | __system_use_shell
4396 | __system_allow_multiple_cmds
4397 | __system_allow_long_cmds
4398 | __system_handle_null_commands
4399 | __system_emulate_chdir
);
4402 result
= system (cmnd
);
4403 __system_flags
= save_system_flags
;
4407 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4410 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4415 emacs_close (inbak
);
4416 emacs_close (outbak
);
4417 emacs_close (errbak
);
4419 if (!noninteractive
)
4420 dos_ttraw (CURTTY ());
4424 mouse_moveto (x
, y
);
4427 /* Some programs might change the meaning of the highest bit of the
4428 text attribute byte, so we get blinking characters instead of the
4429 bright background colors. Restore that. */
4430 if (!noninteractive
)
4437 argv
[1] = saveargv1
;
4438 argv
[2] = saveargv2
;
4447 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4448 reset_all_sys_modes ();
4453 * A few unimplemented functions that we silently ignore.
4455 setpgrp () {return 0; }
4456 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4458 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4460 /* Augment DJGPP library POSIX signal functions. This is needed
4461 as of DJGPP v2.01, but might be in the library in later releases. */
4463 #include <libc/bss.h>
4465 /* A counter to know when to re-initialize the static sets. */
4466 static int sigprocmask_count
= -1;
4468 /* Which signals are currently blocked (initially none). */
4469 static sigset_t current_mask
;
4471 /* Which signals are pending (initially none). */
4472 static sigset_t msdos_pending_signals
;
4474 /* Previous handlers to restore when the blocked signals are unblocked. */
4475 typedef void (*sighandler_t
)(int);
4476 static sighandler_t prev_handlers
[320];
4478 /* A signal handler which just records that a signal occurred
4479 (it will be raised later, if and when the signal is unblocked). */
4481 sig_suspender (signo
)
4484 sigaddset (&msdos_pending_signals
, signo
);
4488 sigprocmask (how
, new_set
, old_set
)
4490 const sigset_t
*new_set
;
4496 /* If called for the first time, initialize. */
4497 if (sigprocmask_count
!= __bss_count
)
4499 sigprocmask_count
= __bss_count
;
4500 sigemptyset (&msdos_pending_signals
);
4501 sigemptyset (¤t_mask
);
4502 for (signo
= 0; signo
< 320; signo
++)
4503 prev_handlers
[signo
] = SIG_ERR
;
4507 *old_set
= current_mask
;
4512 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4518 sigemptyset (&new_mask
);
4520 /* DJGPP supports upto 320 signals. */
4521 for (signo
= 0; signo
< 320; signo
++)
4523 if (sigismember (¤t_mask
, signo
))
4524 sigaddset (&new_mask
, signo
);
4525 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4527 sigaddset (&new_mask
, signo
);
4529 /* SIGKILL is silently ignored, as on other platforms. */
4530 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4531 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4533 if (( how
== SIG_UNBLOCK
4534 && sigismember (&new_mask
, signo
)
4535 && sigismember (new_set
, signo
))
4536 || (how
== SIG_SETMASK
4537 && sigismember (&new_mask
, signo
)
4538 && !sigismember (new_set
, signo
)))
4540 sigdelset (&new_mask
, signo
);
4541 if (prev_handlers
[signo
] != SIG_ERR
)
4543 signal (signo
, prev_handlers
[signo
]);
4544 prev_handlers
[signo
] = SIG_ERR
;
4546 if (sigismember (&msdos_pending_signals
, signo
))
4548 sigdelset (&msdos_pending_signals
, signo
);
4553 current_mask
= new_mask
;
4557 #endif /* not __DJGPP_MINOR__ < 2 */
4560 #include "sysselect.h"
4562 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4563 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4564 ((long)(time).tv_sec < 0 \
4565 || ((time).tv_sec == 0 \
4566 && (long)(time).tv_usec <= 0))
4569 /* This yields the rest of the current time slice to the task manager.
4570 It should be called by any code which knows that it has nothing
4571 useful to do except idle.
4573 I don't use __dpmi_yield here, since versions of library before 2.02
4574 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4575 on some versions of Windows 9X. */
4578 dos_yield_time_slice (void)
4580 _go32_dpmi_registers r
;
4583 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
4584 _go32_dpmi_simulate_int (0x2f, &r
);
4589 /* Only event queue is checked. */
4590 /* We don't have to call timer_check here
4591 because wait_reading_process_output takes care of that. */
4593 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
4595 SELECT_TYPE
*rfds
, *wfds
, *efds
;
4596 EMACS_TIME
*timeout
;
4604 check_input
= FD_ISSET (0, rfds
);
4615 /* If we are looking only for the terminal, with no timeout,
4616 just read it and wait -- that's more efficient. */
4619 while (!detect_input_pending ())
4621 dos_yield_time_slice ();
4626 EMACS_TIME clnow
, cllast
, cldiff
;
4629 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
4631 while (!check_input
|| !detect_input_pending ())
4634 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
4635 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
4637 /* When seconds wrap around, we assume that no more than
4638 1 minute passed since last `gettime'. */
4639 if (EMACS_TIME_NEG_P (cldiff
))
4640 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
4641 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
4643 /* Stop when timeout value crosses zero. */
4644 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
4647 dos_yield_time_slice ();
4657 * Define overlaid functions:
4659 * chdir -> sys_chdir
4660 * tzset -> init_gettimeofday
4661 * abort -> dos_abort
4666 extern int chdir ();
4672 int len
= strlen (path
);
4673 char *tmp
= (char *)path
;
4675 if (*tmp
&& tmp
[1] == ':')
4677 if (getdisk () != tolower (tmp
[0]) - 'a')
4678 setdisk (tolower (tmp
[0]) - 'a');
4679 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
4683 if (len
> 1 && (tmp
[len
- 1] == '/'))
4685 char *tmp1
= (char *) alloca (len
+ 1);
4696 extern void tzset (void);
4699 init_gettimeofday ()
4705 ltm
= gtm
= time (NULL
);
4706 ltm
= mktime (lstm
= localtime (<m
));
4707 gtm
= mktime (gmtime (>m
));
4708 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
4709 time_rec
.tm_isdst
= lstm
->tm_isdst
;
4710 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
4717 dos_abort (file
, line
)
4721 char buffer1
[200], buffer2
[400];
4724 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
4725 for (i
= j
= 0; buffer1
[i
]; i
++) {
4726 buffer2
[j
++] = buffer1
[i
];
4727 buffer2
[j
++] = 0x70;
4729 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
4730 ScreenSetCursor (2, 0);
4738 ScreenSetCursor (10, 0);
4739 cputs ("\r\n\nEmacs aborted!\r\n");
4740 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4741 if (screen_virtual_segment
)
4742 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
4743 /* Generate traceback, so we could tell whodunit. */
4744 signal (SIGINT
, SIG_DFL
);
4745 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4746 #else /* __DJGPP_MINOR__ >= 2 */
4748 #endif /* __DJGPP_MINOR__ >= 2 */
4753 /* The following variables are required so that cus-start.el won't
4754 complain about unbound variables. */
4755 #ifndef subprocesses
4756 /* Nonzero means delete a process right away if it exits (process.c). */
4757 static int delete_exited_processes
;
4762 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
4763 staticpro (&recent_doskeys
);
4765 #ifndef HAVE_X_WINDOWS
4767 /* The following two are from xfns.c: */
4768 Qreverse
= intern ("reverse");
4769 staticpro (&Qreverse
);
4771 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
4772 doc
: /* *Glyph to display instead of chars not supported by current codepage.
4773 This variable is used only by MS-DOS terminals. */);
4774 Vdos_unsupported_char_glyph
= make_number ('\177');
4777 #ifndef subprocesses
4778 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
4779 doc
: /* *Non-nil means delete processes immediately when they exit.
4780 A value of nil means don't delete them until `list-processes' is run. */);
4781 delete_exited_processes
= 0;
4784 defsubr (&Srecent_doskeys
);
4785 defsubr (&Smsdos_long_file_names
);
4786 defsubr (&Smsdos_downcase_filename
);
4787 defsubr (&Smsdos_remember_default_colors
);
4788 defsubr (&Smsdos_set_mouse_buttons
);
4793 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
4794 (do not change this comment) */