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
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 */
43 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
45 #include <io.h> /* for setmode */
46 #include <dpmi.h> /* for __dpmi_xxx stuff */
47 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
48 #include <libc/dosio.h> /* for _USE_LFN */
49 #include <conio.h> /* for cputs */
55 #include "termhooks.h"
57 #include "dispextern.h"
60 #include "character.h"
66 #include "blockinput.h"
68 #include "intervals.h"
72 /* #include <process.h> */
73 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
81 #define _dos_ds _go32_info_block.selector_for_linear_memory
87 #include "syssignal.h"
93 /* If other `malloc' than ours is used, force our `sbrk' behave like
94 Unix programs expect (resize memory blocks to keep them contiguous).
95 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
96 because that's what `gmalloc' expects to get. */
100 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
101 #else /* not REL_ALLOC */
102 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
103 #endif /* not REL_ALLOC */
104 #endif /* GNU_MALLOC */
106 #endif /* not SYSTEM_MALLOC */
107 #endif /* __DJGPP__ > 1 */
126 /* ------------------------ Mouse control ---------------------------
128 * Coordinates are in screen positions and zero based.
129 * Mouse buttons are numbered from left to right and also zero based.
132 /* This used to be in termhooks.h, but mainstream Emacs code no longer
133 uses it, and it was removed... */
134 #define NUM_MOUSE_BUTTONS (5)
136 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
137 static int mouse_visible
;
139 static int mouse_last_x
;
140 static int mouse_last_y
;
142 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
143 static int mouse_button_count
;
150 if (have_mouse
> 0 && !mouse_visible
)
152 struct tty_display_info
*tty
= CURTTY ();
155 fprintf (tty
->termscript
, "<M_ON>");
157 int86 (0x33, ®s
, ®s
);
167 if (have_mouse
> 0 && mouse_visible
)
169 struct tty_display_info
*tty
= CURTTY ();
172 fprintf (tty
->termscript
, "<M_OFF>");
174 int86 (0x33, ®s
, ®s
);
180 mouse_setup_buttons (int n_buttons
)
184 mouse_button_count
= 3;
185 mouse_button_translate
[0] = 0; /* Left */
186 mouse_button_translate
[1] = 2; /* Middle */
187 mouse_button_translate
[2] = 1; /* Right */
189 else /* two, what else? */
191 mouse_button_count
= 2;
192 mouse_button_translate
[0] = 0;
193 mouse_button_translate
[1] = 1;
197 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons
, Smsdos_set_mouse_buttons
,
198 1, 1, "NSet number of mouse buttons to: ",
199 doc
: /* Set the number of mouse buttons to use by Emacs.
200 This is useful with mice that report the number of buttons inconsistently,
201 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
202 them. This happens with wheeled mice on Windows 9X, for example. */)
204 Lisp_Object nbuttons
;
208 CHECK_NUMBER (nbuttons
);
211 xsignal2 (Qargs_out_of_range
,
212 build_string ("only 2 or 3 mouse buttons are supported"),
214 mouse_setup_buttons (n
);
219 mouse_get_xy (int *x
, int *y
)
224 int86 (0x33, ®s
, ®s
);
234 struct tty_display_info
*tty
= CURTTY ();
237 fprintf (tty
->termscript
, "<M_XY=%dx%d>", x
, y
);
239 mouse_last_x
= regs
.x
.cx
= x
* 8;
240 mouse_last_y
= regs
.x
.dx
= y
* 8;
241 int86 (0x33, ®s
, ®s
);
245 mouse_pressed (b
, xp
, yp
)
250 if (b
>= mouse_button_count
)
253 regs
.x
.bx
= mouse_button_translate
[b
];
254 int86 (0x33, ®s
, ®s
);
256 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
257 return (regs
.x
.bx
!= 0);
261 mouse_released (b
, xp
, yp
)
266 if (b
>= mouse_button_count
)
269 regs
.x
.bx
= mouse_button_translate
[b
];
270 int86 (0x33, ®s
, ®s
);
272 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
273 return (regs
.x
.bx
!= 0);
277 mouse_button_depressed (b
, xp
, yp
)
282 if (b
>= mouse_button_count
)
285 int86 (0x33, ®s
, ®s
);
286 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
296 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
299 Lisp_Object
*bar_window
, *x
, *y
;
300 enum scroll_bar_part
*part
;
304 Lisp_Object frame
, tail
;
306 /* Clear the mouse-moved flag for every frame on this display. */
307 FOR_EACH_FRAME (tail
, frame
)
308 XFRAME (frame
)->mouse_moved
= 0;
310 *f
= SELECTED_FRAME();
312 mouse_get_xy (&ix
, &iy
);
313 *time
= event_timestamp ();
314 *x
= make_number (mouse_last_x
= ix
);
315 *y
= make_number (mouse_last_y
= iy
);
323 mouse_get_xy (&x
, &y
);
324 SELECTED_FRAME()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
329 /* Force the mouse driver to ``forget'' about any button clicks until
332 mouse_clear_clicks (void)
336 for (b
= 0; b
< mouse_button_count
; b
++)
338 int dummy_x
, dummy_y
;
340 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
341 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
349 struct tty_display_info
*tty
= CURTTY ();
352 fprintf (tty
->termscript
, "<M_INIT>");
355 int86 (0x33, ®s
, ®s
);
357 /* Reset the mouse last press/release info. It seems that Windows
358 doesn't do that automatically when function 21h is called, which
359 causes Emacs to ``remember'' the click that switched focus to the
360 window just before Emacs was started from that window. */
361 mouse_clear_clicks ();
365 regs
.x
.dx
= 8 * (ScreenCols () - 1);
366 int86 (0x33, ®s
, ®s
);
370 regs
.x
.dx
= 8 * (ScreenRows () - 1);
371 int86 (0x33, ®s
, ®s
);
377 /* ------------------------- Screen control ----------------------
381 static int internal_terminal
= 0;
383 #ifndef HAVE_X_WINDOWS
384 extern unsigned char ScreenAttrib
;
385 static int screen_face
;
387 static int screen_size_X
;
388 static int screen_size_Y
;
389 static int screen_size
;
391 static int current_pos_X
;
392 static int current_pos_Y
;
393 static int new_pos_X
;
394 static int new_pos_Y
;
396 static void *startup_screen_buffer
;
397 static int startup_screen_size_X
;
398 static int startup_screen_size_Y
;
399 static int startup_pos_X
;
400 static int startup_pos_Y
;
401 static unsigned char startup_screen_attrib
;
403 static clock_t startup_time
;
405 static int term_setup_done
;
407 static unsigned short outside_cursor
;
409 /* Similar to the_only_frame. */
410 struct tty_display_info the_only_display_info
;
412 /* Support for DOS/V (allows Japanese characters to be displayed on
413 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
415 /* Holds the address of the text-mode screen buffer. */
416 static unsigned long screen_old_address
= 0;
417 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
418 static unsigned short screen_virtual_segment
= 0;
419 static unsigned short screen_virtual_offset
= 0;
420 /* A flag to control how to display unibyte 8-bit characters. */
421 extern int unibyte_display_via_language_environment
;
423 extern Lisp_Object Qcursor_type
;
424 extern Lisp_Object Qbar
, Qhbar
;
426 /* The screen colors of the current frame, which serve as the default
427 colors for newly-created frames. */
428 static int initial_screen_colors
[2];
431 /* Update the screen from a part of relocated DOS/V screen buffer which
432 begins at OFFSET and includes COUNT characters. */
434 dosv_refresh_virtual_screen (int offset
, int count
)
438 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
441 regs
.h
.ah
= 0xff; /* update relocated screen */
442 regs
.x
.es
= screen_virtual_segment
;
443 regs
.x
.di
= screen_virtual_offset
+ offset
;
445 __dpmi_int (0x10, ®s
);
450 dos_direct_output (y
, x
, buf
, len
)
455 int t0
= 2 * (x
+ y
* screen_size_X
);
456 int t
= t0
+ (int) ScreenPrimary
;
461 dosmemput (buf
++, 1, t
);
465 /* This is faster. */
466 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
467 _farnspokeb (t
, *buf
);
469 if (screen_virtual_segment
)
470 dosv_refresh_virtual_screen (t0
, l0
);
475 /* Flash the screen as a substitute for BEEPs. */
479 do_visible_bell (xorattr
)
480 unsigned char xorattr
;
485 movl _ScreenPrimary,%%eax \n\
492 xorb %%al,%%gs:(%%ebx) \n\
495 jne visible_bell_1 \n\
497 jne visible_bell_3 \n\
499 movzwl %%ax,%%eax \n\
500 movzwl %%ax,%%eax \n\
501 movzwl %%ax,%%eax \n\
502 movzwl %%ax,%%eax \n\
504 jne visible_bell_2 \n\
505 jmp visible_bell_0 \n\
508 : "m" (xorattr
), "g" (screen_size
)
509 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
513 ScreenVisualBell (void)
515 /* This creates an xor-mask that will swap the default fore- and
516 background colors. */
517 do_visible_bell (((FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ())
518 ^ FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()))
523 #ifndef HAVE_X_WINDOWS
525 static int blink_bit
= -1; /* the state of the blink bit at startup */
527 /* Enable bright background colors. */
533 /* Remember the original state of the blink/bright-background bit.
534 It is stored at 0040:0065h in the BIOS data area. */
536 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
540 int86 (0x10, ®s
, ®s
);
543 /* Disable bright background colors (and enable blinking) if we found
544 the video system in that state at startup. */
546 maybe_enable_blinking (void)
554 int86 (0x10, ®s
, ®s
);
558 /* Return non-zero if the system has a VGA adapter. */
565 int86 (0x10, ®s
, ®s
);
566 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
571 /* Set the screen dimensions so that it can show no less than
572 ROWS x COLS frame. */
575 dos_set_window_size (rows
, cols
)
580 Lisp_Object video_mode
;
581 int video_mode_value
, have_vga
= 0;
582 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
584 if (*rows
== current_rows
&& *cols
== current_cols
)
588 have_vga
= vga_installed ();
590 /* If the user specified a special video mode for these dimensions,
592 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
593 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
596 if (INTEGERP (video_mode
)
597 && (video_mode_value
= XINT (video_mode
)) > 0)
599 regs
.x
.ax
= video_mode_value
;
600 int86 (0x10, ®s
, ®s
);
604 /* Must hardware-reset the mouse, or else it won't update
605 its notion of screen dimensions for some non-standard
606 video modes. This is *painfully* slow... */
608 int86 (0x33, ®s
, ®s
);
612 /* Find one of the dimensions supported by standard EGA/VGA
613 which gives us at least the required dimensions. */
621 } std_dimension
[] = {
631 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
633 if (std_dimension
[i
].need_vga
<= have_vga
634 && std_dimension
[i
].rows
>= *rows
)
636 if (std_dimension
[i
].rows
!= current_rows
637 || *cols
!= current_cols
)
638 _set_screen_lines (std_dimension
[i
].rows
);
645 #else /* not __DJGPP__ > 1 */
647 else if (*rows
<= 25)
649 if (current_rows
!= 25 || current_cols
!= 80)
652 int86 (0x10, ®s
, ®s
);
655 int86 (0x10, ®s
, ®s
);
658 int86 (0x10, ®s
, ®s
);
660 int86 (0x10, ®s
, ®s
);
663 else if (*rows
<= 50)
664 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
665 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
668 int86 (0x10, ®s
, ®s
);
671 int86 (0x10, ®s
, ®s
);
674 int86 (0x10, ®s
, ®s
);
677 int86 (0x10, ®s
, ®s
);
679 #endif /* not __DJGPP__ > 1 */
687 /* Tell the caller what dimensions have been REALLY set. */
688 *rows
= ScreenRows ();
689 *cols
= ScreenCols ();
691 /* Update Emacs' notion of screen dimensions. */
692 screen_size_X
= *cols
;
693 screen_size_Y
= *rows
;
694 screen_size
= *cols
* *rows
;
697 /* If the dimensions changed, the mouse highlight info is invalid. */
698 if (current_rows
!= *rows
|| current_cols
!= *cols
)
700 struct frame
*f
= SELECTED_FRAME();
701 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
702 Lisp_Object window
= dpyinfo
->mouse_face_window
;
704 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
706 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
707 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
708 dpyinfo
->mouse_face_window
= Qnil
;
713 /* Enable bright background colors. */
716 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
717 be defensive anyway. */
718 if (screen_virtual_segment
)
719 dosv_refresh_virtual_screen (0, *cols
* *rows
);
722 /* If we write a character in the position where the mouse is,
723 the mouse cursor may need to be refreshed. */
733 mouse_get_xy (&x
, &y
);
734 if (y
!= new_pos_Y
|| x
< new_pos_X
)
740 #define DEFAULT_CURSOR_START (-1)
741 #define DEFAULT_CURSOR_WIDTH (-1)
742 #define BOX_CURSOR_WIDTH (-32)
744 /* Set cursor to begin at scan line START_LINE in the character cell
745 and extend for WIDTH scan lines. Scan lines are counted from top
746 of the character cell, starting from zero. */
748 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
751 unsigned desired_cursor
;
753 int max_line
, top_line
, bot_line
;
754 struct tty_display_info
*tty
= FRAME_TTY (f
);
756 /* Avoid the costly BIOS call if F isn't the currently selected
757 frame. Allow for NULL as unconditionally meaning the selected
759 if (f
&& f
!= SELECTED_FRAME())
763 fprintf (tty
->termscript
, "\nCURSOR SHAPE=(%d,%d)", start_line
, width
);
765 /* The character cell size in scan lines is stored at 40:85 in the
767 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
770 default: /* this relies on CGA cursor emulation being ON! */
787 if (width
== BOX_CURSOR_WIDTH
)
792 else if (start_line
!= DEFAULT_CURSOR_START
)
794 top_line
= start_line
;
795 bot_line
= top_line
- width
- 1;
797 else if (width
!= DEFAULT_CURSOR_WIDTH
)
800 bot_line
= -1 - width
;
803 top_line
= bot_line
+ 1;
807 /* [31, 0] seems to DTRT for all screen sizes. */
811 else /* WIDTH is positive */
813 if (start_line
!= DEFAULT_CURSOR_START
)
814 bot_line
= start_line
;
815 top_line
= bot_line
- (width
- 1);
818 /* If the current cursor shape is already what they want, we are
820 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
821 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
825 regs
.x
.cx
= desired_cursor
;
826 __dpmi_int (0x10, ®s
);
827 #endif /* __DJGPP__ > 1 */
831 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
833 if (EQ (cursor_type
, Qbar
) || EQ (cursor_type
, Qhbar
))
835 /* Just BAR means the normal EGA/VGA cursor. */
836 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
838 else if (CONSP (cursor_type
)
839 && (EQ (XCAR (cursor_type
), Qbar
)
840 || EQ (XCAR (cursor_type
), Qhbar
)))
842 Lisp_Object bar_parms
= XCDR (cursor_type
);
845 if (INTEGERP (bar_parms
))
847 /* Feature: negative WIDTH means cursor at the top
848 of the character cell, zero means invisible cursor. */
849 width
= XINT (bar_parms
);
850 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
853 else if (CONSP (bar_parms
)
854 && INTEGERP (XCAR (bar_parms
))
855 && INTEGERP (XCDR (bar_parms
)))
857 int start_line
= XINT (XCDR (bar_parms
));
859 width
= XINT (XCAR (bar_parms
));
860 msdos_set_cursor_shape (f
, start_line
, width
);
865 /* Treat anything unknown as "box cursor". This includes nil, so
866 that a frame which doesn't specify a cursor type gets a box,
867 which is the default in Emacs. */
868 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
873 IT_ring_bell (struct frame
*f
)
882 union REGS inregs
, outregs
;
885 intdos (&inregs
, &outregs
);
889 /* Given a face id FACE, extract the face parameters to be used for
890 display until the face changes. The face parameters (actually, its
891 color) are used to construct the video attribute byte for each
892 glyph during the construction of the buffer that is then blitted to
895 IT_set_face (int face
)
897 struct frame
*sf
= SELECTED_FRAME();
898 struct face
*fp
= FACE_FROM_ID (sf
, face
);
899 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
900 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
901 struct tty_display_info
*tty
= FRAME_TTY (sf
);
906 /* The default face for the frame should always be realized and
914 dflt_fg
= dfp
->foreground
;
915 dflt_bg
= dfp
->background
;
917 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
918 mean use the colors of the default face. Note that we assume all
919 16 colors to be available for the background, since Emacs switches
920 on this mode (and loses the blinking attribute) at startup. */
921 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
922 fg
= FRAME_FOREGROUND_PIXEL (sf
);
923 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
924 fg
= FRAME_BACKGROUND_PIXEL (sf
);
925 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
926 bg
= FRAME_BACKGROUND_PIXEL (sf
);
927 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
928 bg
= FRAME_FOREGROUND_PIXEL (sf
);
930 /* Make sure highlighted lines really stand out, come what may. */
931 if (fp
->tty_reverse_p
&& (fg
== dflt_fg
&& bg
== dflt_bg
))
933 unsigned long tem
= fg
;
938 /* If the user requested inverse video, obey. */
941 unsigned long tem2
= fg
;
947 fprintf (tty
->termscript
, "<FACE %d: %d/%d[FG:%d/BG:%d]>", face
,
948 fp
->foreground
, fp
->background
, fg
, bg
);
949 if (fg
>= 0 && fg
< 16)
951 ScreenAttrib
&= 0xf0;
954 if (bg
>= 0 && bg
< 16)
956 ScreenAttrib
&= 0x0f;
957 ScreenAttrib
|= ((bg
& 0x0f) << 4);
961 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
962 width of a DOS display in any known text mode. We multiply by 2 to
963 accomodate the screen attribute byte. */
964 #define MAX_SCREEN_BUF 160*2
966 Lisp_Object Vdos_unsupported_char_glyph
;
967 extern unsigned char *encode_terminal_code (struct glyph
*, int,
968 struct coding_system
*);
970 IT_write_glyphs (struct frame
*f
, struct glyph
*str
, int str_len
)
972 unsigned char screen_buf
[MAX_SCREEN_BUF
], *screen_bp
, *bp
;
973 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
974 register int sl
= str_len
;
975 struct tty_display_info
*tty
= FRAME_TTY (f
);
977 unsigned char *conversion_buffer
;
979 /* Do we need to consider conversion of unibyte characters to
981 int convert_unibyte_characters
982 = (NILP (current_buffer
->enable_multibyte_characters
)
983 && unibyte_display_via_language_environment
);
985 /* If terminal_coding does any conversion, use it, otherwise use
986 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
987 because it always returns 1 if terminal_coding.src_multibyte is 1. */
988 struct coding_system
*coding
= FRAME_TERMINAL_CODING (f
);
990 if (!(coding
->common_flags
& CODING_REQUIRE_ENCODING_MASK
))
991 coding
= &safe_terminal_coding
;
993 if (str_len
<= 0) return;
995 sf
= SELECTED_FRAME();
997 /* Since faces get cached and uncached behind our back, we can't
998 rely on their indices in the cache being consistent across
999 invocations. So always reset the screen face to the default
1000 face of the frame, before writing glyphs, and let the glyphs
1001 set the right face if it's different from the default. */
1002 IT_set_face (DEFAULT_FACE_ID
);
1004 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
1006 coding
->mode
&= ~CODING_MODE_LAST_BLOCK
;
1007 screen_bp
= &screen_buf
[0];
1013 /* If the face of this glyph is different from the current
1014 screen face, update the screen attribute byte. */
1016 if (cf
!= screen_face
)
1017 IT_set_face (cf
); /* handles invalid faces gracefully */
1019 /* Identify a run of glyphs with the same face. */
1020 for (n
= 1; n
< sl
; ++n
)
1021 if (str
[n
].face_id
!= cf
)
1025 /* This is the last glyph. */
1026 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
1028 conversion_buffer
= encode_terminal_code (str
, n
, coding
);
1029 if (coding
->produced
> 0)
1031 /* Copy the encoded bytes to the screen buffer. */
1032 for (bp
= conversion_buffer
; coding
->produced
--; bp
++)
1034 /* Paranoia: discard bytes that would overrun the end of
1035 the screen buffer. */
1036 if (screen_bp
- screen_buf
<= MAX_SCREEN_BUF
- 2)
1038 *screen_bp
++ = (unsigned char)*bp
;
1039 *screen_bp
++ = ScreenAttrib
;
1041 if (tty
->termscript
)
1042 fputc (*bp
, tty
->termscript
);
1045 /* Update STR and its remaining length. */
1050 /* Dump whatever we have in the screen buffer. */
1052 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
1053 if (screen_virtual_segment
)
1054 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1055 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1058 /************************************************************************
1059 Mouse Highlight (and friends..)
1060 ************************************************************************/
1062 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
1063 static Lisp_Object last_mouse_window
;
1065 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1067 /* Set the mouse pointer shape according to whether it is in the
1068 area where the mouse highlight is in effect. */
1070 IT_set_mouse_pointer (int mode
)
1072 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1073 many possibilities to change its shape, and the available
1074 functionality pretty much sucks (e.g., almost every reasonable
1075 shape will conceal the character it is on). Since the color of
1076 the pointer changes in the highlighted area, it is not clear to
1077 me whether anything else is required, anyway. */
1080 /* Display the active region described by mouse_face_*
1081 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1083 show_mouse_face (struct tty_display_info
*dpyinfo
, int hl
)
1085 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
1086 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
1089 struct tty_display_info
*tty
= FRAME_TTY (f
);
1092 /* If window is in the process of being destroyed, don't bother
1094 if (w
->current_matrix
== NULL
)
1095 goto set_cursor_shape
;
1097 /* Recognize when we are called to operate on rows that don't exist
1098 anymore. This can happen when a window is split. */
1099 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
1100 goto set_cursor_shape
;
1102 /* There's no sense to do anything if the mouse face isn't realized. */
1105 if (dpyinfo
->mouse_face_hidden
)
1106 goto set_cursor_shape
;
1108 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1110 goto set_cursor_shape
;
1113 /* Note that mouse_face_beg_row etc. are window relative. */
1114 for (i
= dpyinfo
->mouse_face_beg_row
;
1115 i
<= dpyinfo
->mouse_face_end_row
;
1118 int start_hpos
, end_hpos
;
1119 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1121 /* Don't do anything if row doesn't have valid contents. */
1122 if (!row
->enabled_p
)
1125 /* For all but the first row, the highlight starts at column 0. */
1126 if (i
== dpyinfo
->mouse_face_beg_row
)
1127 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1131 if (i
== dpyinfo
->mouse_face_end_row
)
1132 end_hpos
= dpyinfo
->mouse_face_end_col
;
1134 end_hpos
= row
->used
[TEXT_AREA
];
1136 if (end_hpos
<= start_hpos
)
1138 /* Record that some glyphs of this row are displayed in
1140 row
->mouse_face_p
= hl
> 0;
1143 int vpos
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1144 int kstart
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1145 int nglyphs
= end_hpos
- start_hpos
;
1146 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1147 int start_offset
= offset
;
1149 if (tty
->termscript
)
1150 fprintf (tty
->termscript
, "\n<MH+ %d-%d:%d>",
1151 kstart
, kstart
+ nglyphs
- 1, vpos
);
1154 IT_set_face (dpyinfo
->mouse_face_face_id
);
1155 /* Since we are going to change only the _colors_ of the
1156 displayed text, there's no need to go through all the
1157 pain of generating and encoding the text from the glyphs.
1158 Instead, we simply poke the attribute byte of each
1159 affected position in video memory with the colors
1160 computed by IT_set_face! */
1161 _farsetsel (_dos_ds
);
1164 _farnspokeb (offset
, ScreenAttrib
);
1167 if (screen_virtual_segment
)
1168 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1173 /* We are removing a previously-drawn mouse highlight. The
1174 safest way to do so is to redraw the glyphs anew, since
1175 all kinds of faces and display tables could have changed
1177 int nglyphs
= end_hpos
- start_hpos
;
1178 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1180 if (end_hpos
>= row
->used
[TEXT_AREA
])
1181 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1183 /* IT_write_glyphs writes at cursor position, so we need to
1184 temporarily move cursor coordinates to the beginning of
1185 the highlight region. */
1186 new_pos_X
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1187 new_pos_Y
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1189 if (tty
->termscript
)
1190 fprintf (tty
->termscript
, "<MH- %d-%d:%d>",
1191 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1192 IT_write_glyphs (f
, row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1193 if (tty
->termscript
)
1194 fputs ("\n", tty
->termscript
);
1201 /* Change the mouse pointer shape. */
1202 IT_set_mouse_pointer (hl
);
1205 /* Clear out the mouse-highlighted active region.
1206 Redraw it un-highlighted first. */
1208 clear_mouse_face (struct tty_display_info
*dpyinfo
)
1210 if (!dpyinfo
->mouse_face_hidden
&& ! NILP (dpyinfo
->mouse_face_window
))
1211 show_mouse_face (dpyinfo
, 0);
1213 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1214 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1215 dpyinfo
->mouse_face_window
= Qnil
;
1218 /* Find the glyph matrix position of buffer position POS in window W.
1219 *HPOS and *VPOS are set to the positions found. W's current glyphs
1220 must be up to date. If POS is above window start return (0, 0).
1221 If POS is after end of W, return end of last line in W. */
1223 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1225 int i
, lastcol
, line_start_position
, maybe_next_line_p
= 0;
1226 int yb
= window_text_bottom_y (w
);
1227 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0), *best_row
= row
;
1231 if (row
->used
[TEXT_AREA
])
1232 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1234 line_start_position
= 0;
1236 if (line_start_position
> pos
)
1238 /* If the position sought is the end of the buffer,
1239 don't include the blank lines at the bottom of the window. */
1240 else if (line_start_position
== pos
1241 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1243 maybe_next_line_p
= 1;
1246 else if (line_start_position
> 0)
1249 /* Don't overstep the last matrix row, lest we get into the
1250 never-never land... */
1251 if (row
->y
+ 1 >= yb
)
1257 /* Find the right column within BEST_ROW. */
1260 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1262 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1265 charpos
= glyph
->charpos
;
1272 else if (charpos
> pos
)
1274 else if (charpos
> 0)
1278 /* If we're looking for the end of the buffer,
1279 and we didn't find it in the line we scanned,
1280 use the start of the following line. */
1281 if (maybe_next_line_p
)
1288 *hpos
= lastcol
+ 1;
1292 /* Take proper action when mouse has moved to the mode or top line of
1293 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1294 mode line. X is relative to the start of the text display area of
1295 W, so the width of fringes and scroll bars must be subtracted
1296 to get a position relative to the start of the mode line. */
1298 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1300 struct frame
*f
= XFRAME (w
->frame
);
1301 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1302 struct glyph_row
*row
;
1305 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1307 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1311 extern Lisp_Object Qhelp_echo
;
1312 struct glyph
*glyph
, *end
;
1313 Lisp_Object help
, map
;
1315 /* Find the glyph under X. */
1316 glyph
= (row
->glyphs
[TEXT_AREA
]
1318 /* in case someone implements scroll bars some day... */
1319 - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w
));
1320 end
= glyph
+ row
->used
[TEXT_AREA
];
1322 && STRINGP (glyph
->object
)
1323 && STRING_INTERVALS (glyph
->object
)
1324 && glyph
->charpos
>= 0
1325 && glyph
->charpos
< SCHARS (glyph
->object
))
1327 /* If we're on a string with `help-echo' text property,
1328 arrange for the help to be displayed. This is done by
1329 setting the global variable help_echo to the help string. */
1330 help
= Fget_text_property (make_number (glyph
->charpos
),
1331 Qhelp_echo
, glyph
->object
);
1334 help_echo_string
= help
;
1335 XSETWINDOW (help_echo_window
, w
);
1336 help_echo_object
= glyph
->object
;
1337 help_echo_pos
= glyph
->charpos
;
1343 /* Take proper action when the mouse has moved to position X, Y on
1344 frame F as regards highlighting characters that have mouse-face
1345 properties. Also de-highlighting chars where the mouse was before.
1346 X and Y can be negative or out of range. */
1348 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1350 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1351 enum window_part part
= ON_NOTHING
;
1355 /* When a menu is active, don't highlight because this looks odd. */
1356 if (mouse_preempted
)
1359 if (NILP (Vmouse_highlight
)
1360 || !f
->glyphs_initialized_p
)
1363 dpyinfo
->mouse_face_mouse_x
= x
;
1364 dpyinfo
->mouse_face_mouse_y
= y
;
1365 dpyinfo
->mouse_face_mouse_frame
= f
;
1367 if (dpyinfo
->mouse_face_defer
)
1372 dpyinfo
->mouse_face_deferred_gc
= 1;
1376 /* Which window is that in? */
1377 window
= window_from_coordinates (f
, x
, y
, &part
, &x
, &y
, 0);
1379 /* If we were displaying active text in another window, clear that. */
1380 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1381 clear_mouse_face (dpyinfo
);
1383 /* Not on a window -> return. */
1384 if (!WINDOWP (window
))
1387 /* Convert to window-relative coordinates. */
1388 w
= XWINDOW (window
);
1390 if (part
== ON_MODE_LINE
|| part
== ON_HEADER_LINE
)
1392 /* Mouse is on the mode or top line. */
1393 IT_note_mode_line_highlight (w
, x
, part
== ON_MODE_LINE
);
1397 IT_set_mouse_pointer (0);
1399 /* Are we in a window whose display is up to date?
1400 And verify the buffer's text has not changed. */
1402 && EQ (w
->window_end_valid
, w
->buffer
)
1403 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1404 && (XFASTINT (w
->last_overlay_modified
)
1405 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1407 int pos
, i
, nrows
= w
->current_matrix
->nrows
;
1408 struct glyph_row
*row
;
1409 struct glyph
*glyph
;
1411 /* Find the glyph under X/Y. */
1413 if (y
>= 0 && y
< nrows
)
1415 row
= MATRIX_ROW (w
->current_matrix
, y
);
1416 /* Give up if some row before the one we are looking for is
1418 for (i
= 0; i
<= y
; i
++)
1419 if (!MATRIX_ROW (w
->current_matrix
, i
)->enabled_p
)
1421 if (i
> y
/* all rows upto and including the one at Y are enabled */
1422 && row
->displays_text_p
1423 && x
< window_box_width (w
, TEXT_AREA
))
1425 glyph
= row
->glyphs
[TEXT_AREA
];
1426 if (x
>= row
->used
[TEXT_AREA
])
1431 if (!BUFFERP (glyph
->object
))
1437 /* Clear mouse face if X/Y not over text. */
1440 clear_mouse_face (dpyinfo
);
1444 if (!BUFFERP (glyph
->object
))
1446 pos
= glyph
->charpos
;
1448 /* Check for mouse-face and help-echo. */
1450 extern Lisp_Object Qmouse_face
;
1451 Lisp_Object mouse_face
, overlay
, position
, *overlay_vec
;
1452 int noverlays
, obegv
, ozv
;
1453 struct buffer
*obuf
;
1455 /* If we get an out-of-range value, return now; avoid an error. */
1456 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1459 /* Make the window's buffer temporarily current for
1460 overlays_at and compute_char_face. */
1461 obuf
= current_buffer
;
1462 current_buffer
= XBUFFER (w
->buffer
);
1468 /* Is this char mouse-active or does it have help-echo? */
1469 XSETINT (position
, pos
);
1471 /* Put all the overlays we want in a vector in overlay_vec. */
1472 GET_OVERLAYS_AT (pos
, overlay_vec
, noverlays
, NULL
, 0);
1473 /* Sort overlays into increasing priority order. */
1474 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1476 /* Check mouse-face highlighting. */
1477 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1478 && y
>= dpyinfo
->mouse_face_beg_row
1479 && y
<= dpyinfo
->mouse_face_end_row
1480 && (y
> dpyinfo
->mouse_face_beg_row
1481 || x
>= dpyinfo
->mouse_face_beg_col
)
1482 && (y
< dpyinfo
->mouse_face_end_row
1483 || x
< dpyinfo
->mouse_face_end_col
1484 || dpyinfo
->mouse_face_past_end
)))
1486 /* Clear the display of the old active region, if any. */
1487 clear_mouse_face (dpyinfo
);
1489 /* Find highest priority overlay that has a mouse-face prop. */
1491 for (i
= noverlays
- 1; i
>= 0; --i
)
1493 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1494 if (!NILP (mouse_face
))
1496 overlay
= overlay_vec
[i
];
1501 /* If no overlay applies, get a text property. */
1503 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1506 /* Handle the overlay case. */
1507 if (! NILP (overlay
))
1509 /* Find the range of text around this char that
1510 should be active. */
1511 Lisp_Object before
, after
;
1514 before
= Foverlay_start (overlay
);
1515 after
= Foverlay_end (overlay
);
1516 /* Record this as the current active region. */
1517 fast_find_position (w
, XFASTINT (before
),
1518 &dpyinfo
->mouse_face_beg_col
,
1519 &dpyinfo
->mouse_face_beg_row
);
1520 dpyinfo
->mouse_face_past_end
1521 = !fast_find_position (w
, XFASTINT (after
),
1522 &dpyinfo
->mouse_face_end_col
,
1523 &dpyinfo
->mouse_face_end_row
);
1524 dpyinfo
->mouse_face_window
= window
;
1525 dpyinfo
->mouse_face_face_id
1526 = face_at_buffer_position (w
, pos
, 0, 0,
1528 !dpyinfo
->mouse_face_hidden
,
1531 /* Display it as active. */
1532 show_mouse_face (dpyinfo
, 1);
1534 /* Handle the text property case. */
1535 else if (! NILP (mouse_face
))
1537 /* Find the range of text around this char that
1538 should be active. */
1539 Lisp_Object before
, after
, beginning
, end
;
1542 beginning
= Fmarker_position (w
->start
);
1543 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1544 - XFASTINT (w
->window_end_pos
)));
1546 = Fprevious_single_property_change (make_number (pos
+ 1),
1548 w
->buffer
, beginning
);
1550 = Fnext_single_property_change (position
, Qmouse_face
,
1552 /* Record this as the current active region. */
1553 fast_find_position (w
, XFASTINT (before
),
1554 &dpyinfo
->mouse_face_beg_col
,
1555 &dpyinfo
->mouse_face_beg_row
);
1556 dpyinfo
->mouse_face_past_end
1557 = !fast_find_position (w
, XFASTINT (after
),
1558 &dpyinfo
->mouse_face_end_col
,
1559 &dpyinfo
->mouse_face_end_row
);
1560 dpyinfo
->mouse_face_window
= window
;
1561 dpyinfo
->mouse_face_face_id
1562 = face_at_buffer_position (w
, pos
, 0, 0,
1564 !dpyinfo
->mouse_face_hidden
,
1567 /* Display it as active. */
1568 show_mouse_face (dpyinfo
, 1);
1572 /* Look for a `help-echo' property. */
1575 extern Lisp_Object Qhelp_echo
;
1577 /* Check overlays first. */
1579 for (i
= noverlays
- 1; i
>= 0 && NILP (help
); --i
)
1581 overlay
= overlay_vec
[i
];
1582 help
= Foverlay_get (overlay
, Qhelp_echo
);
1587 help_echo_string
= help
;
1588 help_echo_window
= window
;
1589 help_echo_object
= overlay
;
1590 help_echo_pos
= pos
;
1592 /* Try text properties. */
1593 else if (NILP (help
)
1594 && ((STRINGP (glyph
->object
)
1595 && glyph
->charpos
>= 0
1596 && glyph
->charpos
< SCHARS (glyph
->object
))
1597 || (BUFFERP (glyph
->object
)
1598 && glyph
->charpos
>= BEGV
1599 && glyph
->charpos
< ZV
)))
1601 help
= Fget_text_property (make_number (glyph
->charpos
),
1602 Qhelp_echo
, glyph
->object
);
1605 help_echo_string
= help
;
1606 help_echo_window
= window
;
1607 help_echo_object
= glyph
->object
;
1608 help_echo_pos
= glyph
->charpos
;
1615 current_buffer
= obuf
;
1621 IT_clear_end_of_line (struct frame
*f
, int first_unused
)
1624 int i
, j
, offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1625 extern int fatal_error_in_progress
;
1626 struct tty_display_info
*tty
= FRAME_TTY (f
);
1628 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1632 i
= (j
= first_unused
- new_pos_X
) * 2;
1633 if (tty
->termscript
)
1634 fprintf (tty
->termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1635 spaces
= sp
= alloca (i
);
1640 *sp
++ = ScreenAttrib
;
1644 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1645 if (screen_virtual_segment
)
1646 dosv_refresh_virtual_screen (offset
, i
/ 2);
1648 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1649 Let's follow their lead, in case someone relies on this. */
1650 new_pos_X
= first_unused
;
1654 IT_clear_screen (struct frame
*f
)
1656 struct tty_display_info
*tty
= FRAME_TTY (f
);
1658 if (tty
->termscript
)
1659 fprintf (tty
->termscript
, "<CLR:SCR>");
1660 /* We are sometimes called (from clear_garbaged_frames) when a new
1661 frame is being created, but its faces are not yet realized. In
1662 such a case we cannot call IT_set_face, since it will fail to find
1663 any valid faces and will abort. Instead, use the initial screen
1664 colors; that should mimic what a Unix tty does, which simply clears
1665 the screen with whatever default colors are in use. */
1666 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1667 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1672 if (screen_virtual_segment
)
1673 dosv_refresh_virtual_screen (0, screen_size
);
1674 new_pos_X
= new_pos_Y
= 0;
1678 IT_clear_to_end (struct frame
*f
)
1680 struct tty_display_info
*tty
= FRAME_TTY (f
);
1682 if (tty
->termscript
)
1683 fprintf (tty
->termscript
, "<CLR:EOS>");
1685 while (new_pos_Y
< screen_size_Y
) {
1687 IT_clear_end_of_line (f
, screen_size_X
);
1693 IT_cursor_to (struct frame
*f
, int y
, int x
)
1695 struct tty_display_info
*tty
= FRAME_TTY (f
);
1697 if (tty
->termscript
)
1698 fprintf (tty
->termscript
, "\n<XY=%dx%d>", x
, y
);
1703 static int cursor_cleared
;
1706 IT_display_cursor (int on
)
1708 struct tty_display_info
*tty
= CURTTY ();
1710 if (on
&& cursor_cleared
)
1712 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1714 if (tty
->termscript
)
1715 fprintf (tty
->termscript
, "\nCURSOR ON");
1717 else if (!on
&& !cursor_cleared
)
1719 ScreenSetCursor (-1, -1);
1721 if (tty
->termscript
)
1722 fprintf (tty
->termscript
, "\nCURSOR OFF");
1726 /* Emacs calls cursor-movement functions a lot when it updates the
1727 display (probably a legacy of old terminals where you cannot
1728 update a screen line without first moving the cursor there).
1729 However, cursor movement is expensive on MSDOS (it calls a slow
1730 BIOS function and requires 2 mode switches), while actual screen
1731 updates access the video memory directly and don't depend on
1732 cursor position. To avoid slowing down the redisplay, we cheat:
1733 all functions that move the cursor only set internal variables
1734 which record the cursor position, whereas the cursor is only
1735 moved to its final position whenever screen update is complete.
1737 `IT_cmgoto' is called from the keyboard reading loop and when the
1738 frame update is complete. This means that we are ready for user
1739 input, so we update the cursor position to show where the point is,
1740 and also make the mouse pointer visible.
1742 Special treatment is required when the cursor is in the echo area,
1743 to put the cursor at the end of the text displayed there. */
1746 IT_cmgoto (FRAME_PTR f
)
1748 /* Only set the cursor to where it should be if the display is
1749 already in sync with the window contents. */
1750 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1751 struct tty_display_info
*tty
= FRAME_TTY (f
);
1753 /* FIXME: This needs to be rewritten for the new redisplay, or
1756 static int previous_pos_X
= -1;
1758 update_cursor_pos
= 1; /* temporary!!! */
1760 /* If the display is in sync, forget any previous knowledge about
1761 cursor position. This is primarily for unexpected events like
1762 C-g in the minibuffer. */
1763 if (update_cursor_pos
&& previous_pos_X
>= 0)
1764 previous_pos_X
= -1;
1765 /* If we are in the echo area, put the cursor at the
1766 end of the echo area message. */
1767 if (!update_cursor_pos
1768 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f
))) <= new_pos_Y
)
1770 int tem_X
= current_pos_X
, dummy
;
1772 if (echo_area_glyphs
)
1774 tem_X
= echo_area_glyphs_length
;
1775 /* Save current cursor position, to be restored after the
1776 echo area message is erased. Only remember one level
1777 of previous cursor position. */
1778 if (previous_pos_X
== -1)
1779 ScreenGetCursor (&dummy
, &previous_pos_X
);
1781 else if (previous_pos_X
>= 0)
1783 /* We wind up here after the echo area message is erased.
1784 Restore the cursor position we remembered above. */
1785 tem_X
= previous_pos_X
;
1786 previous_pos_X
= -1;
1789 if (current_pos_X
!= tem_X
)
1792 update_cursor_pos
= 1;
1797 if (update_cursor_pos
1798 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1800 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1801 if (tty
->termscript
)
1802 fprintf (tty
->termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1805 /* Maybe cursor is invisible, so make it visible. */
1806 IT_display_cursor (1);
1808 /* Mouse pointer should be always visible if we are waiting for
1815 IT_update_begin (struct frame
*f
)
1817 struct tty_display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1818 struct frame
*mouse_face_frame
= display_info
->mouse_face_mouse_frame
;
1820 if (display_info
->termscript
)
1821 fprintf (display_info
->termscript
, "\n\n<UPDATE_BEGIN");
1825 if (f
&& f
== mouse_face_frame
)
1827 /* Don't do highlighting for mouse motion during the update. */
1828 display_info
->mouse_face_defer
= 1;
1830 /* If F needs to be redrawn, simply forget about any prior mouse
1832 if (FRAME_GARBAGED_P (f
))
1833 display_info
->mouse_face_window
= Qnil
;
1835 /* Can we tell that this update does not affect the window
1836 where the mouse highlight is? If so, no need to turn off.
1837 Likewise, don't do anything if none of the enabled rows
1838 contains glyphs highlighted in mouse face. */
1839 if (!NILP (display_info
->mouse_face_window
)
1840 && WINDOWP (display_info
->mouse_face_window
))
1842 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1845 /* If the mouse highlight is in the window that was deleted
1846 (e.g., if it was popped by completion), clear highlight
1848 if (NILP (w
->buffer
))
1849 display_info
->mouse_face_window
= Qnil
;
1852 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1853 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1854 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1858 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1859 clear_mouse_face (display_info
);
1862 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
1864 /* If the frame with mouse highlight was deleted, invalidate the
1866 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
1867 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
1868 display_info
->mouse_face_window
= Qnil
;
1869 display_info
->mouse_face_deferred_gc
= 0;
1870 display_info
->mouse_face_mouse_frame
= NULL
;
1877 IT_update_end (struct frame
*f
)
1879 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1881 if (dpyinfo
->termscript
)
1882 fprintf (dpyinfo
->termscript
, "\n<UPDATE_END\n");
1883 dpyinfo
->mouse_face_defer
= 0;
1887 IT_frame_up_to_date (struct frame
*f
)
1889 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1890 Lisp_Object new_cursor
, frame_desired_cursor
;
1893 if (dpyinfo
->mouse_face_deferred_gc
1894 || (f
&& f
== dpyinfo
->mouse_face_mouse_frame
))
1897 if (dpyinfo
->mouse_face_mouse_frame
)
1898 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
1899 dpyinfo
->mouse_face_mouse_x
,
1900 dpyinfo
->mouse_face_mouse_y
);
1901 dpyinfo
->mouse_face_deferred_gc
= 0;
1905 /* Set the cursor type to whatever they wanted. In a minibuffer
1906 window, we want the cursor to appear only if we are reading input
1907 from this window, and we want the cursor to be taken from the
1908 frame parameters. For the selected window, we use either its
1909 buffer-local value or the value from the frame parameters if the
1910 buffer doesn't define its local value for the cursor type. */
1911 sw
= XWINDOW (f
->selected_window
);
1912 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1913 if (cursor_in_echo_area
1914 && FRAME_HAS_MINIBUF_P (f
)
1915 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1916 && sw
== XWINDOW (echo_area_window
))
1917 new_cursor
= frame_desired_cursor
;
1920 struct buffer
*b
= XBUFFER (sw
->buffer
);
1922 if (EQ (b
->cursor_type
, Qt
))
1923 new_cursor
= frame_desired_cursor
;
1924 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
1925 new_cursor
= Fcons (Qbar
, make_number (0));
1927 new_cursor
= b
->cursor_type
;
1930 IT_set_cursor_type (f
, new_cursor
);
1932 IT_cmgoto (f
); /* position cursor when update is done */
1935 /* Copy LEN glyphs displayed on a single line whose vertical position
1936 is YPOS, beginning at horizontal position XFROM to horizontal
1937 position XTO, by moving blocks in the video memory. Used by
1938 functions that insert and delete glyphs. */
1940 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1942 /* The offsets of source and destination relative to the
1943 conventional memorty selector. */
1944 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1945 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1947 if (from
== to
|| len
<= 0)
1950 _farsetsel (_dos_ds
);
1952 /* The source and destination might overlap, so we need to move
1953 glyphs non-destructively. */
1956 for ( ; len
; from
+= 2, to
+= 2, len
--)
1957 _farnspokew (to
, _farnspeekw (from
));
1961 from
+= (len
- 1) * 2;
1962 to
+= (len
- 1) * 2;
1963 for ( ; len
; from
-= 2, to
-= 2, len
--)
1964 _farnspokew (to
, _farnspeekw (from
));
1966 if (screen_virtual_segment
)
1967 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1970 /* Insert and delete glyphs. */
1972 IT_insert_glyphs (f
, start
, len
)
1974 register struct glyph
*start
;
1977 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1979 /* Shift right the glyphs from the nominal cursor position to the
1980 end of this line. */
1981 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
1983 /* Now write the glyphs to be inserted. */
1984 IT_write_glyphs (f
, start
, len
);
1988 IT_delete_glyphs (f
, n
)
1995 /* set-window-configuration on window.c needs this. */
1997 x_set_menu_bar_lines (f
, value
, oldval
)
1999 Lisp_Object value
, oldval
;
2001 set_menu_bar_lines (f
, value
, oldval
);
2004 /* This was copied from xfaces.c */
2006 extern Lisp_Object Qbackground_color
;
2007 extern Lisp_Object Qforeground_color
;
2008 Lisp_Object Qreverse
;
2009 extern Lisp_Object Qtitle
;
2011 /* IT_set_terminal_modes is called when emacs is started,
2012 resumed, and whenever the screen is redrawn! */
2015 IT_set_terminal_modes (struct terminal
*term
)
2017 struct tty_display_info
*tty
;
2019 /* If called with initial terminal, it's too early to do anything
2021 if (term
->type
== output_initial
)
2024 tty
= term
->display_info
.tty
;
2026 if (tty
->termscript
)
2027 fprintf (tty
->termscript
, "\n<SET_TERM>");
2029 screen_size_X
= ScreenCols ();
2030 screen_size_Y
= ScreenRows ();
2031 screen_size
= screen_size_X
* screen_size_Y
;
2033 new_pos_X
= new_pos_Y
= 0;
2034 current_pos_X
= current_pos_Y
= -1;
2036 if (term_setup_done
)
2038 term_setup_done
= 1;
2040 startup_screen_size_X
= screen_size_X
;
2041 startup_screen_size_Y
= screen_size_Y
;
2042 startup_screen_attrib
= ScreenAttrib
;
2045 /* Is DOS/V (or any other RSIS software which relocates
2046 the screen) installed? */
2048 unsigned short es_value
;
2051 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2052 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2053 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2054 else if (screen_old_address
) /* already switched to Japanese mode once */
2055 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2057 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2059 es_value
= regs
.x
.es
;
2060 __dpmi_int (0x10, ®s
);
2062 if (regs
.x
.es
!= es_value
)
2064 /* screen_old_address is only set if ScreenPrimary does NOT
2065 already point to the relocated buffer address returned by
2066 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2067 ScreenPrimary to that address at startup under DOS/V. */
2068 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2069 screen_old_address
= ScreenPrimary
;
2070 screen_virtual_segment
= regs
.x
.es
;
2071 screen_virtual_offset
= regs
.x
.di
;
2072 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2075 #endif /* __DJGPP__ > 1 */
2077 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2078 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2083 /* IT_reset_terminal_modes is called when emacs is
2084 suspended or killed. */
2087 IT_reset_terminal_modes (struct terminal
*term
)
2089 int display_row_start
= (int) ScreenPrimary
;
2090 int saved_row_len
= startup_screen_size_X
* 2;
2091 int update_row_len
= ScreenCols () * 2, current_rows
= ScreenRows ();
2092 int to_next_row
= update_row_len
;
2093 unsigned char *saved_row
= startup_screen_buffer
;
2094 int cursor_pos_X
= ScreenCols () - 1, cursor_pos_Y
= ScreenRows () - 1;
2095 struct tty_display_info
*tty
= term
->display_info
.tty
;
2097 if (tty
->termscript
)
2098 fprintf (tty
->termscript
, "\n<RESET_TERM>");
2100 if (!term_setup_done
)
2105 /* Leave the video system in the same state as we found it,
2106 as far as the blink/bright-background bit is concerned. */
2107 maybe_enable_blinking ();
2109 /* We have a situation here.
2110 We cannot just do ScreenUpdate(startup_screen_buffer) because
2111 the luser could have changed screen dimensions inside Emacs
2112 and failed (or didn't want) to restore them before killing
2113 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2114 thus will happily use memory outside what was allocated for
2115 `startup_screen_buffer'.
2116 Thus we only restore as much as the current screen dimensions
2117 can hold, and clear the rest (if the saved screen is smaller than
2118 the current) with the color attribute saved at startup. The cursor
2119 is also restored within the visible dimensions. */
2121 ScreenAttrib
= startup_screen_attrib
;
2123 /* Don't restore the screen if we are exiting less than 2 seconds
2124 after startup: we might be crashing, and the screen might show
2125 some vital clues to what's wrong. */
2126 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2129 if (screen_virtual_segment
)
2130 dosv_refresh_virtual_screen (0, screen_size
);
2132 if (update_row_len
> saved_row_len
)
2133 update_row_len
= saved_row_len
;
2134 if (current_rows
> startup_screen_size_Y
)
2135 current_rows
= startup_screen_size_Y
;
2137 if (tty
->termscript
)
2138 fprintf (tty
->termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2139 update_row_len
/ 2, current_rows
);
2141 while (current_rows
--)
2143 dosmemput (saved_row
, update_row_len
, display_row_start
);
2144 if (screen_virtual_segment
)
2145 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2146 update_row_len
/ 2);
2147 saved_row
+= saved_row_len
;
2148 display_row_start
+= to_next_row
;
2151 if (startup_pos_X
< cursor_pos_X
)
2152 cursor_pos_X
= startup_pos_X
;
2153 if (startup_pos_Y
< cursor_pos_Y
)
2154 cursor_pos_Y
= startup_pos_Y
;
2156 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2157 xfree (startup_screen_buffer
);
2158 startup_screen_buffer
= NULL
;
2160 term_setup_done
= 0;
2164 IT_set_terminal_window (struct frame
*f
, int foo
)
2168 /* Remember the screen colors of the curent frame, to serve as the
2169 default colors for newly-created frames. */
2170 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2171 Smsdos_remember_default_colors
, 1, 1, 0,
2172 doc
: /* Remember the screen colors of the current frame. */)
2178 CHECK_FRAME (frame
);
2181 /* This function is called after applying default-frame-alist to the
2182 initial frame. At that time, if reverse-colors option was
2183 specified in default-frame-alist, it was already applied, and
2184 frame colors are reversed. */
2185 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
2186 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
2190 IT_set_frame_parameters (f
, alist
)
2195 int i
, j
, length
= XINT (Flength (alist
));
2197 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2199 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2200 /* Do we have to reverse the foreground and background colors? */
2201 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2202 int need_to_reverse
, was_reverse
= reverse
;
2203 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2204 unsigned long orig_fg
, orig_bg
;
2205 Lisp_Object frame_bg
, frame_fg
;
2206 extern Lisp_Object Qdefault
, QCforeground
, QCbackground
;
2207 struct tty_display_info
*tty
= FRAME_TTY (f
);
2209 /* If we are creating a new frame, begin with the original screen colors
2210 used for the initial frame. */
2211 if (EQ (alist
, Vdefault_frame_alist
)
2212 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2214 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2215 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2216 init_frame_faces (f
);
2218 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2219 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2220 frame_fg
= Fcdr (Fassq (Qforeground_color
, f
->param_alist
));
2221 frame_bg
= Fcdr (Fassq (Qbackground_color
, f
->param_alist
));
2222 /* frame_fg and frame_bg could be nil if, for example,
2223 f->param_alist is nil, e.g. if we are called from
2224 Fmake_terminal_frame. */
2225 if (NILP (frame_fg
))
2226 frame_fg
= build_string (unspecified_fg
);
2227 if (NILP (frame_bg
))
2228 frame_bg
= build_string (unspecified_bg
);
2230 /* Extract parm names and values into those vectors. */
2232 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2237 parms
[i
] = Fcar (elt
);
2238 CHECK_SYMBOL (parms
[i
]);
2239 values
[i
] = Fcdr (elt
);
2245 for (i
= 0; i
< j
; i
++)
2247 Lisp_Object prop
, val
;
2252 if (EQ (prop
, Qreverse
))
2253 reverse
= EQ (val
, Qt
);
2256 need_to_reverse
= reverse
&& !was_reverse
;
2257 if (tty
->termscript
&& need_to_reverse
)
2258 fprintf (tty
->termscript
, "<INVERSE-VIDEO>\n");
2260 /* Now process the alist elements in reverse of specified order. */
2261 for (i
--; i
>= 0; i
--)
2263 Lisp_Object prop
, val
, frame
;
2268 if (EQ (prop
, Qforeground_color
))
2270 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2271 ? LFACE_BACKGROUND_INDEX
2272 : LFACE_FOREGROUND_INDEX
);
2273 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2274 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2275 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2277 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2278 /* Make sure the foreground of the default face for this
2279 frame is changed as well. */
2280 XSETFRAME (frame
, f
);
2281 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2285 if (tty
->termscript
)
2286 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
2289 else if (EQ (prop
, Qbackground_color
))
2291 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2292 ? LFACE_FOREGROUND_INDEX
2293 : LFACE_BACKGROUND_INDEX
);
2294 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2295 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2296 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2298 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2299 /* Make sure the background of the default face for this
2300 frame is changed as well. */
2301 XSETFRAME (frame
, f
);
2302 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2306 if (tty
->termscript
)
2307 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
2310 else if (EQ (prop
, Qtitle
))
2312 x_set_title (f
, val
);
2313 if (tty
->termscript
)
2314 fprintf (tty
->termscript
, "<TITLE: %s>\n", SDATA (val
));
2316 else if (EQ (prop
, Qcursor_type
))
2318 IT_set_cursor_type (f
, val
);
2319 if (tty
->termscript
)
2320 fprintf (tty
->termscript
, "<CTYPE: %s>\n",
2321 EQ (val
, Qbar
) || EQ (val
, Qhbar
)
2322 || CONSP (val
) && (EQ (XCAR (val
), Qbar
)
2323 || EQ (XCAR (val
), Qhbar
))
2326 else if (EQ (prop
, Qtty_type
))
2328 internal_terminal_init ();
2329 if (tty
->termscript
)
2330 fprintf (tty
->termscript
, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
2331 SBYTES (val
), SDATA (val
));
2333 store_frame_param (f
, prop
, val
);
2336 /* If they specified "reverse", but not the colors, we need to swap
2337 the current frame colors. */
2338 if (need_to_reverse
)
2344 XSETFRAME (frame
, f
);
2345 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2346 tty_color_name (f
, orig_bg
),
2352 XSETFRAME (frame
, f
);
2353 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2354 tty_color_name (f
, orig_fg
),
2362 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2363 if (f
== SELECTED_FRAME())
2368 extern void init_frame_faces (FRAME_PTR
);
2370 #endif /* !HAVE_X_WINDOWS */
2373 /* Do we need the internal terminal? */
2376 internal_terminal_init ()
2378 static int init_needed
= 1;
2379 char *term
= getenv ("TERM"), *colors
;
2380 struct frame
*sf
= SELECTED_FRAME();
2381 struct tty_display_info
*tty
;
2383 #ifdef HAVE_X_WINDOWS
2384 if (!inhibit_window_system
)
2388 /* If this is the initial terminal, we are done here. */
2389 if (sf
->output_method
== output_initial
)
2393 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2395 #ifndef HAVE_X_WINDOWS
2396 if (!internal_terminal
|| inhibit_window_system
)
2398 sf
->output_method
= output_termcap
;
2402 tty
= FRAME_TTY (sf
);
2403 current_kboard
->Vwindow_system
= Qpc
;
2404 sf
->output_method
= output_msdos_raw
;
2407 if (!tty
->termscript
&& getenv ("EMACSTEST"))
2408 tty
->termscript
= fopen (getenv ("EMACSTEST"), "wt");
2409 if (tty
->termscript
)
2411 time_t now
= time (NULL
);
2412 struct tm
*tnow
= localtime (&now
);
2415 strftime (tbuf
, sizeof (tbuf
) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow
);
2416 fprintf (tty
->termscript
, "\nEmacs session started at %s\n", tbuf
);
2417 fprintf (tty
->termscript
, "=====================\n\n");
2420 Vinitial_window_system
= Qpc
;
2421 Vwindow_system_version
= make_number (23); /* RE Emacs version */
2422 tty
->terminal
->type
= output_msdos_raw
;
2424 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
2426 screen_old_address
= 0;
2428 /* Forget the stale screen colors as well. */
2429 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2431 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
2432 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
2434 colors
= getenv ("EMACSCOLORS");
2435 if (colors
&& strlen (colors
) >= 2)
2437 /* The colors use 4 bits each (we enable bright background). */
2438 if (isdigit (colors
[0]))
2440 else if (isxdigit (colors
[0]))
2441 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2442 if (colors
[0] >= 0 && colors
[0] < 16)
2443 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors
[0];
2444 if (isdigit (colors
[1]))
2446 else if (isxdigit (colors
[1]))
2447 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2448 if (colors
[1] >= 0 && colors
[1] < 16)
2449 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors
[1];
2451 the_only_display_info
.mouse_face_mouse_frame
= NULL
;
2452 the_only_display_info
.mouse_face_deferred_gc
= 0;
2453 the_only_display_info
.mouse_face_beg_row
=
2454 the_only_display_info
.mouse_face_beg_col
= -1;
2455 the_only_display_info
.mouse_face_end_row
=
2456 the_only_display_info
.mouse_face_end_col
= -1;
2457 the_only_display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2458 the_only_display_info
.mouse_face_window
= Qnil
;
2459 the_only_display_info
.mouse_face_mouse_x
=
2460 the_only_display_info
.mouse_face_mouse_y
= 0;
2461 the_only_display_info
.mouse_face_defer
= 0;
2462 the_only_display_info
.mouse_face_hidden
= 0;
2464 if (have_mouse
) /* detected in dos_ttraw, which see */
2466 have_mouse
= 1; /* enable mouse */
2468 mouse_setup_buttons (mouse_button_count
);
2469 tty
->terminal
->mouse_position_hook
= &mouse_get_pos
;
2473 if (tty
->termscript
&& screen_size
)
2474 fprintf (tty
->termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2475 screen_size_X
, screen_size_Y
);
2477 init_frame_faces (sf
);
2484 initialize_msdos_display (struct terminal
*term
)
2486 term
->rif
= 0; /* we don't support window-based display */
2487 term
->cursor_to_hook
= term
->raw_cursor_to_hook
= IT_cursor_to
;
2488 term
->clear_to_end_hook
= IT_clear_to_end
;
2489 term
->clear_frame_hook
= IT_clear_screen
;
2490 term
->clear_end_of_line_hook
= IT_clear_end_of_line
;
2491 term
->ins_del_lines_hook
= 0;
2492 term
->insert_glyphs_hook
= IT_insert_glyphs
;
2493 term
->write_glyphs_hook
= IT_write_glyphs
;
2494 term
->delete_glyphs_hook
= IT_delete_glyphs
;
2495 term
->ring_bell_hook
= IT_ring_bell
;
2496 term
->reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2497 term
->set_terminal_modes_hook
= IT_set_terminal_modes
;
2498 term
->set_terminal_window_hook
= IT_set_terminal_window
;
2499 term
->update_begin_hook
= IT_update_begin
;
2500 term
->update_end_hook
= IT_update_end
;
2501 term
->frame_up_to_date_hook
= IT_frame_up_to_date
;
2502 term
->mouse_position_hook
= 0; /* set later by dos_ttraw */
2503 term
->frame_rehighlight_hook
= 0;
2504 term
->frame_raise_lower_hook
= 0;
2505 term
->set_vertical_scroll_bar_hook
= 0;
2506 term
->condemn_scroll_bars_hook
= 0;
2507 term
->redeem_scroll_bar_hook
= 0;
2508 term
->judge_scroll_bars_hook
= 0;
2509 term
->read_socket_hook
= &tty_read_avail_input
; /* from keyboard.c */
2512 dos_get_saved_screen (screen
, rows
, cols
)
2517 #ifndef HAVE_X_WINDOWS
2518 *screen
= startup_screen_buffer
;
2519 *cols
= startup_screen_size_X
;
2520 *rows
= startup_screen_size_Y
;
2521 return *screen
!= (char *)0;
2527 #ifndef HAVE_X_WINDOWS
2529 /* We are not X, but we can emulate it well enough for our needs... */
2533 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2534 error ("Not running under a window system");
2540 /* ----------------------- Keyboard control ----------------------
2542 * Keymaps reflect the following keyboard layout:
2544 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2545 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2546 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2547 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2551 #define Ignore 0x0000
2552 #define Normal 0x0000 /* normal key - alt changes scan-code */
2553 #define FctKey 0x1000 /* func key if c == 0, else c */
2554 #define Special 0x2000 /* func key even if c != 0 */
2555 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2556 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2557 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2558 #define Grey 0x6000 /* Grey keypad key */
2560 #define Alt 0x0100 /* alt scan-code */
2561 #define Ctrl 0x0200 /* ctrl scan-code */
2562 #define Shift 0x0400 /* shift scan-code */
2564 static int extended_kbd
; /* 101 (102) keyboard present. */
2566 struct kbd_translate
{
2569 unsigned short code
;
2572 struct dos_keyboard_map
2577 struct kbd_translate
*translate_table
;
2581 static struct dos_keyboard_map us_keyboard
= {
2583 /* 01234567890123456789012345678901234567890 12345678901234 */
2584 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2585 /* 0123456789012345678901234567890123456789 012345678901234 */
2586 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2587 0, /* no Alt-Gr key */
2588 0 /* no translate table */
2591 static struct dos_keyboard_map fr_keyboard
= {
2593 /* 012 3456789012345678901234567890123456789012345678901234 */
2594 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2595 /* 0123456789012345678901234567890123456789012345678901234 */
2596 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2597 /* 01234567 89012345678901234567890123456789012345678901234 */
2599 0 /* no translate table */
2603 * Italian keyboard support, country code 39.
2606 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2607 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2610 static struct kbd_translate it_kbd_translate_table
[] = {
2611 { 0x56, 0x3c, Normal
| 13 },
2612 { 0x56, 0x3e, Normal
| 27 },
2615 static struct dos_keyboard_map it_keyboard
= {
2617 /* 0 123456789012345678901234567890123456789012345678901234 */
2618 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2619 /* 01 23456789012345678901234567890123456789012345678901234 */
2620 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2621 /* 0123456789012345678901234567890123456789012345678901234 */
2623 it_kbd_translate_table
2626 static struct dos_keyboard_map dk_keyboard
= {
2628 /* 0123456789012345678901234567890123456789012345678901234 */
2629 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2630 /* 01 23456789012345678901234567890123456789012345678901234 */
2631 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2632 /* 0123456789012345678901234567890123456789012345678901234 */
2634 0 /* no translate table */
2637 static struct kbd_translate jp_kbd_translate_table
[] = {
2638 { 0x73, 0x5c, Normal
| 0 },
2639 { 0x73, 0x5f, Normal
| 0 },
2640 { 0x73, 0x1c, Map
| 0 },
2641 { 0x7d, 0x5c, Normal
| 13 },
2642 { 0x7d, 0x7c, Normal
| 13 },
2643 { 0x7d, 0x1c, Map
| 13 },
2646 static struct dos_keyboard_map jp_keyboard
= {
2648 /* 0123456789012 345678901234567890123456789012345678901234 */
2649 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2650 /* 01 23456789012345678901234567890123456789012345678901234 */
2651 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2652 0, /* no Alt-Gr key */
2653 jp_kbd_translate_table
2656 static struct keyboard_layout_list
2659 struct dos_keyboard_map
*keyboard_map
;
2660 } keyboard_layout_list
[] =
2669 static struct dos_keyboard_map
*keyboard
;
2670 static int keyboard_map_all
;
2671 static int international_keyboard
;
2674 dos_set_keyboard (code
, always
)
2679 _go32_dpmi_registers regs
;
2681 /* See if Keyb.Com is installed (for international keyboard support).
2682 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2683 of Windows 9X! So don't do that! */
2685 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2686 _go32_dpmi_simulate_int (0x2f, ®s
);
2687 if (regs
.h
.al
== 0xff)
2688 international_keyboard
= 1;
2690 /* Initialize to US settings, for countries that don't have their own. */
2691 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2692 keyboard_map_all
= always
;
2693 dos_keyboard_layout
= 1;
2695 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2696 if (code
== keyboard_layout_list
[i
].country_code
)
2698 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2699 keyboard_map_all
= always
;
2700 dos_keyboard_layout
= code
;
2708 unsigned char char_code
; /* normal code */
2709 unsigned char meta_code
; /* M- code */
2710 unsigned char keypad_code
; /* keypad code */
2711 unsigned char editkey_code
; /* edit key */
2712 } keypad_translate_map
[] = {
2713 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2714 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2715 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2716 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2717 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2718 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2719 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2720 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2721 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2722 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2723 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2728 unsigned char char_code
; /* normal code */
2729 unsigned char keypad_code
; /* keypad code */
2730 } grey_key_translate_map
[] = {
2731 '/', 0xaf, /* kp-decimal */
2732 '*', 0xaa, /* kp-multiply */
2733 '-', 0xad, /* kp-subtract */
2734 '+', 0xab, /* kp-add */
2735 '\r', 0x8d /* kp-enter */
2738 static unsigned short
2739 ibmpc_translate_map
[] =
2741 /* --------------- 00 to 0f --------------- */
2742 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2743 Alt
| ModFct
| 0x1b, /* Escape */
2744 Normal
| 1, /* '1' */
2745 Normal
| 2, /* '2' */
2746 Normal
| 3, /* '3' */
2747 Normal
| 4, /* '4' */
2748 Normal
| 5, /* '5' */
2749 Normal
| 6, /* '6' */
2750 Normal
| 7, /* '7' */
2751 Normal
| 8, /* '8' */
2752 Normal
| 9, /* '9' */
2753 Normal
| 10, /* '0' */
2754 Normal
| 11, /* '-' */
2755 Normal
| 12, /* '=' */
2756 Special
| 0x08, /* Backspace */
2757 ModFct
| 0x74, /* Tab/Backtab */
2759 /* --------------- 10 to 1f --------------- */
2772 ModFct
| 0x0d, /* Return */
2777 /* --------------- 20 to 2f --------------- */
2786 Map
| 40, /* '\'' */
2788 Ignore
, /* Left shift */
2789 Map
| 41, /* '\\' */
2795 /* --------------- 30 to 3f --------------- */
2802 Ignore
, /* Right shift */
2803 Grey
| 1, /* Grey * */
2805 Normal
| 55, /* ' ' */
2806 Ignore
, /* Caps Lock */
2807 FctKey
| 0xbe, /* F1 */
2808 FctKey
| 0xbf, /* F2 */
2809 FctKey
| 0xc0, /* F3 */
2810 FctKey
| 0xc1, /* F4 */
2811 FctKey
| 0xc2, /* F5 */
2813 /* --------------- 40 to 4f --------------- */
2814 FctKey
| 0xc3, /* F6 */
2815 FctKey
| 0xc4, /* F7 */
2816 FctKey
| 0xc5, /* F8 */
2817 FctKey
| 0xc6, /* F9 */
2818 FctKey
| 0xc7, /* F10 */
2819 Ignore
, /* Num Lock */
2820 Ignore
, /* Scroll Lock */
2821 KeyPad
| 7, /* Home */
2822 KeyPad
| 8, /* Up */
2823 KeyPad
| 9, /* Page Up */
2824 Grey
| 2, /* Grey - */
2825 KeyPad
| 4, /* Left */
2826 KeyPad
| 5, /* Keypad 5 */
2827 KeyPad
| 6, /* Right */
2828 Grey
| 3, /* Grey + */
2829 KeyPad
| 1, /* End */
2831 /* --------------- 50 to 5f --------------- */
2832 KeyPad
| 2, /* Down */
2833 KeyPad
| 3, /* Page Down */
2834 KeyPad
| 0, /* Insert */
2835 KeyPad
| 10, /* Delete */
2836 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2837 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2838 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2839 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2840 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2841 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2842 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2843 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2844 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2845 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2846 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2847 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2849 /* --------------- 60 to 6f --------------- */
2850 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2851 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2852 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2853 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2854 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2855 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2856 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2857 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2858 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2859 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2860 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2861 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2862 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2863 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2864 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2865 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2867 /* --------------- 70 to 7f --------------- */
2868 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2869 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2870 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2871 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2872 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2873 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2874 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2875 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2876 Alt
| Map
| 1, /* '1' */
2877 Alt
| Map
| 2, /* '2' */
2878 Alt
| Map
| 3, /* '3' */
2879 Alt
| Map
| 4, /* '4' */
2880 Alt
| Map
| 5, /* '5' */
2881 Alt
| Map
| 6, /* '6' */
2882 Alt
| Map
| 7, /* '7' */
2883 Alt
| Map
| 8, /* '8' */
2885 /* --------------- 80 to 8f --------------- */
2886 Alt
| Map
| 9, /* '9' */
2887 Alt
| Map
| 10, /* '0' */
2888 Alt
| Map
| 11, /* '-' */
2889 Alt
| Map
| 12, /* '=' */
2890 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2891 FctKey
| 0xc8, /* F11 */
2892 FctKey
| 0xc9, /* F12 */
2893 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2894 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2895 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2896 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2897 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2898 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2899 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2900 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2901 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2903 /* --------------- 90 to 9f --------------- */
2904 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2905 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2906 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2907 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2908 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2909 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2910 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2911 Alt
| FctKey
| 0x50, /* (Alt) Home */
2912 Alt
| FctKey
| 0x52, /* (Alt) Up */
2913 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2914 Ignore
, /* NO KEY */
2915 Alt
| FctKey
| 0x51, /* (Alt) Left */
2916 Ignore
, /* NO KEY */
2917 Alt
| FctKey
| 0x53, /* (Alt) Right */
2918 Ignore
, /* NO KEY */
2919 Alt
| FctKey
| 0x57, /* (Alt) End */
2921 /* --------------- a0 to af --------------- */
2922 Alt
| KeyPad
| 2, /* (Alt) Down */
2923 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2924 Alt
| KeyPad
| 0, /* (Alt) Insert */
2925 Alt
| KeyPad
| 10, /* (Alt) Delete */
2926 Alt
| Grey
| 0, /* (Alt) Grey / */
2927 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2928 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2931 /* These bit-positions corresponds to values returned by BIOS */
2932 #define SHIFT_P 0x0003 /* two bits! */
2933 #define CTRL_P 0x0004
2934 #define ALT_P 0x0008
2935 #define SCRLOCK_P 0x0010
2936 #define NUMLOCK_P 0x0020
2937 #define CAPSLOCK_P 0x0040
2938 #define ALT_GR_P 0x0800
2939 #define SUPER_P 0x4000 /* pseudo */
2940 #define HYPER_P 0x8000 /* pseudo */
2943 dos_get_modifiers (keymask
)
2947 int mask
, modifiers
= 0;
2949 /* Calculate modifier bits */
2950 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2951 int86 (0x16, ®s
, ®s
);
2955 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2956 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2960 mask
= regs
.h
.al
& (SHIFT_P
|
2961 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2963 /* Do not break international keyboard support. */
2964 /* When Keyb.Com is loaded, the right Alt key is */
2965 /* used for accessing characters like { and } */
2966 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2969 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2972 if (dos_hyper_key
== 1)
2975 modifiers
|= hyper_modifier
;
2977 else if (dos_super_key
== 1)
2980 modifiers
|= super_modifier
;
2982 else if (!international_keyboard
)
2984 /* If Keyb.Com is NOT installed, let Right Alt behave
2985 like the Left Alt. */
2991 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2994 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2996 if (dos_hyper_key
== 2)
2999 modifiers
|= hyper_modifier
;
3001 else if (dos_super_key
== 2)
3004 modifiers
|= super_modifier
;
3012 modifiers
|= shift_modifier
;
3014 modifiers
|= ctrl_modifier
;
3016 modifiers
|= meta_modifier
;
3023 #define NUM_RECENT_DOSKEYS (100)
3024 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
3025 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
3026 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
3028 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
3029 doc
: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
3030 Each input key receives two values in this vector: first the ASCII code,
3031 and then the scan code. */)
3034 Lisp_Object val
, *keys
= XVECTOR (recent_doskeys
)->contents
;
3036 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
3037 return Fvector (total_doskeys
, keys
);
3040 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
3041 bcopy (keys
+ recent_doskeys_index
,
3042 XVECTOR (val
)->contents
,
3043 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
3045 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
3046 recent_doskeys_index
* sizeof (Lisp_Object
));
3051 /* Get a char from keyboard. Function keys are put into the event queue. */
3055 struct input_event event
;
3057 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (SELECTED_FRAME());
3060 #ifndef HAVE_X_WINDOWS
3061 /* Maybe put the cursor where it should be. */
3062 IT_cmgoto (SELECTED_FRAME());
3065 /* The following condition is equivalent to `kbhit ()', except that
3066 it uses the bios to do its job. This pleases DESQview/X. */
3067 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
3068 int86 (0x16, ®s
, ®s
),
3069 (regs
.x
.flags
& 0x40) == 0)
3072 register unsigned char c
;
3073 int modifiers
, sc
, code
= -1, mask
, kp_mode
;
3075 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
3076 int86 (0x16, ®s
, ®s
);
3081 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3083 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3084 recent_doskeys_index
= 0;
3085 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3087 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3088 recent_doskeys_index
= 0;
3090 modifiers
= dos_get_modifiers (&mask
);
3092 #ifndef HAVE_X_WINDOWS
3093 if (!NILP (Vdos_display_scancodes
))
3096 sprintf (buf
, "%02x:%02x*%04x",
3097 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3098 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3106 case 10: /* Ctrl Grey Enter */
3107 code
= Ctrl
| Grey
| 4;
3109 case 13: /* Grey Enter */
3112 case '/': /* Grey / */
3122 /* Try the keyboard-private translation table first. */
3123 if (keyboard
->translate_table
)
3125 struct kbd_translate
*p
= keyboard
->translate_table
;
3129 if (p
->sc
== sc
&& p
->ch
== c
)
3137 /* If the private table didn't translate it, use the general
3141 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3143 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3150 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3151 Emacs is ready to read a key. Therefore, if they press
3152 `Alt-x' when Emacs is busy, by the time we get to
3153 `dos_get_modifiers', they might have already released the
3154 Alt key, and Emacs gets just `x', which is BAD.
3155 However, for keys with the `Map' property set, the ASCII
3156 code returns zero only if Alt is pressed. So, when we DON'T
3157 have to support international_keyboard, we don't have to
3158 distinguish between the left and right Alt keys, and we
3159 can set the META modifier for any keys with the `Map'
3160 property if they return zero ASCII code (c = 0). */
3162 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3163 modifiers
|= meta_modifier
;
3165 modifiers
|= ctrl_modifier
;
3167 modifiers
|= shift_modifier
;
3170 switch (code
& 0xf000)
3173 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3175 c
= 0; /* Special */
3188 if (c
== 0) /* ctrl-break */
3190 return c
; /* ALT-nnn */
3192 if (!keyboard_map_all
)
3201 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3202 if (!keyboard_map_all
)
3206 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3207 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3211 code
= keyboard
->shifted
[code
];
3213 modifiers
&= ~shift_modifier
;
3216 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3217 code
= keyboard
->alt_gr
[code
];
3219 code
= keyboard
->unshifted
[code
];
3224 if (c
== 0xe0) /* edit key */
3227 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3228 kp_mode
= dos_keypad_mode
& 0x03;
3230 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3235 if (code
== 10 && dos_decimal_point
)
3236 return dos_decimal_point
;
3237 return keypad_translate_map
[code
].char_code
;
3240 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3244 code
= keypad_translate_map
[code
].meta_code
;
3245 modifiers
= meta_modifier
;
3249 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3256 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3257 if (dos_keypad_mode
& kp_mode
)
3258 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3260 code
= grey_key_translate_map
[code
].char_code
;
3268 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
))
3270 clear_mouse_face (dpyinfo
);
3271 dpyinfo
->mouse_face_hidden
= 1;
3275 event
.kind
= NON_ASCII_KEYSTROKE_EVENT
;
3277 event
.kind
= ASCII_KEYSTROKE_EVENT
;
3279 event
.modifiers
= modifiers
;
3280 event
.frame_or_window
= selected_frame
;
3282 event
.timestamp
= event_timestamp ();
3283 kbd_buffer_store_event (&event
);
3286 if (have_mouse
> 0 && !mouse_preempted
)
3288 int but
, press
, x
, y
, ok
;
3289 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3290 Lisp_Object mouse_window
= Qnil
;
3292 /* Check for mouse movement *before* buttons. */
3293 mouse_check_moved ();
3295 /* If the mouse moved from the spot of its last sighting, we
3296 might need to update mouse highlight. */
3297 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3299 if (dpyinfo
->mouse_face_hidden
)
3301 dpyinfo
->mouse_face_hidden
= 0;
3302 clear_mouse_face (dpyinfo
);
3305 /* Generate SELECT_WINDOW_EVENTs when needed. */
3306 if (!NILP (Vmouse_autoselect_window
))
3308 mouse_window
= window_from_coordinates (SELECTED_FRAME(),
3312 /* A window will be selected only when it is not
3313 selected now, and the last mouse movement event was
3314 not in it. A minibuffer window will be selected iff
3316 if (WINDOWP (mouse_window
)
3317 && !EQ (mouse_window
, last_mouse_window
)
3318 && !EQ (mouse_window
, selected_window
))
3320 event
.kind
= SELECT_WINDOW_EVENT
;
3321 event
.frame_or_window
= mouse_window
;
3323 event
.timestamp
= event_timestamp ();
3324 kbd_buffer_store_event (&event
);
3326 last_mouse_window
= mouse_window
;
3329 last_mouse_window
= Qnil
;
3331 previous_help_echo_string
= help_echo_string
;
3332 help_echo_string
= help_echo_object
= help_echo_window
= Qnil
;
3334 IT_note_mouse_highlight (SELECTED_FRAME(),
3335 mouse_last_x
, mouse_last_y
);
3336 /* If the contents of the global variable help_echo has
3337 changed, generate a HELP_EVENT. */
3338 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
3340 event
.kind
= HELP_EVENT
;
3341 event
.frame_or_window
= selected_frame
;
3342 event
.arg
= help_echo_object
;
3343 event
.x
= WINDOWP (help_echo_window
)
3344 ? help_echo_window
: selected_frame
;
3345 event
.y
= help_echo_string
;
3346 event
.timestamp
= event_timestamp ();
3347 event
.code
= help_echo_pos
;
3348 kbd_buffer_store_event (&event
);
3352 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3353 for (press
= 0; press
< 2; press
++)
3355 int button_num
= but
;
3358 ok
= mouse_pressed (but
, &x
, &y
);
3360 ok
= mouse_released (but
, &x
, &y
);
3363 /* Allow a simultaneous press/release of Mouse-1 and
3364 Mouse-2 to simulate Mouse-3 on two-button mice. */
3365 if (mouse_button_count
== 2 && but
< 2)
3367 int x2
, y2
; /* don't clobber original coordinates */
3369 /* If only one button is pressed, wait 100 msec and
3370 check again. This way, Speedy Gonzales isn't
3371 punished, while the slow get their chance. */
3372 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3373 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3378 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3379 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3384 event
.kind
= MOUSE_CLICK_EVENT
;
3385 event
.code
= button_num
;
3386 event
.modifiers
= dos_get_modifiers (0)
3387 | (press
? down_modifier
: up_modifier
);
3388 event
.x
= make_number (x
);
3389 event
.y
= make_number (y
);
3390 event
.frame_or_window
= selected_frame
;
3392 event
.timestamp
= event_timestamp ();
3393 kbd_buffer_store_event (&event
);
3401 static int prev_get_char
= -1;
3403 /* Return 1 if a key is ready to be read without suspending execution. */
3407 if (prev_get_char
!= -1)
3410 return ((prev_get_char
= dos_rawgetc ()) != -1);
3413 /* Read a key. Return -1 if no key is ready. */
3417 if (prev_get_char
!= -1)
3419 int c
= prev_get_char
;
3424 return dos_rawgetc ();
3427 #ifndef HAVE_X_WINDOWS
3429 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3432 Actually, I don't know the meaning of all the parameters of the functions
3433 here -- I only know how they are called by xmenu.c. I could of course
3434 grab the nearest Xlib manual (down the hall, second-to-last door on the
3435 left), but I don't think it's worth the effort. */
3437 /* These hold text of the current and the previous menu help messages. */
3438 static char *menu_help_message
, *prev_menu_help_message
;
3439 /* Pane number and item number of the menu item which generated the
3440 last menu help message. */
3441 static int menu_help_paneno
, menu_help_itemno
;
3448 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3449 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3453 /* Allocate some (more) memory for MENU ensuring that there is room for one
3457 IT_menu_make_room (XMenu
*menu
)
3459 if (menu
->allocated
== 0)
3461 int count
= menu
->allocated
= 10;
3462 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3463 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3464 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3465 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3467 else if (menu
->allocated
== menu
->count
)
3469 int count
= menu
->allocated
= menu
->allocated
+ 10;
3471 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3473 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3475 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3477 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3481 /* Search the given menu structure for a given pane number. */
3484 IT_menu_search_pane (XMenu
*menu
, int pane
)
3489 for (i
= 0; i
< menu
->count
; i
++)
3490 if (menu
->submenu
[i
])
3492 if (pane
== menu
->panenumber
[i
])
3493 return menu
->submenu
[i
];
3494 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3500 /* Determine how much screen space a given menu needs. */
3503 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3505 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3508 maxheight
= menu
->count
;
3509 for (i
= 0; i
< menu
->count
; i
++)
3511 if (menu
->submenu
[i
])
3513 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3514 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3515 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3518 *width
= menu
->width
+ maxsubwidth
;
3519 *height
= maxheight
;
3522 /* Display MENU at (X,Y) using FACES. */
3524 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
3527 (GLYPH).type = CHAR_GLYPH; \
3528 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
3529 (GLYPH).charpos = -1; \
3534 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3536 int i
, j
, face
, width
, mx
, my
, enabled
, mousehere
, row
, col
;
3537 struct glyph
*text
, *p
;
3538 const unsigned char *q
;
3539 struct frame
*sf
= SELECTED_FRAME();
3541 menu_help_message
= NULL
;
3543 width
= menu
->width
;
3544 /* We multiply width by 2 to account for possible control characters.
3545 FIXME: cater to non-ASCII characters in menus. */
3546 text
= (struct glyph
*) xmalloc ((width
* 2 + 2) * sizeof (struct glyph
));
3547 ScreenGetCursor (&row
, &col
);
3548 mouse_get_xy (&mx
, &my
);
3549 IT_update_begin (sf
);
3550 for (i
= 0; i
< menu
->count
; i
++)
3552 int max_width
= width
+ 2;
3554 IT_cursor_to (sf
, y
+ i
, x
);
3556 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3557 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ max_width
);
3558 face
= faces
[enabled
+ mousehere
* 2];
3559 /* The following if clause means that we display the menu help
3560 strings even if the menu item is currently disabled. */
3561 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3563 menu_help_message
= menu
->help_text
[i
];
3564 menu_help_paneno
= pn
- 1;
3565 menu_help_itemno
= i
;
3568 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
3570 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3572 unsigned c
= STRING_CHAR_ADVANCE (q
);
3576 BUILD_CHAR_GLYPH (*p
, c
, face
, 0);
3579 else /* make '^x' */
3581 BUILD_CHAR_GLYPH (*p
, '^', face
, 0);
3584 BUILD_CHAR_GLYPH (*p
, c
+ 64, face
, 0);
3588 /* Don't let the menu text overflow into the next screen row. */
3589 if (x
+ max_width
> screen_size_X
)
3591 max_width
= screen_size_X
- x
;
3592 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3594 for (; j
< max_width
- 2; j
++, p
++)
3595 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
3597 /* 16 is the character code of a character that on DOS terminal
3598 produces a nice-looking right-pointing arrow glyph. */
3599 BUILD_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3601 IT_write_glyphs (sf
, text
, max_width
);
3604 IT_cursor_to (sf
, row
, col
);
3608 /* --------------------------- X Menu emulation ---------------------- */
3610 /* Report availability of menus. */
3613 have_menus_p () { return 1; }
3615 /* Create a brand new menu structure. */
3618 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3620 return IT_menu_create ();
3623 /* Create a new pane and place it on the outer-most level. It is not
3624 clear that it should be placed out there, but I don't know what else
3628 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3636 IT_menu_make_room (menu
);
3637 menu
->submenu
[menu
->count
] = IT_menu_create ();
3638 menu
->text
[menu
->count
] = txt
;
3639 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3640 menu
->help_text
[menu
->count
] = NULL
;
3643 /* Adjust length for possible control characters (which will
3644 be written as ^x). */
3645 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3649 if (len
> menu
->width
)
3652 return menu
->panecount
;
3655 /* Create a new item in a menu pane. */
3658 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3659 int foo
, char *txt
, int enable
, char *help_text
)
3665 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3667 IT_menu_make_room (menu
);
3668 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3669 menu
->text
[menu
->count
] = txt
;
3670 menu
->panenumber
[menu
->count
] = enable
;
3671 menu
->help_text
[menu
->count
] = help_text
;
3674 /* Adjust length for possible control characters (which will
3675 be written as ^x). */
3676 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3680 if (len
> menu
->width
)
3686 /* Decide where the menu would be placed if requested at (X,Y). */
3689 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3690 int *ulx
, int *uly
, int *width
, int *height
)
3692 IT_menu_calc_size (menu
, width
, height
);
3698 struct IT_menu_state
3700 void *screen_behind
;
3707 /* Display menu, wait for user's response, and return that response. */
3710 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3711 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3712 void (*help_callback
)(char *, int, int))
3714 struct IT_menu_state
*state
;
3715 int statecount
, x
, y
, i
, b
, screensize
, leave
, result
, onepane
;
3716 int title_faces
[4]; /* face to display the menu title */
3717 int faces
[4], buffers_num_deleted
= 0;
3718 struct frame
*sf
= SELECTED_FRAME();
3719 Lisp_Object saved_echo_area_message
, selectface
;
3721 /* Just in case we got here without a mouse present... */
3722 if (have_mouse
<= 0)
3723 return XM_IA_SELECT
;
3724 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3725 around the display. */
3731 /* We will process all the mouse events directly, so we had
3732 better prevent dos_rawgetc from stealing them from us. */
3735 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3736 screensize
= screen_size
* 2;
3738 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3739 DEFAULT_FACE_ID
, 1);
3741 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3742 DEFAULT_FACE_ID
, 1);
3743 selectface
= intern ("msdos-menu-select-face");
3744 faces
[2] = lookup_derived_face (sf
, selectface
,
3746 faces
[3] = lookup_derived_face (sf
, selectface
,
3749 /* Make sure the menu title is always displayed with
3750 `msdos-menu-active-face', no matter where the mouse pointer is. */
3751 for (i
= 0; i
< 4; i
++)
3752 title_faces
[i
] = faces
[3];
3756 /* Don't let the title for the "Buffers" popup menu include a
3757 digit (which is ugly).
3759 This is a terrible kludge, but I think the "Buffers" case is
3760 the only one where the title includes a number, so it doesn't
3761 seem to be necessary to make this more general. */
3762 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3764 menu
->text
[0][7] = '\0';
3765 buffers_num_deleted
= 1;
3768 /* We need to save the current echo area message, so that we could
3769 restore it below, before we exit. See the commentary below,
3770 before the call to message_with_string. */
3771 saved_echo_area_message
= Fcurrent_message ();
3772 state
[0].menu
= menu
;
3774 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3776 /* Turn off the cursor. Otherwise it shows through the menu
3777 panes, which is ugly. */
3778 IT_display_cursor (0);
3780 /* Display the menu title. */
3781 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3782 if (buffers_num_deleted
)
3783 menu
->text
[0][7] = ' ';
3784 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3786 menu
->width
= menu
->submenu
[0]->width
;
3787 state
[0].menu
= menu
->submenu
[0];
3791 state
[0].menu
= menu
;
3793 state
[0].x
= x0
- 1;
3795 state
[0].pane
= onepane
;
3797 mouse_last_x
= -1; /* A hack that forces display. */
3801 if (!mouse_visible
) mouse_on ();
3802 mouse_check_moved ();
3803 if (sf
->mouse_moved
)
3805 sf
->mouse_moved
= 0;
3806 result
= XM_IA_SELECT
;
3807 mouse_get_xy (&x
, &y
);
3808 for (i
= 0; i
< statecount
; i
++)
3809 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3811 int dy
= y
- state
[i
].y
;
3812 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3814 if (!state
[i
].menu
->submenu
[dy
])
3815 if (state
[i
].menu
->panenumber
[dy
])
3816 result
= XM_SUCCESS
;
3818 result
= XM_IA_SELECT
;
3819 *pane
= state
[i
].pane
- 1;
3821 /* We hit some part of a menu, so drop extra menus that
3822 have been opened. That does not include an open and
3824 if (i
!= statecount
- 2
3825 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3826 while (i
!= statecount
- 1)
3830 ScreenUpdate (state
[statecount
].screen_behind
);
3831 if (screen_virtual_segment
)
3832 dosv_refresh_virtual_screen (0, screen_size
);
3833 xfree (state
[statecount
].screen_behind
);
3835 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3837 IT_menu_display (state
[i
].menu
,
3842 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3843 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3845 ScreenRetrieve (state
[statecount
].screen_behind
3846 = xmalloc (screensize
));
3848 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3849 state
[statecount
].y
= y
;
3854 IT_menu_display (state
[statecount
- 1].menu
,
3855 state
[statecount
- 1].y
,
3856 state
[statecount
- 1].x
,
3857 state
[statecount
- 1].pane
,
3862 if ((menu_help_message
|| prev_menu_help_message
)
3863 && menu_help_message
!= prev_menu_help_message
)
3865 help_callback (menu_help_message
,
3866 menu_help_paneno
, menu_help_itemno
);
3867 IT_display_cursor (0);
3868 prev_menu_help_message
= menu_help_message
;
3870 /* We are busy-waiting for the mouse to move, so let's be nice
3871 to other Windows applications by releasing our time slice. */
3874 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3876 /* Only leave if user both pressed and released the mouse, and in
3877 that order. This avoids popping down the menu pane unless
3878 the user is really done with it. */
3879 if (mouse_pressed (b
, &x
, &y
))
3881 while (mouse_button_depressed (b
, &x
, &y
))
3885 (void) mouse_released (b
, &x
, &y
);
3890 ScreenUpdate (state
[0].screen_behind
);
3891 if (screen_virtual_segment
)
3892 dosv_refresh_virtual_screen (0, screen_size
);
3894 /* We have a situation here. ScreenUpdate has just restored the
3895 screen contents as it was before we started drawing this menu.
3896 That includes any echo area message that could have been
3897 displayed back then. (In reality, that echo area message will
3898 almost always be the ``keystroke echo'' that echoes the sequence
3899 of menu items chosen by the user.) However, if the menu had some
3900 help messages, then displaying those messages caused Emacs to
3901 forget about the original echo area message. So when
3902 ScreenUpdate restored it, it created a discrepancy between the
3903 actual screen contents and what Emacs internal data structures
3906 To avoid this conflict, we force Emacs to restore the original
3907 echo area message as we found it when we entered this function.
3908 The irony of this is that we then erase the restored message
3909 right away, so the only purpose of restoring it is so that
3910 erasing it works correctly... */
3911 if (! NILP (saved_echo_area_message
))
3912 message_with_string ("%s", saved_echo_area_message
, 0);
3914 while (statecount
--)
3915 xfree (state
[statecount
].screen_behind
);
3916 IT_display_cursor (1); /* turn cursor back on */
3917 /* Clean up any mouse events that are waiting inside Emacs event queue.
3918 These events are likely to be generated before the menu was even
3919 displayed, probably because the user pressed and released the button
3920 (which invoked the menu) too quickly. If we don't remove these events,
3921 Emacs will process them after we return and surprise the user. */
3922 discard_mouse_events ();
3923 mouse_clear_clicks ();
3924 if (!kbd_buffer_events_waiting (1))
3925 clear_input_pending ();
3926 /* Allow mouse events generation by dos_rawgetc. */
3931 /* Dispose of a menu. */
3934 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3937 if (menu
->allocated
)
3939 for (i
= 0; i
< menu
->count
; i
++)
3940 if (menu
->submenu
[i
])
3941 XMenuDestroy (foo
, menu
->submenu
[i
]);
3943 xfree (menu
->submenu
);
3944 xfree (menu
->panenumber
);
3945 xfree (menu
->help_text
);
3948 menu_help_message
= prev_menu_help_message
= NULL
;
3952 x_pixel_width (struct frame
*f
)
3954 return FRAME_COLS (f
);
3958 x_pixel_height (struct frame
*f
)
3960 return FRAME_LINES (f
);
3962 #endif /* !HAVE_X_WINDOWS */
3964 /* ----------------------- DOS / UNIX conversion --------------------- */
3966 void msdos_downcase_filename (unsigned char *);
3968 /* Destructively turn backslashes into slashes. */
3971 dostounix_filename (p
)
3974 msdos_downcase_filename (p
);
3984 /* Destructively turn slashes into backslashes. */
3987 unixtodos_filename (p
)
3990 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4004 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4007 getdefdir (drive
, dst
)
4011 char in_path
[4], *p
= in_path
, e
= errno
;
4013 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4016 *p
++ = drive
+ 'A' - 1;
4023 _fixpath (in_path
, dst
);
4024 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4025 it queries the LFN support, so ignore that error. */
4026 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
4029 msdos_downcase_filename (dst
);
4036 emacs_root_dir (void)
4038 static char root_dir
[4];
4040 sprintf (root_dir
, "%c:/", 'A' + getdisk ());
4041 root_dir
[0] = tolower (root_dir
[0]);
4045 /* Remove all CR's that are followed by a LF. */
4050 register unsigned char *buf
;
4052 unsigned char *np
= buf
, *startp
= buf
, *endp
= buf
+ n
;
4056 while (buf
< endp
- 1)
4060 if (*(++buf
) != 0x0a)
4071 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4073 /* In DJGPP v2.0, library `write' can call `malloc', which might
4074 cause relocation of the buffer whose address we get in ADDR.
4075 Here is a version of `write' that avoids calling `malloc',
4076 to serve us until such time as the library is fixed.
4077 Actually, what we define here is called `__write', because
4078 `write' is a stub that just jmp's to `__write' (to be
4079 POSIXLY-correct with respect to the global name-space). */
4081 #include <io.h> /* for _write */
4082 #include <libc/dosio.h> /* for __file_handle_modes[] */
4084 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
4086 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4089 __write (int handle
, const void *buffer
, size_t count
)
4094 if(__file_handle_modes
[handle
] & O_BINARY
)
4095 return _write (handle
, buffer
, count
);
4099 const char *bp
= buffer
;
4100 int total_written
= 0;
4101 int nmoved
= 0, ncr
= 0;
4105 /* The next test makes sure there's space for at least 2 more
4106 characters in xbuf[], so both CR and LF can be put there. */
4118 if (xbp
>= XBUF_END
|| !count
)
4120 size_t to_write
= nmoved
+ ncr
;
4121 int written
= _write (handle
, xbuf
, to_write
);
4126 total_written
+= nmoved
; /* CRs aren't counted in ret value */
4128 /* If some, but not all were written (disk full?), return
4129 an estimate of the total written bytes not counting CRs. */
4130 if (written
< to_write
)
4131 return total_written
- (to_write
- written
) * nmoved
/to_write
;
4138 return total_written
;
4142 /* A low-level file-renaming function which works around Windows 95 bug.
4143 This is pulled directly out of DJGPP v2.01 library sources, and only
4144 used when you compile with DJGPP v2.0. */
4148 int _rename(const char *old
, const char *new)
4151 int olen
= strlen(old
) + 1;
4153 int use_lfn
= _USE_LFN
;
4154 char tempfile
[FILENAME_MAX
];
4155 const char *orig
= old
;
4158 r
.x
.dx
= __tb_offset
;
4159 r
.x
.di
= __tb_offset
+ olen
;
4160 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4164 /* Windows 95 bug: for some filenames, when you rename
4165 file -> file~ (as in Emacs, to leave a backup), the
4166 short 8+3 alias doesn't change, which effectively
4167 makes OLD and NEW the same file. We must rename
4168 through a temporary file to work around this. */
4170 char *pbase
= 0, *p
;
4171 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4172 int idx
= sizeof(try_char
) - 1;
4174 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4175 might point to another drive, which will fail the DOS call. */
4176 strcpy(tempfile
, old
);
4177 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4178 if (*p
== '/' || *p
== '\\' || *p
== ':')
4184 strcpy(pbase
, "X$$djren$$.$$temp$$");
4190 *pbase
= try_char
[--idx
];
4191 } while (_chmod(tempfile
, 0) != -1);
4194 _put_path2(tempfile
, olen
);
4196 __dpmi_int(0x21, &r
);
4199 errno
= __doserr_to_errno(r
.x
.ax
);
4203 /* Now create a file with the original name. This will
4204 ensure that NEW will always have a 8+3 alias
4205 different from that of OLD. (Seems to be required
4206 when NameNumericTail in the Registry is set to 0.) */
4207 lfn_fd
= _creat(old
, 0);
4209 olen
= strlen(tempfile
) + 1;
4211 r
.x
.di
= __tb_offset
+ olen
;
4220 _put_path2(new, olen
);
4222 __dpmi_int(0x21, &r
);
4225 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4226 remove(new); /* and try again */
4229 errno
= __doserr_to_errno(r
.x
.ax
);
4231 /* Restore to original name if we renamed it to temporary. */
4239 _put_path2(orig
, olen
);
4240 _put_path(tempfile
);
4242 __dpmi_int(0x21, &r
);
4251 /* Success. Delete the file possibly created to work
4252 around the Windows 95 bug. */
4254 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4258 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4260 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4262 doc
: /* Return non-nil if long file names are supported on MS-DOS. */)
4265 return (_USE_LFN
? Qt
: Qnil
);
4268 /* Convert alphabetic characters in a filename to lower-case. */
4271 msdos_downcase_filename (p
)
4272 register unsigned char *p
;
4274 /* Always lower-case drive letters a-z, even if the filesystem
4275 preserves case in filenames.
4276 This is so MSDOS filenames could be compared by string comparison
4277 functions that are case-sensitive. Even case-preserving filesystems
4278 do not distinguish case in drive letters. */
4279 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4285 /* Under LFN we expect to get pathnames in their true case. */
4286 if (NILP (Fmsdos_long_file_names ()))
4288 if (*p
>= 'A' && *p
<= 'Z')
4292 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4294 doc
: /* Convert alphabetic characters in FILENAME to lower case and return that.
4295 When long filenames are supported, doesn't change FILENAME.
4296 If FILENAME is not a string, returns nil.
4297 The argument object is never altered--the value is a copy. */)
4299 Lisp_Object filename
;
4303 if (! STRINGP (filename
))
4306 tem
= Fcopy_sequence (filename
);
4307 msdos_downcase_filename (SDATA (tem
));
4311 /* The Emacs root directory as determined by init_environment. */
4313 static char emacsroot
[MAXPATHLEN
];
4316 rootrelativepath (rel
)
4319 static char result
[MAXPATHLEN
+ 10];
4321 strcpy (result
, emacsroot
);
4322 strcat (result
, "/");
4323 strcat (result
, rel
);
4327 /* Define a lot of environment variables if not already defined. Don't
4328 remove anything unless you know what you're doing -- lots of code will
4329 break if one or more of these are missing. */
4332 init_environment (argc
, argv
, skip_args
)
4339 static const char * const tempdirs
[] = {
4340 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4342 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4344 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4345 temporary files and assume "/tmp" if $TMPDIR is unset, which
4346 will break on DOS/Windows. Refuse to work if we cannot find
4347 a directory, not even "c:/", usable for that purpose. */
4348 for (i
= 0; i
< imax
; i
++)
4350 const char *tmp
= tempdirs
[i
];
4351 char buf
[FILENAME_MAX
];
4357 tmp
= getenv (tmp
+ 1);
4361 /* Some lusers set TMPDIR=e:, probably because some losing
4362 programs cannot handle multiple slashes if they use e:/.
4363 e: fails in `access' below, so we interpret e: as e:/. */
4364 tmp_len
= strlen(tmp
);
4365 if (tmp
[tmp_len
- 1] != '/' && tmp
[tmp_len
- 1] != '\\')
4368 buf
[tmp_len
++] = '/', buf
[tmp_len
] = 0;
4373 /* Note that `access' can lie to us if the directory resides on a
4374 read-only filesystem, like CD-ROM or a write-protected floppy.
4375 The only way to be really sure is to actually create a file and
4376 see if it succeeds. But I think that's too much to ask. */
4377 if (tmp
&& access (tmp
, D_OK
) == 0)
4379 setenv ("TMPDIR", tmp
, 1);
4386 Fcons (build_string ("no usable temporary directories found!!"),
4388 "While setting TMPDIR: ");
4390 /* Note the startup time, so we know not to clear the screen if we
4391 exit immediately; see IT_reset_terminal_modes.
4392 (Yes, I know `clock' returns zero the first time it's called, but
4393 I do this anyway, in case some wiseguy changes that at some point.) */
4394 startup_time
= clock ();
4396 /* Find our root from argv[0]. Assuming argv[0] is, say,
4397 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4398 root
= alloca (MAXPATHLEN
+ 20);
4399 _fixpath (argv
[0], root
);
4400 msdos_downcase_filename (root
);
4401 len
= strlen (root
);
4402 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4406 && (strcmp (root
+ len
- 4, "/bin") == 0
4407 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4408 root
[len
- 4] = '\0';
4410 strcpy (root
, "c:/emacs"); /* let's be defensive */
4411 len
= strlen (root
);
4412 strcpy (emacsroot
, root
);
4414 /* We default HOME to our root. */
4415 setenv ("HOME", root
, 0);
4417 /* We default EMACSPATH to root + "/bin". */
4418 strcpy (root
+ len
, "/bin");
4419 setenv ("EMACSPATH", root
, 0);
4421 /* I don't expect anybody to ever use other terminals so the internal
4422 terminal is the default. */
4423 setenv ("TERM", "internal", 0);
4425 #ifdef HAVE_X_WINDOWS
4426 /* Emacs expects DISPLAY to be set. */
4427 setenv ("DISPLAY", "unix:0.0", 0);
4430 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4431 downcase it and mirror the backslashes. */
4432 s
= getenv ("COMSPEC");
4433 if (!s
) s
= "c:/command.com";
4434 t
= alloca (strlen (s
) + 1);
4436 dostounix_filename (t
);
4437 setenv ("SHELL", t
, 0);
4439 /* PATH is also downcased and backslashes mirrored. */
4440 s
= getenv ("PATH");
4442 t
= alloca (strlen (s
) + 3);
4443 /* Current directory is always considered part of MsDos's path but it is
4444 not normally mentioned. Now it is. */
4445 strcat (strcpy (t
, ".;"), s
);
4446 dostounix_filename (t
); /* Not a single file name, but this should work. */
4447 setenv ("PATH", t
, 1);
4449 /* In some sense all dos users have root privileges, so... */
4450 setenv ("USER", "root", 0);
4451 setenv ("NAME", getenv ("USER"), 0);
4453 /* Time zone determined from country code. To make this possible, the
4454 country code may not span more than one time zone. In other words,
4455 in the USA, you lose. */
4457 switch (dos_country_code
)
4459 case 31: /* Belgium */
4460 case 32: /* The Netherlands */
4461 case 33: /* France */
4462 case 34: /* Spain */
4463 case 36: /* Hungary */
4464 case 38: /* Yugoslavia (or what's left of it?) */
4465 case 39: /* Italy */
4466 case 41: /* Switzerland */
4467 case 42: /* Tjekia */
4468 case 45: /* Denmark */
4469 case 46: /* Sweden */
4470 case 47: /* Norway */
4471 case 48: /* Poland */
4472 case 49: /* Germany */
4473 /* Daylight saving from last Sunday in March to last Sunday in
4474 September, both at 2AM. */
4475 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4477 case 44: /* United Kingdom */
4478 case 351: /* Portugal */
4479 case 354: /* Iceland */
4480 setenv ("TZ", "GMT+00", 0);
4482 case 81: /* Japan */
4483 case 82: /* Korea */
4484 setenv ("TZ", "JST-09", 0);
4486 case 90: /* Turkey */
4487 case 358: /* Finland */
4488 setenv ("TZ", "EET-02", 0);
4490 case 972: /* Israel */
4491 /* This is an approximation. (For exact rules, use the
4492 `zoneinfo/israel' file which comes with DJGPP, but you need
4493 to install it in `/usr/share/zoneinfo/' directory first.) */
4494 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4502 static int break_stat
; /* BREAK check mode status. */
4503 static int stdin_stat
; /* stdin IOCTL status. */
4507 /* These must be global. */
4508 static _go32_dpmi_seginfo ctrl_break_vector
;
4509 static _go32_dpmi_registers ctrl_break_regs
;
4510 static int ctrlbreakinstalled
= 0;
4512 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4515 ctrl_break_func (regs
)
4516 _go32_dpmi_registers
*regs
;
4522 install_ctrl_break_check ()
4524 if (!ctrlbreakinstalled
)
4526 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4527 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4528 ctrlbreakinstalled
= 1;
4529 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4530 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4532 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4536 #endif /* __DJGPP__ < 2 */
4538 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4539 control chars by DOS. Determine the keyboard type. */
4542 dos_ttraw (struct tty_display_info
*tty
)
4544 union REGS inregs
, outregs
;
4545 static int first_time
= 1;
4547 /* If we are called for the initial terminal, it's too early to do
4548 anything, and termscript isn't set up. */
4549 if (tty
->terminal
->type
== output_initial
)
4552 break_stat
= getcbrk ();
4555 install_ctrl_break_check ();
4561 int86 (0x15, &inregs
, &outregs
);
4562 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4567 #ifdef HAVE_X_WINDOWS
4568 && inhibit_window_system
4572 inregs
.x
.ax
= 0x0021;
4573 int86 (0x33, &inregs
, &outregs
);
4574 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4577 /* Reportedly, the above doesn't work for some mouse drivers. There
4578 is an additional detection method that should work, but might be
4579 a little slower. Use that as an alternative. */
4580 inregs
.x
.ax
= 0x0000;
4581 int86 (0x33, &inregs
, &outregs
);
4582 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4585 mouse_button_count
= outregs
.x
.bx
;
4587 #ifndef HAVE_X_WINDOWS
4589 /* Save the cursor shape used outside Emacs. */
4590 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4599 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4600 return (stdin_stat
!= -1);
4603 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4605 #else /* __DJGPP__ < 2 */
4609 /* I think it is wrong to overwrite `stdin_stat' every time
4610 but the first one this function is called, but I don't
4611 want to change the way it used to work in v1.x.--EZ */
4613 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4614 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4615 intdos (&inregs
, &outregs
);
4616 stdin_stat
= outregs
.h
.dl
;
4618 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4619 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4620 intdos (&inregs
, &outregs
);
4621 return !outregs
.x
.cflag
;
4623 #endif /* __DJGPP__ < 2 */
4626 /* Restore status of standard input and Ctrl-C checking. */
4631 union REGS inregs
, outregs
;
4633 setcbrk (break_stat
);
4638 #ifndef HAVE_X_WINDOWS
4639 /* Restore the cursor shape we found on startup. */
4643 inregs
.x
.cx
= outside_cursor
;
4644 int86 (0x10, &inregs
, &outregs
);
4648 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4650 #else /* not __DJGPP__ >= 2 */
4652 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4653 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4654 inregs
.x
.dx
= stdin_stat
;
4655 intdos (&inregs
, &outregs
);
4656 return !outregs
.x
.cflag
;
4658 #endif /* not __DJGPP__ >= 2 */
4662 /* Run command as specified by ARGV in directory DIR.
4663 The command is run with input from TEMPIN, output to
4664 file TEMPOUT and stderr to TEMPERR. */
4667 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4668 unsigned char **argv
;
4669 const char *working_dir
;
4670 int tempin
, tempout
, temperr
;
4673 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4674 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4675 int msshell
, result
= -1, inbak
, outbak
, errbak
, x
, y
;
4678 /* Get current directory as MSDOS cwd is not per-process. */
4681 /* If argv[0] is the shell, it might come in any lettercase.
4682 Since `Fmember' is case-sensitive, we need to downcase
4683 argv[0], even if we are on case-preserving filesystems. */
4684 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4685 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4688 if (*pl
>= 'A' && *pl
<= 'Z')
4693 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4694 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4695 && !strcmp ("-c", argv
[1]);
4698 saveargv1
= argv
[1];
4699 saveargv2
= argv
[2];
4701 /* We only need to mirror slashes if a DOS shell will be invoked
4702 not via `system' (which does the mirroring itself). Yes, that
4703 means DJGPP v1.x will lose here. */
4704 if (argv
[2] && argv
[3])
4706 char *p
= alloca (strlen (argv
[2]) + 1);
4708 strcpy (argv
[2] = p
, saveargv2
);
4709 while (*p
&& isspace (*p
))
4721 chdir (working_dir
);
4725 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4726 goto done
; /* Allocation might fail due to lack of descriptors. */
4729 mouse_get_xy (&x
, &y
);
4731 if (!noninteractive
)
4732 dos_ttcooked (); /* do it here while 0 = stdin */
4740 if (msshell
&& !argv
[3])
4742 /* MS-DOS native shells are too restrictive. For starters, they
4743 cannot grok commands longer than 126 characters. In DJGPP v2
4744 and later, `system' is much smarter, so we'll call it instead. */
4748 /* A shell gets a single argument--its full command
4749 line--whose original was saved in `saveargv2'. */
4751 /* Don't let them pass empty command lines to `system', since
4752 with some shells it will try to invoke an interactive shell,
4753 which will hang Emacs. */
4754 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4758 extern char **environ
;
4759 char **save_env
= environ
;
4760 int save_system_flags
= __system_flags
;
4762 /* Request the most powerful version of `system'. We need
4763 all the help we can get to avoid calling stock DOS shells. */
4764 __system_flags
= (__system_redirect
4765 | __system_use_shell
4766 | __system_allow_multiple_cmds
4767 | __system_allow_long_cmds
4768 | __system_handle_null_commands
4769 | __system_emulate_chdir
);
4772 result
= system (cmnd
);
4773 __system_flags
= save_system_flags
;
4777 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4781 #endif /* __DJGPP__ > 1 */
4783 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4788 emacs_close (inbak
);
4789 emacs_close (outbak
);
4790 emacs_close (errbak
);
4792 if (!noninteractive
)
4793 dos_ttraw (CURTTY ());
4797 mouse_moveto (x
, y
);
4800 /* Some programs might change the meaning of the highest bit of the
4801 text attribute byte, so we get blinking characters instead of the
4802 bright background colors. Restore that. */
4803 if (!noninteractive
)
4810 argv
[1] = saveargv1
;
4811 argv
[2] = saveargv2
;
4820 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4821 reset_all_sys_modes ();
4827 /* ------------------------- Compatibility functions -------------------
4832 /* Hostnames for a pc are not really funny,
4833 but they are used in change log so we emulate the best we can. */
4835 gethostname (p
, size
)
4839 char *q
= egetenv ("HOSTNAME");
4846 /* When time zones are set from Ms-Dos too many C-libraries are playing
4847 tricks with time values. We solve this by defining our own version
4848 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4849 once and after each call to `tzset' with TZ changed. That is
4850 accomplished by aliasing tzset to init_gettimeofday. */
4852 static struct tm time_rec
;
4855 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4863 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4867 time_rec
.tm_year
= d
.da_year
- 1900;
4868 time_rec
.tm_mon
= d
.da_mon
- 1;
4869 time_rec
.tm_mday
= d
.da_day
;
4872 time_rec
.tm_hour
= t
.ti_hour
;
4873 time_rec
.tm_min
= t
.ti_min
;
4874 time_rec
.tm_sec
= t
.ti_sec
;
4877 tm
.tm_gmtoff
= dos_timezone_offset
;
4879 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4880 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4882 /* Ignore tzp; it's obsolescent. */
4886 #endif /* __DJGPP__ < 2 */
4889 * A list of unimplemented functions that we silently ignore.
4893 unsigned alarm (s
) unsigned s
; {}
4894 fork () { return 0; }
4895 int kill (x
, y
) int x
, y
; { return -1; }
4897 void volatile pause () {}
4898 sigsetmask (x
) int x
; { return 0; }
4899 sigblock (mask
) int mask
; { return 0; }
4902 setpgrp () {return 0; }
4903 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4906 #if __DJGPP_MINOR__ < 2
4908 #ifdef POSIX_SIGNALS
4910 /* Augment DJGPP library POSIX signal functions. This is needed
4911 as of DJGPP v2.01, but might be in the library in later releases. */
4913 #include <libc/bss.h>
4915 /* A counter to know when to re-initialize the static sets. */
4916 static int sigprocmask_count
= -1;
4918 /* Which signals are currently blocked (initially none). */
4919 static sigset_t current_mask
;
4921 /* Which signals are pending (initially none). */
4922 static sigset_t msdos_pending_signals
;
4924 /* Previous handlers to restore when the blocked signals are unblocked. */
4925 typedef void (*sighandler_t
)(int);
4926 static sighandler_t prev_handlers
[320];
4928 /* A signal handler which just records that a signal occurred
4929 (it will be raised later, if and when the signal is unblocked). */
4931 sig_suspender (signo
)
4934 sigaddset (&msdos_pending_signals
, signo
);
4938 sigprocmask (how
, new_set
, old_set
)
4940 const sigset_t
*new_set
;
4946 /* If called for the first time, initialize. */
4947 if (sigprocmask_count
!= __bss_count
)
4949 sigprocmask_count
= __bss_count
;
4950 sigemptyset (&msdos_pending_signals
);
4951 sigemptyset (¤t_mask
);
4952 for (signo
= 0; signo
< 320; signo
++)
4953 prev_handlers
[signo
] = SIG_ERR
;
4957 *old_set
= current_mask
;
4962 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4968 sigemptyset (&new_mask
);
4970 /* DJGPP supports upto 320 signals. */
4971 for (signo
= 0; signo
< 320; signo
++)
4973 if (sigismember (¤t_mask
, signo
))
4974 sigaddset (&new_mask
, signo
);
4975 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4977 sigaddset (&new_mask
, signo
);
4979 /* SIGKILL is silently ignored, as on other platforms. */
4980 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4981 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4983 if (( how
== SIG_UNBLOCK
4984 && sigismember (&new_mask
, signo
)
4985 && sigismember (new_set
, signo
))
4986 || (how
== SIG_SETMASK
4987 && sigismember (&new_mask
, signo
)
4988 && !sigismember (new_set
, signo
)))
4990 sigdelset (&new_mask
, signo
);
4991 if (prev_handlers
[signo
] != SIG_ERR
)
4993 signal (signo
, prev_handlers
[signo
]);
4994 prev_handlers
[signo
] = SIG_ERR
;
4996 if (sigismember (&msdos_pending_signals
, signo
))
4998 sigdelset (&msdos_pending_signals
, signo
);
5003 current_mask
= new_mask
;
5007 #else /* not POSIX_SIGNALS */
5009 sigsetmask (x
) int x
; { return 0; }
5010 sigblock (mask
) int mask
; { return 0; }
5012 #endif /* not POSIX_SIGNALS */
5013 #endif /* not __DJGPP_MINOR__ < 2 */
5014 #endif /* __DJGPP__ > 1 */
5017 #include "sysselect.h"
5019 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5020 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5021 ((long)(time).tv_sec < 0 \
5022 || ((time).tv_sec == 0 \
5023 && (long)(time).tv_usec <= 0))
5026 /* This yields the rest of the current time slice to the task manager.
5027 It should be called by any code which knows that it has nothing
5028 useful to do except idle.
5030 I don't use __dpmi_yield here, since versions of library before 2.02
5031 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5032 on some versions of Windows 9X. */
5035 dos_yield_time_slice (void)
5037 _go32_dpmi_registers r
;
5040 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
5041 _go32_dpmi_simulate_int (0x2f, &r
);
5046 /* Only event queue is checked. */
5047 /* We don't have to call timer_check here
5048 because wait_reading_process_output takes care of that. */
5050 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5052 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5053 EMACS_TIME
*timeout
;
5061 check_input
= FD_ISSET (0, rfds
);
5072 /* If we are looking only for the terminal, with no timeout,
5073 just read it and wait -- that's more efficient. */
5076 while (!detect_input_pending ())
5078 dos_yield_time_slice ();
5083 EMACS_TIME clnow
, cllast
, cldiff
;
5086 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
5088 while (!check_input
|| !detect_input_pending ())
5091 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
5092 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
5094 /* When seconds wrap around, we assume that no more than
5095 1 minute passed since last `gettime'. */
5096 if (EMACS_TIME_NEG_P (cldiff
))
5097 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
5098 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
5100 /* Stop when timeout value crosses zero. */
5101 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
5104 dos_yield_time_slice ();
5114 * Define overlaid functions:
5116 * chdir -> sys_chdir
5117 * tzset -> init_gettimeofday
5118 * abort -> dos_abort
5123 extern int chdir ();
5129 int len
= strlen (path
);
5130 char *tmp
= (char *)path
;
5132 if (*tmp
&& tmp
[1] == ':')
5134 if (getdisk () != tolower (tmp
[0]) - 'a')
5135 setdisk (tolower (tmp
[0]) - 'a');
5136 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
5140 if (len
> 1 && (tmp
[len
- 1] == '/'))
5142 char *tmp1
= (char *) alloca (len
+ 1);
5153 extern void tzset (void);
5156 init_gettimeofday ()
5162 ltm
= gtm
= time (NULL
);
5163 ltm
= mktime (lstm
= localtime (<m
));
5164 gtm
= mktime (gmtime (>m
));
5165 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
5166 time_rec
.tm_isdst
= lstm
->tm_isdst
;
5167 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
5174 dos_abort (file
, line
)
5178 char buffer1
[200], buffer2
[400];
5181 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5182 for (i
= j
= 0; buffer1
[i
]; i
++) {
5183 buffer2
[j
++] = buffer1
[i
];
5184 buffer2
[j
++] = 0x70;
5186 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5187 ScreenSetCursor (2, 0);
5195 ScreenSetCursor (10, 0);
5196 cputs ("\r\n\nEmacs aborted!\r\n");
5198 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5199 if (screen_virtual_segment
)
5200 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5201 /* Generate traceback, so we could tell whodunit. */
5202 signal (SIGINT
, SIG_DFL
);
5203 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5204 #else /* __DJGPP_MINOR__ >= 2 */
5206 #endif /* __DJGPP_MINOR__ >= 2 */
5212 /* The following variables are required so that cus-start.el won't
5213 complain about unbound variables. */
5214 #ifndef subprocesses
5215 /* Nonzero means delete a process right away if it exits (process.c). */
5216 static int delete_exited_processes
;
5221 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5222 staticpro (&recent_doskeys
);
5224 #ifndef HAVE_X_WINDOWS
5226 /* The following two are from xfns.c: */
5227 Qreverse
= intern ("reverse");
5228 staticpro (&Qreverse
);
5230 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5231 doc
: /* *Glyph to display instead of chars not supported by current codepage.
5232 This variable is used only by MS-DOS terminals. */);
5233 Vdos_unsupported_char_glyph
= make_number ('\177');
5236 #ifndef subprocesses
5237 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5238 doc
: /* *Non-nil means delete processes immediately when they exit.
5239 A value of nil means don't delete them until `list-processes' is run. */);
5240 delete_exited_processes
= 0;
5243 defsubr (&Srecent_doskeys
);
5244 defsubr (&Smsdos_long_file_names
);
5245 defsubr (&Smsdos_downcase_filename
);
5246 defsubr (&Smsdos_remember_default_colors
);
5247 defsubr (&Smsdos_set_mouse_buttons
);
5252 /* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30
5253 (do not change this comment) */