1 /* MS-DOS specific C utilities. -*- coding: cp850 -*-
3 Copyright (C) 1993-1997, 1999-2013 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 /* Contributed by Morten Welinder */
21 /* New display, keyboard, and mouse control by Kim F. Storm */
23 /* Note: This file MUST use a unibyte encoding, to both display the
24 keys on the non-US keyboard layout as their respective labels, and
25 provide the correct byte values for the keyboard input to inject
26 into Emacs. See 'struct dos_keyboard_map' below. As long as there
27 are only European keyboard layouts here, we are OK with DOS
28 codepage 850 encoding. */
30 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
39 #include <sys/param.h>
41 /* gettime and settime in dos.h clash with their namesakes from
42 gnulib, so we move out of our way the prototypes in dos.h. */
43 #define gettime dos_h_gettime_
44 #define settime dos_h_settime_
49 #include <sys/stat.h> /* for _fixpath */
50 #include <unistd.h> /* for chdir, dup, dup2, etc. */
51 #include <dir.h> /* for getdisk */
52 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
54 #include <io.h> /* for setmode */
55 #include <dpmi.h> /* for __dpmi_xxx stuff */
56 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
57 #include <libc/dosio.h> /* for _USE_LFN */
58 #include <conio.h> /* for cputs */
63 #include "termhooks.h"
65 #include "dispextern.h"
68 #include "character.h"
74 #include "blockinput.h"
76 #include "intervals.h"
80 /* #include <process.h> */
81 /* Damn that local process.h! Instead we can define P_WAIT and
84 extern int spawnve (int, const char *, char *const [], char *const []);
91 #define _dos_ds _go32_info_block.selector_for_linear_memory
95 #include "syssignal.h"
97 #include "careadlinkat.h"
98 #include "allocator.h"
100 #ifndef SYSTEM_MALLOC
104 /* If other `malloc' than ours is used, force our `sbrk' behave like
105 Unix programs expect (resize memory blocks to keep them contiguous).
106 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
107 because that's what `gmalloc' expects to get. */
111 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
112 #else /* not REL_ALLOC */
113 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
114 #endif /* not REL_ALLOC */
115 #endif /* GNU_MALLOC */
117 #endif /* not SYSTEM_MALLOC */
119 /* Return the current timestamp in milliseconds since midnight. */
121 event_timestamp (void)
130 s
+= t
.tv_nsec
* 1000000;
136 /* ------------------------ Mouse control ---------------------------
138 * Coordinates are in screen positions and zero based.
139 * Mouse buttons are numbered from left to right and also zero based.
142 /* This used to be in termhooks.h, but mainstream Emacs code no longer
143 uses it, and it was removed... */
144 #define NUM_MOUSE_BUTTONS (5)
146 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
147 static int mouse_visible
;
149 static int mouse_last_x
;
150 static int mouse_last_y
;
152 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
153 static int mouse_button_count
;
160 if (have_mouse
> 0 && !mouse_visible
)
162 struct tty_display_info
*tty
= CURTTY ();
165 fprintf (tty
->termscript
, "<M_ON>");
167 int86 (0x33, ®s
, ®s
);
177 if (have_mouse
> 0 && mouse_visible
)
179 struct tty_display_info
*tty
= CURTTY ();
182 fprintf (tty
->termscript
, "<M_OFF>");
184 int86 (0x33, ®s
, ®s
);
190 mouse_setup_buttons (int n_buttons
)
194 mouse_button_count
= 3;
195 mouse_button_translate
[0] = 0; /* Left */
196 mouse_button_translate
[1] = 2; /* Middle */
197 mouse_button_translate
[2] = 1; /* Right */
199 else /* two, what else? */
201 mouse_button_count
= 2;
202 mouse_button_translate
[0] = 0;
203 mouse_button_translate
[1] = 1;
207 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons
, Smsdos_set_mouse_buttons
,
208 1, 1, "NSet number of mouse buttons to: ",
209 doc
: /* Set the number of mouse buttons to use by Emacs.
210 This is useful with mice that report the number of buttons inconsistently,
211 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
212 them. This happens with wheeled mice on Windows 9X, for example. */)
213 (Lisp_Object nbuttons
)
217 CHECK_NUMBER (nbuttons
);
220 xsignal2 (Qargs_out_of_range
,
221 build_string ("only 2 or 3 mouse buttons are supported"),
223 mouse_setup_buttons (n
);
228 mouse_get_xy (int *x
, int *y
)
233 int86 (0x33, ®s
, ®s
);
239 mouse_moveto (int x
, int y
)
242 struct tty_display_info
*tty
= CURTTY ();
245 fprintf (tty
->termscript
, "<M_XY=%dx%d>", x
, y
);
247 mouse_last_x
= regs
.x
.cx
= x
* 8;
248 mouse_last_y
= regs
.x
.dx
= y
* 8;
249 int86 (0x33, ®s
, ®s
);
253 mouse_pressed (int b
, int *xp
, int *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_released (int b
, int *xp
, int *yp
)
272 if (b
>= mouse_button_count
)
275 regs
.x
.bx
= mouse_button_translate
[b
];
276 int86 (0x33, ®s
, ®s
);
278 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
279 return (regs
.x
.bx
!= 0);
283 mouse_button_depressed (int b
, int *xp
, int *yp
)
287 if (b
>= mouse_button_count
)
290 int86 (0x33, ®s
, ®s
);
291 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
301 mouse_get_pos (struct frame
**f
, int insist
, Lisp_Object
*bar_window
,
302 enum scroll_bar_part
*part
, Lisp_Object
*x
, Lisp_Object
*y
,
306 Lisp_Object frame
, tail
;
308 /* Clear the mouse-moved flag for every frame on this display. */
309 FOR_EACH_FRAME (tail
, frame
)
310 XFRAME (frame
)->mouse_moved
= 0;
312 *f
= SELECTED_FRAME ();
314 mouse_get_xy (&ix
, &iy
);
315 *time
= event_timestamp ();
316 *x
= make_number (mouse_last_x
= ix
);
317 *y
= make_number (mouse_last_y
= iy
);
321 mouse_check_moved (void)
325 mouse_get_xy (&x
, &y
);
326 SELECTED_FRAME ()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
331 /* Force the mouse driver to ``forget'' about any button clicks until
334 mouse_clear_clicks (void)
338 for (b
= 0; b
< mouse_button_count
; b
++)
340 int dummy_x
, dummy_y
;
342 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
343 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
351 struct tty_display_info
*tty
= CURTTY ();
354 fprintf (tty
->termscript
, "<M_INIT>");
357 int86 (0x33, ®s
, ®s
);
359 /* Reset the mouse last press/release info. It seems that Windows
360 doesn't do that automatically when function 21h is called, which
361 causes Emacs to ``remember'' the click that switched focus to the
362 window just before Emacs was started from that window. */
363 mouse_clear_clicks ();
367 regs
.x
.dx
= 8 * (ScreenCols () - 1);
368 int86 (0x33, ®s
, ®s
);
372 regs
.x
.dx
= 8 * (ScreenRows () - 1);
373 int86 (0x33, ®s
, ®s
);
379 /* ------------------------- Screen control ----------------------
383 static int internal_terminal
= 0;
385 #ifndef HAVE_X_WINDOWS
386 extern unsigned char ScreenAttrib
;
387 static int screen_face
;
389 static int screen_size_X
;
390 static int screen_size_Y
;
391 static int screen_size
;
393 static int current_pos_X
;
394 static int current_pos_Y
;
395 static int new_pos_X
;
396 static int new_pos_Y
;
398 static void *startup_screen_buffer
;
399 static int startup_screen_size_X
;
400 static int startup_screen_size_Y
;
401 static int startup_pos_X
;
402 static int startup_pos_Y
;
403 static unsigned char startup_screen_attrib
;
405 static clock_t startup_time
;
407 static int term_setup_done
;
409 static unsigned short outside_cursor
;
411 /* Similar to the_only_frame. */
412 struct tty_display_info the_only_display_info
;
414 /* Support for DOS/V (allows Japanese characters to be displayed on
415 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
417 /* Holds the address of the text-mode screen buffer. */
418 static unsigned long screen_old_address
= 0;
419 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
420 static unsigned short screen_virtual_segment
= 0;
421 static unsigned short screen_virtual_offset
= 0;
422 extern Lisp_Object Qcursor_type
;
423 extern Lisp_Object Qbar
, Qhbar
;
425 /* The screen colors of the current frame, which serve as the default
426 colors for newly-created frames. */
427 static int initial_screen_colors
[2];
429 /* Update the screen from a part of relocated DOS/V screen buffer which
430 begins at OFFSET and includes COUNT characters. */
432 dosv_refresh_virtual_screen (int offset
, int count
)
436 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
439 regs
.h
.ah
= 0xff; /* update relocated screen */
440 regs
.x
.es
= screen_virtual_segment
;
441 regs
.x
.di
= screen_virtual_offset
+ offset
;
443 __dpmi_int (0x10, ®s
);
447 dos_direct_output (int y
, int x
, char *buf
, int len
)
449 int t0
= 2 * (x
+ y
* screen_size_X
);
450 int t
= t0
+ (int) ScreenPrimary
;
453 /* This is faster. */
454 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
455 _farnspokeb (t
, *buf
);
457 if (screen_virtual_segment
)
458 dosv_refresh_virtual_screen (t0
, l0
);
462 #ifndef HAVE_X_WINDOWS
464 static int blink_bit
= -1; /* the state of the blink bit at startup */
466 /* Enable bright background colors. */
472 /* Remember the original state of the blink/bright-background bit.
473 It is stored at 0040:0065h in the BIOS data area. */
475 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
479 int86 (0x10, ®s
, ®s
);
482 /* Disable bright background colors (and enable blinking) if we found
483 the video system in that state at startup. */
485 maybe_enable_blinking (void)
493 int86 (0x10, ®s
, ®s
);
497 /* Return non-zero if the system has a VGA adapter. */
504 int86 (0x10, ®s
, ®s
);
505 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
510 /* Set the screen dimensions so that it can show no less than
511 ROWS x COLS frame. */
514 dos_set_window_size (int *rows
, int *cols
)
518 Lisp_Object video_mode
;
519 int video_mode_value
, have_vga
= 0;
520 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
522 if (*rows
== current_rows
&& *cols
== current_cols
)
526 have_vga
= vga_installed ();
528 /* If the user specified a special video mode for these dimensions,
531 = Fsymbol_value (Fintern_soft (make_formatted_string
532 (video_name
, "screen-dimensions-%dx%d",
533 *rows
, *cols
), Qnil
));
535 if (INTEGERP (video_mode
)
536 && (video_mode_value
= XINT (video_mode
)) > 0)
538 regs
.x
.ax
= video_mode_value
;
539 int86 (0x10, ®s
, ®s
);
543 /* Must hardware-reset the mouse, or else it won't update
544 its notion of screen dimensions for some non-standard
545 video modes. This is *painfully* slow... */
547 int86 (0x33, ®s
, ®s
);
551 /* Find one of the dimensions supported by standard EGA/VGA
552 which gives us at least the required dimensions. */
557 } std_dimension
[] = {
567 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
569 if (std_dimension
[i
].need_vga
<= have_vga
570 && std_dimension
[i
].rows
>= *rows
)
572 if (std_dimension
[i
].rows
!= current_rows
573 || *cols
!= current_cols
)
574 _set_screen_lines (std_dimension
[i
].rows
);
588 /* Tell the caller what dimensions have been REALLY set. */
589 *rows
= ScreenRows ();
590 *cols
= ScreenCols ();
592 /* Update Emacs' notion of screen dimensions. */
593 screen_size_X
= *cols
;
594 screen_size_Y
= *rows
;
595 screen_size
= *cols
* *rows
;
597 /* If the dimensions changed, the mouse highlight info is invalid. */
598 if (current_rows
!= *rows
|| current_cols
!= *cols
)
600 struct frame
*f
= SELECTED_FRAME ();
601 Mouse_HLInfo
*hlinfo
= MOUSE_HL_INFO (f
);
602 Lisp_Object window
= hlinfo
->mouse_face_window
;
604 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
605 reset_mouse_highlight (hlinfo
);
608 /* Enable bright background colors. */
611 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
612 be defensive anyway. */
613 if (screen_virtual_segment
)
614 dosv_refresh_virtual_screen (0, *cols
* *rows
);
617 /* If we write a character in the position where the mouse is,
618 the mouse cursor may need to be refreshed. */
621 mouse_off_maybe (void)
628 mouse_get_xy (&x
, &y
);
629 if (y
!= new_pos_Y
|| x
< new_pos_X
)
635 #define DEFAULT_CURSOR_START (-1)
636 #define DEFAULT_CURSOR_WIDTH (-1)
637 #define BOX_CURSOR_WIDTH (-32)
639 /* Set cursor to begin at scan line START_LINE in the character cell
640 and extend for WIDTH scan lines. Scan lines are counted from top
641 of the character cell, starting from zero. */
643 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
645 unsigned desired_cursor
;
647 int max_line
, top_line
, bot_line
;
648 struct tty_display_info
*tty
= FRAME_TTY (f
);
650 /* Avoid the costly BIOS call if F isn't the currently selected
651 frame. Allow for NULL as unconditionally meaning the selected
653 if (f
&& f
!= SELECTED_FRAME ())
657 fprintf (tty
->termscript
, "\nCURSOR SHAPE=(%d,%d)", start_line
, width
);
659 /* The character cell size in scan lines is stored at 40:85 in the
661 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
664 default: /* this relies on CGA cursor emulation being ON! */
681 if (width
== BOX_CURSOR_WIDTH
)
686 else if (start_line
!= DEFAULT_CURSOR_START
)
688 top_line
= start_line
;
689 bot_line
= top_line
- width
- 1;
691 else if (width
!= DEFAULT_CURSOR_WIDTH
)
694 bot_line
= -1 - width
;
697 top_line
= bot_line
+ 1;
701 /* [31, 0] seems to DTRT for all screen sizes. */
705 else /* WIDTH is positive */
707 if (start_line
!= DEFAULT_CURSOR_START
)
708 bot_line
= start_line
;
709 top_line
= bot_line
- (width
- 1);
712 /* If the current cursor shape is already what they want, we are
714 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
715 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
719 regs
.x
.cx
= desired_cursor
;
720 __dpmi_int (0x10, ®s
);
724 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
726 if (EQ (cursor_type
, Qbar
) || EQ (cursor_type
, Qhbar
))
728 /* Just BAR means the normal EGA/VGA cursor. */
729 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
731 else if (CONSP (cursor_type
)
732 && (EQ (XCAR (cursor_type
), Qbar
)
733 || EQ (XCAR (cursor_type
), Qhbar
)))
735 Lisp_Object bar_parms
= XCDR (cursor_type
);
738 if (INTEGERP (bar_parms
))
740 /* Feature: negative WIDTH means cursor at the top
741 of the character cell, zero means invisible cursor. */
742 width
= XINT (bar_parms
);
743 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
746 else if (CONSP (bar_parms
)
747 && INTEGERP (XCAR (bar_parms
))
748 && INTEGERP (XCDR (bar_parms
)))
750 int start_line
= XINT (XCDR (bar_parms
));
752 width
= XINT (XCAR (bar_parms
));
753 msdos_set_cursor_shape (f
, start_line
, width
);
758 /* Treat anything unknown as "box cursor". This includes nil, so
759 that a frame which doesn't specify a cursor type gets a box,
760 which is the default in Emacs. */
761 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
766 IT_ring_bell (struct frame
*f
)
775 union REGS inregs
, outregs
;
778 intdos (&inregs
, &outregs
);
782 /* Given a face id FACE, extract the face parameters to be used for
783 display until the face changes. The face parameters (actually, its
784 color) are used to construct the video attribute byte for each
785 glyph during the construction of the buffer that is then blitted to
788 IT_set_face (int face
)
790 struct frame
*sf
= SELECTED_FRAME ();
791 struct face
*fp
= FACE_FROM_ID (sf
, face
);
792 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
793 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
794 struct tty_display_info
*tty
= FRAME_TTY (sf
);
799 /* The default face for the frame should always be realized and
807 dflt_fg
= dfp
->foreground
;
808 dflt_bg
= dfp
->background
;
810 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
811 mean use the colors of the default face. Note that we assume all
812 16 colors to be available for the background, since Emacs switches
813 on this mode (and loses the blinking attribute) at startup. */
814 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
815 fg
= FRAME_FOREGROUND_PIXEL (sf
);
816 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
817 fg
= FRAME_BACKGROUND_PIXEL (sf
);
818 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
819 bg
= FRAME_BACKGROUND_PIXEL (sf
);
820 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
821 bg
= FRAME_FOREGROUND_PIXEL (sf
);
823 /* Make sure highlighted lines really stand out, come what may. */
824 if (fp
->tty_reverse_p
&& (fg
== dflt_fg
&& bg
== dflt_bg
))
826 unsigned long tem
= fg
;
831 /* If the user requested inverse video, obey. */
834 unsigned long tem2
= fg
;
840 fprintf (tty
->termscript
, "<FACE %d: %lu/%lu[FG:%lu/BG:%lu]>", face
,
841 fp
->foreground
, fp
->background
, fg
, bg
);
842 if (fg
>= 0 && fg
< 16)
844 ScreenAttrib
&= 0xf0;
847 if (bg
>= 0 && bg
< 16)
849 ScreenAttrib
&= 0x0f;
850 ScreenAttrib
|= ((bg
& 0x0f) << 4);
854 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
855 width of a DOS display in any known text mode. We multiply by 2 to
856 accommodate the screen attribute byte. */
857 #define MAX_SCREEN_BUF 160*2
859 extern unsigned char *encode_terminal_code (struct glyph
*, int,
860 struct coding_system
*);
863 IT_write_glyphs (struct frame
*f
, struct glyph
*str
, int str_len
)
865 unsigned char screen_buf
[MAX_SCREEN_BUF
], *screen_bp
, *bp
;
866 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
867 register int sl
= str_len
;
868 struct tty_display_info
*tty
= FRAME_TTY (f
);
870 unsigned char *conversion_buffer
;
872 /* If terminal_coding does any conversion, use it, otherwise use
873 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
874 because it always returns 1 if terminal_coding.src_multibyte is 1. */
875 struct coding_system
*coding
= FRAME_TERMINAL_CODING (f
);
877 if (!(coding
->common_flags
& CODING_REQUIRE_ENCODING_MASK
))
878 coding
= &safe_terminal_coding
;
880 if (str_len
<= 0) return;
882 sf
= SELECTED_FRAME ();
884 /* Since faces get cached and uncached behind our back, we can't
885 rely on their indices in the cache being consistent across
886 invocations. So always reset the screen face to the default
887 face of the frame, before writing glyphs, and let the glyphs
888 set the right face if it's different from the default. */
889 IT_set_face (DEFAULT_FACE_ID
);
891 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
893 coding
->mode
&= ~CODING_MODE_LAST_BLOCK
;
894 screen_bp
= &screen_buf
[0];
900 /* If the face of this glyph is different from the current
901 screen face, update the screen attribute byte. */
903 if (cf
!= screen_face
)
904 IT_set_face (cf
); /* handles invalid faces gracefully */
906 /* Identify a run of glyphs with the same face. */
907 for (n
= 1; n
< sl
; ++n
)
908 if (str
[n
].face_id
!= cf
)
912 /* This is the last glyph. */
913 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
915 conversion_buffer
= encode_terminal_code (str
, n
, coding
);
916 if (coding
->produced
> 0)
918 /* Copy the encoded bytes to the screen buffer. */
919 for (bp
= conversion_buffer
; coding
->produced
--; bp
++)
921 /* Paranoia: discard bytes that would overrun the end of
922 the screen buffer. */
923 if (screen_bp
- screen_buf
<= MAX_SCREEN_BUF
- 2)
925 *screen_bp
++ = (unsigned char)*bp
;
926 *screen_bp
++ = ScreenAttrib
;
929 fputc (*bp
, tty
->termscript
);
932 /* Update STR and its remaining length. */
937 /* Dump whatever we have in the screen buffer. */
939 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
940 if (screen_virtual_segment
)
941 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
942 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
945 /************************************************************************
946 Mouse Highlight (and friends..)
947 ************************************************************************/
949 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
950 static Lisp_Object last_mouse_window
;
952 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
955 popup_activated (void)
957 return mouse_preempted
;
960 /* Draw TEXT_AREA glyphs between START and END of glyph row ROW on
961 window W. X is relative to TEXT_AREA in W. HL is a face override
962 for drawing the glyphs. */
964 tty_draw_row_with_mouse_face (struct window
*w
, struct glyph_row
*row
,
965 int start_hpos
, int end_hpos
,
966 enum draw_glyphs_face hl
)
968 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
969 struct tty_display_info
*tty
= FRAME_TTY (f
);
970 Mouse_HLInfo
*hlinfo
= &tty
->mouse_highlight
;
972 if (hl
== DRAW_MOUSE_FACE
)
974 int vpos
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
975 int kstart
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
976 int nglyphs
= end_hpos
- start_hpos
;
977 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
978 int start_offset
= offset
;
981 fprintf (tty
->termscript
, "\n<MH+ %d-%d:%d>",
982 kstart
, kstart
+ nglyphs
- 1, vpos
);
985 IT_set_face (hlinfo
->mouse_face_face_id
);
986 /* Since we are going to change only the _colors_ of already
987 displayed text, there's no need to go through all the pain of
988 generating and encoding the text from the glyphs. Instead,
989 we simply poke the attribute byte of each affected position
990 in video memory with the colors computed by IT_set_face! */
991 _farsetsel (_dos_ds
);
994 _farnspokeb (offset
, ScreenAttrib
);
997 if (screen_virtual_segment
)
998 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1001 else if (hl
== DRAW_NORMAL_TEXT
)
1003 /* We are removing a previously-drawn mouse highlight. The
1004 safest way to do so is to redraw the glyphs anew, since all
1005 kinds of faces and display tables could have changed behind
1007 int nglyphs
= end_hpos
- start_hpos
;
1008 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1010 if (end_hpos
>= row
->used
[TEXT_AREA
])
1011 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1013 /* IT_write_glyphs writes at cursor position, so we need to
1014 temporarily move cursor coordinates to the beginning of
1015 the highlight region. */
1016 new_pos_X
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1017 new_pos_Y
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1019 if (tty
->termscript
)
1020 fprintf (tty
->termscript
, "<MH- %d-%d:%d>",
1021 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1022 IT_write_glyphs (f
, row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1023 if (tty
->termscript
)
1024 fputs ("\n", tty
->termscript
);
1031 IT_clear_end_of_line (struct frame
*f
, int first_unused
)
1034 int i
, j
, offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1035 struct tty_display_info
*tty
= FRAME_TTY (f
);
1037 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1041 i
= (j
= first_unused
- new_pos_X
) * 2;
1042 if (tty
->termscript
)
1043 fprintf (tty
->termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1044 spaces
= sp
= alloca (i
);
1049 *sp
++ = ScreenAttrib
;
1053 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1054 if (screen_virtual_segment
)
1055 dosv_refresh_virtual_screen (offset
, i
/ 2);
1057 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1058 Let's follow their lead, in case someone relies on this. */
1059 new_pos_X
= first_unused
;
1063 IT_clear_screen (struct frame
*f
)
1065 struct tty_display_info
*tty
= FRAME_TTY (f
);
1067 if (tty
->termscript
)
1068 fprintf (tty
->termscript
, "<CLR:SCR>");
1069 /* We are sometimes called (from clear_garbaged_frames) when a new
1070 frame is being created, but its faces are not yet realized. In
1071 such a case we cannot call IT_set_face, since it will fail to find
1072 any valid faces and will abort. Instead, use the initial screen
1073 colors; that should mimic what a Unix tty does, which simply clears
1074 the screen with whatever default colors are in use. */
1075 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1076 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1081 if (screen_virtual_segment
)
1082 dosv_refresh_virtual_screen (0, screen_size
);
1083 new_pos_X
= new_pos_Y
= 0;
1087 IT_clear_to_end (struct frame
*f
)
1089 struct tty_display_info
*tty
= FRAME_TTY (f
);
1091 if (tty
->termscript
)
1092 fprintf (tty
->termscript
, "<CLR:EOS>");
1094 while (new_pos_Y
< screen_size_Y
) {
1096 IT_clear_end_of_line (f
, screen_size_X
);
1102 IT_cursor_to (struct frame
*f
, int y
, int x
)
1104 struct tty_display_info
*tty
= FRAME_TTY (f
);
1106 if (tty
->termscript
)
1107 fprintf (tty
->termscript
, "\n<XY=%dx%d>", x
, y
);
1112 static int cursor_cleared
;
1115 IT_display_cursor (int on
)
1117 struct tty_display_info
*tty
= CURTTY ();
1119 if (on
&& cursor_cleared
)
1121 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1123 if (tty
->termscript
)
1124 fprintf (tty
->termscript
, "\nCURSOR ON (%dx%d)",
1125 current_pos_Y
, current_pos_X
);
1127 else if (!on
&& !cursor_cleared
)
1129 ScreenSetCursor (-1, -1);
1131 if (tty
->termscript
)
1132 fprintf (tty
->termscript
, "\nCURSOR OFF (%dx%d)",
1133 current_pos_Y
, current_pos_X
);
1137 /* Emacs calls cursor-movement functions a lot when it updates the
1138 display (probably a legacy of old terminals where you cannot
1139 update a screen line without first moving the cursor there).
1140 However, cursor movement is expensive on MSDOS (it calls a slow
1141 BIOS function and requires 2 mode switches), while actual screen
1142 updates access the video memory directly and don't depend on
1143 cursor position. To avoid slowing down the redisplay, we cheat:
1144 all functions that move the cursor only set internal variables
1145 which record the cursor position, whereas the cursor is only
1146 moved to its final position whenever screen update is complete.
1148 `IT_cmgoto' is called from the keyboard reading loop and when the
1149 frame update is complete. This means that we are ready for user
1150 input, so we update the cursor position to show where the point is,
1151 and also make the mouse pointer visible.
1153 Special treatment is required when the cursor is in the echo area,
1154 to put the cursor at the end of the text displayed there. */
1157 IT_cmgoto (struct frame
*f
)
1159 /* Only set the cursor to where it should be if the display is
1160 already in sync with the window contents. */
1161 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1162 struct tty_display_info
*tty
= FRAME_TTY (f
);
1164 /* FIXME: This needs to be rewritten for the new redisplay, or
1167 static int previous_pos_X
= -1;
1169 update_cursor_pos
= 1; /* temporary!!! */
1171 /* If the display is in sync, forget any previous knowledge about
1172 cursor position. This is primarily for unexpected events like
1173 C-g in the minibuffer. */
1174 if (update_cursor_pos
&& previous_pos_X
>= 0)
1175 previous_pos_X
= -1;
1176 /* If we are in the echo area, put the cursor at the
1177 end of the echo area message. */
1178 if (!update_cursor_pos
1179 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f
))) <= new_pos_Y
)
1181 int tem_X
= current_pos_X
, dummy
;
1183 if (echo_area_glyphs
)
1185 tem_X
= echo_area_glyphs_length
;
1186 /* Save current cursor position, to be restored after the
1187 echo area message is erased. Only remember one level
1188 of previous cursor position. */
1189 if (previous_pos_X
== -1)
1190 ScreenGetCursor (&dummy
, &previous_pos_X
);
1192 else if (previous_pos_X
>= 0)
1194 /* We wind up here after the echo area message is erased.
1195 Restore the cursor position we remembered above. */
1196 tem_X
= previous_pos_X
;
1197 previous_pos_X
= -1;
1200 if (current_pos_X
!= tem_X
)
1203 update_cursor_pos
= 1;
1208 if (update_cursor_pos
1209 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1211 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1212 if (tty
->termscript
)
1213 fprintf (tty
->termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1216 /* Maybe cursor is invisible, so make it visible. */
1217 IT_display_cursor (1);
1219 /* Mouse pointer should be always visible if we are waiting for
1226 IT_update_begin (struct frame
*f
)
1228 struct tty_display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1229 Mouse_HLInfo
*hlinfo
= &display_info
->mouse_highlight
;
1230 struct frame
*mouse_face_frame
= hlinfo
->mouse_face_mouse_frame
;
1232 if (display_info
->termscript
)
1233 fprintf (display_info
->termscript
, "\n\n<UPDATE_BEGIN");
1237 if (f
&& f
== mouse_face_frame
)
1239 /* Don't do highlighting for mouse motion during the update. */
1240 hlinfo
->mouse_face_defer
= 1;
1242 /* If F needs to be redrawn, simply forget about any prior mouse
1244 if (FRAME_GARBAGED_P (f
))
1245 hlinfo
->mouse_face_window
= Qnil
;
1247 /* Can we tell that this update does not affect the window
1248 where the mouse highlight is? If so, no need to turn off.
1249 Likewise, don't do anything if none of the enabled rows
1250 contains glyphs highlighted in mouse face. */
1251 if (!NILP (hlinfo
->mouse_face_window
)
1252 && WINDOWP (hlinfo
->mouse_face_window
))
1254 struct window
*w
= XWINDOW (hlinfo
->mouse_face_window
);
1257 /* If the mouse highlight is in the window that was deleted
1258 (e.g., if it was popped by completion), clear highlight
1260 if (NILP (w
->contents
))
1261 hlinfo
->mouse_face_window
= Qnil
;
1264 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1265 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1266 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1270 if (NILP (w
->contents
) || i
< w
->desired_matrix
->nrows
)
1271 clear_mouse_face (hlinfo
);
1274 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
1275 /* If the frame with mouse highlight was deleted, invalidate the
1277 reset_mouse_highlight (hlinfo
);
1283 IT_update_end (struct frame
*f
)
1285 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1287 if (dpyinfo
->termscript
)
1288 fprintf (dpyinfo
->termscript
, "\n<UPDATE_END\n");
1289 dpyinfo
->mouse_highlight
.mouse_face_defer
= 0;
1293 IT_frame_up_to_date (struct frame
*f
)
1295 Lisp_Object new_cursor
, frame_desired_cursor
;
1298 FRAME_MOUSE_UPDATE (f
);
1300 /* Set the cursor type to whatever they wanted. In a minibuffer
1301 window, we want the cursor to appear only if we are reading input
1302 from this window, and we want the cursor to be taken from the
1303 frame parameters. For the selected window, we use either its
1304 buffer-local value or the value from the frame parameters if the
1305 buffer doesn't define its local value for the cursor type. */
1306 sw
= XWINDOW (f
->selected_window
);
1307 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1308 if (cursor_in_echo_area
1309 && FRAME_HAS_MINIBUF_P (f
)
1310 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1311 && sw
== XWINDOW (echo_area_window
))
1312 new_cursor
= frame_desired_cursor
;
1315 struct buffer
*b
= XBUFFER (sw
->contents
);
1317 if (EQ (BVAR (b
,cursor_type
), Qt
))
1318 new_cursor
= frame_desired_cursor
;
1319 else if (NILP (BVAR (b
, cursor_type
))) /* nil means no cursor */
1320 new_cursor
= Fcons (Qbar
, make_number (0));
1322 new_cursor
= BVAR (b
, cursor_type
);
1325 IT_set_cursor_type (f
, new_cursor
);
1327 IT_cmgoto (f
); /* position cursor when update is done */
1330 /* Copy LEN glyphs displayed on a single line whose vertical position
1331 is YPOS, beginning at horizontal position XFROM to horizontal
1332 position XTO, by moving blocks in the video memory. Used by
1333 functions that insert and delete glyphs. */
1335 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1337 /* The offsets of source and destination relative to the
1338 conventional memory selector. */
1339 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1340 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1342 if (from
== to
|| len
<= 0)
1345 _farsetsel (_dos_ds
);
1347 /* The source and destination might overlap, so we need to move
1348 glyphs non-destructively. */
1351 for ( ; len
; from
+= 2, to
+= 2, len
--)
1352 _farnspokew (to
, _farnspeekw (from
));
1356 from
+= (len
- 1) * 2;
1357 to
+= (len
- 1) * 2;
1358 for ( ; len
; from
-= 2, to
-= 2, len
--)
1359 _farnspokew (to
, _farnspeekw (from
));
1361 if (screen_virtual_segment
)
1362 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1365 /* Insert and delete glyphs. */
1367 IT_insert_glyphs (struct frame
*f
, struct glyph
*start
, int len
)
1369 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1371 /* Shift right the glyphs from the nominal cursor position to the
1372 end of this line. */
1373 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
1375 /* Now write the glyphs to be inserted. */
1376 IT_write_glyphs (f
, start
, len
);
1380 IT_delete_glyphs (struct frame
*f
, int n
)
1385 /* set-window-configuration on window.c needs this. */
1387 x_set_menu_bar_lines (struct frame
*f
, Lisp_Object value
, Lisp_Object oldval
)
1389 set_menu_bar_lines (f
, value
, oldval
);
1392 /* This was copied from xfaces.c */
1394 extern Lisp_Object Qbackground_color
;
1395 extern Lisp_Object Qforeground_color
;
1396 Lisp_Object Qreverse
;
1397 extern Lisp_Object Qtitle
;
1399 /* IT_set_terminal_modes is called when emacs is started,
1400 resumed, and whenever the screen is redrawn! */
1403 IT_set_terminal_modes (struct terminal
*term
)
1405 struct tty_display_info
*tty
;
1407 /* If called with initial terminal, it's too early to do anything
1409 if (term
->type
== output_initial
)
1412 tty
= term
->display_info
.tty
;
1414 if (tty
->termscript
)
1415 fprintf (tty
->termscript
, "\n<SET_TERM>");
1417 screen_size_X
= ScreenCols ();
1418 screen_size_Y
= ScreenRows ();
1419 screen_size
= screen_size_X
* screen_size_Y
;
1421 new_pos_X
= new_pos_Y
= 0;
1422 current_pos_X
= current_pos_Y
= -1;
1424 if (term_setup_done
)
1426 term_setup_done
= 1;
1428 startup_screen_size_X
= screen_size_X
;
1429 startup_screen_size_Y
= screen_size_Y
;
1430 startup_screen_attrib
= ScreenAttrib
;
1432 /* Is DOS/V (or any other RSIS software which relocates
1433 the screen) installed? */
1435 unsigned short es_value
;
1438 regs
.h
.ah
= 0xfe; /* get relocated screen address */
1439 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
1440 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
1441 else if (screen_old_address
) /* already switched to Japanese mode once */
1442 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
1444 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
1446 es_value
= regs
.x
.es
;
1447 __dpmi_int (0x10, ®s
);
1449 if (regs
.x
.es
!= es_value
)
1451 /* screen_old_address is only set if ScreenPrimary does NOT
1452 already point to the relocated buffer address returned by
1453 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1454 ScreenPrimary to that address at startup under DOS/V. */
1455 if (regs
.x
.es
!= ((ScreenPrimary
>> 4) & 0xffff))
1456 screen_old_address
= ScreenPrimary
;
1457 screen_virtual_segment
= regs
.x
.es
;
1458 screen_virtual_offset
= regs
.x
.di
;
1459 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
1463 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
1464 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
1469 /* IT_reset_terminal_modes is called when emacs is
1470 suspended or killed. */
1473 IT_reset_terminal_modes (struct terminal
*term
)
1475 int display_row_start
= (int) ScreenPrimary
;
1476 int saved_row_len
= startup_screen_size_X
* 2;
1477 int update_row_len
= ScreenCols () * 2, current_rows
= ScreenRows ();
1478 int to_next_row
= update_row_len
;
1479 unsigned char *saved_row
= startup_screen_buffer
;
1480 int cursor_pos_X
= ScreenCols () - 1, cursor_pos_Y
= ScreenRows () - 1;
1481 struct tty_display_info
*tty
= term
->display_info
.tty
;
1483 if (tty
->termscript
)
1484 fprintf (tty
->termscript
, "\n<RESET_TERM>");
1486 if (!term_setup_done
)
1491 /* Leave the video system in the same state as we found it,
1492 as far as the blink/bright-background bit is concerned. */
1493 maybe_enable_blinking ();
1495 /* We have a situation here.
1496 We cannot just do ScreenUpdate(startup_screen_buffer) because
1497 the luser could have changed screen dimensions inside Emacs
1498 and failed (or didn't want) to restore them before killing
1499 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1500 thus will happily use memory outside what was allocated for
1501 `startup_screen_buffer'.
1502 Thus we only restore as much as the current screen dimensions
1503 can hold, and clear the rest (if the saved screen is smaller than
1504 the current) with the color attribute saved at startup. The cursor
1505 is also restored within the visible dimensions. */
1507 ScreenAttrib
= startup_screen_attrib
;
1509 /* Don't restore the screen if we are exiting less than 2 seconds
1510 after startup: we might be crashing, and the screen might show
1511 some vital clues to what's wrong. */
1512 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
1515 if (screen_virtual_segment
)
1516 dosv_refresh_virtual_screen (0, screen_size
);
1518 if (update_row_len
> saved_row_len
)
1519 update_row_len
= saved_row_len
;
1520 if (current_rows
> startup_screen_size_Y
)
1521 current_rows
= startup_screen_size_Y
;
1523 if (tty
->termscript
)
1524 fprintf (tty
->termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1525 update_row_len
/ 2, current_rows
);
1527 while (current_rows
--)
1529 dosmemput (saved_row
, update_row_len
, display_row_start
);
1530 if (screen_virtual_segment
)
1531 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
1532 update_row_len
/ 2);
1533 saved_row
+= saved_row_len
;
1534 display_row_start
+= to_next_row
;
1537 if (startup_pos_X
< cursor_pos_X
)
1538 cursor_pos_X
= startup_pos_X
;
1539 if (startup_pos_Y
< cursor_pos_Y
)
1540 cursor_pos_Y
= startup_pos_Y
;
1542 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
1543 xfree (startup_screen_buffer
);
1544 startup_screen_buffer
= NULL
;
1546 term_setup_done
= 0;
1550 IT_set_terminal_window (struct frame
*f
, int foo
)
1554 /* Remember the screen colors of the current frame, to serve as the
1555 default colors for newly-created frames. */
1556 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
1557 Smsdos_remember_default_colors
, 1, 1, 0,
1558 doc
: /* Remember the screen colors of the current frame. */)
1563 CHECK_FRAME (frame
);
1566 /* This function is called after applying default-frame-alist to the
1567 initial frame. At that time, if reverse-colors option was
1568 specified in default-frame-alist, it was already applied, and
1569 frame colors are reversed. */
1570 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
1571 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
1577 IT_set_frame_parameters (struct frame
*f
, Lisp_Object alist
)
1580 int i
, j
, length
= XINT (Flength (alist
));
1582 = (Lisp_Object
*) alloca (length
* word_size
);
1584 = (Lisp_Object
*) alloca (length
* word_size
);
1585 /* Do we have to reverse the foreground and background colors? */
1586 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
1587 int redraw
= 0, fg_set
= 0, bg_set
= 0;
1588 unsigned long orig_fg
, orig_bg
;
1589 struct tty_display_info
*tty
= FRAME_TTY (f
);
1591 /* If we are creating a new frame, begin with the original screen colors
1592 used for the initial frame. */
1593 if (!f
->default_face_done_p
1594 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
1596 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
1597 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
1598 init_frame_faces (f
);
1599 f
->default_face_done_p
= 1;
1601 orig_fg
= reverse
? FRAME_BACKGROUND_PIXEL (f
) : FRAME_FOREGROUND_PIXEL (f
);
1602 orig_bg
= reverse
? FRAME_FOREGROUND_PIXEL (f
) : FRAME_BACKGROUND_PIXEL (f
);
1604 /* Extract parm names and values into those vectors. */
1606 for (tail
= alist
; CONSP (tail
); tail
= XCDR (tail
))
1608 Lisp_Object elt
= XCAR (tail
);
1609 parms
[i
] = Fcar (elt
);
1610 CHECK_SYMBOL (parms
[i
]);
1611 values
[i
] = Fcdr (elt
);
1617 for (i
= 0; i
< j
; i
++)
1619 Lisp_Object prop
, val
;
1624 if (EQ (prop
, Qreverse
))
1625 reverse
= EQ (val
, Qt
);
1628 if (tty
->termscript
&& reverse
)
1629 fprintf (tty
->termscript
, "<INVERSE-VIDEO>\n");
1631 /* Now process the alist elements in reverse of specified order. */
1632 for (i
--; i
>= 0; i
--)
1634 Lisp_Object prop
, val
;
1639 if (EQ (prop
, Qforeground_color
))
1641 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
1642 ? LFACE_BACKGROUND_INDEX
1643 : LFACE_FOREGROUND_INDEX
);
1644 if (new_color
!= FACE_TTY_DEFAULT_COLOR
1645 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
1646 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
1650 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1651 /* Make sure the foreground of the default face for
1652 this frame is changed as well. */
1653 update_face_from_frame_parameter (f
, Qforeground_color
, val
);
1655 if (tty
->termscript
)
1656 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
1660 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1661 update_face_from_frame_parameter (f
, Qbackground_color
, val
);
1663 if (tty
->termscript
)
1664 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
1669 else if (EQ (prop
, Qbackground_color
))
1671 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
1672 ? LFACE_FOREGROUND_INDEX
1673 : LFACE_BACKGROUND_INDEX
);
1674 if (new_color
!= FACE_TTY_DEFAULT_COLOR
1675 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
1676 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
1680 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1681 /* Make sure the background of the default face for
1682 this frame is changed as well. */
1684 update_face_from_frame_parameter (f
, Qbackground_color
, val
);
1685 if (tty
->termscript
)
1686 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
1690 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1692 update_face_from_frame_parameter (f
, Qforeground_color
, val
);
1693 if (tty
->termscript
)
1694 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
1699 else if (EQ (prop
, Qtitle
))
1701 x_set_title (f
, val
);
1702 if (tty
->termscript
)
1703 fprintf (tty
->termscript
, "<TITLE: %s>\n", SDATA (val
));
1705 else if (EQ (prop
, Qcursor_type
))
1707 IT_set_cursor_type (f
, val
);
1708 if (tty
->termscript
)
1709 fprintf (tty
->termscript
, "<CTYPE: %s>\n",
1712 || (CONSP (val
) && (EQ (XCAR (val
), Qbar
)
1713 || EQ (XCAR (val
), Qhbar
)))
1716 else if (EQ (prop
, Qtty_type
))
1718 internal_terminal_init ();
1719 if (tty
->termscript
)
1720 fprintf (tty
->termscript
, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
1721 SBYTES (val
), SDATA (val
));
1723 store_frame_param (f
, prop
, val
);
1726 /* If they specified "reverse", but not the colors, we need to swap
1727 the current frame colors. */
1732 FRAME_FOREGROUND_PIXEL (f
) = orig_bg
;
1733 update_face_from_frame_parameter (f
, Qforeground_color
,
1734 tty_color_name (f
, orig_bg
));
1739 FRAME_BACKGROUND_PIXEL (f
) = orig_fg
;
1740 update_face_from_frame_parameter (f
, Qbackground_color
,
1741 tty_color_name (f
, orig_fg
));
1748 face_change_count
++; /* forces xdisp.c to recompute basic faces */
1749 if (f
== SELECTED_FRAME ())
1754 extern void init_frame_faces (struct frame
*);
1756 #endif /* !HAVE_X_WINDOWS */
1759 /* Do we need the internal terminal? */
1762 internal_terminal_init (void)
1764 static int init_needed
= 1;
1765 char *term
= getenv ("TERM"), *colors
;
1766 struct frame
*sf
= SELECTED_FRAME ();
1767 struct tty_display_info
*tty
;
1769 #ifdef HAVE_X_WINDOWS
1770 if (!inhibit_window_system
)
1774 /* If this is the initial terminal, we are done here. */
1775 if (sf
->output_method
== output_initial
)
1779 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1781 #ifndef HAVE_X_WINDOWS
1782 if (!internal_terminal
|| inhibit_window_system
)
1784 sf
->output_method
= output_termcap
;
1788 tty
= FRAME_TTY (sf
);
1789 kset_window_system (current_kboard
, Qpc
);
1790 sf
->output_method
= output_msdos_raw
;
1793 if (!tty
->termscript
&& getenv ("EMACSTEST"))
1794 tty
->termscript
= fopen (getenv ("EMACSTEST"), "wt");
1795 if (tty
->termscript
)
1797 time_t now
= time (NULL
);
1798 struct tm
*tnow
= localtime (&now
);
1801 strftime (tbuf
, sizeof (tbuf
) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow
);
1802 fprintf (tty
->termscript
, "\nEmacs session started at %s\n", tbuf
);
1803 fprintf (tty
->termscript
, "=====================\n\n");
1806 Vinitial_window_system
= Qpc
;
1807 Vwindow_system_version
= make_number (24); /* RE Emacs version */
1808 tty
->terminal
->type
= output_msdos_raw
;
1810 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
1812 screen_old_address
= 0;
1814 /* Forget the stale screen colors as well. */
1815 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
1817 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
1818 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
1820 colors
= getenv ("EMACSCOLORS");
1821 if (colors
&& strlen (colors
) >= 2)
1823 /* The colors use 4 bits each (we enable bright background). */
1824 if (isdigit (colors
[0]))
1826 else if (isxdigit (colors
[0]))
1827 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1828 if (colors
[0] >= 0 && colors
[0] < 16)
1829 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors
[0];
1830 if (isdigit (colors
[1]))
1832 else if (isxdigit (colors
[1]))
1833 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1834 if (colors
[1] >= 0 && colors
[1] < 16)
1835 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors
[1];
1838 reset_mouse_highlight (&the_only_display_info
.mouse_highlight
);
1840 if (have_mouse
) /* detected in dos_ttraw, which see */
1842 have_mouse
= 1; /* enable mouse */
1844 mouse_setup_buttons (mouse_button_count
);
1845 tty
->terminal
->mouse_position_hook
= &mouse_get_pos
;
1849 if (tty
->termscript
&& screen_size
)
1850 fprintf (tty
->termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1851 screen_size_X
, screen_size_Y
);
1853 init_frame_faces (sf
);
1860 initialize_msdos_display (struct terminal
*term
)
1862 term
->rif
= 0; /* we don't support window-based display */
1863 term
->cursor_to_hook
= term
->raw_cursor_to_hook
= IT_cursor_to
;
1864 term
->clear_to_end_hook
= IT_clear_to_end
;
1865 term
->clear_frame_hook
= IT_clear_screen
;
1866 term
->clear_end_of_line_hook
= IT_clear_end_of_line
;
1867 term
->ins_del_lines_hook
= 0;
1868 term
->insert_glyphs_hook
= IT_insert_glyphs
;
1869 term
->write_glyphs_hook
= IT_write_glyphs
;
1870 term
->delete_glyphs_hook
= IT_delete_glyphs
;
1871 term
->ring_bell_hook
= IT_ring_bell
;
1872 term
->reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1873 term
->set_terminal_modes_hook
= IT_set_terminal_modes
;
1874 term
->set_terminal_window_hook
= IT_set_terminal_window
;
1875 term
->update_begin_hook
= IT_update_begin
;
1876 term
->update_end_hook
= IT_update_end
;
1877 term
->frame_up_to_date_hook
= IT_frame_up_to_date
;
1878 term
->mouse_position_hook
= 0; /* set later by dos_ttraw */
1879 term
->frame_rehighlight_hook
= 0;
1880 term
->frame_raise_lower_hook
= 0;
1881 term
->set_vertical_scroll_bar_hook
= 0;
1882 term
->condemn_scroll_bars_hook
= 0;
1883 term
->redeem_scroll_bar_hook
= 0;
1884 term
->judge_scroll_bars_hook
= 0;
1885 term
->read_socket_hook
= &tty_read_avail_input
; /* from keyboard.c */
1889 dos_get_saved_screen (char **screen
, int *rows
, int *cols
)
1891 #ifndef HAVE_X_WINDOWS
1892 *screen
= startup_screen_buffer
;
1893 *cols
= startup_screen_size_X
;
1894 *rows
= startup_screen_size_Y
;
1895 return *screen
!= (char *)0;
1901 #ifndef HAVE_X_WINDOWS
1903 /* We are not X, but we can emulate it well enough for our needs... */
1905 check_window_system (void)
1907 if (! FRAME_MSDOS_P (SELECTED_FRAME ()))
1908 error ("Not running under a window system");
1914 /* ----------------------- Keyboard control ----------------------
1916 * Keymaps reflect the following keyboard layout:
1918 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1919 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1920 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1921 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1925 #define Ignore 0x0000
1926 #define Normal 0x0000 /* normal key - alt changes scan-code */
1927 #define FctKey 0x1000 /* func key if c == 0, else c */
1928 #define Special 0x2000 /* func key even if c != 0 */
1929 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1930 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1931 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1932 #define Grey 0x6000 /* Grey keypad key */
1934 #define Alt 0x0100 /* alt scan-code */
1935 #define Ctrl 0x0200 /* ctrl scan-code */
1936 #define Shift 0x0400 /* shift scan-code */
1938 static int extended_kbd
; /* 101 (102) keyboard present. */
1940 struct kbd_translate
{
1943 unsigned short code
;
1946 struct dos_keyboard_map
1951 struct kbd_translate
*translate_table
;
1955 static struct dos_keyboard_map us_keyboard
= {
1957 /* 01234567890123456789012345678901234567890 123 45678901234 */
1958 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ \\zxcvbnm,./ ",
1959 /* 0123456789012345678901234567890123456789 012345678901234 */
1960 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| |ZXCVBNM<>? ",
1961 0, /* no Alt-Gr key */
1962 0 /* no translate table */
1965 static struct dos_keyboard_map fr_keyboard
= {
1967 /* 012 3456789012345678901234567890123456789012345678901234 */
1968 "ý&‚\"'(-Š_€…)= azertyuiop^$ qsdfghjklm—* <wxcvbn,;:! ",
1969 /* 0123456789012345678901234567890123456789012345678901234 */
1970 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ >WXCVBN?./õ ",
1971 /* 01234567 89012345678901234567890123456789012345678901234 */
1973 0 /* no translate table */
1977 * Italian keyboard support, country code 39.
1980 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1981 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1984 static struct kbd_translate it_kbd_translate_table
[] = {
1985 { 0x56, 0x3c, Normal
| 13 },
1986 { 0x56, 0x3e, Normal
| 27 },
1989 static struct dos_keyboard_map it_keyboard
= {
1991 /* 0 123456789012345678901234567890123456789012345678901234 */
1992 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— <zxcvbnm,.- ",
1993 /* 01 23456789012345678901234567890123456789012345678901234 */
1994 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ >ZXCVBNM;:_ ",
1995 /* 0123456789012345678901234567890123456789012345678901234 */
1997 it_kbd_translate_table
2000 static struct dos_keyboard_map dk_keyboard
= {
2002 /* 0123456789012345678901234567890123456789012345678901234 */
2003 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' <zxcvbnm,.- ",
2004 /* 01 23456789012345678901234567890123456789012345678901234 */
2005 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* >ZXCVBNM;:_ ",
2006 /* 0123456789012345678901234567890123456789012345678901234 */
2008 0 /* no translate table */
2011 static struct kbd_translate jp_kbd_translate_table
[] = {
2012 { 0x73, 0x5c, Normal
| 0 },
2013 { 0x73, 0x5f, Normal
| 0 },
2014 { 0x73, 0x1c, Map
| 0 },
2015 { 0x7d, 0x5c, Normal
| 13 },
2016 { 0x7d, 0x7c, Normal
| 13 },
2017 { 0x7d, 0x1c, Map
| 13 },
2020 static struct dos_keyboard_map jp_keyboard
= {
2022 /* 0123456789012 345678901234567890123456789012345678901234 */
2023 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2024 /* 01 23456789012345678901234567890123456789012345678901234 */
2025 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2026 0, /* no Alt-Gr key */
2027 jp_kbd_translate_table
2030 static struct keyboard_layout_list
2033 struct dos_keyboard_map
*keyboard_map
;
2034 } keyboard_layout_list
[] =
2036 { 1, &us_keyboard
},
2037 { 33, &fr_keyboard
},
2038 { 39, &it_keyboard
},
2039 { 45, &dk_keyboard
},
2040 { 81, &jp_keyboard
}
2043 static struct dos_keyboard_map
*keyboard
;
2044 static int keyboard_map_all
;
2045 static int international_keyboard
;
2048 dos_set_keyboard (int code
, int always
)
2051 _go32_dpmi_registers regs
;
2053 /* See if Keyb.Com is installed (for international keyboard support).
2054 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2055 of Windows 9X! So don't do that! */
2057 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2058 _go32_dpmi_simulate_int (0x2f, ®s
);
2059 if (regs
.h
.al
== 0xff)
2060 international_keyboard
= 1;
2062 /* Initialize to US settings, for countries that don't have their own. */
2063 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2064 keyboard_map_all
= always
;
2065 dos_keyboard_layout
= 1;
2067 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2068 if (code
== keyboard_layout_list
[i
].country_code
)
2070 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2071 keyboard_map_all
= always
;
2072 dos_keyboard_layout
= code
;
2080 unsigned char char_code
; /* normal code */
2081 unsigned char meta_code
; /* M- code */
2082 unsigned char keypad_code
; /* keypad code */
2083 unsigned char editkey_code
; /* edit key */
2084 } keypad_translate_map
[] = {
2085 { '0', '0', 0xb0, /* kp-0 */ 0x63 /* insert */ },
2086 { '1', '1', 0xb1, /* kp-1 */ 0x57 /* end */ },
2087 { '2', '2', 0xb2, /* kp-2 */ 0x54 /* down */ },
2088 { '3', '3', 0xb3, /* kp-3 */ 0x56 /* next */ },
2089 { '4', '4', 0xb4, /* kp-4 */ 0x51 /* left */ },
2090 { '5', '5', 0xb5, /* kp-5 */ 0xb5 /* kp-5 */ },
2091 { '6', '6', 0xb6, /* kp-6 */ 0x53 /* right */ },
2092 { '7', '7', 0xb7, /* kp-7 */ 0x50 /* home */ },
2093 { '8', '8', 0xb8, /* kp-8 */ 0x52 /* up */ },
2094 { '9', '9', 0xb9, /* kp-9 */ 0x55 /* prior */ },
2095 { '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */}
2100 unsigned char char_code
; /* normal code */
2101 unsigned char keypad_code
; /* keypad code */
2102 } grey_key_translate_map
[] = {
2103 { '/', 0xaf /* kp-decimal */ },
2104 { '*', 0xaa /* kp-multiply */ },
2105 { '-', 0xad /* kp-subtract */ },
2106 { '+', 0xab /* kp-add */ },
2107 { '\r', 0x8d /* kp-enter */ }
2110 static unsigned short
2111 ibmpc_translate_map
[] =
2113 /* --------------- 00 to 0f --------------- */
2114 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2115 Alt
| ModFct
| 0x1b, /* Escape */
2116 Normal
| 1, /* '1' */
2117 Normal
| 2, /* '2' */
2118 Normal
| 3, /* '3' */
2119 Normal
| 4, /* '4' */
2120 Normal
| 5, /* '5' */
2121 Normal
| 6, /* '6' */
2122 Normal
| 7, /* '7' */
2123 Normal
| 8, /* '8' */
2124 Normal
| 9, /* '9' */
2125 Normal
| 10, /* '0' */
2126 Normal
| 11, /* '-' */
2127 Normal
| 12, /* '=' */
2128 Special
| 0x08, /* Backspace */
2129 ModFct
| 0x74, /* Tab/Backtab */
2131 /* --------------- 10 to 1f --------------- */
2144 ModFct
| 0x0d, /* Return */
2149 /* --------------- 20 to 2f --------------- */
2158 Map
| 40, /* '\'' */
2160 Ignore
, /* Left shift */
2161 Map
| 41, /* '\\' */
2167 /* --------------- 30 to 3f --------------- */
2174 Ignore
, /* Right shift */
2175 Grey
| 1, /* Grey * */
2177 Normal
| 55, /* ' ' */
2178 Ignore
, /* Caps Lock */
2179 FctKey
| 0xbe, /* F1 */
2180 FctKey
| 0xbf, /* F2 */
2181 FctKey
| 0xc0, /* F3 */
2182 FctKey
| 0xc1, /* F4 */
2183 FctKey
| 0xc2, /* F5 */
2185 /* --------------- 40 to 4f --------------- */
2186 FctKey
| 0xc3, /* F6 */
2187 FctKey
| 0xc4, /* F7 */
2188 FctKey
| 0xc5, /* F8 */
2189 FctKey
| 0xc6, /* F9 */
2190 FctKey
| 0xc7, /* F10 */
2191 Ignore
, /* Num Lock */
2192 Ignore
, /* Scroll Lock */
2193 KeyPad
| 7, /* Home */
2194 KeyPad
| 8, /* Up */
2195 KeyPad
| 9, /* Page Up */
2196 Grey
| 2, /* Grey - */
2197 KeyPad
| 4, /* Left */
2198 KeyPad
| 5, /* Keypad 5 */
2199 KeyPad
| 6, /* Right */
2200 Grey
| 3, /* Grey + */
2201 KeyPad
| 1, /* End */
2203 /* --------------- 50 to 5f --------------- */
2204 KeyPad
| 2, /* Down */
2205 KeyPad
| 3, /* Page Down */
2206 KeyPad
| 0, /* Insert */
2207 KeyPad
| 10, /* Delete */
2208 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2209 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2210 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2211 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2212 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2213 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2214 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2215 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2216 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2217 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2218 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2219 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2221 /* --------------- 60 to 6f --------------- */
2222 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2223 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2224 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2225 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2226 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2227 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2228 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2229 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2230 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2231 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2232 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2233 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2234 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2235 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2236 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2237 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2239 /* --------------- 70 to 7f --------------- */
2240 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2241 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2242 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2243 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2244 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2245 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2246 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2247 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2248 Alt
| Map
| 1, /* '1' */
2249 Alt
| Map
| 2, /* '2' */
2250 Alt
| Map
| 3, /* '3' */
2251 Alt
| Map
| 4, /* '4' */
2252 Alt
| Map
| 5, /* '5' */
2253 Alt
| Map
| 6, /* '6' */
2254 Alt
| Map
| 7, /* '7' */
2255 Alt
| Map
| 8, /* '8' */
2257 /* --------------- 80 to 8f --------------- */
2258 Alt
| Map
| 9, /* '9' */
2259 Alt
| Map
| 10, /* '0' */
2260 Alt
| Map
| 11, /* '-' */
2261 Alt
| Map
| 12, /* '=' */
2262 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2263 FctKey
| 0xc8, /* F11 */
2264 FctKey
| 0xc9, /* F12 */
2265 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2266 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2267 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2268 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2269 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2270 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2271 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2272 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2273 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2275 /* --------------- 90 to 9f --------------- */
2276 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2277 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2278 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2279 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2280 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2281 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2282 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2283 Alt
| FctKey
| 0x50, /* (Alt) Home */
2284 Alt
| FctKey
| 0x52, /* (Alt) Up */
2285 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2286 Ignore
, /* NO KEY */
2287 Alt
| FctKey
| 0x51, /* (Alt) Left */
2288 Ignore
, /* NO KEY */
2289 Alt
| FctKey
| 0x53, /* (Alt) Right */
2290 Ignore
, /* NO KEY */
2291 Alt
| FctKey
| 0x57, /* (Alt) End */
2293 /* --------------- a0 to af --------------- */
2294 Alt
| KeyPad
| 2, /* (Alt) Down */
2295 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2296 Alt
| KeyPad
| 0, /* (Alt) Insert */
2297 Alt
| KeyPad
| 10, /* (Alt) Delete */
2298 Alt
| Grey
| 0, /* (Alt) Grey / */
2299 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2300 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2303 /* These bit-positions corresponds to values returned by BIOS */
2304 #define SHIFT_P 0x0003 /* two bits! */
2305 #define CTRL_P 0x0004
2306 #define ALT_P 0x0008
2307 #define SCRLOCK_P 0x0010
2308 #define NUMLOCK_P 0x0020
2309 #define CAPSLOCK_P 0x0040
2310 #define ALT_GR_P 0x0800
2311 #define SUPER_P 0x4000 /* pseudo */
2312 #define HYPER_P 0x8000 /* pseudo */
2315 dos_get_modifiers (int *keymask
)
2318 int mask
, modifiers
= 0;
2320 /* Calculate modifier bits */
2321 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2322 int86 (0x16, ®s
, ®s
);
2326 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2327 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2331 mask
= regs
.h
.al
& (SHIFT_P
|
2332 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2334 /* Do not break international keyboard support. */
2335 /* When Keyb.Com is loaded, the right Alt key is */
2336 /* used for accessing characters like { and } */
2337 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2340 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2343 if (dos_hyper_key
== 1)
2346 modifiers
|= hyper_modifier
;
2348 else if (dos_super_key
== 1)
2351 modifiers
|= super_modifier
;
2353 else if (!international_keyboard
)
2355 /* If Keyb.Com is NOT installed, let Right Alt behave
2356 like the Left Alt. */
2362 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2365 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2367 if (dos_hyper_key
== 2)
2370 modifiers
|= hyper_modifier
;
2372 else if (dos_super_key
== 2)
2375 modifiers
|= super_modifier
;
2383 modifiers
|= shift_modifier
;
2385 modifiers
|= ctrl_modifier
;
2387 modifiers
|= meta_modifier
;
2394 #define NUM_RECENT_DOSKEYS (100)
2395 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2396 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
2397 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
2399 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
2400 doc
: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2401 Each input key receives two values in this vector: first the ASCII code,
2402 and then the scan code. */)
2405 Lisp_Object val
, *keys
= XVECTOR (recent_doskeys
)->contents
;
2407 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
2408 return Fvector (total_doskeys
, keys
);
2411 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
2412 vcopy (val
, 0, keys
+ recent_doskeys_index
,
2413 NUM_RECENT_DOSKEYS
- recent_doskeys_index
);
2414 vcopy (val
, NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
2415 keys
, recent_doskeys_index
);
2420 /* Get a char from keyboard. Function keys are put into the event queue. */
2424 struct input_event event
;
2426 Mouse_HLInfo
*hlinfo
= MOUSE_HL_INFO (SELECTED_FRAME ());
2429 #ifndef HAVE_X_WINDOWS
2430 /* Maybe put the cursor where it should be. */
2431 IT_cmgoto (SELECTED_FRAME ());
2434 /* The following condition is equivalent to `kbhit ()', except that
2435 it uses the bios to do its job. This pleases DESQview/X. */
2436 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
2437 int86 (0x16, ®s
, ®s
),
2438 (regs
.x
.flags
& 0x40) == 0)
2441 register unsigned char c
;
2442 int modifiers
, sc
, code
= -1, mask
, kp_mode
;
2444 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
2445 int86 (0x16, ®s
, ®s
);
2450 ASET (recent_doskeys
, recent_doskeys_index
, make_number (c
));
2451 recent_doskeys_index
++;
2452 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2453 recent_doskeys_index
= 0;
2454 ASET (recent_doskeys
, recent_doskeys_index
, make_number (sc
));
2455 recent_doskeys_index
++;
2456 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2457 recent_doskeys_index
= 0;
2459 modifiers
= dos_get_modifiers (&mask
);
2461 #ifndef HAVE_X_WINDOWS
2462 if (!NILP (Vdos_display_scancodes
))
2465 sprintf (buf
, "%02x:%02x*%04x",
2466 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
2467 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
2475 case 10: /* Ctrl Grey Enter */
2476 code
= Ctrl
| Grey
| 4;
2478 case 13: /* Grey Enter */
2481 case '/': /* Grey / */
2491 /* Try the keyboard-private translation table first. */
2492 if (keyboard
->translate_table
)
2494 struct kbd_translate
*p
= keyboard
->translate_table
;
2498 if (p
->sc
== sc
&& p
->ch
== c
)
2506 /* If the private table didn't translate it, use the general
2510 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
2512 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
2519 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2520 Emacs is ready to read a key. Therefore, if they press
2521 `Alt-x' when Emacs is busy, by the time we get to
2522 `dos_get_modifiers', they might have already released the
2523 Alt key, and Emacs gets just `x', which is BAD.
2524 However, for keys with the `Map' property set, the ASCII
2525 code returns zero only if Alt is pressed. So, when we DON'T
2526 have to support international_keyboard, we don't have to
2527 distinguish between the left and right Alt keys, and we
2528 can set the META modifier for any keys with the `Map'
2529 property if they return zero ASCII code (c = 0). */
2531 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
2532 modifiers
|= meta_modifier
;
2534 modifiers
|= ctrl_modifier
;
2536 modifiers
|= shift_modifier
;
2539 switch (code
& 0xf000)
2542 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
2544 c
= 0; /* Special */
2557 if (c
== 0) /* ctrl-break */
2559 return c
; /* ALT-nnn */
2561 if (!keyboard_map_all
)
2570 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
2571 if (!keyboard_map_all
)
2575 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
2576 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
2580 code
= keyboard
->shifted
[code
];
2582 modifiers
&= ~shift_modifier
;
2585 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
2586 code
= keyboard
->alt_gr
[code
];
2588 code
= keyboard
->unshifted
[code
];
2593 if (c
== 0xe0) /* edit key */
2596 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
2597 kp_mode
= dos_keypad_mode
& 0x03;
2599 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
2604 if (code
== 10 && dos_decimal_point
)
2605 return dos_decimal_point
;
2606 return keypad_translate_map
[code
].char_code
;
2609 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
2613 code
= keypad_translate_map
[code
].meta_code
;
2614 modifiers
= meta_modifier
;
2618 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
2625 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
2626 if (dos_keypad_mode
& kp_mode
)
2627 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
2629 code
= grey_key_translate_map
[code
].char_code
;
2636 if (!hlinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
))
2638 clear_mouse_face (hlinfo
);
2639 hlinfo
->mouse_face_hidden
= 1;
2643 event
.kind
= NON_ASCII_KEYSTROKE_EVENT
;
2645 event
.kind
= ASCII_KEYSTROKE_EVENT
;
2647 event
.modifiers
= modifiers
;
2648 event
.frame_or_window
= selected_frame
;
2650 event
.timestamp
= event_timestamp ();
2651 kbd_buffer_store_event (&event
);
2654 if (have_mouse
> 0 && !mouse_preempted
)
2656 int but
, press
, x
, y
, ok
;
2657 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
2658 Lisp_Object mouse_window
= Qnil
;
2660 /* Check for mouse movement *before* buttons. */
2661 mouse_check_moved ();
2663 /* If the mouse moved from the spot of its last sighting, we
2664 might need to update mouse highlight. */
2665 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
2667 if (hlinfo
->mouse_face_hidden
)
2669 hlinfo
->mouse_face_hidden
= 0;
2670 clear_mouse_face (hlinfo
);
2673 /* Generate SELECT_WINDOW_EVENTs when needed. */
2674 if (!NILP (Vmouse_autoselect_window
))
2676 mouse_window
= window_from_coordinates (SELECTED_FRAME (),
2680 /* A window will be selected only when it is not
2681 selected now, and the last mouse movement event was
2682 not in it. A minibuffer window will be selected iff
2684 if (WINDOWP (mouse_window
)
2685 && !EQ (mouse_window
, last_mouse_window
)
2686 && !EQ (mouse_window
, selected_window
))
2688 event
.kind
= SELECT_WINDOW_EVENT
;
2689 event
.frame_or_window
= mouse_window
;
2691 event
.timestamp
= event_timestamp ();
2692 kbd_buffer_store_event (&event
);
2694 last_mouse_window
= mouse_window
;
2697 last_mouse_window
= Qnil
;
2699 previous_help_echo_string
= help_echo_string
;
2700 help_echo_string
= help_echo_object
= help_echo_window
= Qnil
;
2702 note_mouse_highlight (SELECTED_FRAME (), mouse_last_x
, mouse_last_y
);
2703 /* If the contents of the global variable help_echo has
2704 changed, generate a HELP_EVENT. */
2705 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
2706 gen_help_event (help_echo_string
, selected_frame
, help_echo_window
,
2707 help_echo_object
, help_echo_pos
);
2710 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
2711 for (press
= 0; press
< 2; press
++)
2713 int button_num
= but
;
2716 ok
= mouse_pressed (but
, &x
, &y
);
2718 ok
= mouse_released (but
, &x
, &y
);
2721 /* Allow a simultaneous press/release of Mouse-1 and
2722 Mouse-2 to simulate Mouse-3 on two-button mice. */
2723 if (mouse_button_count
== 2 && but
< 2)
2725 int x2
, y2
; /* don't clobber original coordinates */
2727 /* If only one button is pressed, wait 100 msec and
2728 check again. This way, Speedy Gonzales isn't
2729 punished, while the slow get their chance. */
2730 if ((press
&& mouse_pressed (1-but
, &x2
, &y2
))
2731 || (!press
&& mouse_released (1-but
, &x2
, &y2
)))
2736 if ((press
&& mouse_pressed (1-but
, &x2
, &y2
))
2737 || (!press
&& mouse_released (1-but
, &x2
, &y2
)))
2742 event
.kind
= MOUSE_CLICK_EVENT
;
2743 event
.code
= button_num
;
2744 event
.modifiers
= dos_get_modifiers (0)
2745 | (press
? down_modifier
: up_modifier
);
2746 event
.x
= make_number (x
);
2747 event
.y
= make_number (y
);
2748 event
.frame_or_window
= selected_frame
;
2750 event
.timestamp
= event_timestamp ();
2751 kbd_buffer_store_event (&event
);
2759 static int prev_get_char
= -1;
2761 /* Return 1 if a key is ready to be read without suspending execution. */
2765 if (prev_get_char
!= -1)
2768 return ((prev_get_char
= dos_rawgetc ()) != -1);
2771 /* Read a key. Return -1 if no key is ready. */
2775 if (prev_get_char
!= -1)
2777 int c
= prev_get_char
;
2782 return dos_rawgetc ();
2785 #ifndef HAVE_X_WINDOWS
2787 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2790 Actually, I don't know the meaning of all the parameters of the functions
2791 here -- I only know how they are called by xmenu.c. I could of course
2792 grab the nearest Xlib manual (down the hall, second-to-last door on the
2793 left), but I don't think it's worth the effort. */
2795 /* These hold text of the current and the previous menu help messages. */
2796 static const char *menu_help_message
, *prev_menu_help_message
;
2797 /* Pane number and item number of the menu item which generated the
2798 last menu help message. */
2799 static int menu_help_paneno
, menu_help_itemno
;
2802 IT_menu_create (void)
2806 menu
= xmalloc (sizeof (XMenu
));
2807 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
2811 /* Allocate some (more) memory for MENU ensuring that there is room for one
2815 IT_menu_make_room (XMenu
*menu
)
2817 if (menu
->allocated
== 0)
2819 int count
= menu
->allocated
= 10;
2820 menu
->text
= xmalloc (count
* sizeof (char *));
2821 menu
->submenu
= xmalloc (count
* sizeof (XMenu
*));
2822 menu
->panenumber
= xmalloc (count
* sizeof (int));
2823 menu
->help_text
= xmalloc (count
* sizeof (char *));
2825 else if (menu
->allocated
== menu
->count
)
2827 int count
= menu
->allocated
= menu
->allocated
+ 10;
2829 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
2831 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
2833 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
2835 = (const char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
2839 /* Search the given menu structure for a given pane number. */
2842 IT_menu_search_pane (XMenu
*menu
, int pane
)
2847 for (i
= 0; i
< menu
->count
; i
++)
2848 if (menu
->submenu
[i
])
2850 if (pane
== menu
->panenumber
[i
])
2851 return menu
->submenu
[i
];
2852 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
2858 /* Determine how much screen space a given menu needs. */
2861 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
2863 int i
, h2
, w2
, maxsubwidth
, maxheight
;
2866 maxheight
= menu
->count
;
2867 for (i
= 0; i
< menu
->count
; i
++)
2869 if (menu
->submenu
[i
])
2871 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
2872 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
2873 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
2876 *width
= menu
->width
+ maxsubwidth
;
2877 *height
= maxheight
;
2880 /* Display MENU at (X,Y) using FACES. */
2882 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
2885 (GLYPH).type = CHAR_GLYPH; \
2886 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
2887 (GLYPH).charpos = -1; \
2892 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
2894 int i
, j
, face
, width
, mx
, my
, enabled
, mousehere
, row
, col
;
2895 struct glyph
*text
, *p
;
2896 const unsigned char *q
;
2897 struct frame
*sf
= SELECTED_FRAME ();
2899 menu_help_message
= NULL
;
2901 width
= menu
->width
;
2902 /* We multiply width by 2 to account for possible control characters.
2903 FIXME: cater to non-ASCII characters in menus. */
2904 text
= xmalloc ((width
* 2 + 2) * sizeof (struct glyph
));
2905 ScreenGetCursor (&row
, &col
);
2906 mouse_get_xy (&mx
, &my
);
2907 IT_update_begin (sf
);
2908 for (i
= 0; i
< menu
->count
; i
++)
2910 int max_width
= width
+ 2;
2912 IT_cursor_to (sf
, y
+ i
, x
);
2914 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
2915 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ max_width
);
2916 face
= faces
[enabled
+ mousehere
* 2];
2917 /* The following if clause means that we display the menu help
2918 strings even if the menu item is currently disabled. */
2919 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
2921 menu_help_message
= menu
->help_text
[i
];
2922 menu_help_paneno
= pn
- 1;
2923 menu_help_itemno
= i
;
2926 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
2928 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
2930 unsigned c
= STRING_CHAR_ADVANCE (q
);
2934 BUILD_CHAR_GLYPH (*p
, c
, face
, 0);
2937 else /* make '^x' */
2939 BUILD_CHAR_GLYPH (*p
, '^', face
, 0);
2942 BUILD_CHAR_GLYPH (*p
, c
+ 64, face
, 0);
2946 /* Don't let the menu text overflow into the next screen row. */
2947 if (x
+ max_width
> screen_size_X
)
2949 max_width
= screen_size_X
- x
;
2950 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
2952 for (; j
< max_width
- 2; j
++, p
++)
2953 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
2955 /* 16 is the character code of a character that on DOS terminal
2956 produces a nice-looking right-pointing arrow glyph. */
2957 BUILD_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
2959 IT_write_glyphs (sf
, text
, max_width
);
2962 IT_cursor_to (sf
, row
, col
);
2966 /* --------------------------- X Menu emulation ---------------------- */
2968 /* Create a brand new menu structure. */
2971 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2973 return IT_menu_create ();
2976 /* Create a new pane and place it on the outer-most level. It is not
2977 clear that it should be placed out there, but I don't know what else
2981 XMenuAddPane (Display
*foo
, XMenu
*menu
, const char *txt
, int enable
)
2989 IT_menu_make_room (menu
);
2990 menu
->submenu
[menu
->count
] = IT_menu_create ();
2991 menu
->text
[menu
->count
] = (char *)txt
;
2992 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
2993 menu
->help_text
[menu
->count
] = NULL
;
2996 /* Adjust length for possible control characters (which will
2997 be written as ^x). */
2998 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3002 if (len
> menu
->width
)
3005 return menu
->panecount
;
3008 /* Create a new item in a menu pane. */
3011 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3012 int foo
, char *txt
, int enable
, char const *help_text
)
3018 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3020 IT_menu_make_room (menu
);
3021 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3022 menu
->text
[menu
->count
] = txt
;
3023 menu
->panenumber
[menu
->count
] = enable
;
3024 menu
->help_text
[menu
->count
] = help_text
;
3027 /* Adjust length for possible control characters (which will
3028 be written as ^x). */
3029 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3033 if (len
> menu
->width
)
3039 /* Decide where the menu would be placed if requested at (X,Y). */
3042 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3043 int *ulx
, int *uly
, int *width
, int *height
)
3045 IT_menu_calc_size (menu
, width
, height
);
3051 struct IT_menu_state
3053 void *screen_behind
;
3060 /* Display menu, wait for user's response, and return that response. */
3063 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3064 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3065 void (*help_callback
)(char const *, int, int))
3067 struct IT_menu_state
*state
;
3068 int statecount
, x
, y
, i
, b
, screensize
, leave
, result
, onepane
;
3069 int title_faces
[4]; /* face to display the menu title */
3070 int faces
[4], buffers_num_deleted
= 0;
3071 struct frame
*sf
= SELECTED_FRAME ();
3072 Lisp_Object saved_echo_area_message
, selectface
;
3074 /* Just in case we got here without a mouse present... */
3075 if (have_mouse
<= 0)
3076 return XM_IA_SELECT
;
3077 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3078 around the display. */
3084 /* We will process all the mouse events directly, so we had
3085 better prevent dos_rawgetc from stealing them from us. */
3088 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3089 screensize
= screen_size
* 2;
3091 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3092 DEFAULT_FACE_ID
, 1);
3094 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3095 DEFAULT_FACE_ID
, 1);
3096 selectface
= intern ("msdos-menu-select-face");
3097 faces
[2] = lookup_derived_face (sf
, selectface
,
3099 faces
[3] = lookup_derived_face (sf
, selectface
,
3102 /* Make sure the menu title is always displayed with
3103 `msdos-menu-active-face', no matter where the mouse pointer is. */
3104 for (i
= 0; i
< 4; i
++)
3105 title_faces
[i
] = faces
[3];
3109 /* Don't let the title for the "Buffers" popup menu include a
3110 digit (which is ugly).
3112 This is a terrible kludge, but I think the "Buffers" case is
3113 the only one where the title includes a number, so it doesn't
3114 seem to be necessary to make this more general. */
3115 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3117 menu
->text
[0][7] = '\0';
3118 buffers_num_deleted
= 1;
3121 /* We need to save the current echo area message, so that we could
3122 restore it below, before we exit. See the commentary below,
3123 before the call to message_with_string. */
3124 saved_echo_area_message
= Fcurrent_message ();
3125 state
[0].menu
= menu
;
3127 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3129 /* Turn off the cursor. Otherwise it shows through the menu
3130 panes, which is ugly. */
3131 IT_display_cursor (0);
3133 /* Display the menu title. */
3134 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3135 if (buffers_num_deleted
)
3136 menu
->text
[0][7] = ' ';
3137 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3139 menu
->width
= menu
->submenu
[0]->width
;
3140 state
[0].menu
= menu
->submenu
[0];
3144 state
[0].menu
= menu
;
3146 state
[0].x
= x0
- 1;
3148 state
[0].pane
= onepane
;
3150 mouse_last_x
= -1; /* A hack that forces display. */
3154 if (!mouse_visible
) mouse_on ();
3155 mouse_check_moved ();
3156 if (sf
->mouse_moved
)
3158 sf
->mouse_moved
= 0;
3159 result
= XM_IA_SELECT
;
3160 mouse_get_xy (&x
, &y
);
3161 for (i
= 0; i
< statecount
; i
++)
3162 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3164 int dy
= y
- state
[i
].y
;
3165 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3167 if (!state
[i
].menu
->submenu
[dy
])
3169 if (state
[i
].menu
->panenumber
[dy
])
3170 result
= XM_SUCCESS
;
3172 result
= XM_IA_SELECT
;
3174 *pane
= state
[i
].pane
- 1;
3176 /* We hit some part of a menu, so drop extra menus that
3177 have been opened. That does not include an open and
3179 if (i
!= statecount
- 2
3180 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3181 while (i
!= statecount
- 1)
3185 ScreenUpdate (state
[statecount
].screen_behind
);
3186 if (screen_virtual_segment
)
3187 dosv_refresh_virtual_screen (0, screen_size
);
3188 xfree (state
[statecount
].screen_behind
);
3190 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3192 IT_menu_display (state
[i
].menu
,
3197 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3198 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3200 ScreenRetrieve (state
[statecount
].screen_behind
3201 = xmalloc (screensize
));
3203 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3204 state
[statecount
].y
= y
;
3209 IT_menu_display (state
[statecount
- 1].menu
,
3210 state
[statecount
- 1].y
,
3211 state
[statecount
- 1].x
,
3212 state
[statecount
- 1].pane
,
3217 if ((menu_help_message
|| prev_menu_help_message
)
3218 && menu_help_message
!= prev_menu_help_message
)
3220 help_callback (menu_help_message
,
3221 menu_help_paneno
, menu_help_itemno
);
3222 IT_display_cursor (0);
3223 prev_menu_help_message
= menu_help_message
;
3225 /* We are busy-waiting for the mouse to move, so let's be nice
3226 to other Windows applications by releasing our time slice. */
3229 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3231 /* Only leave if user both pressed and released the mouse, and in
3232 that order. This avoids popping down the menu pane unless
3233 the user is really done with it. */
3234 if (mouse_pressed (b
, &x
, &y
))
3236 while (mouse_button_depressed (b
, &x
, &y
))
3240 (void) mouse_released (b
, &x
, &y
);
3245 ScreenUpdate (state
[0].screen_behind
);
3246 if (screen_virtual_segment
)
3247 dosv_refresh_virtual_screen (0, screen_size
);
3249 /* We have a situation here. ScreenUpdate has just restored the
3250 screen contents as it was before we started drawing this menu.
3251 That includes any echo area message that could have been
3252 displayed back then. (In reality, that echo area message will
3253 almost always be the ``keystroke echo'' that echoes the sequence
3254 of menu items chosen by the user.) However, if the menu had some
3255 help messages, then displaying those messages caused Emacs to
3256 forget about the original echo area message. So when
3257 ScreenUpdate restored it, it created a discrepancy between the
3258 actual screen contents and what Emacs internal data structures
3261 To avoid this conflict, we force Emacs to restore the original
3262 echo area message as we found it when we entered this function.
3263 The irony of this is that we then erase the restored message
3264 right away, so the only purpose of restoring it is so that
3265 erasing it works correctly... */
3266 if (! NILP (saved_echo_area_message
))
3267 message_with_string ("%s", saved_echo_area_message
, 0);
3269 while (statecount
--)
3270 xfree (state
[statecount
].screen_behind
);
3271 IT_display_cursor (1); /* Turn cursor back on. */
3272 /* Clean up any mouse events that are waiting inside Emacs event queue.
3273 These events are likely to be generated before the menu was even
3274 displayed, probably because the user pressed and released the button
3275 (which invoked the menu) too quickly. If we don't remove these events,
3276 Emacs will process them after we return and surprise the user. */
3277 discard_mouse_events ();
3278 mouse_clear_clicks ();
3279 if (!kbd_buffer_events_waiting ())
3280 clear_input_pending ();
3281 /* Allow mouse events generation by dos_rawgetc. */
3286 /* Dispose of a menu. */
3289 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3292 if (menu
->allocated
)
3294 for (i
= 0; i
< menu
->count
; i
++)
3295 if (menu
->submenu
[i
])
3296 XMenuDestroy (foo
, menu
->submenu
[i
]);
3298 xfree (menu
->submenu
);
3299 xfree (menu
->panenumber
);
3300 xfree (menu
->help_text
);
3303 menu_help_message
= prev_menu_help_message
= NULL
;
3305 #endif /* !HAVE_X_WINDOWS */
3307 /* ----------------------- DOS / UNIX conversion --------------------- */
3309 void msdos_downcase_filename (unsigned char *);
3311 /* Destructively turn backslashes into slashes. */
3314 dostounix_filename (char *p
, int ignore
)
3316 msdos_downcase_filename (p
);
3326 /* Destructively turn slashes into backslashes. */
3329 unixtodos_filename (char *p
)
3331 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3345 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3348 getdefdir (int drive
, char *dst
)
3350 char in_path
[4], *p
= in_path
, e
= errno
;
3352 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3355 *p
++ = drive
+ 'A' - 1;
3362 _fixpath (in_path
, dst
);
3363 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3364 it queries the LFN support, so ignore that error. */
3365 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
3368 msdos_downcase_filename (dst
);
3375 emacs_root_dir (void)
3377 static char root_dir
[4];
3379 sprintf (root_dir
, "%c:/", 'A' + getdisk ());
3380 root_dir
[0] = tolower (root_dir
[0]);
3384 /* Remove all CR's that are followed by a LF. */
3387 crlf_to_lf (int n
, unsigned char *buf
)
3389 unsigned char *np
= buf
, *startp
= buf
, *endp
= buf
+ n
;
3393 while (buf
< endp
- 1)
3397 if (*(++buf
) != 0x0a)
3408 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
3410 doc
: /* Return non-nil if long file names are supported on MS-DOS. */)
3413 return (_USE_LFN
? Qt
: Qnil
);
3416 /* Convert alphabetic characters in a filename to lower-case. */
3419 msdos_downcase_filename (unsigned char *p
)
3421 /* Always lower-case drive letters a-z, even if the filesystem
3422 preserves case in filenames.
3423 This is so MSDOS filenames could be compared by string comparison
3424 functions that are case-sensitive. Even case-preserving filesystems
3425 do not distinguish case in drive letters. */
3426 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3432 /* Under LFN we expect to get pathnames in their true case. */
3433 if (NILP (Fmsdos_long_file_names ()))
3435 if (*p
>= 'A' && *p
<= 'Z')
3439 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
3441 doc
: /* Convert alphabetic characters in FILENAME to lower case and return that.
3442 When long filenames are supported, doesn't change FILENAME.
3443 If FILENAME is not a string, returns nil.
3444 The argument object is never altered--the value is a copy. */)
3445 (Lisp_Object filename
)
3449 if (! STRINGP (filename
))
3452 tem
= Fcopy_sequence (filename
);
3453 msdos_downcase_filename (SDATA (tem
));
3457 /* The Emacs root directory as determined by init_environment. */
3459 static char emacsroot
[MAXPATHLEN
];
3462 rootrelativepath (char *rel
)
3464 static char result
[MAXPATHLEN
+ 10];
3466 strcpy (result
, emacsroot
);
3467 strcat (result
, "/");
3468 strcat (result
, rel
);
3472 /* Define a lot of environment variables if not already defined. Don't
3473 remove anything unless you know what you're doing -- lots of code will
3474 break if one or more of these are missing. */
3477 init_environment (int argc
, char **argv
, int skip_args
)
3481 static const char * const tempdirs
[] = {
3482 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3484 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
3486 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3487 temporary files and assume "/tmp" if $TMPDIR is unset, which
3488 will break on DOS/Windows. Refuse to work if we cannot find
3489 a directory, not even "c:/", usable for that purpose. */
3490 for (i
= 0; i
< imax
; i
++)
3492 const char *tmp
= tempdirs
[i
];
3493 char buf
[FILENAME_MAX
];
3499 tmp
= getenv (tmp
+ 1);
3503 /* Some lusers set TMPDIR=e:, probably because some losing
3504 programs cannot handle multiple slashes if they use e:/.
3505 e: fails in `access' below, so we interpret e: as e:/. */
3506 tmp_len
= strlen (tmp
);
3507 if (tmp
[tmp_len
- 1] != '/' && tmp
[tmp_len
- 1] != '\\')
3510 buf
[tmp_len
++] = '/', buf
[tmp_len
] = 0;
3515 /* Note that `access' can lie to us if the directory resides on a
3516 read-only filesystem, like CD-ROM or a write-protected floppy.
3517 The only way to be really sure is to actually create a file and
3518 see if it succeeds. But I think that's too much to ask. */
3519 if (tmp
&& access (tmp
, D_OK
) == 0)
3521 setenv ("TMPDIR", tmp
, 1);
3528 Fcons (build_string ("no usable temporary directories found!!"),
3530 "While setting TMPDIR: ");
3532 /* Note the startup time, so we know not to clear the screen if we
3533 exit immediately; see IT_reset_terminal_modes.
3534 (Yes, I know `clock' returns zero the first time it's called, but
3535 I do this anyway, in case some wiseguy changes that at some point.) */
3536 startup_time
= clock ();
3538 /* Find our root from argv[0]. Assuming argv[0] is, say,
3539 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3540 root
= alloca (MAXPATHLEN
+ 20);
3541 _fixpath (argv
[0], root
);
3542 msdos_downcase_filename (root
);
3543 len
= strlen (root
);
3544 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
3548 && (strcmp (root
+ len
- 4, "/bin") == 0
3549 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
3550 root
[len
- 4] = '\0';
3552 strcpy (root
, "c:/emacs"); /* let's be defensive */
3553 len
= strlen (root
);
3554 strcpy (emacsroot
, root
);
3556 /* We default HOME to our root. */
3557 setenv ("HOME", root
, 0);
3559 /* We default EMACSPATH to root + "/bin". */
3560 strcpy (root
+ len
, "/bin");
3561 setenv ("EMACSPATH", root
, 0);
3563 /* I don't expect anybody to ever use other terminals so the internal
3564 terminal is the default. */
3565 setenv ("TERM", "internal", 0);
3567 #ifdef HAVE_X_WINDOWS
3568 /* Emacs expects DISPLAY to be set. */
3569 setenv ("DISPLAY", "unix:0.0", 0);
3572 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3573 downcase it and mirror the backslashes. */
3574 s
= getenv ("COMSPEC");
3575 if (!s
) s
= "c:/command.com";
3576 t
= alloca (strlen (s
) + 1);
3578 dostounix_filename (t
, 0);
3579 setenv ("SHELL", t
, 0);
3581 /* PATH is also downcased and backslashes mirrored. */
3582 s
= getenv ("PATH");
3584 t
= alloca (strlen (s
) + 3);
3585 /* Current directory is always considered part of MsDos's path but it is
3586 not normally mentioned. Now it is. */
3587 strcat (strcpy (t
, ".;"), s
);
3588 dostounix_filename (t
, 0); /* Not a single file name, but this should work. */
3589 setenv ("PATH", t
, 1);
3591 /* In some sense all dos users have root privileges, so... */
3592 setenv ("USER", "root", 0);
3593 setenv ("NAME", getenv ("USER"), 0);
3595 /* Time zone determined from country code. To make this possible, the
3596 country code may not span more than one time zone. In other words,
3597 in the USA, you lose. */
3599 switch (dos_country_code
)
3601 case 31: /* Belgium */
3602 case 32: /* The Netherlands */
3603 case 33: /* France */
3604 case 34: /* Spain */
3605 case 36: /* Hungary */
3606 case 38: /* Yugoslavia (or what's left of it?) */
3607 case 39: /* Italy */
3608 case 41: /* Switzerland */
3609 case 42: /* Tjekia */
3610 case 45: /* Denmark */
3611 case 46: /* Sweden */
3612 case 47: /* Norway */
3613 case 48: /* Poland */
3614 case 49: /* Germany */
3615 /* Daylight saving from last Sunday in March to last Sunday in
3616 September, both at 2AM. */
3617 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3619 case 44: /* United Kingdom */
3620 case 351: /* Portugal */
3621 case 354: /* Iceland */
3622 setenv ("TZ", "GMT+00", 0);
3624 case 81: /* Japan */
3625 case 82: /* Korea */
3626 setenv ("TZ", "JST-09", 0);
3628 case 90: /* Turkey */
3629 case 358: /* Finland */
3630 setenv ("TZ", "EET-02", 0);
3632 case 972: /* Israel */
3633 /* This is an approximation. (For exact rules, use the
3634 `zoneinfo/israel' file which comes with DJGPP, but you need
3635 to install it in `/usr/share/zoneinfo/' directory first.) */
3636 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3644 static int break_stat
; /* BREAK check mode status. */
3645 static int stdin_stat
; /* stdin IOCTL status. */
3647 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3648 control chars by DOS. Determine the keyboard type. */
3651 dos_ttraw (struct tty_display_info
*tty
)
3653 union REGS inregs
, outregs
;
3654 static int first_time
= 1;
3656 /* If we are called for the initial terminal, it's too early to do
3657 anything, and termscript isn't set up. */
3658 if (tty
->terminal
->type
== output_initial
)
3661 break_stat
= getcbrk ();
3667 int86 (0x15, &inregs
, &outregs
);
3668 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
3673 #ifdef HAVE_X_WINDOWS
3674 && inhibit_window_system
3678 inregs
.x
.ax
= 0x0021;
3679 int86 (0x33, &inregs
, &outregs
);
3680 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3683 /* Reportedly, the above doesn't work for some mouse drivers. There
3684 is an additional detection method that should work, but might be
3685 a little slower. Use that as an alternative. */
3686 inregs
.x
.ax
= 0x0000;
3687 int86 (0x33, &inregs
, &outregs
);
3688 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3691 mouse_button_count
= outregs
.x
.bx
;
3693 #ifndef HAVE_X_WINDOWS
3694 /* Save the cursor shape used outside Emacs. */
3695 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
3701 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
3702 return (stdin_stat
!= -1);
3705 return (setmode (fileno (stdin
), O_BINARY
) != -1);
3708 /* Restore status of standard input and Ctrl-C checking. */
3713 union REGS inregs
, outregs
;
3715 setcbrk (break_stat
);
3718 #ifndef HAVE_X_WINDOWS
3719 /* Restore the cursor shape we found on startup. */
3723 inregs
.x
.cx
= outside_cursor
;
3724 int86 (0x10, &inregs
, &outregs
);
3728 return (setmode (fileno (stdin
), stdin_stat
) != -1);
3732 /* Run command as specified by ARGV in directory DIR.
3733 The command is run with input from TEMPIN, output to
3734 file TEMPOUT and stderr to TEMPERR. */
3737 run_msdos_command (unsigned char **argv
, const char *working_dir
,
3738 int tempin
, int tempout
, int temperr
, char **envv
)
3740 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
3741 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
3742 int msshell
, result
= -1, inbak
, outbak
, errbak
, x
, y
;
3745 /* Get current directory as MSDOS cwd is not per-process. */
3748 /* If argv[0] is the shell, it might come in any lettercase.
3749 Since `Fmember' is case-sensitive, we need to downcase
3750 argv[0], even if we are on case-preserving filesystems. */
3751 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
3752 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
3755 if (*pl
>= 'A' && *pl
<= 'Z')
3760 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
3761 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
3762 && !strcmp ("-c", argv
[1]);
3765 saveargv1
= argv
[1];
3766 saveargv2
= argv
[2];
3768 /* We only need to mirror slashes if a DOS shell will be invoked
3769 not via `system' (which does the mirroring itself). Yes, that
3770 means DJGPP v1.x will lose here. */
3771 if (argv
[2] && argv
[3])
3773 char *p
= alloca (strlen (argv
[2]) + 1);
3775 strcpy (argv
[2] = p
, saveargv2
);
3776 while (*p
&& isspace (*p
))
3788 chdir (working_dir
);
3792 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3793 goto done
; /* Allocation might fail due to lack of descriptors. */
3796 mouse_get_xy (&x
, &y
);
3798 if (!noninteractive
)
3799 dos_ttcooked (); /* do it here while 0 = stdin */
3805 if (msshell
&& !argv
[3])
3807 /* MS-DOS native shells are too restrictive. For starters, they
3808 cannot grok commands longer than 126 characters. In DJGPP v2
3809 and later, `system' is much smarter, so we'll call it instead. */
3813 /* A shell gets a single argument--its full command
3814 line--whose original was saved in `saveargv2'. */
3816 /* Don't let them pass empty command lines to `system', since
3817 with some shells it will try to invoke an interactive shell,
3818 which will hang Emacs. */
3819 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
3823 extern char **environ
;
3824 char **save_env
= environ
;
3825 int save_system_flags
= __system_flags
;
3827 /* Request the most powerful version of `system'. We need
3828 all the help we can get to avoid calling stock DOS shells. */
3829 __system_flags
= (__system_redirect
3830 | __system_use_shell
3831 | __system_allow_multiple_cmds
3832 | __system_allow_long_cmds
3833 | __system_handle_null_commands
3834 | __system_emulate_chdir
);
3837 result
= system (cmnd
);
3838 __system_flags
= save_system_flags
;
3842 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
3845 result
= spawnve (P_WAIT
, argv
[0], (char **)argv
, envv
);
3850 emacs_close (inbak
);
3851 emacs_close (outbak
);
3852 emacs_close (errbak
);
3854 if (!noninteractive
)
3855 dos_ttraw (CURTTY ());
3859 mouse_moveto (x
, y
);
3862 /* Some programs might change the meaning of the highest bit of the
3863 text attribute byte, so we get blinking characters instead of the
3864 bright background colors. Restore that. */
3865 if (!noninteractive
)
3872 argv
[1] = saveargv1
;
3873 argv
[2] = saveargv2
;
3879 croak (char *badfunc
)
3881 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3882 reset_all_sys_modes ();
3887 * A few unimplemented functions that we silently ignore.
3889 pid_t
tcgetpgrp (int fd
) { return 0; }
3890 int setpgid (int pid
, int pgid
) { return 0; }
3891 int setpriority (int x
, int y
, int z
) { return 0; }
3892 pid_t
setsid (void) { return 0; }
3894 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 4
3896 readlink (const char *name
, char *dummy1
, size_t dummy2
)
3898 /* `access' is much faster than `stat' on MS-DOS. */
3899 if (access (name
, F_OK
) == 0)
3906 careadlinkat (int fd
, char const *filename
,
3907 char *buffer
, size_t buffer_size
,
3908 struct allocator
const *alloc
,
3909 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
3913 /* We don't support the fancy auto-allocation feature. */
3922 ssize_t len
= preadlinkat (fd
, filename
, buffer
, buffer_size
);
3924 if (len
< 0 || len
== buffer_size
)
3927 buffer
[len
+ 1] = '\0';
3933 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
3935 /* Augment DJGPP library POSIX signal functions. This is needed
3936 as of DJGPP v2.01, but might be in the library in later releases. */
3938 #include <libc/bss.h>
3940 /* A counter to know when to re-initialize the static sets. */
3941 static int sigprocmask_count
= -1;
3943 /* Which signals are currently blocked (initially none). */
3944 static sigset_t current_mask
;
3946 /* Which signals are pending (initially none). */
3947 static sigset_t msdos_pending_signals
;
3949 /* Previous handlers to restore when the blocked signals are unblocked. */
3950 typedef void (*sighandler_t
)(int);
3951 static sighandler_t prev_handlers
[320];
3953 /* A signal handler which just records that a signal occurred
3954 (it will be raised later, if and when the signal is unblocked). */
3956 sig_suspender (int signo
)
3958 sigaddset (&msdos_pending_signals
, signo
);
3962 sigprocmask (int how
, const sigset_t
*new_set
, sigset_t
*old_set
)
3967 /* If called for the first time, initialize. */
3968 if (sigprocmask_count
!= __bss_count
)
3970 sigprocmask_count
= __bss_count
;
3971 sigemptyset (&msdos_pending_signals
);
3972 sigemptyset (¤t_mask
);
3973 for (signo
= 0; signo
< 320; signo
++)
3974 prev_handlers
[signo
] = SIG_ERR
;
3978 *old_set
= current_mask
;
3983 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
3989 sigemptyset (&new_mask
);
3991 /* DJGPP supports upto 320 signals. */
3992 for (signo
= 0; signo
< 320; signo
++)
3994 if (sigismember (¤t_mask
, signo
))
3995 sigaddset (&new_mask
, signo
);
3996 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
3998 sigaddset (&new_mask
, signo
);
4000 /* SIGKILL is silently ignored, as on other platforms. */
4001 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4002 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4004 if (( how
== SIG_UNBLOCK
4005 && sigismember (&new_mask
, signo
)
4006 && sigismember (new_set
, signo
))
4007 || (how
== SIG_SETMASK
4008 && sigismember (&new_mask
, signo
)
4009 && !sigismember (new_set
, signo
)))
4011 sigdelset (&new_mask
, signo
);
4012 if (prev_handlers
[signo
] != SIG_ERR
)
4014 signal (signo
, prev_handlers
[signo
]);
4015 prev_handlers
[signo
] = SIG_ERR
;
4017 if (sigismember (&msdos_pending_signals
, signo
))
4019 sigdelset (&msdos_pending_signals
, signo
);
4024 current_mask
= new_mask
;
4028 #endif /* not __DJGPP_MINOR__ < 2 */
4031 #include "sysselect.h"
4033 /* This yields the rest of the current time slice to the task manager.
4034 It should be called by any code which knows that it has nothing
4035 useful to do except idle.
4037 I don't use __dpmi_yield here, since versions of library before 2.02
4038 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4039 on some versions of Windows 9X. */
4042 dos_yield_time_slice (void)
4044 _go32_dpmi_registers r
;
4047 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
4048 _go32_dpmi_simulate_int (0x2f, &r
);
4053 /* Only event queue is checked. */
4054 /* We don't have to call timer_check here
4055 because wait_reading_process_output takes care of that. */
4057 sys_select (int nfds
, SELECT_TYPE
*rfds
, SELECT_TYPE
*wfds
, SELECT_TYPE
*efds
,
4058 struct timespec
*timeout
, void *ignored
)
4066 check_input
= FD_ISSET (0, rfds
);
4077 /* If we are looking only for the terminal, with no timeout,
4078 just read it and wait -- that's more efficient. */
4081 while (!detect_input_pending ())
4083 dos_yield_time_slice ();
4088 struct timespec clnow
, cllast
, cldiff
;
4091 cllast
= make_timespec (t
.tv_sec
, t
.tv_nsec
);
4093 while (!check_input
|| !detect_input_pending ())
4096 clnow
= make_timespec (t
.tv_sec
, t
.tv_nsec
);
4097 cldiff
= timespec_sub (clnow
, cllast
);
4098 *timeout
= timespec_sub (*timeout
, cldiff
);
4100 /* Stop when timeout value crosses zero. */
4101 if (timespec_sign (*timeout
) <= 0)
4104 dos_yield_time_slice ();
4114 * Define overlaid functions:
4116 * chdir -> sys_chdir
4117 * tzset -> init_gettimeofday
4118 * abort -> dos_abort
4123 extern int chdir (const char *);
4126 sys_chdir (const char *path
)
4128 int len
= strlen (path
);
4129 char *tmp
= (char *)path
;
4131 if (*tmp
&& tmp
[1] == ':')
4133 if (getdisk () != tolower (tmp
[0]) - 'a')
4134 setdisk (tolower (tmp
[0]) - 'a');
4135 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
4139 if (len
> 1 && (tmp
[len
- 1] == '/'))
4141 char *tmp1
= (char *) alloca (len
+ 1);
4152 extern void tzset (void);
4155 init_gettimeofday (void)
4161 ltm
= gtm
= time (NULL
);
4162 ltm
= mktime (lstm
= localtime (<m
));
4163 gtm
= mktime (gmtime (>m
));
4164 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
4165 time_rec
.tm_isdst
= lstm
->tm_isdst
;
4166 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
4174 ScreenSetCursor (10, 0);
4175 cputs ("\r\n\nEmacs aborted!\r\n");
4176 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4177 if (screen_virtual_segment
)
4178 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
4179 /* Generate traceback, so we could tell whodunit. */
4180 signal (SIGINT
, SIG_DFL
);
4181 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4182 #else /* __DJGPP_MINOR__ >= 2 */
4184 #endif /* __DJGPP_MINOR__ >= 2 */
4189 msdos_fatal_signal (int sig
)
4198 syms_of_msdos (void)
4200 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
4201 staticpro (&recent_doskeys
);
4203 #ifndef HAVE_X_WINDOWS
4205 /* The following two are from xfns.c: */
4206 DEFSYM (Qreverse
, "reverse");
4208 DEFVAR_LISP ("dos-unsupported-char-glyph", Vdos_unsupported_char_glyph
,
4209 doc
: /* Glyph to display instead of chars not supported by current codepage.
4210 This variable is used only by MS-DOS terminals. */);
4211 Vdos_unsupported_char_glyph
= make_number ('\177');
4215 defsubr (&Srecent_doskeys
);
4216 defsubr (&Smsdos_long_file_names
);
4217 defsubr (&Smsdos_downcase_filename
);
4218 defsubr (&Smsdos_remember_default_colors
);
4219 defsubr (&Smsdos_set_mouse_buttons
);