1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 94, 95, 96, 97, 1999 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
33 #include <sys/param.h>
37 #include <string.h> /* for bzero and string functions */
38 #include <sys/stat.h> /* for _fixpath */
39 #include <unistd.h> /* for chdir, dup, dup2, etc. */
42 #include <io.h> /* for setmode */
43 #include <dpmi.h> /* for __dpmi_xxx stuff */
44 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
45 #include <libc/dosio.h> /* for _USE_LFN */
46 #include <conio.h> /* for cputs */
51 #include "termhooks.h"
53 #include "dispextern.h"
63 #include "blockinput.h"
68 /* #include <process.h> */
69 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
77 #define _dos_ds _go32_info_block.selector_for_linear_memory
83 #include "syssignal.h"
89 /* If other `malloc' than ours is used, force our `sbrk' behave like
90 Unix programs expect (resize memory blocks to keep them contiguous).
91 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
92 because that's what `gmalloc' expects to get. */
96 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
97 #else /* not REL_ALLOC */
98 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
99 #endif /* not REL_ALLOC */
100 #endif /* GNU_MALLOC */
102 #endif /* not SYSTEM_MALLOC */
103 #endif /* __DJGPP__ > 1 */
122 /* ------------------------ Mouse control ---------------------------
124 * Coordinates are in screen positions and zero based.
125 * Mouse buttons are numbered from left to right and also zero based.
128 /* This used to be in termhooks.h, but mainstream Emacs code no longer
129 uses it, and it was removed... */
130 #define NUM_MOUSE_BUTTONS (5)
132 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
133 static int mouse_visible
;
135 static int mouse_last_x
;
136 static int mouse_last_y
;
138 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
139 static int mouse_button_count
;
146 if (have_mouse
> 0 && !mouse_visible
)
149 fprintf (termscript
, "<M_ON>");
151 int86 (0x33, ®s
, ®s
);
161 if (have_mouse
> 0 && mouse_visible
)
164 fprintf (termscript
, "<M_OFF>");
166 int86 (0x33, ®s
, ®s
);
172 mouse_setup_buttons (int n_buttons
)
176 mouse_button_count
= 3;
177 mouse_button_translate
[0] = 0; /* Left */
178 mouse_button_translate
[1] = 2; /* Middle */
179 mouse_button_translate
[2] = 1; /* Right */
181 else /* two, what else? */
183 mouse_button_count
= 2;
184 mouse_button_translate
[0] = 0;
185 mouse_button_translate
[1] = 1;
189 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons
, Smsdos_set_mouse_buttons
,
190 1, 1, "NSet number of mouse buttons to: ",
191 "Set the number of mouse buttons to use by Emacs.\n\
192 This is useful with mice that report the number of buttons inconsistently,\n\
193 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of\n\
194 them. This happens with wheeled mice on Windows 9X, for example.")
196 Lisp_Object nbuttons
;
200 CHECK_NUMBER (nbuttons
, 0);
203 Fsignal (Qargs_out_of_range
,
204 Fcons (build_string ("only 2 or 3 mouse buttons are supported"),
205 Fcons (nbuttons
, Qnil
)));
206 mouse_setup_buttons (n
);
211 mouse_get_xy (int *x
, int *y
)
216 int86 (0x33, ®s
, ®s
);
228 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
230 mouse_last_x
= regs
.x
.cx
= x
* 8;
231 mouse_last_y
= regs
.x
.dx
= y
* 8;
232 int86 (0x33, ®s
, ®s
);
236 mouse_pressed (b
, xp
, yp
)
241 if (b
>= mouse_button_count
)
244 regs
.x
.bx
= mouse_button_translate
[b
];
245 int86 (0x33, ®s
, ®s
);
247 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
248 return (regs
.x
.bx
!= 0);
252 mouse_released (b
, xp
, yp
)
257 if (b
>= mouse_button_count
)
260 regs
.x
.bx
= mouse_button_translate
[b
];
261 int86 (0x33, ®s
, ®s
);
263 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
264 return (regs
.x
.bx
!= 0);
268 mouse_button_depressed (b
, xp
, yp
)
273 if (b
>= mouse_button_count
)
276 int86 (0x33, ®s
, ®s
);
277 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
287 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
290 Lisp_Object
*bar_window
, *x
, *y
;
291 enum scroll_bar_part
*part
;
295 Lisp_Object frame
, tail
;
297 /* Clear the mouse-moved flag for every frame on this display. */
298 FOR_EACH_FRAME (tail
, frame
)
299 XFRAME (frame
)->mouse_moved
= 0;
301 *f
= SELECTED_FRAME();
303 mouse_get_xy (&ix
, &iy
);
304 *time
= event_timestamp ();
305 *x
= make_number (mouse_last_x
= ix
);
306 *y
= make_number (mouse_last_y
= iy
);
314 mouse_get_xy (&x
, &y
);
315 SELECTED_FRAME()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
320 /* Force the mouse driver to ``forget'' about any button clicks until
323 mouse_clear_clicks (void)
327 for (b
= 0; b
< mouse_button_count
; b
++)
329 int dummy_x
, dummy_y
;
331 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
332 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
342 fprintf (termscript
, "<M_INIT>");
345 int86 (0x33, ®s
, ®s
);
347 /* Reset the mouse last press/release info. It seems that Windows
348 doesn't do that automatically when function 21h is called, which
349 causes Emacs to ``remember'' the click that switched focus to the
350 window just before Emacs was started from that window. */
351 mouse_clear_clicks ();
355 regs
.x
.dx
= 8 * (ScreenCols () - 1);
356 int86 (0x33, ®s
, ®s
);
360 regs
.x
.dx
= 8 * (ScreenRows () - 1);
361 int86 (0x33, ®s
, ®s
);
367 /* ------------------------- Screen control ----------------------
371 static int internal_terminal
= 0;
373 #ifndef HAVE_X_WINDOWS
374 extern unsigned char ScreenAttrib
;
375 static int screen_face
;
376 static int highlight
;
378 static int screen_size_X
;
379 static int screen_size_Y
;
380 static int screen_size
;
382 static int current_pos_X
;
383 static int current_pos_Y
;
384 static int new_pos_X
;
385 static int new_pos_Y
;
387 static void *startup_screen_buffer
;
388 static int startup_screen_size_X
;
389 static int startup_screen_size_Y
;
390 static int startup_pos_X
;
391 static int startup_pos_Y
;
392 static unsigned char startup_screen_attrib
;
394 static clock_t startup_time
;
396 static int term_setup_done
;
398 static unsigned short outside_cursor
;
400 /* Similar to the_only_frame. */
401 struct x_output the_only_x_display
;
403 /* Support for DOS/V (allows Japanese characters to be displayed on
404 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
406 /* Holds the address of the text-mode screen buffer. */
407 static unsigned long screen_old_address
= 0;
408 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
409 static unsigned short screen_virtual_segment
= 0;
410 static unsigned short screen_virtual_offset
= 0;
411 /* A flag to control how to display unibyte 8-bit characters. */
412 extern int unibyte_display_via_language_environment
;
417 /* Update the screen from a part of relocated DOS/V screen buffer which
418 begins at OFFSET and includes COUNT characters. */
420 dosv_refresh_virtual_screen (int offset
, int count
)
424 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
427 regs
.h
.ah
= 0xff; /* update relocated screen */
428 regs
.x
.es
= screen_virtual_segment
;
429 regs
.x
.di
= screen_virtual_offset
+ offset
;
431 __dpmi_int (0x10, ®s
);
436 dos_direct_output (y
, x
, buf
, len
)
442 int t0
= 2 * (x
+ y
* screen_size_X
);
443 int t
= t0
+ (int) ScreenPrimary
;
448 dosmemput (buf
++, 1, t
);
452 /* This is faster. */
453 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
454 _farnspokeb (t
, *buf
);
456 if (screen_virtual_segment
)
457 dosv_refresh_virtual_screen (t0
, l0
);
462 /* Flash the screen as a substitute for BEEPs. */
466 do_visible_bell (xorattr
)
467 unsigned char xorattr
;
472 movl _ScreenPrimary,%%eax
479 xorb %%al,%%gs:(%%ebx)
495 : "m" (xorattr
), "g" (screen_size
)
496 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
500 ScreenVisualBell (void)
502 /* This creates an xor-mask that will swap the default fore- and
503 background colors. */
504 do_visible_bell (((the_only_x_display
.foreground_pixel
505 ^ the_only_x_display
.background_pixel
)
510 #ifndef HAVE_X_WINDOWS
512 static int blink_bit
= -1; /* the state of the blink bit at startup */
514 /* Enable bright background colors. */
520 /* Remember the original state of the blink/bright-background bit.
521 It is stored at 0040:0065h in the BIOS data area. */
523 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
527 int86 (0x10, ®s
, ®s
);
530 /* Disable bright background colors (and enable blinking) if we found
531 the video system in that state at startup. */
533 maybe_enable_blinking (void)
541 int86 (0x10, ®s
, ®s
);
545 /* Return non-zero if the system has a VGA adapter. */
552 int86 (0x10, ®s
, ®s
);
553 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
558 /* Set the screen dimensions so that it can show no less than
559 ROWS x COLS frame. */
562 dos_set_window_size (rows
, cols
)
566 Lisp_Object video_mode
;
567 int video_mode_value
;
570 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
572 if (*rows
== current_rows
&& *cols
== current_cols
)
576 have_vga
= vga_installed ();
578 /* If the user specified a special video mode for these dimensions,
580 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
581 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
584 if (INTEGERP (video_mode
)
585 && (video_mode_value
= XINT (video_mode
)) > 0)
587 regs
.x
.ax
= video_mode_value
;
588 int86 (0x10, ®s
, ®s
);
592 /* Must hardware-reset the mouse, or else it won't update
593 its notion of screen dimensions for some non-standard
594 video modes. This is *painfully* slow... */
596 int86 (0x33, ®s
, ®s
);
600 /* Find one of the dimensions supported by standard EGA/VGA
601 which gives us at least the required dimensions. */
610 } std_dimension
[] = {
620 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
622 if (std_dimension
[i
].need_vga
<= have_vga
623 && std_dimension
[i
].rows
>= *rows
)
625 if (std_dimension
[i
].rows
!= current_rows
626 || *cols
!= current_cols
)
627 _set_screen_lines (std_dimension
[i
].rows
);
634 #else /* not __DJGPP__ > 1 */
636 else if (*rows
<= 25)
638 if (current_rows
!= 25 || current_cols
!= 80)
641 int86 (0x10, ®s
, ®s
);
644 int86 (0x10, ®s
, ®s
);
647 int86 (0x10, ®s
, ®s
);
649 int86 (0x10, ®s
, ®s
);
652 else if (*rows
<= 50)
653 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
654 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
657 int86 (0x10, ®s
, ®s
);
660 int86 (0x10, ®s
, ®s
);
663 int86 (0x10, ®s
, ®s
);
666 int86 (0x10, ®s
, ®s
);
668 #endif /* not __DJGPP__ > 1 */
676 /* Tell the caller what dimensions have been REALLY set. */
677 *rows
= ScreenRows ();
678 *cols
= ScreenCols ();
680 /* Update Emacs' notion of screen dimensions. */
681 screen_size_X
= *cols
;
682 screen_size_Y
= *rows
;
683 screen_size
= *cols
* *rows
;
686 /* If the dimensions changed, the mouse highlight info is invalid. */
687 if (current_rows
!= *rows
|| current_cols
!= *cols
)
689 struct frame
*f
= SELECTED_FRAME();
690 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
691 Lisp_Object window
= dpyinfo
->mouse_face_window
;
693 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
695 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
696 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
697 dpyinfo
->mouse_face_window
= Qnil
;
702 /* Enable bright background colors. */
705 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
706 be defensive anyway. */
707 if (screen_virtual_segment
)
708 dosv_refresh_virtual_screen (0, *cols
* *rows
);
711 /* If we write a character in the position where the mouse is,
712 the mouse cursor may need to be refreshed. */
722 mouse_get_xy (&x
, &y
);
723 if (y
!= new_pos_Y
|| x
< new_pos_X
)
729 #define DEFAULT_CURSOR_START (-1)
730 #define DEFAULT_CURSOR_WIDTH (-1)
731 #define BOX_CURSOR_WIDTH (-32)
733 /* Set cursor to begin at scan line START_LINE in the character cell
734 and extend for WIDTH scan lines. Scan lines are counted from top
735 of the character cell, starting from zero. */
737 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
740 unsigned desired_cursor
;
742 int max_line
, top_line
, bot_line
;
744 /* Avoid the costly BIOS call if F isn't the currently selected
745 frame. Allow for NULL as unconditionally meaning the selected
747 if (f
&& f
!= SELECTED_FRAME())
750 /* The character cell size in scan lines is stored at 40:85 in the
752 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
755 default: /* this relies on CGA cursor emulation being ON! */
772 if (width
== BOX_CURSOR_WIDTH
)
777 else if (start_line
!= DEFAULT_CURSOR_START
)
779 top_line
= start_line
;
780 bot_line
= top_line
- width
- 1;
782 else if (width
!= DEFAULT_CURSOR_WIDTH
)
785 bot_line
= -1 - width
;
788 top_line
= bot_line
+ 1;
792 /* [31, 0] seems to DTRT for all screen sizes. */
796 else /* WIDTH is positive */
798 if (start_line
!= DEFAULT_CURSOR_START
)
799 bot_line
= start_line
;
800 top_line
= bot_line
- (width
- 1);
803 /* If the current cursor shape is already what they want, we are
805 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
806 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
810 regs
.x
.cx
= desired_cursor
;
811 __dpmi_int (0x10, ®s
);
812 #endif /* __DJGPP__ > 1 */
816 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
818 if (EQ (cursor_type
, Qbar
))
820 /* Just BAR means the normal EGA/VGA cursor. */
821 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
823 else if (CONSP (cursor_type
) && EQ (XCAR (cursor_type
), Qbar
))
825 Lisp_Object bar_parms
= XCDR (cursor_type
);
828 if (INTEGERP (bar_parms
))
830 /* Feature: negative WIDTH means cursor at the top
831 of the character cell, zero means invisible cursor. */
832 width
= XINT (bar_parms
);
833 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
836 else if (CONSP (bar_parms
)
837 && INTEGERP (XCAR (bar_parms
))
838 && INTEGERP (XCDR (bar_parms
)))
840 int start_line
= XINT (XCDR (bar_parms
));
842 width
= XINT (XCAR (bar_parms
));
843 msdos_set_cursor_shape (f
, start_line
, width
);
847 /* Treat anything unknown as "box cursor". This includes nil, so
848 that a frame which doesn't specify a cursor type gets a box,
849 which is the default in Emacs. */
850 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
863 union REGS inregs
, outregs
;
866 intdos (&inregs
, &outregs
);
870 /* Given a face id FACE, extract the face parameters to be used for
871 display until the face changes. The face parameters (actually, its
872 color) are used to construct the video attribute byte for each
873 glyph during the construction of the buffer that is then blitted to
876 IT_set_face (int face
)
878 struct frame
*sf
= SELECTED_FRAME();
879 struct face
*fp
= FACE_FROM_ID (sf
, face
);
880 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
881 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
886 /* The default face for the frame should always be realized and
894 dflt_fg
= dfp
->foreground
;
895 dflt_bg
= dfp
->background
;
897 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_*
898 colors mean use the colors of the default face, except that if
899 highlight is on, invert the foreground and the background. Note
900 that we assume all 16 colors to be available for the background,
901 since Emacs switches on this mode (and loses the blinking
902 attribute) at startup. */
903 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
904 fg
= FRAME_FOREGROUND_PIXEL (sf
);
905 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
906 fg
= FRAME_BACKGROUND_PIXEL (sf
);
907 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
908 bg
= FRAME_BACKGROUND_PIXEL (sf
);
909 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
910 bg
= FRAME_FOREGROUND_PIXEL (sf
);
912 /* Make sure highlighted lines really stand out, come what may. */
913 if ((highlight
|| fp
->tty_reverse_p
)
914 && (fg
== dflt_fg
&& bg
== dflt_bg
))
916 unsigned long tem
= fg
;
921 /* If the user requested inverse video, obey. */
924 unsigned long tem2
= fg
;
930 fprintf (termscript
, "<FACE %d%s: %d/%d[FG:%d/BG:%d]>", face
,
931 highlight
? "H" : "", fp
->foreground
, fp
->background
, fg
, bg
);
932 if (fg
>= 0 && fg
< 16)
934 ScreenAttrib
&= 0xf0;
937 if (bg
>= 0 && bg
< 16)
939 ScreenAttrib
&= 0x0f;
940 ScreenAttrib
|= ((bg
& 0x0f) << 4);
944 Lisp_Object Vdos_unsupported_char_glyph
;
947 IT_write_glyphs (struct glyph
*str
, int str_len
)
949 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
950 int unsupported_face
= FAST_GLYPH_FACE (Vdos_unsupported_char_glyph
);
951 unsigned unsupported_char
= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph
);
952 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
953 register int sl
= str_len
;
954 register int tlen
= GLYPH_TABLE_LENGTH
;
955 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
957 /* If terminal_coding does any conversion, use it, otherwise use
958 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
959 because it always returns 1 if terminal_coding.src_multibyte is 1. */
960 struct coding_system
*coding
=
961 (terminal_coding
.common_flags
& CODING_REQUIRE_ENCODING_MASK
963 : &safe_terminal_coding
);
966 /* Do we need to consider conversion of unibyte characters to
968 int convert_unibyte_characters
969 = (NILP (current_buffer
->enable_multibyte_characters
)
970 && unibyte_display_via_language_environment
);
972 unsigned char conversion_buffer
[256];
973 int conversion_buffer_size
= sizeof conversion_buffer
;
975 if (str_len
<= 0) return;
977 screen_buf
= screen_bp
= alloca (str_len
* 2);
978 screen_buf_end
= screen_buf
+ str_len
* 2;
979 sf
= SELECTED_FRAME();
981 /* Since faces get cached and uncached behind our back, we can't
982 rely on their indices in the cache being consistent across
983 invocations. So always reset the screen face to the default
984 face of the frame, before writing glyphs, and let the glyphs
985 set the right face if it's different from the default. */
986 IT_set_face (DEFAULT_FACE_ID
);
988 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
990 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
993 int cf
, chlen
, enclen
;
994 unsigned char workbuf
[MAX_MULTIBYTE_LENGTH
], *buf
;
997 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
998 only for the redisplay code to know how many columns does
999 this character occupy on the screen. Skip padding glyphs. */
1000 if (CHAR_GLYPH_PADDING_P (*str
))
1007 register GLYPH g
= GLYPH_FROM_CHAR_GLYPH (*str
);
1008 int glyph_not_in_table
= 0;
1010 /* If g is negative, it means we have a multibyte character
1011 in *str. That's what GLYPH_FROM_CHAR_GLYPH returns for
1012 multibyte characters. */
1013 if (g
< 0 || g
>= tlen
)
1015 /* This glyph doesn't have an entry in Vglyph_table. */
1017 glyph_not_in_table
= 1;
1021 /* This glyph has an entry in Vglyph_table, so process
1022 any aliases before testing for simpleness. */
1023 GLYPH_FOLLOW_ALIASES (tbase
, tlen
, g
);
1024 ch
= FAST_GLYPH_CHAR (g
);
1027 /* Convert the character code to multibyte, if they
1028 requested display via language environment. We only want
1029 to convert unibyte characters to multibyte in unibyte
1030 buffers! Otherwise, the 8-bit value in CH came from the
1031 display table set up to display foreign characters. */
1032 if (SINGLE_BYTE_CHAR_P (ch
) && convert_unibyte_characters
1034 || (ch
>= 0200 && !NILP (Vnonascii_translation_table
))))
1035 ch
= unibyte_char_to_multibyte (ch
);
1037 /* Invalid characters are displayed with a special glyph. */
1038 if (! CHAR_VALID_P (ch
, 0))
1040 g
= !NILP (Vdos_unsupported_char_glyph
)
1041 ? Vdos_unsupported_char_glyph
1042 : MAKE_GLYPH (sf
, '\177', GLYPH_FACE (sf
, g
));
1043 ch
= FAST_GLYPH_CHAR (g
);
1046 /* If the face of this glyph is different from the current
1047 screen face, update the screen attribute byte. */
1049 if (cf
!= screen_face
)
1050 IT_set_face (cf
); /* handles invalid faces gracefully */
1052 if (glyph_not_in_table
|| GLYPH_SIMPLE_P (tbase
, tlen
, g
))
1054 /* We generate the multi-byte form of CH in WORKBUF. */
1055 chlen
= CHAR_STRING (ch
, workbuf
);
1060 /* We have a string in Vglyph_table. */
1061 chlen
= GLYPH_LENGTH (tbase
, g
);
1062 buf
= GLYPH_STRING (tbase
, g
);
1065 /* If the character is not multibyte, don't bother converting it. */
1068 *conversion_buffer
= (unsigned char)ch
;
1074 coding
->src_multibyte
= 1;
1075 encode_coding (coding
, buf
, conversion_buffer
, chlen
,
1076 conversion_buffer_size
);
1077 chlen
-= coding
->consumed
;
1078 enclen
= coding
->produced
;
1080 /* Replace glyph codes that cannot be converted by
1081 terminal_coding with Vdos_unsupported_char_glyph. */
1082 if (*conversion_buffer
== '?')
1084 unsigned char *cbp
= conversion_buffer
;
1086 while (cbp
< conversion_buffer
+ enclen
&& *cbp
== '?')
1087 *cbp
++ = unsupported_char
;
1088 if (unsupported_face
!= screen_face
)
1089 IT_set_face (unsupported_face
);
1093 if (enclen
+ chlen
> screen_buf_end
- screen_bp
)
1095 /* The allocated buffer for screen writes is too small.
1096 Flush it and loop again without incrementing STR, so
1097 that the next loop will begin with the same glyph. */
1098 int nbytes
= screen_bp
- screen_buf
;
1101 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
1102 if (screen_virtual_segment
)
1103 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
1104 new_pos_X
+= nbytes
/ 2;
1107 /* Prepare to reuse the same buffer again. */
1108 screen_bp
= screen_buf
;
1112 /* There's enough place in the allocated buffer to add
1113 the encoding of this glyph. */
1115 /* First, copy the encoded bytes. */
1116 for (bp
= conversion_buffer
; enclen
--; bp
++)
1118 *screen_bp
++ = (unsigned char)*bp
;
1119 *screen_bp
++ = ScreenAttrib
;
1121 fputc (*bp
, termscript
);
1124 /* Now copy the bytes not consumed by the encoding. */
1127 buf
+= coding
->consumed
;
1131 fputc (*buf
, termscript
);
1132 *screen_bp
++ = (unsigned char)*buf
++;
1133 *screen_bp
++ = ScreenAttrib
;
1137 /* Update STR and its remaining length. */
1144 /* Dump whatever is left in the screen buffer. */
1146 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
1147 if (screen_virtual_segment
)
1148 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1149 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1151 /* We may have to output some codes to terminate the writing. */
1152 if (CODING_REQUIRE_FLUSHING (coding
))
1154 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
1155 encode_coding (coding
, "", conversion_buffer
, 0, conversion_buffer_size
);
1156 if (coding
->produced
> 0)
1158 screen_buf
= alloca (coding
->produced
* 2);
1159 for (screen_bp
= screen_buf
, bp
= conversion_buffer
;
1160 coding
->produced
--; bp
++)
1162 *screen_bp
++ = (unsigned char)*bp
;
1163 *screen_bp
++ = ScreenAttrib
;
1165 fputc (*bp
, termscript
);
1167 offset
+= screen_bp
- screen_buf
;
1169 dosmemput (screen_buf
, screen_bp
- screen_buf
,
1170 (int)ScreenPrimary
+ offset
);
1171 if (screen_virtual_segment
)
1172 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
1173 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
1178 /************************************************************************
1179 Mouse Highlight (and friends..)
1180 ************************************************************************/
1182 /* This is used for debugging, to turn off note_mouse_highlight. */
1183 int disable_mouse_highlight
;
1185 /* If non-nil, dos_rawgetc generates an event to display that string.
1186 (The display is done in keyboard.c:read_char, by calling
1188 static Lisp_Object help_echo
;
1189 static Lisp_Object previous_help_echo
; /* a helper temporary variable */
1191 /* These record the window, the object and the position where the help
1192 echo string was generated. */
1193 static Lisp_Object help_echo_window
;
1194 static Lisp_Object help_echo_object
;
1195 static int help_echo_pos
;
1197 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1199 /* Set the mouse pointer shape according to whether it is in the
1200 area where the mouse highlight is in effect. */
1202 IT_set_mouse_pointer (int mode
)
1204 /* A no-op for now. DOS text-mode mouse pointer doesn't offer too
1205 many possibilities to change its shape, and the available
1206 functionality pretty much sucks (e.g., almost every reasonable
1207 shape will conceal the character it is on). Since the color of
1208 the pointer changes in the highlighted area, it is not clear to
1209 me whether anything else is required, anyway. */
1212 /* Display the active region described by mouse_face_*
1213 in its mouse-face if HL > 0, in its normal face if HL = 0. */
1215 show_mouse_face (struct display_info
*dpyinfo
, int hl
)
1217 struct window
*w
= XWINDOW (dpyinfo
->mouse_face_window
);
1218 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
1223 /* If window is in the process of being destroyed, don't bother
1225 if (w
->current_matrix
== NULL
)
1226 goto set_cursor_shape
;
1228 /* Recognize when we are called to operate on rows that don't exist
1229 anymore. This can happen when a window is split. */
1230 if (dpyinfo
->mouse_face_end_row
>= w
->current_matrix
->nrows
)
1231 goto set_cursor_shape
;
1233 /* There's no sense to do anything if the mouse face isn't realized. */
1236 fp
= FACE_FROM_ID (SELECTED_FRAME(), dpyinfo
->mouse_face_face_id
);
1238 goto set_cursor_shape
;
1241 /* Note that mouse_face_beg_row etc. are window relative. */
1242 for (i
= dpyinfo
->mouse_face_beg_row
;
1243 i
<= dpyinfo
->mouse_face_end_row
;
1246 int start_hpos
, end_hpos
;
1247 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, i
);
1249 /* Don't do anything if row doesn't have valid contents. */
1250 if (!row
->enabled_p
)
1253 /* For all but the first row, the highlight starts at column 0. */
1254 if (i
== dpyinfo
->mouse_face_beg_row
)
1255 start_hpos
= dpyinfo
->mouse_face_beg_col
;
1259 if (i
== dpyinfo
->mouse_face_end_row
)
1260 end_hpos
= dpyinfo
->mouse_face_end_col
;
1262 end_hpos
= row
->used
[TEXT_AREA
];
1264 if (end_hpos
<= start_hpos
)
1266 /* Record that some glyphs of this row are displayed in
1268 row
->mouse_face_p
= hl
> 0;
1271 int vpos
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1272 int kstart
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1273 int nglyphs
= end_hpos
- start_hpos
;
1274 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
1275 int start_offset
= offset
;
1278 fprintf (termscript
, "\n<MH+ %d-%d:%d>",
1279 kstart
, kstart
+ nglyphs
- 1, vpos
);
1282 IT_set_face (dpyinfo
->mouse_face_face_id
);
1283 /* Since we are going to change only the _colors_ of the
1284 displayed text, there's no need to go through all the
1285 pain of generating and encoding the text from the glyphs.
1286 Instead, we simply poke the attribute byte of each
1287 affected position in video memory with the colors
1288 computed by IT_set_face! */
1289 _farsetsel (_dos_ds
);
1292 _farnspokeb (offset
, ScreenAttrib
);
1295 if (screen_virtual_segment
)
1296 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1301 /* We are removing a previously-drawn mouse highlight. The
1302 safest way to do so is to redraw the glyphs anew, since
1303 all kinds of faces and display tables could have changed
1305 int nglyphs
= end_hpos
- start_hpos
;
1306 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1308 if (end_hpos
>= row
->used
[TEXT_AREA
])
1309 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1311 /* IT_write_glyphs writes at cursor position, so we need to
1312 temporarily move cursor coordinates to the beginning of
1313 the highlight region. */
1314 new_pos_X
= start_hpos
+ WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1315 new_pos_Y
= row
->y
+ WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1318 fprintf (termscript
, "<MH- %d-%d:%d>",
1319 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1320 IT_write_glyphs (row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1322 fputs ("\n", termscript
);
1330 /* Change the mouse pointer shape. */
1331 IT_set_mouse_pointer (hl
);
1334 /* Clear out the mouse-highlighted active region.
1335 Redraw it un-highlighted first. */
1337 clear_mouse_face (struct display_info
*dpyinfo
)
1339 if (! NILP (dpyinfo
->mouse_face_window
))
1340 show_mouse_face (dpyinfo
, 0);
1342 dpyinfo
->mouse_face_beg_row
= dpyinfo
->mouse_face_beg_col
= -1;
1343 dpyinfo
->mouse_face_end_row
= dpyinfo
->mouse_face_end_col
= -1;
1344 dpyinfo
->mouse_face_window
= Qnil
;
1347 /* Find the glyph matrix position of buffer position POS in window W.
1348 *HPOS and *VPOS are set to the positions found. W's current glyphs
1349 must be up to date. If POS is above window start return (0, 0).
1350 If POS is after end of W, return end of last line in W. */
1352 fast_find_position (struct window
*w
, int pos
, int *hpos
, int *vpos
)
1356 int maybe_next_line_p
= 0;
1357 int line_start_position
;
1358 int yb
= window_text_bottom_y (w
);
1359 struct glyph_row
*row
= MATRIX_ROW (w
->current_matrix
, 0);
1360 struct glyph_row
*best_row
= row
;
1364 if (row
->used
[TEXT_AREA
])
1365 line_start_position
= row
->glyphs
[TEXT_AREA
]->charpos
;
1367 line_start_position
= 0;
1369 if (line_start_position
> pos
)
1371 /* If the position sought is the end of the buffer,
1372 don't include the blank lines at the bottom of the window. */
1373 else if (line_start_position
== pos
1374 && pos
== BUF_ZV (XBUFFER (w
->buffer
)))
1376 maybe_next_line_p
= 1;
1379 else if (line_start_position
> 0)
1382 /* Don't overstep the last matrix row, lest we get into the
1383 never-never land... */
1384 if (row
->y
+ 1 >= yb
)
1390 /* Find the right column within BEST_ROW. */
1393 for (i
= 0; i
< row
->used
[TEXT_AREA
]; i
++)
1395 struct glyph
*glyph
= row
->glyphs
[TEXT_AREA
] + i
;
1398 charpos
= glyph
->charpos
;
1405 else if (charpos
> pos
)
1407 else if (charpos
> 0)
1411 /* If we're looking for the end of the buffer,
1412 and we didn't find it in the line we scanned,
1413 use the start of the following line. */
1414 if (maybe_next_line_p
)
1421 *hpos
= lastcol
+ 1;
1425 /* Take proper action when mouse has moved to the mode or top line of
1426 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
1427 mode line. X is relative to the start of the text display area of
1428 W, so the width of bitmap areas and scroll bars must be subtracted
1429 to get a position relative to the start of the mode line. */
1431 IT_note_mode_line_highlight (struct window
*w
, int x
, int mode_line_p
)
1433 struct frame
*f
= XFRAME (w
->frame
);
1434 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1435 struct glyph_row
*row
;
1438 row
= MATRIX_MODE_LINE_ROW (w
->current_matrix
);
1440 row
= MATRIX_HEADER_LINE_ROW (w
->current_matrix
);
1444 extern Lisp_Object Qhelp_echo
;
1445 struct glyph
*glyph
, *end
;
1446 Lisp_Object help
, map
;
1448 /* Find the glyph under X. */
1449 glyph
= row
->glyphs
[TEXT_AREA
]
1450 + x
- FRAME_LEFT_SCROLL_BAR_WIDTH (f
) * CANON_X_UNIT (f
);
1451 end
= glyph
+ row
->used
[TEXT_AREA
];
1453 && STRINGP (glyph
->object
)
1454 && XSTRING (glyph
->object
)->intervals
1455 && glyph
->charpos
>= 0
1456 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1458 /* If we're on a string with `help-echo' text property,
1459 arrange for the help to be displayed. This is done by
1460 setting the global variable help_echo to the help string. */
1461 help
= Fget_text_property (make_number (glyph
->charpos
),
1462 Qhelp_echo
, glyph
->object
);
1466 XSETWINDOW (help_echo_window
, w
);
1467 help_echo_object
= glyph
->object
;
1468 help_echo_pos
= glyph
->charpos
;
1474 /* Take proper action when the mouse has moved to position X, Y on
1475 frame F as regards highlighting characters that have mouse-face
1476 properties. Also de-highlighting chars where the mouse was before.
1477 X and Y can be negative or out of range. */
1479 IT_note_mouse_highlight (struct frame
*f
, int x
, int y
)
1481 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1486 /* When a menu is active, don't highlight because this looks odd. */
1487 if (mouse_preempted
)
1490 if (disable_mouse_highlight
1491 || !f
->glyphs_initialized_p
)
1494 dpyinfo
->mouse_face_mouse_x
= x
;
1495 dpyinfo
->mouse_face_mouse_y
= y
;
1496 dpyinfo
->mouse_face_mouse_frame
= f
;
1498 if (dpyinfo
->mouse_face_defer
)
1503 dpyinfo
->mouse_face_deferred_gc
= 1;
1507 /* Which window is that in? */
1508 window
= window_from_coordinates (f
, x
, y
, &portion
, 0);
1510 /* If we were displaying active text in another window, clear that. */
1511 if (! EQ (window
, dpyinfo
->mouse_face_window
))
1512 clear_mouse_face (dpyinfo
);
1514 /* Not on a window -> return. */
1515 if (!WINDOWP (window
))
1518 /* Convert to window-relative coordinates. */
1519 w
= XWINDOW (window
);
1520 x
-= WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w
);
1521 y
-= WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w
);
1523 if (portion
== 1 || portion
== 3)
1525 /* Mouse is on the mode or top line. */
1526 IT_note_mode_line_highlight (w
, x
, portion
== 1);
1530 IT_set_mouse_pointer (0);
1532 /* Are we in a window whose display is up to date?
1533 And verify the buffer's text has not changed. */
1534 if (/* Within text portion of the window. */
1536 && EQ (w
->window_end_valid
, w
->buffer
)
1537 && XFASTINT (w
->last_modified
) == BUF_MODIFF (XBUFFER (w
->buffer
))
1538 && (XFASTINT (w
->last_overlay_modified
)
1539 == BUF_OVERLAY_MODIFF (XBUFFER (w
->buffer
))))
1542 struct glyph_row
*row
;
1543 struct glyph
*glyph
;
1544 int nrows
= w
->current_matrix
->nrows
;
1546 /* Find the glyph under X/Y. */
1548 if (y
>= 0 && y
< nrows
)
1550 row
= MATRIX_ROW (w
->current_matrix
, y
);
1551 /* Give up if some row before the one we are looking for is
1553 for (i
= 0; i
<= y
; i
++)
1554 if (!MATRIX_ROW (w
->current_matrix
, i
)->enabled_p
)
1556 if (i
> y
/* all rows upto and including the one at Y are enabled */
1557 && row
->displays_text_p
1558 && x
< window_box_width (w
, TEXT_AREA
))
1560 glyph
= row
->glyphs
[TEXT_AREA
];
1561 if (x
>= row
->used
[TEXT_AREA
])
1566 if (!BUFFERP (glyph
->object
))
1572 /* Clear mouse face if X/Y not over text. */
1575 clear_mouse_face (dpyinfo
);
1579 if (!BUFFERP (glyph
->object
))
1581 pos
= glyph
->charpos
;
1583 /* Check for mouse-face and help-echo. */
1585 extern Lisp_Object Qmouse_face
;
1586 Lisp_Object mouse_face
, overlay
, position
;
1587 Lisp_Object
*overlay_vec
;
1589 struct buffer
*obuf
;
1592 /* If we get an out-of-range value, return now; avoid an error. */
1593 if (pos
> BUF_Z (XBUFFER (w
->buffer
)))
1596 /* Make the window's buffer temporarily current for
1597 overlays_at and compute_char_face. */
1598 obuf
= current_buffer
;
1599 current_buffer
= XBUFFER (w
->buffer
);
1605 /* Is this char mouse-active or does it have help-echo? */
1606 XSETINT (position
, pos
);
1608 /* Put all the overlays we want in a vector in overlay_vec.
1609 Store the length in len. If there are more than 10, make
1610 enough space for all, and try again. */
1612 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1613 noverlays
= overlays_at (pos
, 0, &overlay_vec
, &len
, NULL
, NULL
, 0);
1614 if (noverlays
> len
)
1617 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1618 noverlays
= overlays_at (pos
,
1619 0, &overlay_vec
, &len
, NULL
, NULL
, 0);
1622 /* Sort overlays into increasing priority order. */
1623 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
1625 /* Check mouse-face highlighting. */
1626 if (! (EQ (window
, dpyinfo
->mouse_face_window
)
1627 && y
>= dpyinfo
->mouse_face_beg_row
1628 && y
<= dpyinfo
->mouse_face_end_row
1629 && (y
> dpyinfo
->mouse_face_beg_row
1630 || x
>= dpyinfo
->mouse_face_beg_col
)
1631 && (y
< dpyinfo
->mouse_face_end_row
1632 || x
< dpyinfo
->mouse_face_end_col
1633 || dpyinfo
->mouse_face_past_end
)))
1635 /* Clear the display of the old active region, if any. */
1636 clear_mouse_face (dpyinfo
);
1638 /* Find highest priority overlay that has a mouse-face prop. */
1640 for (i
= noverlays
- 1; i
>= 0; --i
)
1642 mouse_face
= Foverlay_get (overlay_vec
[i
], Qmouse_face
);
1643 if (!NILP (mouse_face
))
1645 overlay
= overlay_vec
[i
];
1650 /* If no overlay applies, get a text property. */
1652 mouse_face
= Fget_text_property (position
, Qmouse_face
,
1655 /* Handle the overlay case. */
1656 if (! NILP (overlay
))
1658 /* Find the range of text around this char that
1659 should be active. */
1660 Lisp_Object before
, after
;
1663 before
= Foverlay_start (overlay
);
1664 after
= Foverlay_end (overlay
);
1665 /* Record this as the current active region. */
1666 fast_find_position (w
, XFASTINT (before
),
1667 &dpyinfo
->mouse_face_beg_col
,
1668 &dpyinfo
->mouse_face_beg_row
);
1669 dpyinfo
->mouse_face_past_end
1670 = !fast_find_position (w
, XFASTINT (after
),
1671 &dpyinfo
->mouse_face_end_col
,
1672 &dpyinfo
->mouse_face_end_row
);
1673 dpyinfo
->mouse_face_window
= window
;
1674 dpyinfo
->mouse_face_face_id
1675 = face_at_buffer_position (w
, pos
, 0, 0,
1676 &ignore
, pos
+ 1, 1);
1678 /* Display it as active. */
1679 show_mouse_face (dpyinfo
, 1);
1681 /* Handle the text property case. */
1682 else if (! NILP (mouse_face
))
1684 /* Find the range of text around this char that
1685 should be active. */
1686 Lisp_Object before
, after
, beginning
, end
;
1689 beginning
= Fmarker_position (w
->start
);
1690 XSETINT (end
, (BUF_Z (XBUFFER (w
->buffer
))
1691 - XFASTINT (w
->window_end_pos
)));
1693 = Fprevious_single_property_change (make_number (pos
+ 1),
1695 w
->buffer
, beginning
);
1697 = Fnext_single_property_change (position
, Qmouse_face
,
1699 /* Record this as the current active region. */
1700 fast_find_position (w
, XFASTINT (before
),
1701 &dpyinfo
->mouse_face_beg_col
,
1702 &dpyinfo
->mouse_face_beg_row
);
1703 dpyinfo
->mouse_face_past_end
1704 = !fast_find_position (w
, XFASTINT (after
),
1705 &dpyinfo
->mouse_face_end_col
,
1706 &dpyinfo
->mouse_face_end_row
);
1707 dpyinfo
->mouse_face_window
= window
;
1708 dpyinfo
->mouse_face_face_id
1709 = face_at_buffer_position (w
, pos
, 0, 0,
1710 &ignore
, pos
+ 1, 1);
1712 /* Display it as active. */
1713 show_mouse_face (dpyinfo
, 1);
1717 /* Look for a `help-echo' property. */
1720 extern Lisp_Object Qhelp_echo
;
1722 /* Check overlays first. */
1724 for (i
= noverlays
- 1; i
>= 0 && NILP (help
); --i
)
1726 overlay
= overlay_vec
[i
];
1727 help
= Foverlay_get (overlay
, Qhelp_echo
);
1733 help_echo_window
= window
;
1734 help_echo_object
= overlay
;
1735 help_echo_pos
= pos
;
1737 /* Try text properties. */
1738 else if (NILP (help
)
1739 && ((STRINGP (glyph
->object
)
1740 && glyph
->charpos
>= 0
1741 && glyph
->charpos
< XSTRING (glyph
->object
)->size
)
1742 || (BUFFERP (glyph
->object
)
1743 && glyph
->charpos
>= BEGV
1744 && glyph
->charpos
< ZV
)))
1746 help
= Fget_text_property (make_number (glyph
->charpos
),
1747 Qhelp_echo
, glyph
->object
);
1751 help_echo_window
= window
;
1752 help_echo_object
= glyph
->object
;
1753 help_echo_pos
= glyph
->charpos
;
1760 current_buffer
= obuf
;
1766 IT_clear_end_of_line (int first_unused
)
1770 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1771 extern int fatal_error_in_progress
;
1773 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1777 i
= (j
= first_unused
- new_pos_X
) * 2;
1779 fprintf (termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1780 spaces
= sp
= alloca (i
);
1785 *sp
++ = ScreenAttrib
;
1789 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1790 if (screen_virtual_segment
)
1791 dosv_refresh_virtual_screen (offset
, i
/ 2);
1793 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1794 Let's follow their lead, in case someone relies on this. */
1795 new_pos_X
= first_unused
;
1799 IT_clear_screen (void)
1802 fprintf (termscript
, "<CLR:SCR>");
1806 if (screen_virtual_segment
)
1807 dosv_refresh_virtual_screen (0, screen_size
);
1808 new_pos_X
= new_pos_Y
= 0;
1812 IT_clear_to_end (void)
1815 fprintf (termscript
, "<CLR:EOS>");
1817 while (new_pos_Y
< screen_size_Y
) {
1819 IT_clear_end_of_line (screen_size_X
);
1825 IT_cursor_to (int y
, int x
)
1828 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
1833 static int cursor_cleared
;
1836 IT_display_cursor (int on
)
1838 if (on
&& cursor_cleared
)
1840 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1843 else if (!on
&& !cursor_cleared
)
1845 ScreenSetCursor (-1, -1);
1850 /* Emacs calls cursor-movement functions a lot when it updates the
1851 display (probably a legacy of old terminals where you cannot
1852 update a screen line without first moving the cursor there).
1853 However, cursor movement is expensive on MSDOS (it calls a slow
1854 BIOS function and requires 2 mode switches), while actual screen
1855 updates access the video memory directly and don't depend on
1856 cursor position. To avoid slowing down the redisplay, we cheat:
1857 all functions that move the cursor only set internal variables
1858 which record the cursor position, whereas the cursor is only
1859 moved to its final position whenever screen update is complete.
1861 `IT_cmgoto' is called from the keyboard reading loop and when the
1862 frame update is complete. This means that we are ready for user
1863 input, so we update the cursor position to show where the point is,
1864 and also make the mouse pointer visible.
1866 Special treatment is required when the cursor is in the echo area,
1867 to put the cursor at the end of the text displayed there. */
1870 IT_cmgoto (FRAME_PTR f
)
1872 /* Only set the cursor to where it should be if the display is
1873 already in sync with the window contents. */
1874 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1876 /* FIXME: This needs to be rewritten for the new redisplay, or
1879 static int previous_pos_X
= -1;
1881 update_cursor_pos
= 1; /* temporary!!! */
1883 /* If the display is in sync, forget any previous knowledge about
1884 cursor position. This is primarily for unexpected events like
1885 C-g in the minibuffer. */
1886 if (update_cursor_pos
&& previous_pos_X
>= 0)
1887 previous_pos_X
= -1;
1888 /* If we are in the echo area, put the cursor at the
1889 end of the echo area message. */
1890 if (!update_cursor_pos
1891 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1893 int tem_X
= current_pos_X
, dummy
;
1895 if (echo_area_glyphs
)
1897 tem_X
= echo_area_glyphs_length
;
1898 /* Save current cursor position, to be restored after the
1899 echo area message is erased. Only remember one level
1900 of previous cursor position. */
1901 if (previous_pos_X
== -1)
1902 ScreenGetCursor (&dummy
, &previous_pos_X
);
1904 else if (previous_pos_X
>= 0)
1906 /* We wind up here after the echo area message is erased.
1907 Restore the cursor position we remembered above. */
1908 tem_X
= previous_pos_X
;
1909 previous_pos_X
= -1;
1912 if (current_pos_X
!= tem_X
)
1915 update_cursor_pos
= 1;
1920 if (update_cursor_pos
1921 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1923 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1925 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1928 /* Maybe cursor is invisible, so make it visible. */
1929 IT_display_cursor (1);
1931 /* Mouse pointer should be always visible if we are waiting for
1938 IT_reassert_line_highlight (int new, int vpos
)
1944 IT_change_line_highlight (int new_highlight
, int y
, int vpos
, int first_unused_hpos
)
1946 highlight
= new_highlight
;
1947 IT_cursor_to (vpos
, 0);
1948 IT_clear_end_of_line (first_unused_hpos
);
1952 IT_update_begin (struct frame
*f
)
1954 struct display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1955 struct frame
*mouse_face_frame
= display_info
->mouse_face_mouse_frame
;
1961 if (f
&& f
== mouse_face_frame
)
1963 /* Don't do highlighting for mouse motion during the update. */
1964 display_info
->mouse_face_defer
= 1;
1966 /* If F needs to be redrawn, simply forget about any prior mouse
1968 if (FRAME_GARBAGED_P (f
))
1969 display_info
->mouse_face_window
= Qnil
;
1971 /* Can we tell that this update does not affect the window
1972 where the mouse highlight is? If so, no need to turn off.
1973 Likewise, don't do anything if none of the enabled rows
1974 contains glyphs highlighted in mouse face. */
1975 if (!NILP (display_info
->mouse_face_window
)
1976 && WINDOWP (display_info
->mouse_face_window
))
1978 struct window
*w
= XWINDOW (display_info
->mouse_face_window
);
1981 /* If the mouse highlight is in the window that was deleted
1982 (e.g., if it was popped by completion), clear highlight
1984 if (NILP (w
->buffer
))
1985 display_info
->mouse_face_window
= Qnil
;
1988 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1989 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1990 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1994 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1995 clear_mouse_face (display_info
);
1998 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
2000 /* If the frame with mouse highlight was deleted, invalidate the
2002 display_info
->mouse_face_beg_row
= display_info
->mouse_face_beg_col
= -1;
2003 display_info
->mouse_face_end_row
= display_info
->mouse_face_end_col
= -1;
2004 display_info
->mouse_face_window
= Qnil
;
2005 display_info
->mouse_face_deferred_gc
= 0;
2006 display_info
->mouse_face_mouse_frame
= NULL
;
2013 IT_update_end (struct frame
*f
)
2016 FRAME_X_DISPLAY_INFO (f
)->mouse_face_defer
= 0;
2019 Lisp_Object Qcursor_type
;
2022 IT_frame_up_to_date (struct frame
*f
)
2024 struct display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
2025 Lisp_Object new_cursor
, frame_desired_cursor
;
2028 if (dpyinfo
->mouse_face_deferred_gc
2029 || (f
&& f
== dpyinfo
->mouse_face_mouse_frame
))
2032 if (dpyinfo
->mouse_face_mouse_frame
)
2033 IT_note_mouse_highlight (dpyinfo
->mouse_face_mouse_frame
,
2034 dpyinfo
->mouse_face_mouse_x
,
2035 dpyinfo
->mouse_face_mouse_y
);
2036 dpyinfo
->mouse_face_deferred_gc
= 0;
2040 /* Set the cursor type to whatever they wanted. In a minibuffer
2041 window, we want the cursor to appear only if we are reading input
2042 from this window, and we want the cursor to be taken from the
2043 frame parameters. For the selected window, we use either its
2044 buffer-local value or the value from the frame parameters if the
2045 buffer doesn't define its local value for the cursor type. */
2046 sw
= XWINDOW (f
->selected_window
);
2047 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
2048 if (cursor_in_echo_area
2049 && FRAME_HAS_MINIBUF_P (f
)
2050 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
2051 && sw
== XWINDOW (echo_area_window
))
2052 new_cursor
= frame_desired_cursor
;
2055 struct buffer
*b
= XBUFFER (sw
->buffer
);
2057 if (EQ (b
->cursor_type
, Qt
))
2058 new_cursor
= frame_desired_cursor
;
2059 else if (NILP (b
->cursor_type
)) /* nil means no cursor */
2060 new_cursor
= Fcons (Qbar
, make_number (0));
2062 new_cursor
= b
->cursor_type
;
2065 IT_set_cursor_type (f
, new_cursor
);
2067 IT_cmgoto (f
); /* position cursor when update is done */
2070 /* Copy LEN glyphs displayed on a single line whose vertical position
2071 is YPOS, beginning at horizontal position XFROM to horizontal
2072 position XTO, by moving blocks in the video memory. Used by
2073 functions that insert and delete glyphs. */
2075 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
2077 /* The offsets of source and destination relative to the
2078 conventional memorty selector. */
2079 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
2080 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
2082 if (from
== to
|| len
<= 0)
2085 _farsetsel (_dos_ds
);
2087 /* The source and destination might overlap, so we need to move
2088 glyphs non-destructively. */
2091 for ( ; len
; from
+= 2, to
+= 2, len
--)
2092 _farnspokew (to
, _farnspeekw (from
));
2096 from
+= (len
- 1) * 2;
2097 to
+= (len
- 1) * 2;
2098 for ( ; len
; from
-= 2, to
-= 2, len
--)
2099 _farnspokew (to
, _farnspeekw (from
));
2101 if (screen_virtual_segment
)
2102 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
2105 /* Insert and delete glyphs. */
2107 IT_insert_glyphs (start
, len
)
2108 register struct glyph
*start
;
2111 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
2113 /* Shift right the glyphs from the nominal cursor position to the
2114 end of this line. */
2115 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
2117 /* Now write the glyphs to be inserted. */
2118 IT_write_glyphs (start
, len
);
2122 IT_delete_glyphs (n
)
2128 /* set-window-configuration on window.c needs this. */
2130 x_set_menu_bar_lines (f
, value
, oldval
)
2132 Lisp_Object value
, oldval
;
2134 set_menu_bar_lines (f
, value
, oldval
);
2137 /* This was copied from xfaces.c */
2139 extern Lisp_Object Qbackground_color
;
2140 extern Lisp_Object Qforeground_color
;
2141 Lisp_Object Qreverse
;
2142 extern Lisp_Object Qtitle
;
2144 /* IT_set_terminal_modes is called when emacs is started,
2145 resumed, and whenever the screen is redrawn! */
2148 IT_set_terminal_modes (void)
2151 fprintf (termscript
, "\n<SET_TERM>");
2154 screen_size_X
= ScreenCols ();
2155 screen_size_Y
= ScreenRows ();
2156 screen_size
= screen_size_X
* screen_size_Y
;
2158 new_pos_X
= new_pos_Y
= 0;
2159 current_pos_X
= current_pos_Y
= -1;
2161 if (term_setup_done
)
2163 term_setup_done
= 1;
2165 startup_screen_size_X
= screen_size_X
;
2166 startup_screen_size_Y
= screen_size_Y
;
2167 startup_screen_attrib
= ScreenAttrib
;
2170 /* Is DOS/V (or any other RSIS software which relocates
2171 the screen) installed? */
2173 unsigned short es_value
;
2176 regs
.h
.ah
= 0xfe; /* get relocated screen address */
2177 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
2178 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
2179 else if (screen_old_address
) /* already switched to Japanese mode once */
2180 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
2182 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
2184 es_value
= regs
.x
.es
;
2185 __dpmi_int (0x10, ®s
);
2187 if (regs
.x
.es
!= es_value
)
2189 /* screen_old_address is only set if ScreenPrimary does NOT
2190 already point to the relocated buffer address returned by
2191 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
2192 ScreenPrimary to that address at startup under DOS/V. */
2193 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
2194 screen_old_address
= ScreenPrimary
;
2195 screen_virtual_segment
= regs
.x
.es
;
2196 screen_virtual_offset
= regs
.x
.di
;
2197 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
2200 #endif /* __DJGPP__ > 1 */
2202 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
2203 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
2206 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
2207 screen_size_X
, screen_size_Y
);
2212 /* IT_reset_terminal_modes is called when emacs is
2213 suspended or killed. */
2216 IT_reset_terminal_modes (void)
2218 int display_row_start
= (int) ScreenPrimary
;
2219 int saved_row_len
= startup_screen_size_X
* 2;
2220 int update_row_len
= ScreenCols () * 2;
2221 int current_rows
= ScreenRows ();
2222 int to_next_row
= update_row_len
;
2223 unsigned char *saved_row
= startup_screen_buffer
;
2224 int cursor_pos_X
= ScreenCols () - 1;
2225 int cursor_pos_Y
= ScreenRows () - 1;
2228 fprintf (termscript
, "\n<RESET_TERM>");
2232 if (!term_setup_done
)
2237 /* Leave the video system in the same state as we found it,
2238 as far as the blink/bright-background bit is concerned. */
2239 maybe_enable_blinking ();
2241 /* We have a situation here.
2242 We cannot just do ScreenUpdate(startup_screen_buffer) because
2243 the luser could have changed screen dimensions inside Emacs
2244 and failed (or didn't want) to restore them before killing
2245 Emacs. ScreenUpdate() uses the *current* screen dimensions and
2246 thus will happily use memory outside what was allocated for
2247 `startup_screen_buffer'.
2248 Thus we only restore as much as the current screen dimensions
2249 can hold, and clear the rest (if the saved screen is smaller than
2250 the current) with the color attribute saved at startup. The cursor
2251 is also restored within the visible dimensions. */
2253 ScreenAttrib
= startup_screen_attrib
;
2255 /* Don't restore the screen if we are exiting less than 2 seconds
2256 after startup: we might be crashing, and the screen might show
2257 some vital clues to what's wrong. */
2258 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
2261 if (screen_virtual_segment
)
2262 dosv_refresh_virtual_screen (0, screen_size
);
2264 if (update_row_len
> saved_row_len
)
2265 update_row_len
= saved_row_len
;
2266 if (current_rows
> startup_screen_size_Y
)
2267 current_rows
= startup_screen_size_Y
;
2270 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
2271 update_row_len
/ 2, current_rows
);
2273 while (current_rows
--)
2275 dosmemput (saved_row
, update_row_len
, display_row_start
);
2276 if (screen_virtual_segment
)
2277 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
2278 update_row_len
/ 2);
2279 saved_row
+= saved_row_len
;
2280 display_row_start
+= to_next_row
;
2283 if (startup_pos_X
< cursor_pos_X
)
2284 cursor_pos_X
= startup_pos_X
;
2285 if (startup_pos_Y
< cursor_pos_Y
)
2286 cursor_pos_Y
= startup_pos_Y
;
2288 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
2289 xfree (startup_screen_buffer
);
2291 term_setup_done
= 0;
2295 IT_set_terminal_window (int foo
)
2299 /* Remember the screen colors of the curent frame, to serve as the
2300 default colors for newly-created frames. */
2302 static int initial_screen_colors
[2];
2304 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
2305 Smsdos_remember_default_colors
, 1, 1, 0,
2306 "Remember the screen colors of the current frame.")
2312 CHECK_FRAME (frame
, 0);
2315 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
2316 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
2320 IT_set_frame_parameters (f
, alist
)
2325 int length
= XINT (Flength (alist
));
2328 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2330 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
2331 /* Do we have to reverse the foreground and background colors? */
2332 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
2333 int was_reverse
= reverse
;
2334 int redraw
= 0, fg_set
= 0, bg_set
= 0;
2335 int need_to_reverse
;
2336 unsigned long orig_fg
;
2337 unsigned long orig_bg
;
2338 Lisp_Object frame_bg
, frame_fg
;
2339 extern Lisp_Object Qdefault
, QCforeground
, QCbackground
;
2341 /* If we are creating a new frame, begin with the original screen colors
2342 used for the initial frame. */
2343 if (alist
== Vdefault_frame_alist
2344 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
2346 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
2347 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
2349 orig_fg
= FRAME_FOREGROUND_PIXEL (f
);
2350 orig_bg
= FRAME_BACKGROUND_PIXEL (f
);
2351 frame_fg
= Fcdr (Fassq (Qforeground_color
, f
->param_alist
));
2352 frame_bg
= Fcdr (Fassq (Qbackground_color
, f
->param_alist
));
2353 /* frame_fg and frame_bg could be nil if, for example,
2354 f->param_alist is nil, e.g. if we are called from
2355 Fmake_terminal_frame. */
2356 if (NILP (frame_fg
))
2357 frame_fg
= build_string (unspecified_fg
);
2358 if (NILP (frame_bg
))
2359 frame_bg
= build_string (unspecified_bg
);
2361 /* Extract parm names and values into those vectors. */
2363 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
2368 parms
[i
] = Fcar (elt
);
2369 CHECK_SYMBOL (parms
[i
], 1);
2370 values
[i
] = Fcdr (elt
);
2376 for (i
= 0; i
< j
; i
++)
2378 Lisp_Object prop
, val
;
2383 if (EQ (prop
, Qreverse
))
2384 reverse
= EQ (val
, Qt
);
2387 need_to_reverse
= reverse
&& !was_reverse
;
2388 if (termscript
&& need_to_reverse
)
2389 fprintf (termscript
, "<INVERSE-VIDEO>\n");
2391 /* Now process the alist elements in reverse of specified order. */
2392 for (i
--; i
>= 0; i
--)
2394 Lisp_Object prop
, val
;
2400 if (EQ (prop
, Qforeground_color
))
2402 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2403 ? LFACE_BACKGROUND_INDEX
2404 : LFACE_FOREGROUND_INDEX
);
2405 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2406 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2407 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2409 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
2410 /* Make sure the foreground of the default face for this
2411 frame is changed as well. */
2412 XSETFRAME (frame
, f
);
2413 if (need_to_reverse
)
2415 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2417 prop
= Qbackground_color
;
2421 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2427 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
2430 else if (EQ (prop
, Qbackground_color
))
2432 unsigned long new_color
= load_color (f
, NULL
, val
, need_to_reverse
2433 ? LFACE_FOREGROUND_INDEX
2434 : LFACE_BACKGROUND_INDEX
);
2435 if (new_color
!= FACE_TTY_DEFAULT_COLOR
2436 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
2437 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
2439 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
2440 /* Make sure the background of the default face for this
2441 frame is changed as well. */
2442 XSETFRAME (frame
, f
);
2443 if (need_to_reverse
)
2445 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2447 prop
= Qforeground_color
;
2451 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2457 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
2460 else if (EQ (prop
, Qtitle
))
2462 x_set_title (f
, val
);
2464 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
2466 else if (EQ (prop
, Qcursor_type
))
2468 IT_set_cursor_type (f
, val
);
2470 fprintf (termscript
, "<CTYPE: %s>\n",
2471 EQ (val
, Qbar
) || CONSP (val
) && EQ (XCAR (val
), Qbar
)
2474 store_frame_param (f
, prop
, val
);
2477 /* If they specified "reverse", but not the colors, we need to swap
2478 the current frame colors. */
2479 if (need_to_reverse
)
2485 XSETFRAME (frame
, f
);
2486 Finternal_set_lisp_face_attribute (Qdefault
, QCbackground
,
2487 tty_color_name (f
, orig_fg
),
2489 store_frame_param (f
, Qbackground_color
, frame_fg
);
2494 XSETFRAME (frame
, f
);
2495 Finternal_set_lisp_face_attribute (Qdefault
, QCforeground
,
2496 tty_color_name (f
, orig_bg
),
2498 store_frame_param (f
, Qforeground_color
, frame_bg
);
2505 face_change_count
++; /* forces xdisp.c to recompute basic faces */
2506 if (f
== SELECTED_FRAME())
2511 extern void init_frame_faces (FRAME_PTR
);
2513 #endif /* !HAVE_X_WINDOWS */
2516 /* Do we need the internal terminal? */
2519 internal_terminal_init ()
2521 char *term
= getenv ("TERM");
2523 struct frame
*sf
= SELECTED_FRAME();
2525 #ifdef HAVE_X_WINDOWS
2526 if (!inhibit_window_system
)
2531 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
2533 if (getenv ("EMACSTEST"))
2534 termscript
= fopen (getenv ("EMACSTEST"), "wt");
2536 #ifndef HAVE_X_WINDOWS
2537 if (!internal_terminal
|| inhibit_window_system
)
2539 sf
->output_method
= output_termcap
;
2543 Vwindow_system
= intern ("pc");
2544 Vwindow_system_version
= make_number (1);
2545 sf
->output_method
= output_msdos_raw
;
2547 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
2548 screen_old_address
= 0;
2550 /* Forget the stale screen colors as well. */
2551 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
2553 bzero (&the_only_x_display
, sizeof the_only_x_display
);
2554 the_only_x_display
.background_pixel
= 7; /* White */
2555 the_only_x_display
.foreground_pixel
= 0; /* Black */
2557 colors
= getenv ("EMACSCOLORS");
2558 if (colors
&& strlen (colors
) >= 2)
2560 /* The colors use 4 bits each (we enable bright background). */
2561 if (isdigit (colors
[0]))
2563 else if (isxdigit (colors
[0]))
2564 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
2565 if (colors
[0] >= 0 && colors
[0] < 16)
2566 the_only_x_display
.foreground_pixel
= colors
[0];
2567 if (isdigit (colors
[1]))
2569 else if (isxdigit (colors
[1]))
2570 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
2571 if (colors
[1] >= 0 && colors
[1] < 16)
2572 the_only_x_display
.background_pixel
= colors
[1];
2574 the_only_x_display
.line_height
= 1;
2575 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
2576 the_only_x_display
.display_info
.mouse_face_mouse_frame
= NULL
;
2577 the_only_x_display
.display_info
.mouse_face_deferred_gc
= 0;
2578 the_only_x_display
.display_info
.mouse_face_beg_row
=
2579 the_only_x_display
.display_info
.mouse_face_beg_col
= -1;
2580 the_only_x_display
.display_info
.mouse_face_end_row
=
2581 the_only_x_display
.display_info
.mouse_face_end_col
= -1;
2582 the_only_x_display
.display_info
.mouse_face_face_id
= DEFAULT_FACE_ID
;
2583 the_only_x_display
.display_info
.mouse_face_window
= Qnil
;
2584 the_only_x_display
.display_info
.mouse_face_mouse_x
=
2585 the_only_x_display
.display_info
.mouse_face_mouse_y
= 0;
2586 the_only_x_display
.display_info
.mouse_face_defer
= 0;
2588 init_frame_faces (sf
);
2590 ring_bell_hook
= IT_ring_bell
;
2591 insert_glyphs_hook
= IT_insert_glyphs
;
2592 delete_glyphs_hook
= IT_delete_glyphs
;
2593 write_glyphs_hook
= IT_write_glyphs
;
2594 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
2595 clear_to_end_hook
= IT_clear_to_end
;
2596 clear_end_of_line_hook
= IT_clear_end_of_line
;
2597 clear_frame_hook
= IT_clear_screen
;
2598 change_line_highlight_hook
= IT_change_line_highlight
;
2599 update_begin_hook
= IT_update_begin
;
2600 update_end_hook
= IT_update_end
;
2601 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
2602 frame_up_to_date_hook
= IT_frame_up_to_date
;
2604 /* These hooks are called by term.c without being checked. */
2605 set_terminal_modes_hook
= IT_set_terminal_modes
;
2606 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
2607 set_terminal_window_hook
= IT_set_terminal_window
;
2608 char_ins_del_ok
= 0;
2612 dos_get_saved_screen (screen
, rows
, cols
)
2617 #ifndef HAVE_X_WINDOWS
2618 *screen
= startup_screen_buffer
;
2619 *cols
= startup_screen_size_X
;
2620 *rows
= startup_screen_size_Y
;
2621 return *screen
!= (char *)0;
2627 #ifndef HAVE_X_WINDOWS
2629 /* We are not X, but we can emulate it well enough for our needs... */
2633 if (! FRAME_MSDOS_P (SELECTED_FRAME()))
2634 error ("Not running under a window system");
2640 /* ----------------------- Keyboard control ----------------------
2642 * Keymaps reflect the following keyboard layout:
2644 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
2645 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
2646 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
2647 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
2651 #define Ignore 0x0000
2652 #define Normal 0x0000 /* normal key - alt changes scan-code */
2653 #define FctKey 0x1000 /* func key if c == 0, else c */
2654 #define Special 0x2000 /* func key even if c != 0 */
2655 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
2656 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
2657 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
2658 #define Grey 0x6000 /* Grey keypad key */
2660 #define Alt 0x0100 /* alt scan-code */
2661 #define Ctrl 0x0200 /* ctrl scan-code */
2662 #define Shift 0x0400 /* shift scan-code */
2664 static int extended_kbd
; /* 101 (102) keyboard present. */
2666 struct kbd_translate
{
2669 unsigned short code
;
2672 struct dos_keyboard_map
2677 struct kbd_translate
*translate_table
;
2681 static struct dos_keyboard_map us_keyboard
= {
2683 /* 01234567890123456789012345678901234567890 12345678901234 */
2684 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
2685 /* 0123456789012345678901234567890123456789 012345678901234 */
2686 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
2687 0, /* no Alt-Gr key */
2688 0 /* no translate table */
2691 static struct dos_keyboard_map fr_keyboard
= {
2693 /* 012 3456789012345678901234567890123456789012345678901234 */
2694 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
2695 /* 0123456789012345678901234567890123456789012345678901234 */
2696 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
2697 /* 01234567 89012345678901234567890123456789012345678901234 */
2699 0 /* no translate table */
2703 * Italian keyboard support, country code 39.
2706 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2707 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2710 static struct kbd_translate it_kbd_translate_table
[] = {
2711 { 0x56, 0x3c, Normal
| 13 },
2712 { 0x56, 0x3e, Normal
| 27 },
2715 static struct dos_keyboard_map it_keyboard
= {
2717 /* 0 123456789012345678901234567890123456789012345678901234 */
2718 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
2719 /* 01 23456789012345678901234567890123456789012345678901234 */
2720 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
2721 /* 0123456789012345678901234567890123456789012345678901234 */
2723 it_kbd_translate_table
2726 static struct dos_keyboard_map dk_keyboard
= {
2728 /* 0123456789012345678901234567890123456789012345678901234 */
2729 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
2730 /* 01 23456789012345678901234567890123456789012345678901234 */
2731 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
2732 /* 0123456789012345678901234567890123456789012345678901234 */
2734 0 /* no translate table */
2737 static struct kbd_translate jp_kbd_translate_table
[] = {
2738 { 0x73, 0x5c, Normal
| 0 },
2739 { 0x73, 0x5f, Normal
| 0 },
2740 { 0x73, 0x1c, Map
| 0 },
2741 { 0x7d, 0x5c, Normal
| 13 },
2742 { 0x7d, 0x7c, Normal
| 13 },
2743 { 0x7d, 0x1c, Map
| 13 },
2746 static struct dos_keyboard_map jp_keyboard
= {
2748 /* 0123456789012 345678901234567890123456789012345678901234 */
2749 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2750 /* 01 23456789012345678901234567890123456789012345678901234 */
2751 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2752 0, /* no Alt-Gr key */
2753 jp_kbd_translate_table
2756 static struct keyboard_layout_list
2759 struct dos_keyboard_map
*keyboard_map
;
2760 } keyboard_layout_list
[] =
2769 static struct dos_keyboard_map
*keyboard
;
2770 static int keyboard_map_all
;
2771 static int international_keyboard
;
2774 dos_set_keyboard (code
, always
)
2779 _go32_dpmi_registers regs
;
2781 /* See if Keyb.Com is installed (for international keyboard support).
2782 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2783 of Windows 9X! So don't do that! */
2785 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2786 _go32_dpmi_simulate_int (0x2f, ®s
);
2787 if (regs
.h
.al
== 0xff)
2788 international_keyboard
= 1;
2790 /* Initialize to US settings, for countries that don't have their own. */
2791 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2792 keyboard_map_all
= always
;
2793 dos_keyboard_layout
= 1;
2795 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2796 if (code
== keyboard_layout_list
[i
].country_code
)
2798 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2799 keyboard_map_all
= always
;
2800 dos_keyboard_layout
= code
;
2808 unsigned char char_code
; /* normal code */
2809 unsigned char meta_code
; /* M- code */
2810 unsigned char keypad_code
; /* keypad code */
2811 unsigned char editkey_code
; /* edit key */
2812 } keypad_translate_map
[] = {
2813 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
2814 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
2815 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
2816 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
2817 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
2818 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
2819 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
2820 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
2821 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
2822 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
2823 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
2828 unsigned char char_code
; /* normal code */
2829 unsigned char keypad_code
; /* keypad code */
2830 } grey_key_translate_map
[] = {
2831 '/', 0xaf, /* kp-decimal */
2832 '*', 0xaa, /* kp-multiply */
2833 '-', 0xad, /* kp-subtract */
2834 '+', 0xab, /* kp-add */
2835 '\r', 0x8d /* kp-enter */
2838 static unsigned short
2839 ibmpc_translate_map
[] =
2841 /* --------------- 00 to 0f --------------- */
2842 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2843 Alt
| ModFct
| 0x1b, /* Escape */
2844 Normal
| 1, /* '1' */
2845 Normal
| 2, /* '2' */
2846 Normal
| 3, /* '3' */
2847 Normal
| 4, /* '4' */
2848 Normal
| 5, /* '5' */
2849 Normal
| 6, /* '6' */
2850 Normal
| 7, /* '7' */
2851 Normal
| 8, /* '8' */
2852 Normal
| 9, /* '9' */
2853 Normal
| 10, /* '0' */
2854 Normal
| 11, /* '-' */
2855 Normal
| 12, /* '=' */
2856 Special
| 0x08, /* Backspace */
2857 ModFct
| 0x74, /* Tab/Backtab */
2859 /* --------------- 10 to 1f --------------- */
2872 ModFct
| 0x0d, /* Return */
2877 /* --------------- 20 to 2f --------------- */
2886 Map
| 40, /* '\'' */
2888 Ignore
, /* Left shift */
2889 Map
| 41, /* '\\' */
2895 /* --------------- 30 to 3f --------------- */
2902 Ignore
, /* Right shift */
2903 Grey
| 1, /* Grey * */
2905 Normal
| 55, /* ' ' */
2906 Ignore
, /* Caps Lock */
2907 FctKey
| 0xbe, /* F1 */
2908 FctKey
| 0xbf, /* F2 */
2909 FctKey
| 0xc0, /* F3 */
2910 FctKey
| 0xc1, /* F4 */
2911 FctKey
| 0xc2, /* F5 */
2913 /* --------------- 40 to 4f --------------- */
2914 FctKey
| 0xc3, /* F6 */
2915 FctKey
| 0xc4, /* F7 */
2916 FctKey
| 0xc5, /* F8 */
2917 FctKey
| 0xc6, /* F9 */
2918 FctKey
| 0xc7, /* F10 */
2919 Ignore
, /* Num Lock */
2920 Ignore
, /* Scroll Lock */
2921 KeyPad
| 7, /* Home */
2922 KeyPad
| 8, /* Up */
2923 KeyPad
| 9, /* Page Up */
2924 Grey
| 2, /* Grey - */
2925 KeyPad
| 4, /* Left */
2926 KeyPad
| 5, /* Keypad 5 */
2927 KeyPad
| 6, /* Right */
2928 Grey
| 3, /* Grey + */
2929 KeyPad
| 1, /* End */
2931 /* --------------- 50 to 5f --------------- */
2932 KeyPad
| 2, /* Down */
2933 KeyPad
| 3, /* Page Down */
2934 KeyPad
| 0, /* Insert */
2935 KeyPad
| 10, /* Delete */
2936 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2937 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2938 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2939 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2940 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2941 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2942 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2943 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2944 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2945 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2946 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2947 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2949 /* --------------- 60 to 6f --------------- */
2950 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2951 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2952 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2953 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2954 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2955 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2956 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2957 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2958 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2959 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2960 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2961 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2962 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2963 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2964 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2965 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2967 /* --------------- 70 to 7f --------------- */
2968 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2969 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2970 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2971 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2972 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2973 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2974 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2975 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2976 Alt
| Map
| 1, /* '1' */
2977 Alt
| Map
| 2, /* '2' */
2978 Alt
| Map
| 3, /* '3' */
2979 Alt
| Map
| 4, /* '4' */
2980 Alt
| Map
| 5, /* '5' */
2981 Alt
| Map
| 6, /* '6' */
2982 Alt
| Map
| 7, /* '7' */
2983 Alt
| Map
| 8, /* '8' */
2985 /* --------------- 80 to 8f --------------- */
2986 Alt
| Map
| 9, /* '9' */
2987 Alt
| Map
| 10, /* '0' */
2988 Alt
| Map
| 11, /* '-' */
2989 Alt
| Map
| 12, /* '=' */
2990 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2991 FctKey
| 0xc8, /* F11 */
2992 FctKey
| 0xc9, /* F12 */
2993 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2994 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2995 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2996 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2997 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2998 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2999 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
3000 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
3001 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
3003 /* --------------- 90 to 9f --------------- */
3004 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
3005 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
3006 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
3007 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
3008 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
3009 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
3010 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
3011 Alt
| FctKey
| 0x50, /* (Alt) Home */
3012 Alt
| FctKey
| 0x52, /* (Alt) Up */
3013 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
3014 Ignore
, /* NO KEY */
3015 Alt
| FctKey
| 0x51, /* (Alt) Left */
3016 Ignore
, /* NO KEY */
3017 Alt
| FctKey
| 0x53, /* (Alt) Right */
3018 Ignore
, /* NO KEY */
3019 Alt
| FctKey
| 0x57, /* (Alt) End */
3021 /* --------------- a0 to af --------------- */
3022 Alt
| KeyPad
| 2, /* (Alt) Down */
3023 Alt
| KeyPad
| 3, /* (Alt) Page Down */
3024 Alt
| KeyPad
| 0, /* (Alt) Insert */
3025 Alt
| KeyPad
| 10, /* (Alt) Delete */
3026 Alt
| Grey
| 0, /* (Alt) Grey / */
3027 Alt
| FctKey
| 0x09, /* (Alt) Tab */
3028 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
3031 /* These bit-positions corresponds to values returned by BIOS */
3032 #define SHIFT_P 0x0003 /* two bits! */
3033 #define CTRL_P 0x0004
3034 #define ALT_P 0x0008
3035 #define SCRLOCK_P 0x0010
3036 #define NUMLOCK_P 0x0020
3037 #define CAPSLOCK_P 0x0040
3038 #define ALT_GR_P 0x0800
3039 #define SUPER_P 0x4000 /* pseudo */
3040 #define HYPER_P 0x8000 /* pseudo */
3043 dos_get_modifiers (keymask
)
3050 /* Calculate modifier bits */
3051 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
3052 int86 (0x16, ®s
, ®s
);
3056 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
3057 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
3061 mask
= regs
.h
.al
& (SHIFT_P
|
3062 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
3064 /* Do not break international keyboard support. */
3065 /* When Keyb.Com is loaded, the right Alt key is */
3066 /* used for accessing characters like { and } */
3067 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
3070 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
3073 if (dos_hyper_key
== 1)
3076 modifiers
|= hyper_modifier
;
3078 else if (dos_super_key
== 1)
3081 modifiers
|= super_modifier
;
3083 else if (!international_keyboard
)
3085 /* If Keyb.Com is NOT installed, let Right Alt behave
3086 like the Left Alt. */
3092 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
3095 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
3097 if (dos_hyper_key
== 2)
3100 modifiers
|= hyper_modifier
;
3102 else if (dos_super_key
== 2)
3105 modifiers
|= super_modifier
;
3113 modifiers
|= shift_modifier
;
3115 modifiers
|= ctrl_modifier
;
3117 modifiers
|= meta_modifier
;
3124 #define NUM_RECENT_DOSKEYS (100)
3125 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
3126 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
3127 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
3129 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
3130 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
3131 Each input key receives two values in this vector: first the ASCII code,\n\
3132 and then the scan code.")
3135 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
3138 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
3139 return Fvector (total_doskeys
, keys
);
3142 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
3143 bcopy (keys
+ recent_doskeys_index
,
3144 XVECTOR (val
)->contents
,
3145 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
3147 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
3148 recent_doskeys_index
* sizeof (Lisp_Object
));
3153 /* Get a char from keyboard. Function keys are put into the event queue. */
3157 struct input_event event
;
3160 #ifndef HAVE_X_WINDOWS
3161 /* Maybe put the cursor where it should be. */
3162 IT_cmgoto (SELECTED_FRAME());
3165 /* The following condition is equivalent to `kbhit ()', except that
3166 it uses the bios to do its job. This pleases DESQview/X. */
3167 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
3168 int86 (0x16, ®s
, ®s
),
3169 (regs
.x
.flags
& 0x40) == 0)
3172 register unsigned char c
;
3173 int sc
, code
= -1, mask
, kp_mode
;
3176 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
3177 int86 (0x16, ®s
, ®s
);
3182 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3184 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3185 recent_doskeys_index
= 0;
3186 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
3188 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
3189 recent_doskeys_index
= 0;
3191 modifiers
= dos_get_modifiers (&mask
);
3193 #ifndef HAVE_X_WINDOWS
3194 if (!NILP (Vdos_display_scancodes
))
3197 sprintf (buf
, "%02x:%02x*%04x",
3198 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
3199 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
3207 case 10: /* Ctrl Grey Enter */
3208 code
= Ctrl
| Grey
| 4;
3210 case 13: /* Grey Enter */
3213 case '/': /* Grey / */
3223 /* Try the keyboard-private translation table first. */
3224 if (keyboard
->translate_table
)
3226 struct kbd_translate
*p
= keyboard
->translate_table
;
3230 if (p
->sc
== sc
&& p
->ch
== c
)
3238 /* If the private table didn't translate it, use the general
3242 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
3244 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
3251 /* We only look at the keyboard Ctrl/Shift/Alt keys when
3252 Emacs is ready to read a key. Therefore, if they press
3253 `Alt-x' when Emacs is busy, by the time we get to
3254 `dos_get_modifiers', they might have already released the
3255 Alt key, and Emacs gets just `x', which is BAD.
3256 However, for keys with the `Map' property set, the ASCII
3257 code returns zero iff Alt is pressed. So, when we DON'T
3258 have to support international_keyboard, we don't have to
3259 distinguish between the left and right Alt keys, and we
3260 can set the META modifier for any keys with the `Map'
3261 property if they return zero ASCII code (c = 0). */
3263 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
3264 modifiers
|= meta_modifier
;
3266 modifiers
|= ctrl_modifier
;
3268 modifiers
|= shift_modifier
;
3271 switch (code
& 0xf000)
3274 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
3276 c
= 0; /* Special */
3289 if (c
== 0) /* ctrl-break */
3291 return c
; /* ALT-nnn */
3293 if (!keyboard_map_all
)
3302 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
3303 if (!keyboard_map_all
)
3307 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
3308 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
3312 code
= keyboard
->shifted
[code
];
3314 modifiers
&= ~shift_modifier
;
3317 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
3318 code
= keyboard
->alt_gr
[code
];
3320 code
= keyboard
->unshifted
[code
];
3325 if (c
== 0xe0) /* edit key */
3328 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
3329 kp_mode
= dos_keypad_mode
& 0x03;
3331 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
3336 if (code
== 10 && dos_decimal_point
)
3337 return dos_decimal_point
;
3338 return keypad_translate_map
[code
].char_code
;
3341 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
3345 code
= keypad_translate_map
[code
].meta_code
;
3346 modifiers
= meta_modifier
;
3350 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
3357 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
3358 if (dos_keypad_mode
& kp_mode
)
3359 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
3361 code
= grey_key_translate_map
[code
].char_code
;
3370 event
.kind
= non_ascii_keystroke
;
3372 event
.kind
= ascii_keystroke
;
3374 event
.modifiers
= modifiers
;
3375 event
.frame_or_window
= selected_frame
;
3377 event
.timestamp
= event_timestamp ();
3378 kbd_buffer_store_event (&event
);
3381 if (have_mouse
> 0 && !mouse_preempted
)
3383 int but
, press
, x
, y
, ok
;
3384 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
3386 /* Check for mouse movement *before* buttons. */
3387 mouse_check_moved ();
3389 /* If the mouse moved from the spot of its last sighting, we
3390 might need to update mouse highlight. */
3391 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
3393 previous_help_echo
= help_echo
;
3394 help_echo
= help_echo_object
= help_echo_window
= Qnil
;
3396 IT_note_mouse_highlight (SELECTED_FRAME(),
3397 mouse_last_x
, mouse_last_y
);
3398 /* If the contents of the global variable help_echo has
3399 changed, generate a HELP_EVENT. */
3400 if (!NILP (help_echo
) || !NILP (previous_help_echo
))
3402 /* HELP_EVENT takes 2 events in the event loop. */
3403 event
.kind
= HELP_EVENT
;
3404 event
.frame_or_window
= selected_frame
;
3405 event
.arg
= help_echo_object
;
3406 event
.x
= make_number (help_echo_pos
);
3407 event
.timestamp
= event_timestamp ();
3409 kbd_buffer_store_event (&event
);
3410 if (WINDOWP (help_echo_window
))
3411 event
.frame_or_window
= help_echo_window
;
3412 event
.arg
= help_echo
;
3414 kbd_buffer_store_event (&event
);
3418 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
3419 for (press
= 0; press
< 2; press
++)
3421 int button_num
= but
;
3424 ok
= mouse_pressed (but
, &x
, &y
);
3426 ok
= mouse_released (but
, &x
, &y
);
3429 /* Allow a simultaneous press/release of Mouse-1 and
3430 Mouse-2 to simulate Mouse-3 on two-button mice. */
3431 if (mouse_button_count
== 2 && but
< 2)
3433 int x2
, y2
; /* don't clobber original coordinates */
3435 /* If only one button is pressed, wait 100 msec and
3436 check again. This way, Speedy Gonzales isn't
3437 punished, while the slow get their chance. */
3438 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3439 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3444 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
3445 || !press
&& mouse_released (1-but
, &x2
, &y2
))
3450 event
.kind
= mouse_click
;
3451 event
.code
= button_num
;
3452 event
.modifiers
= dos_get_modifiers (0)
3453 | (press
? down_modifier
: up_modifier
);
3456 event
.frame_or_window
= selected_frame
;
3458 event
.timestamp
= event_timestamp ();
3459 kbd_buffer_store_event (&event
);
3467 static int prev_get_char
= -1;
3469 /* Return 1 if a key is ready to be read without suspending execution. */
3473 if (prev_get_char
!= -1)
3476 return ((prev_get_char
= dos_rawgetc ()) != -1);
3479 /* Read a key. Return -1 if no key is ready. */
3483 if (prev_get_char
!= -1)
3485 int c
= prev_get_char
;
3490 return dos_rawgetc ();
3493 #ifndef HAVE_X_WINDOWS
3494 /* See xterm.c for more info. */
3496 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
3498 register int pix_x
, pix_y
;
3499 register int *x
, *y
;
3503 if (bounds
) abort ();
3505 /* Ignore clipping. */
3512 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
3515 register int *pix_x
, *pix_y
;
3521 /* Simulation of X's menus. Nothing too fancy here -- just make it work
3524 Actually, I don't know the meaning of all the parameters of the functions
3525 here -- I only know how they are called by xmenu.c. I could of course
3526 grab the nearest Xlib manual (down the hall, second-to-last door on the
3527 left), but I don't think it's worth the effort. */
3529 /* These hold text of the current and the previous menu help messages. */
3530 static char *menu_help_message
, *prev_menu_help_message
;
3531 /* Pane number and item number of the menu item which generated the
3532 last menu help message. */
3533 static int menu_help_paneno
, menu_help_itemno
;
3540 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
3541 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
3545 /* Allocate some (more) memory for MENU ensuring that there is room for one
3549 IT_menu_make_room (XMenu
*menu
)
3551 if (menu
->allocated
== 0)
3553 int count
= menu
->allocated
= 10;
3554 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
3555 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
3556 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
3557 menu
->help_text
= (char **) xmalloc (count
* sizeof (char *));
3559 else if (menu
->allocated
== menu
->count
)
3561 int count
= menu
->allocated
= menu
->allocated
+ 10;
3563 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
3565 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
3567 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
3569 = (char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
3573 /* Search the given menu structure for a given pane number. */
3576 IT_menu_search_pane (XMenu
*menu
, int pane
)
3581 for (i
= 0; i
< menu
->count
; i
++)
3582 if (menu
->submenu
[i
])
3584 if (pane
== menu
->panenumber
[i
])
3585 return menu
->submenu
[i
];
3586 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
3592 /* Determine how much screen space a given menu needs. */
3595 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
3597 int i
, h2
, w2
, maxsubwidth
, maxheight
;
3600 maxheight
= menu
->count
;
3601 for (i
= 0; i
< menu
->count
; i
++)
3603 if (menu
->submenu
[i
])
3605 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
3606 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
3607 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
3610 *width
= menu
->width
+ maxsubwidth
;
3611 *height
= maxheight
;
3614 /* Display MENU at (X,Y) using FACES. */
3617 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
3619 int i
, j
, face
, width
;
3620 struct glyph
*text
, *p
;
3623 int enabled
, mousehere
;
3625 struct frame
*sf
= SELECTED_FRAME();
3627 menu_help_message
= NULL
;
3629 width
= menu
->width
;
3630 text
= (struct glyph
*) xmalloc ((width
+ 2) * sizeof (struct glyph
));
3631 ScreenGetCursor (&row
, &col
);
3632 mouse_get_xy (&mx
, &my
);
3633 IT_update_begin (sf
);
3634 for (i
= 0; i
< menu
->count
; i
++)
3636 int max_width
= width
+ 2;
3638 IT_cursor_to (y
+ i
, x
);
3640 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
3641 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
3642 face
= faces
[enabled
+ mousehere
* 2];
3643 /* The following if clause means that we display the menu help
3644 strings even if the menu item is currently disabled. */
3645 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
3647 menu_help_message
= menu
->help_text
[i
];
3648 menu_help_paneno
= pn
- 1;
3649 menu_help_itemno
= i
;
3652 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3654 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
3658 SET_CHAR_GLYPH (*p
, *q
++, face
, 0);
3661 else /* make '^x' */
3663 SET_CHAR_GLYPH (*p
, '^', face
, 0);
3666 SET_CHAR_GLYPH (*p
, *q
++ + 64, face
, 0);
3670 /* Don't let the menu text overflow into the next screen row. */
3671 if (x
+ max_width
> screen_size_X
)
3673 max_width
= screen_size_X
- x
;
3674 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
3676 for (; j
< max_width
- 2; j
++, p
++)
3677 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
3679 SET_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
3681 IT_write_glyphs (text
, max_width
);
3684 IT_cursor_to (row
, col
);
3688 /* --------------------------- X Menu emulation ---------------------- */
3690 /* Report availability of menus. */
3698 /* Create a brand new menu structure. */
3701 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
3703 return IT_menu_create ();
3706 /* Create a new pane and place it on the outer-most level. It is not
3707 clear that it should be placed out there, but I don't know what else
3711 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
3719 IT_menu_make_room (menu
);
3720 menu
->submenu
[menu
->count
] = IT_menu_create ();
3721 menu
->text
[menu
->count
] = txt
;
3722 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3723 menu
->help_text
[menu
->count
] = NULL
;
3726 /* Adjust length for possible control characters (which will
3727 be written as ^x). */
3728 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3732 if (len
> menu
->width
)
3735 return menu
->panecount
;
3738 /* Create a new item in a menu pane. */
3741 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3742 int foo
, char *txt
, int enable
, char *help_text
)
3748 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3750 IT_menu_make_room (menu
);
3751 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3752 menu
->text
[menu
->count
] = txt
;
3753 menu
->panenumber
[menu
->count
] = enable
;
3754 menu
->help_text
[menu
->count
] = help_text
;
3757 /* Adjust length for possible control characters (which will
3758 be written as ^x). */
3759 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3763 if (len
> menu
->width
)
3769 /* Decide where the menu would be placed if requested at (X,Y). */
3772 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3773 int *ulx
, int *uly
, int *width
, int *height
)
3775 IT_menu_calc_size (menu
, width
, height
);
3781 struct IT_menu_state
3783 void *screen_behind
;
3790 /* Display menu, wait for user's response, and return that response. */
3793 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3794 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3795 void (*help_callback
)(char *, int, int))
3797 struct IT_menu_state
*state
;
3802 Lisp_Object selectface
;
3803 int leave
, result
, onepane
;
3804 int title_faces
[4]; /* face to display the menu title */
3805 int buffers_num_deleted
= 0;
3806 struct frame
*sf
= SELECTED_FRAME();
3807 Lisp_Object saved_echo_area_message
;
3809 /* Just in case we got here without a mouse present... */
3810 if (have_mouse
<= 0)
3811 return XM_IA_SELECT
;
3812 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3813 around the display. */
3819 /* We will process all the mouse events directly, so we had
3820 better prevent dos_rawgetc from stealing them from us. */
3823 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3824 screensize
= screen_size
* 2;
3826 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3827 0, DEFAULT_FACE_ID
);
3829 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3830 0, DEFAULT_FACE_ID
);
3831 selectface
= intern ("msdos-menu-select-face");
3832 faces
[2] = lookup_derived_face (sf
, selectface
,
3834 faces
[3] = lookup_derived_face (sf
, selectface
,
3837 /* Make sure the menu title is always displayed with
3838 `msdos-menu-active-face', no matter where the mouse pointer is. */
3839 for (i
= 0; i
< 4; i
++)
3840 title_faces
[i
] = faces
[3];
3844 /* Don't let the title for the "Buffers" popup menu include a
3845 digit (which is ugly).
3847 This is a terrible kludge, but I think the "Buffers" case is
3848 the only one where the title includes a number, so it doesn't
3849 seem to be necessary to make this more general. */
3850 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3852 menu
->text
[0][7] = '\0';
3853 buffers_num_deleted
= 1;
3856 /* We need to save the current echo area message, so that we could
3857 restore it below, before we exit. See the commentary below,
3858 before the call to message_with_string. */
3859 saved_echo_area_message
= Fcurrent_message ();
3860 state
[0].menu
= menu
;
3862 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3864 /* Turn off the cursor. Otherwise it shows through the menu
3865 panes, which is ugly. */
3866 IT_display_cursor (0);
3868 /* Display the menu title. */
3869 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3870 if (buffers_num_deleted
)
3871 menu
->text
[0][7] = ' ';
3872 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3874 menu
->width
= menu
->submenu
[0]->width
;
3875 state
[0].menu
= menu
->submenu
[0];
3879 state
[0].menu
= menu
;
3881 state
[0].x
= x0
- 1;
3883 state
[0].pane
= onepane
;
3885 mouse_last_x
= -1; /* A hack that forces display. */
3889 if (!mouse_visible
) mouse_on ();
3890 mouse_check_moved ();
3891 if (sf
->mouse_moved
)
3893 sf
->mouse_moved
= 0;
3894 result
= XM_IA_SELECT
;
3895 mouse_get_xy (&x
, &y
);
3896 for (i
= 0; i
< statecount
; i
++)
3897 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3899 int dy
= y
- state
[i
].y
;
3900 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3902 if (!state
[i
].menu
->submenu
[dy
])
3903 if (state
[i
].menu
->panenumber
[dy
])
3904 result
= XM_SUCCESS
;
3906 result
= XM_IA_SELECT
;
3907 *pane
= state
[i
].pane
- 1;
3909 /* We hit some part of a menu, so drop extra menus that
3910 have been opened. That does not include an open and
3912 if (i
!= statecount
- 2
3913 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3914 while (i
!= statecount
- 1)
3918 ScreenUpdate (state
[statecount
].screen_behind
);
3919 if (screen_virtual_segment
)
3920 dosv_refresh_virtual_screen (0, screen_size
);
3921 xfree (state
[statecount
].screen_behind
);
3923 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3925 IT_menu_display (state
[i
].menu
,
3930 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3931 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3933 ScreenRetrieve (state
[statecount
].screen_behind
3934 = xmalloc (screensize
));
3936 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3937 state
[statecount
].y
= y
;
3942 IT_menu_display (state
[statecount
- 1].menu
,
3943 state
[statecount
- 1].y
,
3944 state
[statecount
- 1].x
,
3945 state
[statecount
- 1].pane
,
3950 if ((menu_help_message
|| prev_menu_help_message
)
3951 && menu_help_message
!= prev_menu_help_message
)
3953 help_callback (menu_help_message
,
3954 menu_help_paneno
, menu_help_itemno
);
3955 IT_display_cursor (0);
3956 prev_menu_help_message
= menu_help_message
;
3958 /* We are busy-waiting for the mouse to move, so let's be nice
3959 to other Windows applications by releasing our time slice. */
3962 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3964 /* Only leave if user both pressed and released the mouse, and in
3965 that order. This avoids popping down the menu pane unless
3966 the user is really done with it. */
3967 if (mouse_pressed (b
, &x
, &y
))
3969 while (mouse_button_depressed (b
, &x
, &y
))
3973 (void) mouse_released (b
, &x
, &y
);
3978 ScreenUpdate (state
[0].screen_behind
);
3979 if (screen_virtual_segment
)
3980 dosv_refresh_virtual_screen (0, screen_size
);
3982 /* We have a situation here. ScreenUpdate has just restored the
3983 screen contents as it was before we started drawing this menu.
3984 That includes any echo area message that could have been
3985 displayed back then. (In reality, that echo area message will
3986 almost always be the ``keystroke echo'' that echoes the sequence
3987 of menu items chosen by the user.) However, if the menu had some
3988 help messages, then displaying those messages caused Emacs to
3989 forget about the original echo area message. So when
3990 ScreenUpdate restored it, it created a discrepancy between the
3991 actual screen contents and what Emacs internal data structures
3994 To avoid this conflict, we force Emacs to restore the original
3995 echo area message as we found it when we entered this function.
3996 The irony of this is that we then erase the restored message
3997 right away, so the only purpose of restoring it is so that
3998 erasing it works correctly... */
3999 if (! NILP (saved_echo_area_message
))
4000 message_with_string ("%s", saved_echo_area_message
, 0);
4002 while (statecount
--)
4003 xfree (state
[statecount
].screen_behind
);
4004 IT_display_cursor (1); /* turn cursor back on */
4005 /* Clean up any mouse events that are waiting inside Emacs event queue.
4006 These events are likely to be generated before the menu was even
4007 displayed, probably because the user pressed and released the button
4008 (which invoked the menu) too quickly. If we don't remove these events,
4009 Emacs will process them after we return and surprise the user. */
4010 discard_mouse_events ();
4011 mouse_clear_clicks ();
4012 if (!kbd_buffer_events_waiting (1))
4013 clear_input_pending ();
4014 /* Allow mouse events generation by dos_rawgetc. */
4019 /* Dispose of a menu. */
4022 XMenuDestroy (Display
*foo
, XMenu
*menu
)
4025 if (menu
->allocated
)
4027 for (i
= 0; i
< menu
->count
; i
++)
4028 if (menu
->submenu
[i
])
4029 XMenuDestroy (foo
, menu
->submenu
[i
]);
4031 xfree (menu
->submenu
);
4032 xfree (menu
->panenumber
);
4033 xfree (menu
->help_text
);
4036 menu_help_message
= prev_menu_help_message
= NULL
;
4040 x_pixel_width (struct frame
*f
)
4042 return FRAME_WIDTH (f
);
4046 x_pixel_height (struct frame
*f
)
4048 return FRAME_HEIGHT (f
);
4050 #endif /* !HAVE_X_WINDOWS */
4052 /* ----------------------- DOS / UNIX conversion --------------------- */
4054 void msdos_downcase_filename (unsigned char *);
4056 /* Destructively turn backslashes into slashes. */
4059 dostounix_filename (p
)
4062 msdos_downcase_filename (p
);
4072 /* Destructively turn slashes into backslashes. */
4075 unixtodos_filename (p
)
4078 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4092 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
4095 getdefdir (drive
, dst
)
4099 char in_path
[4], *p
= in_path
;
4102 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
4105 *p
++ = drive
+ 'A' - 1;
4112 _fixpath (in_path
, dst
);
4113 /* _fixpath can set errno to ENOSYS on non-LFN systems because
4114 it queries the LFN support, so ignore that error. */
4115 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
4118 msdos_downcase_filename (dst
);
4124 /* Remove all CR's that are followed by a LF. */
4129 register unsigned char *buf
;
4131 unsigned char *np
= buf
;
4132 unsigned char *startp
= buf
;
4133 unsigned char *endp
= buf
+ n
;
4137 while (buf
< endp
- 1)
4141 if (*(++buf
) != 0x0a)
4152 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
4154 /* In DJGPP v2.0, library `write' can call `malloc', which might
4155 cause relocation of the buffer whose address we get in ADDR.
4156 Here is a version of `write' that avoids calling `malloc',
4157 to serve us until such time as the library is fixed.
4158 Actually, what we define here is called `__write', because
4159 `write' is a stub that just jmp's to `__write' (to be
4160 POSIXLY-correct with respect to the global name-space). */
4162 #include <io.h> /* for _write */
4163 #include <libc/dosio.h> /* for __file_handle_modes[] */
4165 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
4167 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
4170 __write (int handle
, const void *buffer
, size_t count
)
4175 if(__file_handle_modes
[handle
] & O_BINARY
)
4176 return _write (handle
, buffer
, count
);
4180 const char *bp
= buffer
;
4181 int total_written
= 0;
4182 int nmoved
= 0, ncr
= 0;
4186 /* The next test makes sure there's space for at least 2 more
4187 characters in xbuf[], so both CR and LF can be put there. */
4199 if (xbp
>= XBUF_END
|| !count
)
4201 size_t to_write
= nmoved
+ ncr
;
4202 int written
= _write (handle
, xbuf
, to_write
);
4207 total_written
+= nmoved
; /* CRs aren't counted in ret value */
4209 /* If some, but not all were written (disk full?), return
4210 an estimate of the total written bytes not counting CRs. */
4211 if (written
< to_write
)
4212 return total_written
- (to_write
- written
) * nmoved
/to_write
;
4219 return total_written
;
4223 /* A low-level file-renaming function which works around Windows 95 bug.
4224 This is pulled directly out of DJGPP v2.01 library sources, and only
4225 used when you compile with DJGPP v2.0. */
4229 int _rename(const char *old
, const char *new)
4232 int olen
= strlen(old
) + 1;
4234 int use_lfn
= _USE_LFN
;
4235 char tempfile
[FILENAME_MAX
];
4236 const char *orig
= old
;
4239 r
.x
.dx
= __tb_offset
;
4240 r
.x
.di
= __tb_offset
+ olen
;
4241 r
.x
.ds
= r
.x
.es
= __tb_segment
;
4245 /* Windows 95 bug: for some filenames, when you rename
4246 file -> file~ (as in Emacs, to leave a backup), the
4247 short 8+3 alias doesn't change, which effectively
4248 makes OLD and NEW the same file. We must rename
4249 through a temporary file to work around this. */
4251 char *pbase
= 0, *p
;
4252 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
4253 int idx
= sizeof(try_char
) - 1;
4255 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
4256 might point to another drive, which will fail the DOS call. */
4257 strcpy(tempfile
, old
);
4258 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
4259 if (*p
== '/' || *p
== '\\' || *p
== ':')
4265 strcpy(pbase
, "X$$djren$$.$$temp$$");
4271 *pbase
= try_char
[--idx
];
4272 } while (_chmod(tempfile
, 0) != -1);
4275 _put_path2(tempfile
, olen
);
4277 __dpmi_int(0x21, &r
);
4280 errno
= __doserr_to_errno(r
.x
.ax
);
4284 /* Now create a file with the original name. This will
4285 ensure that NEW will always have a 8+3 alias
4286 different from that of OLD. (Seems to be required
4287 when NameNumericTail in the Registry is set to 0.) */
4288 lfn_fd
= _creat(old
, 0);
4290 olen
= strlen(tempfile
) + 1;
4292 r
.x
.di
= __tb_offset
+ olen
;
4301 _put_path2(new, olen
);
4303 __dpmi_int(0x21, &r
);
4306 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
4307 remove(new); /* and try again */
4310 errno
= __doserr_to_errno(r
.x
.ax
);
4312 /* Restore to original name if we renamed it to temporary. */
4320 _put_path2(orig
, olen
);
4321 _put_path(tempfile
);
4323 __dpmi_int(0x21, &r
);
4332 /* Success. Delete the file possibly created to work
4333 around the Windows 95 bug. */
4335 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
4339 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
4341 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
4343 "Return non-nil if long file names are supported on MSDOS.")
4346 return (_USE_LFN
? Qt
: Qnil
);
4349 /* Convert alphabetic characters in a filename to lower-case. */
4352 msdos_downcase_filename (p
)
4353 register unsigned char *p
;
4355 /* Always lower-case drive letters a-z, even if the filesystem
4356 preserves case in filenames.
4357 This is so MSDOS filenames could be compared by string comparison
4358 functions that are case-sensitive. Even case-preserving filesystems
4359 do not distinguish case in drive letters. */
4360 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4366 /* Under LFN we expect to get pathnames in their true case. */
4367 if (NILP (Fmsdos_long_file_names ()))
4369 if (*p
>= 'A' && *p
<= 'Z')
4373 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
4375 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
4376 When long filenames are supported, doesn't change FILENAME.\n\
4377 If FILENAME is not a string, returns nil.\n\
4378 The argument object is never altered--the value is a copy.")
4380 Lisp_Object filename
;
4384 if (! STRINGP (filename
))
4387 tem
= Fcopy_sequence (filename
);
4388 msdos_downcase_filename (XSTRING (tem
)->data
);
4392 /* The Emacs root directory as determined by init_environment. */
4394 static char emacsroot
[MAXPATHLEN
];
4397 rootrelativepath (rel
)
4400 static char result
[MAXPATHLEN
+ 10];
4402 strcpy (result
, emacsroot
);
4403 strcat (result
, "/");
4404 strcat (result
, rel
);
4408 /* Define a lot of environment variables if not already defined. Don't
4409 remove anything unless you know what you're doing -- lots of code will
4410 break if one or more of these are missing. */
4413 init_environment (argc
, argv
, skip_args
)
4420 static const char * const tempdirs
[] = {
4421 "$TMPDIR", "$TEMP", "$TMP", "c:/"
4424 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
4426 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
4427 temporary files and assume "/tmp" if $TMPDIR is unset, which
4428 will break on DOS/Windows. Refuse to work if we cannot find
4429 a directory, not even "c:/", usable for that purpose. */
4430 for (i
= 0; i
< imax
; i
++)
4432 const char *tmp
= tempdirs
[i
];
4435 tmp
= getenv (tmp
+ 1);
4436 /* Note that `access' can lie to us if the directory resides on a
4437 read-only filesystem, like CD-ROM or a write-protected floppy.
4438 The only way to be really sure is to actually create a file and
4439 see if it succeeds. But I think that's too much to ask. */
4440 if (tmp
&& access (tmp
, D_OK
) == 0)
4442 setenv ("TMPDIR", tmp
, 1);
4449 Fcons (build_string ("no usable temporary directories found!!"),
4451 "While setting TMPDIR: ");
4453 /* Note the startup time, so we know not to clear the screen if we
4454 exit immediately; see IT_reset_terminal_modes.
4455 (Yes, I know `clock' returns zero the first time it's called, but
4456 I do this anyway, in case some wiseguy changes that at some point.) */
4457 startup_time
= clock ();
4459 /* Find our root from argv[0]. Assuming argv[0] is, say,
4460 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
4461 root
= alloca (MAXPATHLEN
+ 20);
4462 _fixpath (argv
[0], root
);
4463 msdos_downcase_filename (root
);
4464 len
= strlen (root
);
4465 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
4469 && (strcmp (root
+ len
- 4, "/bin") == 0
4470 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
4471 root
[len
- 4] = '\0';
4473 strcpy (root
, "c:/emacs"); /* let's be defensive */
4474 len
= strlen (root
);
4475 strcpy (emacsroot
, root
);
4477 /* We default HOME to our root. */
4478 setenv ("HOME", root
, 0);
4480 /* We default EMACSPATH to root + "/bin". */
4481 strcpy (root
+ len
, "/bin");
4482 setenv ("EMACSPATH", root
, 0);
4484 /* I don't expect anybody to ever use other terminals so the internal
4485 terminal is the default. */
4486 setenv ("TERM", "internal", 0);
4488 #ifdef HAVE_X_WINDOWS
4489 /* Emacs expects DISPLAY to be set. */
4490 setenv ("DISPLAY", "unix:0.0", 0);
4493 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
4494 downcase it and mirror the backslashes. */
4495 s
= getenv ("COMSPEC");
4496 if (!s
) s
= "c:/command.com";
4497 t
= alloca (strlen (s
) + 1);
4499 dostounix_filename (t
);
4500 setenv ("SHELL", t
, 0);
4502 /* PATH is also downcased and backslashes mirrored. */
4503 s
= getenv ("PATH");
4505 t
= alloca (strlen (s
) + 3);
4506 /* Current directory is always considered part of MsDos's path but it is
4507 not normally mentioned. Now it is. */
4508 strcat (strcpy (t
, ".;"), s
);
4509 dostounix_filename (t
); /* Not a single file name, but this should work. */
4510 setenv ("PATH", t
, 1);
4512 /* In some sense all dos users have root privileges, so... */
4513 setenv ("USER", "root", 0);
4514 setenv ("NAME", getenv ("USER"), 0);
4516 /* Time zone determined from country code. To make this possible, the
4517 country code may not span more than one time zone. In other words,
4518 in the USA, you lose. */
4520 switch (dos_country_code
)
4522 case 31: /* Belgium */
4523 case 32: /* The Netherlands */
4524 case 33: /* France */
4525 case 34: /* Spain */
4526 case 36: /* Hungary */
4527 case 38: /* Yugoslavia (or what's left of it?) */
4528 case 39: /* Italy */
4529 case 41: /* Switzerland */
4530 case 42: /* Tjekia */
4531 case 45: /* Denmark */
4532 case 46: /* Sweden */
4533 case 47: /* Norway */
4534 case 48: /* Poland */
4535 case 49: /* Germany */
4536 /* Daylight saving from last Sunday in March to last Sunday in
4537 September, both at 2AM. */
4538 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
4540 case 44: /* United Kingdom */
4541 case 351: /* Portugal */
4542 case 354: /* Iceland */
4543 setenv ("TZ", "GMT+00", 0);
4545 case 81: /* Japan */
4546 case 82: /* Korea */
4547 setenv ("TZ", "JST-09", 0);
4549 case 90: /* Turkey */
4550 case 358: /* Finland */
4551 setenv ("TZ", "EET-02", 0);
4553 case 972: /* Israel */
4554 /* This is an approximation. (For exact rules, use the
4555 `zoneinfo/israel' file which comes with DJGPP, but you need
4556 to install it in `/usr/share/zoneinfo/' directory first.) */
4557 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
4565 static int break_stat
; /* BREAK check mode status. */
4566 static int stdin_stat
; /* stdin IOCTL status. */
4570 /* These must be global. */
4571 static _go32_dpmi_seginfo ctrl_break_vector
;
4572 static _go32_dpmi_registers ctrl_break_regs
;
4573 static int ctrlbreakinstalled
= 0;
4575 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
4578 ctrl_break_func (regs
)
4579 _go32_dpmi_registers
*regs
;
4585 install_ctrl_break_check ()
4587 if (!ctrlbreakinstalled
)
4589 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
4590 was compiler with Djgpp 1.11 maintenance level 5 or later! */
4591 ctrlbreakinstalled
= 1;
4592 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
4593 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
4595 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
4599 #endif /* __DJGPP__ < 2 */
4601 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
4602 control chars by DOS. Determine the keyboard type. */
4607 union REGS inregs
, outregs
;
4608 static int first_time
= 1;
4610 break_stat
= getcbrk ();
4613 install_ctrl_break_check ();
4619 int86 (0x15, &inregs
, &outregs
);
4620 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
4624 if (internal_terminal
4625 #ifdef HAVE_X_WINDOWS
4626 && inhibit_window_system
4630 inregs
.x
.ax
= 0x0021;
4631 int86 (0x33, &inregs
, &outregs
);
4632 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4635 /* Reportedly, the above doesn't work for some mouse drivers. There
4636 is an additional detection method that should work, but might be
4637 a little slower. Use that as an alternative. */
4638 inregs
.x
.ax
= 0x0000;
4639 int86 (0x33, &inregs
, &outregs
);
4640 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
4645 have_mouse
= 1; /* enable mouse */
4647 mouse_setup_buttons (outregs
.x
.bx
);
4648 mouse_position_hook
= &mouse_get_pos
;
4652 #ifndef HAVE_X_WINDOWS
4654 /* Save the cursor shape used outside Emacs. */
4655 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
4664 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
4665 return (stdin_stat
!= -1);
4668 return (setmode (fileno (stdin
), O_BINARY
) != -1);
4670 #else /* __DJGPP__ < 2 */
4674 /* I think it is wrong to overwrite `stdin_stat' every time
4675 but the first one this function is called, but I don't
4676 want to change the way it used to work in v1.x.--EZ */
4678 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
4679 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4680 intdos (&inregs
, &outregs
);
4681 stdin_stat
= outregs
.h
.dl
;
4683 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
4684 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
4685 intdos (&inregs
, &outregs
);
4686 return !outregs
.x
.cflag
;
4688 #endif /* __DJGPP__ < 2 */
4691 /* Restore status of standard input and Ctrl-C checking. */
4696 union REGS inregs
, outregs
;
4698 setcbrk (break_stat
);
4703 #ifndef HAVE_X_WINDOWS
4704 /* Restore the cursor shape we found on startup. */
4708 inregs
.x
.cx
= outside_cursor
;
4709 int86 (0x10, &inregs
, &outregs
);
4713 return (setmode (fileno (stdin
), stdin_stat
) != -1);
4715 #else /* not __DJGPP__ >= 2 */
4717 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
4718 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
4719 inregs
.x
.dx
= stdin_stat
;
4720 intdos (&inregs
, &outregs
);
4721 return !outregs
.x
.cflag
;
4723 #endif /* not __DJGPP__ >= 2 */
4727 /* Run command as specified by ARGV in directory DIR.
4728 The command is run with input from TEMPIN, output to
4729 file TEMPOUT and stderr to TEMPERR. */
4732 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
4733 unsigned char **argv
;
4734 const char *working_dir
;
4735 int tempin
, tempout
, temperr
;
4738 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
4739 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
4740 int msshell
, result
= -1;
4741 int inbak
, outbak
, errbak
;
4745 /* Get current directory as MSDOS cwd is not per-process. */
4748 /* If argv[0] is the shell, it might come in any lettercase.
4749 Since `Fmember' is case-sensitive, we need to downcase
4750 argv[0], even if we are on case-preserving filesystems. */
4751 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
4752 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
4755 if (*pl
>= 'A' && *pl
<= 'Z')
4760 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
4761 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
4762 && !strcmp ("-c", argv
[1]);
4765 saveargv1
= argv
[1];
4766 saveargv2
= argv
[2];
4768 /* We only need to mirror slashes if a DOS shell will be invoked
4769 not via `system' (which does the mirroring itself). Yes, that
4770 means DJGPP v1.x will lose here. */
4771 if (argv
[2] && argv
[3])
4773 char *p
= alloca (strlen (argv
[2]) + 1);
4775 strcpy (argv
[2] = p
, saveargv2
);
4776 while (*p
&& isspace (*p
))
4788 chdir (working_dir
);
4792 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
4793 goto done
; /* Allocation might fail due to lack of descriptors. */
4796 mouse_get_xy (&x
, &y
);
4798 dos_ttcooked (); /* do it here while 0 = stdin */
4806 if (msshell
&& !argv
[3])
4808 /* MS-DOS native shells are too restrictive. For starters, they
4809 cannot grok commands longer than 126 characters. In DJGPP v2
4810 and later, `system' is much smarter, so we'll call it instead. */
4814 /* A shell gets a single argument--its full command
4815 line--whose original was saved in `saveargv2'. */
4817 /* Don't let them pass empty command lines to `system', since
4818 with some shells it will try to invoke an interactive shell,
4819 which will hang Emacs. */
4820 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
4824 extern char **environ
;
4825 char **save_env
= environ
;
4826 int save_system_flags
= __system_flags
;
4828 /* Request the most powerful version of `system'. We need
4829 all the help we can get to avoid calling stock DOS shells. */
4830 __system_flags
= (__system_redirect
4831 | __system_use_shell
4832 | __system_allow_multiple_cmds
4833 | __system_allow_long_cmds
4834 | __system_handle_null_commands
4835 | __system_emulate_chdir
);
4838 result
= system (cmnd
);
4839 __system_flags
= save_system_flags
;
4843 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
4847 #endif /* __DJGPP__ > 1 */
4849 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
4854 emacs_close (inbak
);
4855 emacs_close (outbak
);
4856 emacs_close (errbak
);
4862 mouse_moveto (x
, y
);
4865 /* Some programs might change the meaning of the highest bit of the
4866 text attribute byte, so we get blinking characters instead of the
4867 bright background colors. Restore that. */
4874 argv
[1] = saveargv1
;
4875 argv
[2] = saveargv2
;
4883 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
4890 /* ------------------------- Compatibility functions -------------------
4895 /* Hostnames for a pc are not really funny,
4896 but they are used in change log so we emulate the best we can. */
4898 gethostname (p
, size
)
4902 char *q
= egetenv ("HOSTNAME");
4909 /* When time zones are set from Ms-Dos too many C-libraries are playing
4910 tricks with time values. We solve this by defining our own version
4911 of `gettimeofday' bypassing GO32. Our version needs to be initialized
4912 once and after each call to `tzset' with TZ changed. That is
4913 accomplished by aliasing tzset to init_gettimeofday. */
4915 static struct tm time_rec
;
4918 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
4926 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
4930 time_rec
.tm_year
= d
.da_year
- 1900;
4931 time_rec
.tm_mon
= d
.da_mon
- 1;
4932 time_rec
.tm_mday
= d
.da_day
;
4935 time_rec
.tm_hour
= t
.ti_hour
;
4936 time_rec
.tm_min
= t
.ti_min
;
4937 time_rec
.tm_sec
= t
.ti_sec
;
4940 tm
.tm_gmtoff
= dos_timezone_offset
;
4942 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
4943 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
4945 /* Ignore tzp; it's obsolescent. */
4949 #endif /* __DJGPP__ < 2 */
4952 * A list of unimplemented functions that we silently ignore.
4956 unsigned alarm (s
) unsigned s
; {}
4957 fork () { return 0; }
4958 int kill (x
, y
) int x
, y
; { return -1; }
4960 void volatile pause () {}
4961 sigsetmask (x
) int x
; { return 0; }
4962 sigblock (mask
) int mask
; { return 0; }
4965 void request_sigio (void) {}
4966 setpgrp () {return 0; }
4967 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
4968 void unrequest_sigio (void) {}
4972 #ifdef POSIX_SIGNALS
4974 /* Augment DJGPP library POSIX signal functions. This is needed
4975 as of DJGPP v2.01, but might be in the library in later releases. */
4977 #include <libc/bss.h>
4979 /* A counter to know when to re-initialize the static sets. */
4980 static int sigprocmask_count
= -1;
4982 /* Which signals are currently blocked (initially none). */
4983 static sigset_t current_mask
;
4985 /* Which signals are pending (initially none). */
4986 static sigset_t pending_signals
;
4988 /* Previous handlers to restore when the blocked signals are unblocked. */
4989 typedef void (*sighandler_t
)(int);
4990 static sighandler_t prev_handlers
[320];
4992 /* A signal handler which just records that a signal occured
4993 (it will be raised later, if and when the signal is unblocked). */
4995 sig_suspender (signo
)
4998 sigaddset (&pending_signals
, signo
);
5002 sigprocmask (how
, new_set
, old_set
)
5004 const sigset_t
*new_set
;
5010 /* If called for the first time, initialize. */
5011 if (sigprocmask_count
!= __bss_count
)
5013 sigprocmask_count
= __bss_count
;
5014 sigemptyset (&pending_signals
);
5015 sigemptyset (¤t_mask
);
5016 for (signo
= 0; signo
< 320; signo
++)
5017 prev_handlers
[signo
] = SIG_ERR
;
5021 *old_set
= current_mask
;
5026 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
5032 sigemptyset (&new_mask
);
5034 /* DJGPP supports upto 320 signals. */
5035 for (signo
= 0; signo
< 320; signo
++)
5037 if (sigismember (¤t_mask
, signo
))
5038 sigaddset (&new_mask
, signo
);
5039 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
5041 sigaddset (&new_mask
, signo
);
5043 /* SIGKILL is silently ignored, as on other platforms. */
5044 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
5045 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
5047 if (( how
== SIG_UNBLOCK
5048 && sigismember (&new_mask
, signo
)
5049 && sigismember (new_set
, signo
))
5050 || (how
== SIG_SETMASK
5051 && sigismember (&new_mask
, signo
)
5052 && !sigismember (new_set
, signo
)))
5054 sigdelset (&new_mask
, signo
);
5055 if (prev_handlers
[signo
] != SIG_ERR
)
5057 signal (signo
, prev_handlers
[signo
]);
5058 prev_handlers
[signo
] = SIG_ERR
;
5060 if (sigismember (&pending_signals
, signo
))
5062 sigdelset (&pending_signals
, signo
);
5067 current_mask
= new_mask
;
5071 #else /* not POSIX_SIGNALS */
5073 sigsetmask (x
) int x
; { return 0; }
5074 sigblock (mask
) int mask
; { return 0; }
5076 #endif /* not POSIX_SIGNALS */
5077 #endif /* __DJGPP__ > 1 */
5080 #include "sysselect.h"
5082 #ifndef EMACS_TIME_ZERO_OR_NEG_P
5083 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
5084 ((long)(time).tv_sec < 0 \
5085 || ((time).tv_sec == 0 \
5086 && (long)(time).tv_usec <= 0))
5089 /* This yields the rest of the current time slice to the task manager.
5090 It should be called by any code which knows that it has nothing
5091 useful to do except idle.
5093 I don't use __dpmi_yield here, since versions of library before 2.02
5094 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
5095 on some versions of Windows 9X. */
5098 dos_yield_time_slice (void)
5100 _go32_dpmi_registers r
;
5103 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
5104 _go32_dpmi_simulate_int (0x2f, &r
);
5109 /* Only event queue is checked. */
5110 /* We don't have to call timer_check here
5111 because wait_reading_process_input takes care of that. */
5113 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
5115 SELECT_TYPE
*rfds
, *wfds
, *efds
;
5116 EMACS_TIME
*timeout
;
5124 check_input
= FD_ISSET (0, rfds
);
5135 /* If we are looking only for the terminal, with no timeout,
5136 just read it and wait -- that's more efficient. */
5139 while (!detect_input_pending ())
5141 dos_yield_time_slice ();
5146 EMACS_TIME clnow
, cllast
, cldiff
;
5149 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
5151 while (!check_input
|| !detect_input_pending ())
5154 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
5155 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
5157 /* When seconds wrap around, we assume that no more than
5158 1 minute passed since last `gettime'. */
5159 if (EMACS_TIME_NEG_P (cldiff
))
5160 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
5161 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
5163 /* Stop when timeout value crosses zero. */
5164 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
5167 dos_yield_time_slice ();
5177 * Define overlaid functions:
5179 * chdir -> sys_chdir
5180 * tzset -> init_gettimeofday
5181 * abort -> dos_abort
5186 extern int chdir ();
5192 int len
= strlen (path
);
5193 char *tmp
= (char *)path
;
5195 if (*tmp
&& tmp
[1] == ':')
5197 if (getdisk () != tolower (tmp
[0]) - 'a')
5198 setdisk (tolower (tmp
[0]) - 'a');
5199 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
5203 if (len
> 1 && (tmp
[len
- 1] == '/'))
5205 char *tmp1
= (char *) alloca (len
+ 1);
5216 extern void tzset (void);
5219 init_gettimeofday ()
5225 ltm
= gtm
= time (NULL
);
5226 ltm
= mktime (lstm
= localtime (<m
));
5227 gtm
= mktime (gmtime (>m
));
5228 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
5229 time_rec
.tm_isdst
= lstm
->tm_isdst
;
5230 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
5237 dos_abort (file
, line
)
5241 char buffer1
[200], buffer2
[400];
5244 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
5245 for (i
= j
= 0; buffer1
[i
]; i
++) {
5246 buffer2
[j
++] = buffer1
[i
];
5247 buffer2
[j
++] = 0x70;
5249 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
5250 ScreenSetCursor (2, 0);
5258 ScreenSetCursor (10, 0);
5259 cputs ("\r\n\nEmacs aborted!\r\n");
5261 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
5262 if (screen_virtual_segment
)
5263 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
5264 /* Generate traceback, so we could tell whodunit. */
5265 signal (SIGINT
, SIG_DFL
);
5266 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
5267 #else /* __DJGPP_MINOR__ >= 2 */
5269 #endif /* __DJGPP_MINOR__ >= 2 */
5275 /* The following variables are required so that cus-start.el won't
5276 complain about unbound variables. */
5277 #ifndef HAVE_X_WINDOWS
5278 /* Search path for bitmap files (xfns.c). */
5279 Lisp_Object Vx_bitmap_file_path
;
5280 int x_stretch_cursor_p
;
5282 #ifndef subprocesses
5283 /* Nonzero means delete a process right away if it exits (process.c). */
5284 static int delete_exited_processes
;
5289 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
5290 staticpro (&recent_doskeys
);
5291 #ifndef HAVE_X_WINDOWS
5293 staticpro (&help_echo
);
5294 help_echo_object
= Qnil
;
5295 staticpro (&help_echo_object
);
5296 help_echo_window
= Qnil
;
5297 staticpro (&help_echo_window
);
5298 previous_help_echo
= Qnil
;
5299 staticpro (&previous_help_echo
);
5302 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
5303 "List of directories to search for bitmap files for X.");
5304 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
5306 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p
,
5307 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
5308 For example, if a block cursor is over a tab, it will be drawn as\n\
5309 wide as that tab on the display. (No effect on MS-DOS.)");
5310 x_stretch_cursor_p
= 0;
5312 /* The following two are from xfns.c: */
5313 Qbar
= intern ("bar");
5315 Qcursor_type
= intern ("cursor-type");
5316 staticpro (&Qcursor_type
);
5317 Qreverse
= intern ("reverse");
5318 staticpro (&Qreverse
);
5320 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
5321 "*Glyph to display instead of chars not supported by current codepage.\n\
5323 This variable is used only by MSDOS terminals.");
5324 Vdos_unsupported_char_glyph
= '\177';
5326 #ifndef subprocesses
5327 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
5328 "*Non-nil means delete processes immediately when they exit.\n\
5329 nil means don't delete them until `list-processes' is run.");
5330 delete_exited_processes
= 0;
5333 defsubr (&Srecent_doskeys
);
5334 defsubr (&Smsdos_long_file_names
);
5335 defsubr (&Smsdos_downcase_filename
);
5336 defsubr (&Smsdos_remember_default_colors
);
5337 defsubr (&Smsdos_set_mouse_buttons
);