1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
3 Copyright (C) 1993-1997, 1999-2012 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: some of the stuff here was taken from end of sysdep.c in demacs. */
32 #include <sys/param.h>
36 #include <sys/stat.h> /* for _fixpath */
37 #include <unistd.h> /* for chdir, dup, dup2, etc. */
38 #include <dir.h> /* for getdisk */
39 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
41 #include <io.h> /* for setmode */
42 #include <dpmi.h> /* for __dpmi_xxx stuff */
43 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
44 #include <libc/dosio.h> /* for _USE_LFN */
45 #include <conio.h> /* for cputs */
50 #include "termhooks.h"
52 #include "dispextern.h"
55 #include "character.h"
61 #include "blockinput.h"
63 #include "intervals.h"
67 /* #include <process.h> */
68 /* Damn that local process.h! Instead we can define P_WAIT and
71 extern int spawnve (int, const char *, char *const [], char *const []);
78 #define _dos_ds _go32_info_block.selector_for_linear_memory
82 #include "syssignal.h"
84 #include "careadlinkat.h"
85 #include "allocator.h"
91 /* If other `malloc' than ours is used, force our `sbrk' behave like
92 Unix programs expect (resize memory blocks to keep them contiguous).
93 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
94 because that's what `gmalloc' expects to get. */
98 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
99 #else /* not REL_ALLOC */
100 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
101 #endif /* not REL_ALLOC */
102 #endif /* GNU_MALLOC */
104 #endif /* not SYSTEM_MALLOC */
107 event_timestamp (void)
123 /* ------------------------ Mouse control ---------------------------
125 * Coordinates are in screen positions and zero based.
126 * Mouse buttons are numbered from left to right and also zero based.
129 /* This used to be in termhooks.h, but mainstream Emacs code no longer
130 uses it, and it was removed... */
131 #define NUM_MOUSE_BUTTONS (5)
133 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
134 static int mouse_visible
;
136 static int mouse_last_x
;
137 static int mouse_last_y
;
139 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
140 static int mouse_button_count
;
147 if (have_mouse
> 0 && !mouse_visible
)
149 struct tty_display_info
*tty
= CURTTY ();
152 fprintf (tty
->termscript
, "<M_ON>");
154 int86 (0x33, ®s
, ®s
);
164 if (have_mouse
> 0 && mouse_visible
)
166 struct tty_display_info
*tty
= CURTTY ();
169 fprintf (tty
->termscript
, "<M_OFF>");
171 int86 (0x33, ®s
, ®s
);
177 mouse_setup_buttons (int n_buttons
)
181 mouse_button_count
= 3;
182 mouse_button_translate
[0] = 0; /* Left */
183 mouse_button_translate
[1] = 2; /* Middle */
184 mouse_button_translate
[2] = 1; /* Right */
186 else /* two, what else? */
188 mouse_button_count
= 2;
189 mouse_button_translate
[0] = 0;
190 mouse_button_translate
[1] = 1;
194 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons
, Smsdos_set_mouse_buttons
,
195 1, 1, "NSet number of mouse buttons to: ",
196 doc
: /* Set the number of mouse buttons to use by Emacs.
197 This is useful with mice that report the number of buttons inconsistently,
198 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
199 them. This happens with wheeled mice on Windows 9X, for example. */)
200 (Lisp_Object nbuttons
)
204 CHECK_NUMBER (nbuttons
);
207 xsignal2 (Qargs_out_of_range
,
208 build_string ("only 2 or 3 mouse buttons are supported"),
210 mouse_setup_buttons (n
);
215 mouse_get_xy (int *x
, int *y
)
220 int86 (0x33, ®s
, ®s
);
226 mouse_moveto (int x
, int y
)
229 struct tty_display_info
*tty
= CURTTY ();
232 fprintf (tty
->termscript
, "<M_XY=%dx%d>", x
, y
);
234 mouse_last_x
= regs
.x
.cx
= x
* 8;
235 mouse_last_y
= regs
.x
.dx
= y
* 8;
236 int86 (0x33, ®s
, ®s
);
240 mouse_pressed (int b
, int *xp
, int *yp
)
244 if (b
>= mouse_button_count
)
247 regs
.x
.bx
= mouse_button_translate
[b
];
248 int86 (0x33, ®s
, ®s
);
250 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
251 return (regs
.x
.bx
!= 0);
255 mouse_released (int b
, int *xp
, int *yp
)
259 if (b
>= mouse_button_count
)
262 regs
.x
.bx
= mouse_button_translate
[b
];
263 int86 (0x33, ®s
, ®s
);
265 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
266 return (regs
.x
.bx
!= 0);
270 mouse_button_depressed (int b
, int *xp
, int *yp
)
274 if (b
>= mouse_button_count
)
277 int86 (0x33, ®s
, ®s
);
278 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
288 mouse_get_pos (FRAME_PTR
*f
, int insist
, Lisp_Object
*bar_window
,
289 enum scroll_bar_part
*part
, Lisp_Object
*x
, Lisp_Object
*y
,
293 Lisp_Object frame
, tail
;
295 /* Clear the mouse-moved flag for every frame on this display. */
296 FOR_EACH_FRAME (tail
, frame
)
297 XFRAME (frame
)->mouse_moved
= 0;
299 *f
= SELECTED_FRAME ();
301 mouse_get_xy (&ix
, &iy
);
302 *time
= event_timestamp ();
303 *x
= make_number (mouse_last_x
= ix
);
304 *y
= make_number (mouse_last_y
= iy
);
308 mouse_check_moved (void)
312 mouse_get_xy (&x
, &y
);
313 SELECTED_FRAME ()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
318 /* Force the mouse driver to ``forget'' about any button clicks until
321 mouse_clear_clicks (void)
325 for (b
= 0; b
< mouse_button_count
; b
++)
327 int dummy_x
, dummy_y
;
329 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
330 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
338 struct tty_display_info
*tty
= CURTTY ();
341 fprintf (tty
->termscript
, "<M_INIT>");
344 int86 (0x33, ®s
, ®s
);
346 /* Reset the mouse last press/release info. It seems that Windows
347 doesn't do that automatically when function 21h is called, which
348 causes Emacs to ``remember'' the click that switched focus to the
349 window just before Emacs was started from that window. */
350 mouse_clear_clicks ();
354 regs
.x
.dx
= 8 * (ScreenCols () - 1);
355 int86 (0x33, ®s
, ®s
);
359 regs
.x
.dx
= 8 * (ScreenRows () - 1);
360 int86 (0x33, ®s
, ®s
);
366 /* ------------------------- Screen control ----------------------
370 static int internal_terminal
= 0;
372 #ifndef HAVE_X_WINDOWS
373 extern unsigned char ScreenAttrib
;
374 static int screen_face
;
376 static int screen_size_X
;
377 static int screen_size_Y
;
378 static int screen_size
;
380 static int current_pos_X
;
381 static int current_pos_Y
;
382 static int new_pos_X
;
383 static int new_pos_Y
;
385 static void *startup_screen_buffer
;
386 static int startup_screen_size_X
;
387 static int startup_screen_size_Y
;
388 static int startup_pos_X
;
389 static int startup_pos_Y
;
390 static unsigned char startup_screen_attrib
;
392 static clock_t startup_time
;
394 static int term_setup_done
;
396 static unsigned short outside_cursor
;
398 /* Similar to the_only_frame. */
399 struct tty_display_info the_only_display_info
;
401 /* Support for DOS/V (allows Japanese characters to be displayed on
402 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
404 /* Holds the address of the text-mode screen buffer. */
405 static unsigned long screen_old_address
= 0;
406 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
407 static unsigned short screen_virtual_segment
= 0;
408 static unsigned short screen_virtual_offset
= 0;
409 extern Lisp_Object Qcursor_type
;
410 extern Lisp_Object Qbar
, Qhbar
;
412 /* The screen colors of the current frame, which serve as the default
413 colors for newly-created frames. */
414 static int initial_screen_colors
[2];
416 /* Update the screen from a part of relocated DOS/V screen buffer which
417 begins at OFFSET and includes COUNT characters. */
419 dosv_refresh_virtual_screen (int offset
, int count
)
423 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
426 regs
.h
.ah
= 0xff; /* update relocated screen */
427 regs
.x
.es
= screen_virtual_segment
;
428 regs
.x
.di
= screen_virtual_offset
+ offset
;
430 __dpmi_int (0x10, ®s
);
434 dos_direct_output (int y
, int x
, char *buf
, int len
)
436 int t0
= 2 * (x
+ y
* screen_size_X
);
437 int t
= t0
+ (int) ScreenPrimary
;
440 /* This is faster. */
441 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
442 _farnspokeb (t
, *buf
);
444 if (screen_virtual_segment
)
445 dosv_refresh_virtual_screen (t0
, l0
);
449 #ifndef HAVE_X_WINDOWS
451 static int blink_bit
= -1; /* the state of the blink bit at startup */
453 /* Enable bright background colors. */
459 /* Remember the original state of the blink/bright-background bit.
460 It is stored at 0040:0065h in the BIOS data area. */
462 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
466 int86 (0x10, ®s
, ®s
);
469 /* Disable bright background colors (and enable blinking) if we found
470 the video system in that state at startup. */
472 maybe_enable_blinking (void)
480 int86 (0x10, ®s
, ®s
);
484 /* Return non-zero if the system has a VGA adapter. */
491 int86 (0x10, ®s
, ®s
);
492 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
497 /* Set the screen dimensions so that it can show no less than
498 ROWS x COLS frame. */
501 dos_set_window_size (int *rows
, int *cols
)
505 Lisp_Object video_mode
;
506 int video_mode_value
, have_vga
= 0;
507 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
509 if (*rows
== current_rows
&& *cols
== current_cols
)
513 have_vga
= vga_installed ();
515 /* If the user specified a special video mode for these dimensions,
517 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
518 video_mode
= Fsymbol_value (Fintern_soft (build_string (video_name
), Qnil
));
520 if (INTEGERP (video_mode
)
521 && (video_mode_value
= XINT (video_mode
)) > 0)
523 regs
.x
.ax
= video_mode_value
;
524 int86 (0x10, ®s
, ®s
);
528 /* Must hardware-reset the mouse, or else it won't update
529 its notion of screen dimensions for some non-standard
530 video modes. This is *painfully* slow... */
532 int86 (0x33, ®s
, ®s
);
536 /* Find one of the dimensions supported by standard EGA/VGA
537 which gives us at least the required dimensions. */
542 } std_dimension
[] = {
552 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
554 if (std_dimension
[i
].need_vga
<= have_vga
555 && std_dimension
[i
].rows
>= *rows
)
557 if (std_dimension
[i
].rows
!= current_rows
558 || *cols
!= current_cols
)
559 _set_screen_lines (std_dimension
[i
].rows
);
573 /* Tell the caller what dimensions have been REALLY set. */
574 *rows
= ScreenRows ();
575 *cols
= ScreenCols ();
577 /* Update Emacs' notion of screen dimensions. */
578 screen_size_X
= *cols
;
579 screen_size_Y
= *rows
;
580 screen_size
= *cols
* *rows
;
582 /* If the dimensions changed, the mouse highlight info is invalid. */
583 if (current_rows
!= *rows
|| current_cols
!= *cols
)
585 struct frame
*f
= SELECTED_FRAME ();
586 Mouse_HLInfo
*hlinfo
= MOUSE_HL_INFO (f
);
587 Lisp_Object window
= hlinfo
->mouse_face_window
;
589 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
591 hlinfo
->mouse_face_beg_row
= hlinfo
->mouse_face_beg_col
= -1;
592 hlinfo
->mouse_face_end_row
= hlinfo
->mouse_face_end_col
= -1;
593 hlinfo
->mouse_face_window
= Qnil
;
597 /* Enable bright background colors. */
600 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
601 be defensive anyway. */
602 if (screen_virtual_segment
)
603 dosv_refresh_virtual_screen (0, *cols
* *rows
);
606 /* If we write a character in the position where the mouse is,
607 the mouse cursor may need to be refreshed. */
610 mouse_off_maybe (void)
617 mouse_get_xy (&x
, &y
);
618 if (y
!= new_pos_Y
|| x
< new_pos_X
)
624 #define DEFAULT_CURSOR_START (-1)
625 #define DEFAULT_CURSOR_WIDTH (-1)
626 #define BOX_CURSOR_WIDTH (-32)
628 /* Set cursor to begin at scan line START_LINE in the character cell
629 and extend for WIDTH scan lines. Scan lines are counted from top
630 of the character cell, starting from zero. */
632 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
634 unsigned desired_cursor
;
636 int max_line
, top_line
, bot_line
;
637 struct tty_display_info
*tty
= FRAME_TTY (f
);
639 /* Avoid the costly BIOS call if F isn't the currently selected
640 frame. Allow for NULL as unconditionally meaning the selected
642 if (f
&& f
!= SELECTED_FRAME ())
646 fprintf (tty
->termscript
, "\nCURSOR SHAPE=(%d,%d)", start_line
, width
);
648 /* The character cell size in scan lines is stored at 40:85 in the
650 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
653 default: /* this relies on CGA cursor emulation being ON! */
670 if (width
== BOX_CURSOR_WIDTH
)
675 else if (start_line
!= DEFAULT_CURSOR_START
)
677 top_line
= start_line
;
678 bot_line
= top_line
- width
- 1;
680 else if (width
!= DEFAULT_CURSOR_WIDTH
)
683 bot_line
= -1 - width
;
686 top_line
= bot_line
+ 1;
690 /* [31, 0] seems to DTRT for all screen sizes. */
694 else /* WIDTH is positive */
696 if (start_line
!= DEFAULT_CURSOR_START
)
697 bot_line
= start_line
;
698 top_line
= bot_line
- (width
- 1);
701 /* If the current cursor shape is already what they want, we are
703 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
704 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
708 regs
.x
.cx
= desired_cursor
;
709 __dpmi_int (0x10, ®s
);
713 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
715 if (EQ (cursor_type
, Qbar
) || EQ (cursor_type
, Qhbar
))
717 /* Just BAR means the normal EGA/VGA cursor. */
718 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
720 else if (CONSP (cursor_type
)
721 && (EQ (XCAR (cursor_type
), Qbar
)
722 || EQ (XCAR (cursor_type
), Qhbar
)))
724 Lisp_Object bar_parms
= XCDR (cursor_type
);
727 if (INTEGERP (bar_parms
))
729 /* Feature: negative WIDTH means cursor at the top
730 of the character cell, zero means invisible cursor. */
731 width
= XINT (bar_parms
);
732 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
735 else if (CONSP (bar_parms
)
736 && INTEGERP (XCAR (bar_parms
))
737 && INTEGERP (XCDR (bar_parms
)))
739 int start_line
= XINT (XCDR (bar_parms
));
741 width
= XINT (XCAR (bar_parms
));
742 msdos_set_cursor_shape (f
, start_line
, width
);
747 /* Treat anything unknown as "box cursor". This includes nil, so
748 that a frame which doesn't specify a cursor type gets a box,
749 which is the default in Emacs. */
750 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
755 IT_ring_bell (struct frame
*f
)
764 union REGS inregs
, outregs
;
767 intdos (&inregs
, &outregs
);
771 /* Given a face id FACE, extract the face parameters to be used for
772 display until the face changes. The face parameters (actually, its
773 color) are used to construct the video attribute byte for each
774 glyph during the construction of the buffer that is then blitted to
777 IT_set_face (int face
)
779 struct frame
*sf
= SELECTED_FRAME ();
780 struct face
*fp
= FACE_FROM_ID (sf
, face
);
781 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
782 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
783 struct tty_display_info
*tty
= FRAME_TTY (sf
);
788 /* The default face for the frame should always be realized and
796 dflt_fg
= dfp
->foreground
;
797 dflt_bg
= dfp
->background
;
799 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
800 mean use the colors of the default face. Note that we assume all
801 16 colors to be available for the background, since Emacs switches
802 on this mode (and loses the blinking attribute) at startup. */
803 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
804 fg
= FRAME_FOREGROUND_PIXEL (sf
);
805 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
806 fg
= FRAME_BACKGROUND_PIXEL (sf
);
807 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
808 bg
= FRAME_BACKGROUND_PIXEL (sf
);
809 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
810 bg
= FRAME_FOREGROUND_PIXEL (sf
);
812 /* Make sure highlighted lines really stand out, come what may. */
813 if (fp
->tty_reverse_p
&& (fg
== dflt_fg
&& bg
== dflt_bg
))
815 unsigned long tem
= fg
;
820 /* If the user requested inverse video, obey. */
823 unsigned long tem2
= fg
;
829 fprintf (tty
->termscript
, "<FACE %d: %lu/%lu[FG:%lu/BG:%lu]>", face
,
830 fp
->foreground
, fp
->background
, fg
, bg
);
831 if (fg
>= 0 && fg
< 16)
833 ScreenAttrib
&= 0xf0;
836 if (bg
>= 0 && bg
< 16)
838 ScreenAttrib
&= 0x0f;
839 ScreenAttrib
|= ((bg
& 0x0f) << 4);
843 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
844 width of a DOS display in any known text mode. We multiply by 2 to
845 accommodate the screen attribute byte. */
846 #define MAX_SCREEN_BUF 160*2
848 extern unsigned char *encode_terminal_code (struct glyph
*, int,
849 struct coding_system
*);
852 IT_write_glyphs (struct frame
*f
, struct glyph
*str
, int str_len
)
854 unsigned char screen_buf
[MAX_SCREEN_BUF
], *screen_bp
, *bp
;
855 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
856 register int sl
= str_len
;
857 struct tty_display_info
*tty
= FRAME_TTY (f
);
859 unsigned char *conversion_buffer
;
861 /* If terminal_coding does any conversion, use it, otherwise use
862 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
863 because it always returns 1 if terminal_coding.src_multibyte is 1. */
864 struct coding_system
*coding
= FRAME_TERMINAL_CODING (f
);
866 if (!(coding
->common_flags
& CODING_REQUIRE_ENCODING_MASK
))
867 coding
= &safe_terminal_coding
;
869 if (str_len
<= 0) return;
871 sf
= SELECTED_FRAME ();
873 /* Since faces get cached and uncached behind our back, we can't
874 rely on their indices in the cache being consistent across
875 invocations. So always reset the screen face to the default
876 face of the frame, before writing glyphs, and let the glyphs
877 set the right face if it's different from the default. */
878 IT_set_face (DEFAULT_FACE_ID
);
880 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
882 coding
->mode
&= ~CODING_MODE_LAST_BLOCK
;
883 screen_bp
= &screen_buf
[0];
889 /* If the face of this glyph is different from the current
890 screen face, update the screen attribute byte. */
892 if (cf
!= screen_face
)
893 IT_set_face (cf
); /* handles invalid faces gracefully */
895 /* Identify a run of glyphs with the same face. */
896 for (n
= 1; n
< sl
; ++n
)
897 if (str
[n
].face_id
!= cf
)
901 /* This is the last glyph. */
902 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
904 conversion_buffer
= encode_terminal_code (str
, n
, coding
);
905 if (coding
->produced
> 0)
907 /* Copy the encoded bytes to the screen buffer. */
908 for (bp
= conversion_buffer
; coding
->produced
--; bp
++)
910 /* Paranoia: discard bytes that would overrun the end of
911 the screen buffer. */
912 if (screen_bp
- screen_buf
<= MAX_SCREEN_BUF
- 2)
914 *screen_bp
++ = (unsigned char)*bp
;
915 *screen_bp
++ = ScreenAttrib
;
918 fputc (*bp
, tty
->termscript
);
921 /* Update STR and its remaining length. */
926 /* Dump whatever we have in the screen buffer. */
928 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
929 if (screen_virtual_segment
)
930 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
931 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
934 /************************************************************************
935 Mouse Highlight (and friends..)
936 ************************************************************************/
938 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
939 static Lisp_Object last_mouse_window
;
941 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
944 popup_activated (void)
946 return mouse_preempted
;
949 /* Draw TEXT_AREA glyphs between START and END of glyph row ROW on
950 window W. X is relative to TEXT_AREA in W. HL is a face override
951 for drawing the glyphs. */
953 tty_draw_row_with_mouse_face (struct window
*w
, struct glyph_row
*row
,
954 int start_hpos
, int end_hpos
,
955 enum draw_glyphs_face hl
)
957 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
958 struct tty_display_info
*tty
= FRAME_TTY (f
);
959 Mouse_HLInfo
*hlinfo
= &tty
->mouse_highlight
;
961 if (hl
== DRAW_MOUSE_FACE
)
963 int vpos
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
964 int kstart
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
965 int nglyphs
= end_hpos
- start_hpos
;
966 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
967 int start_offset
= offset
;
970 fprintf (tty
->termscript
, "\n<MH+ %d-%d:%d>",
971 kstart
, kstart
+ nglyphs
- 1, vpos
);
974 IT_set_face (hlinfo
->mouse_face_face_id
);
975 /* Since we are going to change only the _colors_ of already
976 displayed text, there's no need to go through all the pain of
977 generating and encoding the text from the glyphs. Instead,
978 we simply poke the attribute byte of each affected position
979 in video memory with the colors computed by IT_set_face! */
980 _farsetsel (_dos_ds
);
983 _farnspokeb (offset
, ScreenAttrib
);
986 if (screen_virtual_segment
)
987 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
990 else if (hl
== DRAW_NORMAL_TEXT
)
992 /* We are removing a previously-drawn mouse highlight. The
993 safest way to do so is to redraw the glyphs anew, since all
994 kinds of faces and display tables could have changed behind
996 int nglyphs
= end_hpos
- start_hpos
;
997 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
999 if (end_hpos
>= row
->used
[TEXT_AREA
])
1000 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1002 /* IT_write_glyphs writes at cursor position, so we need to
1003 temporarily move cursor coordinates to the beginning of
1004 the highlight region. */
1005 new_pos_X
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1006 new_pos_Y
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1008 if (tty
->termscript
)
1009 fprintf (tty
->termscript
, "<MH- %d-%d:%d>",
1010 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1011 IT_write_glyphs (f
, row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1012 if (tty
->termscript
)
1013 fputs ("\n", tty
->termscript
);
1020 IT_clear_end_of_line (struct frame
*f
, int first_unused
)
1023 int i
, j
, offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1024 extern int fatal_error_in_progress
;
1025 struct tty_display_info
*tty
= FRAME_TTY (f
);
1027 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1031 i
= (j
= first_unused
- new_pos_X
) * 2;
1032 if (tty
->termscript
)
1033 fprintf (tty
->termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1034 spaces
= sp
= alloca (i
);
1039 *sp
++ = ScreenAttrib
;
1043 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1044 if (screen_virtual_segment
)
1045 dosv_refresh_virtual_screen (offset
, i
/ 2);
1047 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1048 Let's follow their lead, in case someone relies on this. */
1049 new_pos_X
= first_unused
;
1053 IT_clear_screen (struct frame
*f
)
1055 struct tty_display_info
*tty
= FRAME_TTY (f
);
1057 if (tty
->termscript
)
1058 fprintf (tty
->termscript
, "<CLR:SCR>");
1059 /* We are sometimes called (from clear_garbaged_frames) when a new
1060 frame is being created, but its faces are not yet realized. In
1061 such a case we cannot call IT_set_face, since it will fail to find
1062 any valid faces and will abort. Instead, use the initial screen
1063 colors; that should mimic what a Unix tty does, which simply clears
1064 the screen with whatever default colors are in use. */
1065 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1066 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1071 if (screen_virtual_segment
)
1072 dosv_refresh_virtual_screen (0, screen_size
);
1073 new_pos_X
= new_pos_Y
= 0;
1077 IT_clear_to_end (struct frame
*f
)
1079 struct tty_display_info
*tty
= FRAME_TTY (f
);
1081 if (tty
->termscript
)
1082 fprintf (tty
->termscript
, "<CLR:EOS>");
1084 while (new_pos_Y
< screen_size_Y
) {
1086 IT_clear_end_of_line (f
, screen_size_X
);
1092 IT_cursor_to (struct frame
*f
, int y
, int x
)
1094 struct tty_display_info
*tty
= FRAME_TTY (f
);
1096 if (tty
->termscript
)
1097 fprintf (tty
->termscript
, "\n<XY=%dx%d>", x
, y
);
1102 static int cursor_cleared
;
1105 IT_display_cursor (int on
)
1107 struct tty_display_info
*tty
= CURTTY ();
1109 if (on
&& cursor_cleared
)
1111 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1113 if (tty
->termscript
)
1114 fprintf (tty
->termscript
, "\nCURSOR ON (%dx%d)",
1115 current_pos_Y
, current_pos_X
);
1117 else if (!on
&& !cursor_cleared
)
1119 ScreenSetCursor (-1, -1);
1121 if (tty
->termscript
)
1122 fprintf (tty
->termscript
, "\nCURSOR OFF (%dx%d)",
1123 current_pos_Y
, current_pos_X
);
1127 /* Emacs calls cursor-movement functions a lot when it updates the
1128 display (probably a legacy of old terminals where you cannot
1129 update a screen line without first moving the cursor there).
1130 However, cursor movement is expensive on MSDOS (it calls a slow
1131 BIOS function and requires 2 mode switches), while actual screen
1132 updates access the video memory directly and don't depend on
1133 cursor position. To avoid slowing down the redisplay, we cheat:
1134 all functions that move the cursor only set internal variables
1135 which record the cursor position, whereas the cursor is only
1136 moved to its final position whenever screen update is complete.
1138 `IT_cmgoto' is called from the keyboard reading loop and when the
1139 frame update is complete. This means that we are ready for user
1140 input, so we update the cursor position to show where the point is,
1141 and also make the mouse pointer visible.
1143 Special treatment is required when the cursor is in the echo area,
1144 to put the cursor at the end of the text displayed there. */
1147 IT_cmgoto (FRAME_PTR f
)
1149 /* Only set the cursor to where it should be if the display is
1150 already in sync with the window contents. */
1151 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1152 struct tty_display_info
*tty
= FRAME_TTY (f
);
1154 /* FIXME: This needs to be rewritten for the new redisplay, or
1157 static int previous_pos_X
= -1;
1159 update_cursor_pos
= 1; /* temporary!!! */
1161 /* If the display is in sync, forget any previous knowledge about
1162 cursor position. This is primarily for unexpected events like
1163 C-g in the minibuffer. */
1164 if (update_cursor_pos
&& previous_pos_X
>= 0)
1165 previous_pos_X
= -1;
1166 /* If we are in the echo area, put the cursor at the
1167 end of the echo area message. */
1168 if (!update_cursor_pos
1169 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f
))) <= new_pos_Y
)
1171 int tem_X
= current_pos_X
, dummy
;
1173 if (echo_area_glyphs
)
1175 tem_X
= echo_area_glyphs_length
;
1176 /* Save current cursor position, to be restored after the
1177 echo area message is erased. Only remember one level
1178 of previous cursor position. */
1179 if (previous_pos_X
== -1)
1180 ScreenGetCursor (&dummy
, &previous_pos_X
);
1182 else if (previous_pos_X
>= 0)
1184 /* We wind up here after the echo area message is erased.
1185 Restore the cursor position we remembered above. */
1186 tem_X
= previous_pos_X
;
1187 previous_pos_X
= -1;
1190 if (current_pos_X
!= tem_X
)
1193 update_cursor_pos
= 1;
1198 if (update_cursor_pos
1199 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1201 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1202 if (tty
->termscript
)
1203 fprintf (tty
->termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1206 /* Maybe cursor is invisible, so make it visible. */
1207 IT_display_cursor (1);
1209 /* Mouse pointer should be always visible if we are waiting for
1216 IT_update_begin (struct frame
*f
)
1218 struct tty_display_info
*display_info
= FRAME_X_DISPLAY_INFO (f
);
1219 Mouse_HLInfo
*hlinfo
= &display_info
->mouse_highlight
;
1220 struct frame
*mouse_face_frame
= hlinfo
->mouse_face_mouse_frame
;
1222 if (display_info
->termscript
)
1223 fprintf (display_info
->termscript
, "\n\n<UPDATE_BEGIN");
1227 if (f
&& f
== mouse_face_frame
)
1229 /* Don't do highlighting for mouse motion during the update. */
1230 hlinfo
->mouse_face_defer
= 1;
1232 /* If F needs to be redrawn, simply forget about any prior mouse
1234 if (FRAME_GARBAGED_P (f
))
1235 hlinfo
->mouse_face_window
= Qnil
;
1237 /* Can we tell that this update does not affect the window
1238 where the mouse highlight is? If so, no need to turn off.
1239 Likewise, don't do anything if none of the enabled rows
1240 contains glyphs highlighted in mouse face. */
1241 if (!NILP (hlinfo
->mouse_face_window
)
1242 && WINDOWP (hlinfo
->mouse_face_window
))
1244 struct window
*w
= XWINDOW (hlinfo
->mouse_face_window
);
1247 /* If the mouse highlight is in the window that was deleted
1248 (e.g., if it was popped by completion), clear highlight
1250 if (NILP (w
->buffer
))
1251 hlinfo
->mouse_face_window
= Qnil
;
1254 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1255 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1256 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1260 if (NILP (w
->buffer
) || i
< w
->desired_matrix
->nrows
)
1261 clear_mouse_face (hlinfo
);
1264 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
1266 /* If the frame with mouse highlight was deleted, invalidate the
1268 hlinfo
->mouse_face_beg_row
= hlinfo
->mouse_face_beg_col
= -1;
1269 hlinfo
->mouse_face_end_row
= hlinfo
->mouse_face_end_col
= -1;
1270 hlinfo
->mouse_face_window
= Qnil
;
1271 hlinfo
->mouse_face_deferred_gc
= 0;
1272 hlinfo
->mouse_face_mouse_frame
= NULL
;
1279 IT_update_end (struct frame
*f
)
1281 struct tty_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (f
);
1283 if (dpyinfo
->termscript
)
1284 fprintf (dpyinfo
->termscript
, "\n<UPDATE_END\n");
1285 dpyinfo
->mouse_highlight
.mouse_face_defer
= 0;
1289 IT_frame_up_to_date (struct frame
*f
)
1291 Mouse_HLInfo
*hlinfo
= MOUSE_HL_INFO (f
);
1292 Lisp_Object new_cursor
, frame_desired_cursor
;
1295 if (hlinfo
->mouse_face_deferred_gc
1296 || (f
&& f
== hlinfo
->mouse_face_mouse_frame
))
1299 if (hlinfo
->mouse_face_mouse_frame
)
1300 note_mouse_highlight (hlinfo
->mouse_face_mouse_frame
,
1301 hlinfo
->mouse_face_mouse_x
,
1302 hlinfo
->mouse_face_mouse_y
);
1303 hlinfo
->mouse_face_deferred_gc
= 0;
1307 /* Set the cursor type to whatever they wanted. In a minibuffer
1308 window, we want the cursor to appear only if we are reading input
1309 from this window, and we want the cursor to be taken from the
1310 frame parameters. For the selected window, we use either its
1311 buffer-local value or the value from the frame parameters if the
1312 buffer doesn't define its local value for the cursor type. */
1313 sw
= XWINDOW (f
->selected_window
);
1314 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1315 if (cursor_in_echo_area
1316 && FRAME_HAS_MINIBUF_P (f
)
1317 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1318 && sw
== XWINDOW (echo_area_window
))
1319 new_cursor
= frame_desired_cursor
;
1322 struct buffer
*b
= XBUFFER (sw
->buffer
);
1324 if (EQ (BVAR (b
,cursor_type
), Qt
))
1325 new_cursor
= frame_desired_cursor
;
1326 else if (NILP (BVAR (b
, cursor_type
))) /* nil means no cursor */
1327 new_cursor
= Fcons (Qbar
, make_number (0));
1329 new_cursor
= BVAR (b
, cursor_type
);
1332 IT_set_cursor_type (f
, new_cursor
);
1334 IT_cmgoto (f
); /* position cursor when update is done */
1337 /* Copy LEN glyphs displayed on a single line whose vertical position
1338 is YPOS, beginning at horizontal position XFROM to horizontal
1339 position XTO, by moving blocks in the video memory. Used by
1340 functions that insert and delete glyphs. */
1342 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1344 /* The offsets of source and destination relative to the
1345 conventional memory selector. */
1346 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1347 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1349 if (from
== to
|| len
<= 0)
1352 _farsetsel (_dos_ds
);
1354 /* The source and destination might overlap, so we need to move
1355 glyphs non-destructively. */
1358 for ( ; len
; from
+= 2, to
+= 2, len
--)
1359 _farnspokew (to
, _farnspeekw (from
));
1363 from
+= (len
- 1) * 2;
1364 to
+= (len
- 1) * 2;
1365 for ( ; len
; from
-= 2, to
-= 2, len
--)
1366 _farnspokew (to
, _farnspeekw (from
));
1368 if (screen_virtual_segment
)
1369 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1372 /* Insert and delete glyphs. */
1374 IT_insert_glyphs (struct frame
*f
, struct glyph
*start
, int len
)
1376 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1378 /* Shift right the glyphs from the nominal cursor position to the
1379 end of this line. */
1380 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
1382 /* Now write the glyphs to be inserted. */
1383 IT_write_glyphs (f
, start
, len
);
1387 IT_delete_glyphs (struct frame
*f
, int n
)
1392 /* set-window-configuration on window.c needs this. */
1394 x_set_menu_bar_lines (struct frame
*f
, Lisp_Object value
, Lisp_Object oldval
)
1396 set_menu_bar_lines (f
, value
, oldval
);
1399 /* This was copied from xfaces.c */
1401 extern Lisp_Object Qbackground_color
;
1402 extern Lisp_Object Qforeground_color
;
1403 Lisp_Object Qreverse
;
1404 extern Lisp_Object Qtitle
;
1406 /* IT_set_terminal_modes is called when emacs is started,
1407 resumed, and whenever the screen is redrawn! */
1410 IT_set_terminal_modes (struct terminal
*term
)
1412 struct tty_display_info
*tty
;
1414 /* If called with initial terminal, it's too early to do anything
1416 if (term
->type
== output_initial
)
1419 tty
= term
->display_info
.tty
;
1421 if (tty
->termscript
)
1422 fprintf (tty
->termscript
, "\n<SET_TERM>");
1424 screen_size_X
= ScreenCols ();
1425 screen_size_Y
= ScreenRows ();
1426 screen_size
= screen_size_X
* screen_size_Y
;
1428 new_pos_X
= new_pos_Y
= 0;
1429 current_pos_X
= current_pos_Y
= -1;
1431 if (term_setup_done
)
1433 term_setup_done
= 1;
1435 startup_screen_size_X
= screen_size_X
;
1436 startup_screen_size_Y
= screen_size_Y
;
1437 startup_screen_attrib
= ScreenAttrib
;
1439 /* Is DOS/V (or any other RSIS software which relocates
1440 the screen) installed? */
1442 unsigned short es_value
;
1445 regs
.h
.ah
= 0xfe; /* get relocated screen address */
1446 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
1447 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
1448 else if (screen_old_address
) /* already switched to Japanese mode once */
1449 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
1451 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
1453 es_value
= regs
.x
.es
;
1454 __dpmi_int (0x10, ®s
);
1456 if (regs
.x
.es
!= es_value
)
1458 /* screen_old_address is only set if ScreenPrimary does NOT
1459 already point to the relocated buffer address returned by
1460 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1461 ScreenPrimary to that address at startup under DOS/V. */
1462 if (regs
.x
.es
!= ((ScreenPrimary
>> 4) & 0xffff))
1463 screen_old_address
= ScreenPrimary
;
1464 screen_virtual_segment
= regs
.x
.es
;
1465 screen_virtual_offset
= regs
.x
.di
;
1466 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
1470 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
1471 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
1476 /* IT_reset_terminal_modes is called when emacs is
1477 suspended or killed. */
1480 IT_reset_terminal_modes (struct terminal
*term
)
1482 int display_row_start
= (int) ScreenPrimary
;
1483 int saved_row_len
= startup_screen_size_X
* 2;
1484 int update_row_len
= ScreenCols () * 2, current_rows
= ScreenRows ();
1485 int to_next_row
= update_row_len
;
1486 unsigned char *saved_row
= startup_screen_buffer
;
1487 int cursor_pos_X
= ScreenCols () - 1, cursor_pos_Y
= ScreenRows () - 1;
1488 struct tty_display_info
*tty
= term
->display_info
.tty
;
1490 if (tty
->termscript
)
1491 fprintf (tty
->termscript
, "\n<RESET_TERM>");
1493 if (!term_setup_done
)
1498 /* Leave the video system in the same state as we found it,
1499 as far as the blink/bright-background bit is concerned. */
1500 maybe_enable_blinking ();
1502 /* We have a situation here.
1503 We cannot just do ScreenUpdate(startup_screen_buffer) because
1504 the luser could have changed screen dimensions inside Emacs
1505 and failed (or didn't want) to restore them before killing
1506 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1507 thus will happily use memory outside what was allocated for
1508 `startup_screen_buffer'.
1509 Thus we only restore as much as the current screen dimensions
1510 can hold, and clear the rest (if the saved screen is smaller than
1511 the current) with the color attribute saved at startup. The cursor
1512 is also restored within the visible dimensions. */
1514 ScreenAttrib
= startup_screen_attrib
;
1516 /* Don't restore the screen if we are exiting less than 2 seconds
1517 after startup: we might be crashing, and the screen might show
1518 some vital clues to what's wrong. */
1519 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
1522 if (screen_virtual_segment
)
1523 dosv_refresh_virtual_screen (0, screen_size
);
1525 if (update_row_len
> saved_row_len
)
1526 update_row_len
= saved_row_len
;
1527 if (current_rows
> startup_screen_size_Y
)
1528 current_rows
= startup_screen_size_Y
;
1530 if (tty
->termscript
)
1531 fprintf (tty
->termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1532 update_row_len
/ 2, current_rows
);
1534 while (current_rows
--)
1536 dosmemput (saved_row
, update_row_len
, display_row_start
);
1537 if (screen_virtual_segment
)
1538 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
1539 update_row_len
/ 2);
1540 saved_row
+= saved_row_len
;
1541 display_row_start
+= to_next_row
;
1544 if (startup_pos_X
< cursor_pos_X
)
1545 cursor_pos_X
= startup_pos_X
;
1546 if (startup_pos_Y
< cursor_pos_Y
)
1547 cursor_pos_Y
= startup_pos_Y
;
1549 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
1550 xfree (startup_screen_buffer
);
1551 startup_screen_buffer
= NULL
;
1553 term_setup_done
= 0;
1557 IT_set_terminal_window (struct frame
*f
, int foo
)
1561 /* Remember the screen colors of the current frame, to serve as the
1562 default colors for newly-created frames. */
1563 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
1564 Smsdos_remember_default_colors
, 1, 1, 0,
1565 doc
: /* Remember the screen colors of the current frame. */)
1570 CHECK_FRAME (frame
);
1573 /* This function is called after applying default-frame-alist to the
1574 initial frame. At that time, if reverse-colors option was
1575 specified in default-frame-alist, it was already applied, and
1576 frame colors are reversed. */
1577 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
1578 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
1584 IT_set_frame_parameters (struct frame
*f
, Lisp_Object alist
)
1587 int i
, j
, length
= XINT (Flength (alist
));
1589 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1591 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1592 /* Do we have to reverse the foreground and background colors? */
1593 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
1594 int redraw
= 0, fg_set
= 0, bg_set
= 0;
1595 unsigned long orig_fg
, orig_bg
;
1596 struct tty_display_info
*tty
= FRAME_TTY (f
);
1598 /* If we are creating a new frame, begin with the original screen colors
1599 used for the initial frame. */
1600 if (!f
->default_face_done_p
1601 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
1603 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
1604 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
1605 init_frame_faces (f
);
1606 f
->default_face_done_p
= 1;
1608 orig_fg
= reverse
? FRAME_BACKGROUND_PIXEL (f
) : FRAME_FOREGROUND_PIXEL (f
);
1609 orig_bg
= reverse
? FRAME_FOREGROUND_PIXEL (f
) : FRAME_BACKGROUND_PIXEL (f
);
1611 /* Extract parm names and values into those vectors. */
1613 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
1618 parms
[i
] = Fcar (elt
);
1619 CHECK_SYMBOL (parms
[i
]);
1620 values
[i
] = Fcdr (elt
);
1626 for (i
= 0; i
< j
; i
++)
1628 Lisp_Object prop
, val
;
1633 if (EQ (prop
, Qreverse
))
1634 reverse
= EQ (val
, Qt
);
1637 if (tty
->termscript
&& reverse
)
1638 fprintf (tty
->termscript
, "<INVERSE-VIDEO>\n");
1640 /* Now process the alist elements in reverse of specified order. */
1641 for (i
--; i
>= 0; i
--)
1643 Lisp_Object prop
, val
;
1648 if (EQ (prop
, Qforeground_color
))
1650 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
1651 ? LFACE_BACKGROUND_INDEX
1652 : LFACE_FOREGROUND_INDEX
);
1653 if (new_color
!= FACE_TTY_DEFAULT_COLOR
1654 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
1655 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
1659 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1660 /* Make sure the foreground of the default face for
1661 this frame is changed as well. */
1662 update_face_from_frame_parameter (f
, Qforeground_color
, val
);
1664 if (tty
->termscript
)
1665 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
1669 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1670 update_face_from_frame_parameter (f
, Qbackground_color
, val
);
1672 if (tty
->termscript
)
1673 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
1678 else if (EQ (prop
, Qbackground_color
))
1680 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
1681 ? LFACE_FOREGROUND_INDEX
1682 : LFACE_BACKGROUND_INDEX
);
1683 if (new_color
!= FACE_TTY_DEFAULT_COLOR
1684 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
1685 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
1689 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1690 /* Make sure the background of the default face for
1691 this frame is changed as well. */
1693 update_face_from_frame_parameter (f
, Qbackground_color
, val
);
1694 if (tty
->termscript
)
1695 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
1699 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1701 update_face_from_frame_parameter (f
, Qforeground_color
, val
);
1702 if (tty
->termscript
)
1703 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
1708 else if (EQ (prop
, Qtitle
))
1710 x_set_title (f
, val
);
1711 if (tty
->termscript
)
1712 fprintf (tty
->termscript
, "<TITLE: %s>\n", SDATA (val
));
1714 else if (EQ (prop
, Qcursor_type
))
1716 IT_set_cursor_type (f
, val
);
1717 if (tty
->termscript
)
1718 fprintf (tty
->termscript
, "<CTYPE: %s>\n",
1721 || (CONSP (val
) && (EQ (XCAR (val
), Qbar
)
1722 || EQ (XCAR (val
), Qhbar
)))
1725 else if (EQ (prop
, Qtty_type
))
1727 internal_terminal_init ();
1728 if (tty
->termscript
)
1729 fprintf (tty
->termscript
, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
1730 SBYTES (val
), SDATA (val
));
1732 store_frame_param (f
, prop
, val
);
1735 /* If they specified "reverse", but not the colors, we need to swap
1736 the current frame colors. */
1741 FRAME_FOREGROUND_PIXEL (f
) = orig_bg
;
1742 update_face_from_frame_parameter (f
, Qforeground_color
,
1743 tty_color_name (f
, orig_bg
));
1748 FRAME_BACKGROUND_PIXEL (f
) = orig_fg
;
1749 update_face_from_frame_parameter (f
, Qbackground_color
,
1750 tty_color_name (f
, orig_fg
));
1757 face_change_count
++; /* forces xdisp.c to recompute basic faces */
1758 if (f
== SELECTED_FRAME ())
1763 extern void init_frame_faces (FRAME_PTR
);
1765 #endif /* !HAVE_X_WINDOWS */
1768 /* Do we need the internal terminal? */
1771 internal_terminal_init (void)
1773 static int init_needed
= 1;
1774 char *term
= getenv ("TERM"), *colors
;
1775 struct frame
*sf
= SELECTED_FRAME ();
1776 struct tty_display_info
*tty
;
1778 #ifdef HAVE_X_WINDOWS
1779 if (!inhibit_window_system
)
1783 /* If this is the initial terminal, we are done here. */
1784 if (sf
->output_method
== output_initial
)
1788 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1790 #ifndef HAVE_X_WINDOWS
1791 if (!internal_terminal
|| inhibit_window_system
)
1793 sf
->output_method
= output_termcap
;
1797 tty
= FRAME_TTY (sf
);
1798 KVAR (current_kboard
, Vwindow_system
) = Qpc
;
1799 sf
->output_method
= output_msdos_raw
;
1802 if (!tty
->termscript
&& getenv ("EMACSTEST"))
1803 tty
->termscript
= fopen (getenv ("EMACSTEST"), "wt");
1804 if (tty
->termscript
)
1806 time_t now
= time (NULL
);
1807 struct tm
*tnow
= localtime (&now
);
1810 strftime (tbuf
, sizeof (tbuf
) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow
);
1811 fprintf (tty
->termscript
, "\nEmacs session started at %s\n", tbuf
);
1812 fprintf (tty
->termscript
, "=====================\n\n");
1815 Vinitial_window_system
= Qpc
;
1816 Vwindow_system_version
= make_number (24); /* RE Emacs version */
1817 tty
->terminal
->type
= output_msdos_raw
;
1819 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
1821 screen_old_address
= 0;
1823 /* Forget the stale screen colors as well. */
1824 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
1826 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
1827 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
1829 colors
= getenv ("EMACSCOLORS");
1830 if (colors
&& strlen (colors
) >= 2)
1832 /* The colors use 4 bits each (we enable bright background). */
1833 if (isdigit (colors
[0]))
1835 else if (isxdigit (colors
[0]))
1836 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1837 if (colors
[0] >= 0 && colors
[0] < 16)
1838 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors
[0];
1839 if (isdigit (colors
[1]))
1841 else if (isxdigit (colors
[1]))
1842 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1843 if (colors
[1] >= 0 && colors
[1] < 16)
1844 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors
[1];
1846 the_only_display_info
.mouse_highlight
.mouse_face_mouse_frame
= NULL
;
1847 the_only_display_info
.mouse_highlight
.mouse_face_deferred_gc
= 0;
1848 the_only_display_info
.mouse_highlight
.mouse_face_beg_row
=
1849 the_only_display_info
.mouse_highlight
.mouse_face_beg_col
= -1;
1850 the_only_display_info
.mouse_highlight
.mouse_face_end_row
=
1851 the_only_display_info
.mouse_highlight
.mouse_face_end_col
= -1;
1852 the_only_display_info
.mouse_highlight
.mouse_face_face_id
= DEFAULT_FACE_ID
;
1853 the_only_display_info
.mouse_highlight
.mouse_face_window
= Qnil
;
1854 the_only_display_info
.mouse_highlight
.mouse_face_mouse_x
=
1855 the_only_display_info
.mouse_highlight
.mouse_face_mouse_y
= 0;
1856 the_only_display_info
.mouse_highlight
.mouse_face_defer
= 0;
1857 the_only_display_info
.mouse_highlight
.mouse_face_hidden
= 0;
1859 if (have_mouse
) /* detected in dos_ttraw, which see */
1861 have_mouse
= 1; /* enable mouse */
1863 mouse_setup_buttons (mouse_button_count
);
1864 tty
->terminal
->mouse_position_hook
= &mouse_get_pos
;
1868 if (tty
->termscript
&& screen_size
)
1869 fprintf (tty
->termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1870 screen_size_X
, screen_size_Y
);
1872 init_frame_faces (sf
);
1879 initialize_msdos_display (struct terminal
*term
)
1881 term
->rif
= 0; /* we don't support window-based display */
1882 term
->cursor_to_hook
= term
->raw_cursor_to_hook
= IT_cursor_to
;
1883 term
->clear_to_end_hook
= IT_clear_to_end
;
1884 term
->clear_frame_hook
= IT_clear_screen
;
1885 term
->clear_end_of_line_hook
= IT_clear_end_of_line
;
1886 term
->ins_del_lines_hook
= 0;
1887 term
->insert_glyphs_hook
= IT_insert_glyphs
;
1888 term
->write_glyphs_hook
= IT_write_glyphs
;
1889 term
->delete_glyphs_hook
= IT_delete_glyphs
;
1890 term
->ring_bell_hook
= IT_ring_bell
;
1891 term
->reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1892 term
->set_terminal_modes_hook
= IT_set_terminal_modes
;
1893 term
->set_terminal_window_hook
= IT_set_terminal_window
;
1894 term
->update_begin_hook
= IT_update_begin
;
1895 term
->update_end_hook
= IT_update_end
;
1896 term
->frame_up_to_date_hook
= IT_frame_up_to_date
;
1897 term
->mouse_position_hook
= 0; /* set later by dos_ttraw */
1898 term
->frame_rehighlight_hook
= 0;
1899 term
->frame_raise_lower_hook
= 0;
1900 term
->set_vertical_scroll_bar_hook
= 0;
1901 term
->condemn_scroll_bars_hook
= 0;
1902 term
->redeem_scroll_bar_hook
= 0;
1903 term
->judge_scroll_bars_hook
= 0;
1904 term
->read_socket_hook
= &tty_read_avail_input
; /* from keyboard.c */
1908 dos_get_saved_screen (char **screen
, int *rows
, int *cols
)
1910 #ifndef HAVE_X_WINDOWS
1911 *screen
= startup_screen_buffer
;
1912 *cols
= startup_screen_size_X
;
1913 *rows
= startup_screen_size_Y
;
1914 return *screen
!= (char *)0;
1920 #ifndef HAVE_X_WINDOWS
1922 /* We are not X, but we can emulate it well enough for our needs... */
1926 if (! FRAME_MSDOS_P (SELECTED_FRAME ()))
1927 error ("Not running under a window system");
1933 /* ----------------------- Keyboard control ----------------------
1935 * Keymaps reflect the following keyboard layout:
1937 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1938 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1939 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1940 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1944 #define Ignore 0x0000
1945 #define Normal 0x0000 /* normal key - alt changes scan-code */
1946 #define FctKey 0x1000 /* func key if c == 0, else c */
1947 #define Special 0x2000 /* func key even if c != 0 */
1948 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1949 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1950 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1951 #define Grey 0x6000 /* Grey keypad key */
1953 #define Alt 0x0100 /* alt scan-code */
1954 #define Ctrl 0x0200 /* ctrl scan-code */
1955 #define Shift 0x0400 /* shift scan-code */
1957 static int extended_kbd
; /* 101 (102) keyboard present. */
1959 struct kbd_translate
{
1962 unsigned short code
;
1965 struct dos_keyboard_map
1970 struct kbd_translate
*translate_table
;
1974 static struct dos_keyboard_map us_keyboard
= {
1976 /* 01234567890123456789012345678901234567890 12345678901234 */
1977 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1978 /* 0123456789012345678901234567890123456789 012345678901234 */
1979 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1980 0, /* no Alt-Gr key */
1981 0 /* no translate table */
1984 static struct dos_keyboard_map fr_keyboard
= {
1986 /* 012 3456789012345678901234567890123456789012345678901234 */
1987 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1988 /* 0123456789012345678901234567890123456789012345678901234 */
1989 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1990 /* 01234567 89012345678901234567890123456789012345678901234 */
1992 0 /* no translate table */
1996 * Italian keyboard support, country code 39.
1999 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
2000 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
2003 static struct kbd_translate it_kbd_translate_table
[] = {
2004 { 0x56, 0x3c, Normal
| 13 },
2005 { 0x56, 0x3e, Normal
| 27 },
2008 static struct dos_keyboard_map it_keyboard
= {
2010 /* 0 123456789012345678901234567890123456789012345678901234 */
2011 "\\1234567890'\8d< qwertyuiop\8a+> asdfghjkl\95\85\97 zxcvbnm,.- ",
2012 /* 01 23456789012345678901234567890123456789012345678901234 */
2013 "|!\"\9c$%&/()=?^> QWERTYUIOP\82* ASDFGHJKL\87øõ ZXCVBNM;:_ ",
2014 /* 0123456789012345678901234567890123456789012345678901234 */
2016 it_kbd_translate_table
2019 static struct dos_keyboard_map dk_keyboard
= {
2021 /* 0123456789012345678901234567890123456789012345678901234 */
2022 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
2023 /* 01 23456789012345678901234567890123456789012345678901234 */
2024 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
2025 /* 0123456789012345678901234567890123456789012345678901234 */
2027 0 /* no translate table */
2030 static struct kbd_translate jp_kbd_translate_table
[] = {
2031 { 0x73, 0x5c, Normal
| 0 },
2032 { 0x73, 0x5f, Normal
| 0 },
2033 { 0x73, 0x1c, Map
| 0 },
2034 { 0x7d, 0x5c, Normal
| 13 },
2035 { 0x7d, 0x7c, Normal
| 13 },
2036 { 0x7d, 0x1c, Map
| 13 },
2039 static struct dos_keyboard_map jp_keyboard
= {
2041 /* 0123456789012 345678901234567890123456789012345678901234 */
2042 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
2043 /* 01 23456789012345678901234567890123456789012345678901234 */
2044 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2045 0, /* no Alt-Gr key */
2046 jp_kbd_translate_table
2049 static struct keyboard_layout_list
2052 struct dos_keyboard_map
*keyboard_map
;
2053 } keyboard_layout_list
[] =
2055 { 1, &us_keyboard
},
2056 { 33, &fr_keyboard
},
2057 { 39, &it_keyboard
},
2058 { 45, &dk_keyboard
},
2059 { 81, &jp_keyboard
}
2062 static struct dos_keyboard_map
*keyboard
;
2063 static int keyboard_map_all
;
2064 static int international_keyboard
;
2067 dos_set_keyboard (int code
, int always
)
2070 _go32_dpmi_registers regs
;
2072 /* See if Keyb.Com is installed (for international keyboard support).
2073 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2074 of Windows 9X! So don't do that! */
2076 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2077 _go32_dpmi_simulate_int (0x2f, ®s
);
2078 if (regs
.h
.al
== 0xff)
2079 international_keyboard
= 1;
2081 /* Initialize to US settings, for countries that don't have their own. */
2082 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2083 keyboard_map_all
= always
;
2084 dos_keyboard_layout
= 1;
2086 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2087 if (code
== keyboard_layout_list
[i
].country_code
)
2089 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2090 keyboard_map_all
= always
;
2091 dos_keyboard_layout
= code
;
2099 unsigned char char_code
; /* normal code */
2100 unsigned char meta_code
; /* M- code */
2101 unsigned char keypad_code
; /* keypad code */
2102 unsigned char editkey_code
; /* edit key */
2103 } keypad_translate_map
[] = {
2104 { '0', '0', 0xb0, /* kp-0 */ 0x63 /* insert */ },
2105 { '1', '1', 0xb1, /* kp-1 */ 0x57 /* end */ },
2106 { '2', '2', 0xb2, /* kp-2 */ 0x54 /* down */ },
2107 { '3', '3', 0xb3, /* kp-3 */ 0x56 /* next */ },
2108 { '4', '4', 0xb4, /* kp-4 */ 0x51 /* left */ },
2109 { '5', '5', 0xb5, /* kp-5 */ 0xb5 /* kp-5 */ },
2110 { '6', '6', 0xb6, /* kp-6 */ 0x53 /* right */ },
2111 { '7', '7', 0xb7, /* kp-7 */ 0x50 /* home */ },
2112 { '8', '8', 0xb8, /* kp-8 */ 0x52 /* up */ },
2113 { '9', '9', 0xb9, /* kp-9 */ 0x55 /* prior */ },
2114 { '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */}
2119 unsigned char char_code
; /* normal code */
2120 unsigned char keypad_code
; /* keypad code */
2121 } grey_key_translate_map
[] = {
2122 { '/', 0xaf /* kp-decimal */ },
2123 { '*', 0xaa /* kp-multiply */ },
2124 { '-', 0xad /* kp-subtract */ },
2125 { '+', 0xab /* kp-add */ },
2126 { '\r', 0x8d /* kp-enter */ }
2129 static unsigned short
2130 ibmpc_translate_map
[] =
2132 /* --------------- 00 to 0f --------------- */
2133 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2134 Alt
| ModFct
| 0x1b, /* Escape */
2135 Normal
| 1, /* '1' */
2136 Normal
| 2, /* '2' */
2137 Normal
| 3, /* '3' */
2138 Normal
| 4, /* '4' */
2139 Normal
| 5, /* '5' */
2140 Normal
| 6, /* '6' */
2141 Normal
| 7, /* '7' */
2142 Normal
| 8, /* '8' */
2143 Normal
| 9, /* '9' */
2144 Normal
| 10, /* '0' */
2145 Normal
| 11, /* '-' */
2146 Normal
| 12, /* '=' */
2147 Special
| 0x08, /* Backspace */
2148 ModFct
| 0x74, /* Tab/Backtab */
2150 /* --------------- 10 to 1f --------------- */
2163 ModFct
| 0x0d, /* Return */
2168 /* --------------- 20 to 2f --------------- */
2177 Map
| 40, /* '\'' */
2179 Ignore
, /* Left shift */
2180 Map
| 41, /* '\\' */
2186 /* --------------- 30 to 3f --------------- */
2193 Ignore
, /* Right shift */
2194 Grey
| 1, /* Grey * */
2196 Normal
| 55, /* ' ' */
2197 Ignore
, /* Caps Lock */
2198 FctKey
| 0xbe, /* F1 */
2199 FctKey
| 0xbf, /* F2 */
2200 FctKey
| 0xc0, /* F3 */
2201 FctKey
| 0xc1, /* F4 */
2202 FctKey
| 0xc2, /* F5 */
2204 /* --------------- 40 to 4f --------------- */
2205 FctKey
| 0xc3, /* F6 */
2206 FctKey
| 0xc4, /* F7 */
2207 FctKey
| 0xc5, /* F8 */
2208 FctKey
| 0xc6, /* F9 */
2209 FctKey
| 0xc7, /* F10 */
2210 Ignore
, /* Num Lock */
2211 Ignore
, /* Scroll Lock */
2212 KeyPad
| 7, /* Home */
2213 KeyPad
| 8, /* Up */
2214 KeyPad
| 9, /* Page Up */
2215 Grey
| 2, /* Grey - */
2216 KeyPad
| 4, /* Left */
2217 KeyPad
| 5, /* Keypad 5 */
2218 KeyPad
| 6, /* Right */
2219 Grey
| 3, /* Grey + */
2220 KeyPad
| 1, /* End */
2222 /* --------------- 50 to 5f --------------- */
2223 KeyPad
| 2, /* Down */
2224 KeyPad
| 3, /* Page Down */
2225 KeyPad
| 0, /* Insert */
2226 KeyPad
| 10, /* Delete */
2227 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2228 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2229 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2230 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2231 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2232 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2233 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2234 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2235 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2236 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2237 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2238 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2240 /* --------------- 60 to 6f --------------- */
2241 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2242 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2243 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2244 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2245 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2246 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2247 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2248 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2249 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2250 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2251 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2252 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2253 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2254 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2255 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2256 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2258 /* --------------- 70 to 7f --------------- */
2259 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2260 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2261 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2262 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2263 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2264 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2265 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2266 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2267 Alt
| Map
| 1, /* '1' */
2268 Alt
| Map
| 2, /* '2' */
2269 Alt
| Map
| 3, /* '3' */
2270 Alt
| Map
| 4, /* '4' */
2271 Alt
| Map
| 5, /* '5' */
2272 Alt
| Map
| 6, /* '6' */
2273 Alt
| Map
| 7, /* '7' */
2274 Alt
| Map
| 8, /* '8' */
2276 /* --------------- 80 to 8f --------------- */
2277 Alt
| Map
| 9, /* '9' */
2278 Alt
| Map
| 10, /* '0' */
2279 Alt
| Map
| 11, /* '-' */
2280 Alt
| Map
| 12, /* '=' */
2281 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2282 FctKey
| 0xc8, /* F11 */
2283 FctKey
| 0xc9, /* F12 */
2284 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2285 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2286 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2287 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2288 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2289 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2290 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2291 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2292 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2294 /* --------------- 90 to 9f --------------- */
2295 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2296 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2297 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2298 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2299 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2300 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2301 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2302 Alt
| FctKey
| 0x50, /* (Alt) Home */
2303 Alt
| FctKey
| 0x52, /* (Alt) Up */
2304 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2305 Ignore
, /* NO KEY */
2306 Alt
| FctKey
| 0x51, /* (Alt) Left */
2307 Ignore
, /* NO KEY */
2308 Alt
| FctKey
| 0x53, /* (Alt) Right */
2309 Ignore
, /* NO KEY */
2310 Alt
| FctKey
| 0x57, /* (Alt) End */
2312 /* --------------- a0 to af --------------- */
2313 Alt
| KeyPad
| 2, /* (Alt) Down */
2314 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2315 Alt
| KeyPad
| 0, /* (Alt) Insert */
2316 Alt
| KeyPad
| 10, /* (Alt) Delete */
2317 Alt
| Grey
| 0, /* (Alt) Grey / */
2318 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2319 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2322 /* These bit-positions corresponds to values returned by BIOS */
2323 #define SHIFT_P 0x0003 /* two bits! */
2324 #define CTRL_P 0x0004
2325 #define ALT_P 0x0008
2326 #define SCRLOCK_P 0x0010
2327 #define NUMLOCK_P 0x0020
2328 #define CAPSLOCK_P 0x0040
2329 #define ALT_GR_P 0x0800
2330 #define SUPER_P 0x4000 /* pseudo */
2331 #define HYPER_P 0x8000 /* pseudo */
2334 dos_get_modifiers (int *keymask
)
2337 int mask
, modifiers
= 0;
2339 /* Calculate modifier bits */
2340 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2341 int86 (0x16, ®s
, ®s
);
2345 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2346 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2350 mask
= regs
.h
.al
& (SHIFT_P
|
2351 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2353 /* Do not break international keyboard support. */
2354 /* When Keyb.Com is loaded, the right Alt key is */
2355 /* used for accessing characters like { and } */
2356 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2359 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2362 if (dos_hyper_key
== 1)
2365 modifiers
|= hyper_modifier
;
2367 else if (dos_super_key
== 1)
2370 modifiers
|= super_modifier
;
2372 else if (!international_keyboard
)
2374 /* If Keyb.Com is NOT installed, let Right Alt behave
2375 like the Left Alt. */
2381 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2384 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2386 if (dos_hyper_key
== 2)
2389 modifiers
|= hyper_modifier
;
2391 else if (dos_super_key
== 2)
2394 modifiers
|= super_modifier
;
2402 modifiers
|= shift_modifier
;
2404 modifiers
|= ctrl_modifier
;
2406 modifiers
|= meta_modifier
;
2413 #define NUM_RECENT_DOSKEYS (100)
2414 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2415 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
2416 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
2418 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
2419 doc
: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2420 Each input key receives two values in this vector: first the ASCII code,
2421 and then the scan code. */)
2424 Lisp_Object val
, *keys
= XVECTOR (recent_doskeys
)->contents
;
2426 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
2427 return Fvector (total_doskeys
, keys
);
2430 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
2431 memcpy (XVECTOR (val
)->contents
, keys
+ recent_doskeys_index
,
2432 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
2433 memcpy (XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
2434 keys
, recent_doskeys_index
* sizeof (Lisp_Object
));
2439 /* Get a char from keyboard. Function keys are put into the event queue. */
2443 struct input_event event
;
2445 Mouse_HLInfo
*hlinfo
= MOUSE_HL_INFO (SELECTED_FRAME ());
2448 #ifndef HAVE_X_WINDOWS
2449 /* Maybe put the cursor where it should be. */
2450 IT_cmgoto (SELECTED_FRAME ());
2453 /* The following condition is equivalent to `kbhit ()', except that
2454 it uses the bios to do its job. This pleases DESQview/X. */
2455 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
2456 int86 (0x16, ®s
, ®s
),
2457 (regs
.x
.flags
& 0x40) == 0)
2460 register unsigned char c
;
2461 int modifiers
, sc
, code
= -1, mask
, kp_mode
;
2463 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
2464 int86 (0x16, ®s
, ®s
);
2469 ASET (recent_doskeys
, recent_doskeys_index
, make_number (c
)), recent_doskeys_index
++;
2470 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2471 recent_doskeys_index
= 0;
2472 ASET (recent_doskeys
, recent_doskeys_index
, make_number (sc
)), recent_doskeys_index
++;
2473 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2474 recent_doskeys_index
= 0;
2476 modifiers
= dos_get_modifiers (&mask
);
2478 #ifndef HAVE_X_WINDOWS
2479 if (!NILP (Vdos_display_scancodes
))
2482 sprintf (buf
, "%02x:%02x*%04x",
2483 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
2484 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
2492 case 10: /* Ctrl Grey Enter */
2493 code
= Ctrl
| Grey
| 4;
2495 case 13: /* Grey Enter */
2498 case '/': /* Grey / */
2508 /* Try the keyboard-private translation table first. */
2509 if (keyboard
->translate_table
)
2511 struct kbd_translate
*p
= keyboard
->translate_table
;
2515 if (p
->sc
== sc
&& p
->ch
== c
)
2523 /* If the private table didn't translate it, use the general
2527 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
2529 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
2536 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2537 Emacs is ready to read a key. Therefore, if they press
2538 `Alt-x' when Emacs is busy, by the time we get to
2539 `dos_get_modifiers', they might have already released the
2540 Alt key, and Emacs gets just `x', which is BAD.
2541 However, for keys with the `Map' property set, the ASCII
2542 code returns zero only if Alt is pressed. So, when we DON'T
2543 have to support international_keyboard, we don't have to
2544 distinguish between the left and right Alt keys, and we
2545 can set the META modifier for any keys with the `Map'
2546 property if they return zero ASCII code (c = 0). */
2548 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
2549 modifiers
|= meta_modifier
;
2551 modifiers
|= ctrl_modifier
;
2553 modifiers
|= shift_modifier
;
2556 switch (code
& 0xf000)
2559 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
2561 c
= 0; /* Special */
2574 if (c
== 0) /* ctrl-break */
2576 return c
; /* ALT-nnn */
2578 if (!keyboard_map_all
)
2587 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
2588 if (!keyboard_map_all
)
2592 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
2593 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
2597 code
= keyboard
->shifted
[code
];
2599 modifiers
&= ~shift_modifier
;
2602 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
2603 code
= keyboard
->alt_gr
[code
];
2605 code
= keyboard
->unshifted
[code
];
2610 if (c
== 0xe0) /* edit key */
2613 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
2614 kp_mode
= dos_keypad_mode
& 0x03;
2616 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
2621 if (code
== 10 && dos_decimal_point
)
2622 return dos_decimal_point
;
2623 return keypad_translate_map
[code
].char_code
;
2626 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
2630 code
= keypad_translate_map
[code
].meta_code
;
2631 modifiers
= meta_modifier
;
2635 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
2642 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
2643 if (dos_keypad_mode
& kp_mode
)
2644 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
2646 code
= grey_key_translate_map
[code
].char_code
;
2653 if (!hlinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
))
2655 clear_mouse_face (hlinfo
);
2656 hlinfo
->mouse_face_hidden
= 1;
2660 event
.kind
= NON_ASCII_KEYSTROKE_EVENT
;
2662 event
.kind
= ASCII_KEYSTROKE_EVENT
;
2664 event
.modifiers
= modifiers
;
2665 event
.frame_or_window
= selected_frame
;
2667 event
.timestamp
= event_timestamp ();
2668 kbd_buffer_store_event (&event
);
2671 if (have_mouse
> 0 && !mouse_preempted
)
2673 int but
, press
, x
, y
, ok
;
2674 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
2675 Lisp_Object mouse_window
= Qnil
;
2677 /* Check for mouse movement *before* buttons. */
2678 mouse_check_moved ();
2680 /* If the mouse moved from the spot of its last sighting, we
2681 might need to update mouse highlight. */
2682 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
2684 if (hlinfo
->mouse_face_hidden
)
2686 hlinfo
->mouse_face_hidden
= 0;
2687 clear_mouse_face (hlinfo
);
2690 /* Generate SELECT_WINDOW_EVENTs when needed. */
2691 if (!NILP (Vmouse_autoselect_window
))
2693 mouse_window
= window_from_coordinates (SELECTED_FRAME (),
2697 /* A window will be selected only when it is not
2698 selected now, and the last mouse movement event was
2699 not in it. A minibuffer window will be selected iff
2701 if (WINDOWP (mouse_window
)
2702 && !EQ (mouse_window
, last_mouse_window
)
2703 && !EQ (mouse_window
, selected_window
))
2705 event
.kind
= SELECT_WINDOW_EVENT
;
2706 event
.frame_or_window
= mouse_window
;
2708 event
.timestamp
= event_timestamp ();
2709 kbd_buffer_store_event (&event
);
2711 last_mouse_window
= mouse_window
;
2714 last_mouse_window
= Qnil
;
2716 previous_help_echo_string
= help_echo_string
;
2717 help_echo_string
= help_echo_object
= help_echo_window
= Qnil
;
2719 note_mouse_highlight (SELECTED_FRAME (), mouse_last_x
, mouse_last_y
);
2720 /* If the contents of the global variable help_echo has
2721 changed, generate a HELP_EVENT. */
2722 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
2723 gen_help_event (help_echo_string
, selected_frame
, help_echo_window
,
2724 help_echo_object
, help_echo_pos
);
2727 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
2728 for (press
= 0; press
< 2; press
++)
2730 int button_num
= but
;
2733 ok
= mouse_pressed (but
, &x
, &y
);
2735 ok
= mouse_released (but
, &x
, &y
);
2738 /* Allow a simultaneous press/release of Mouse-1 and
2739 Mouse-2 to simulate Mouse-3 on two-button mice. */
2740 if (mouse_button_count
== 2 && but
< 2)
2742 int x2
, y2
; /* don't clobber original coordinates */
2744 /* If only one button is pressed, wait 100 msec and
2745 check again. This way, Speedy Gonzales isn't
2746 punished, while the slow get their chance. */
2747 if ((press
&& mouse_pressed (1-but
, &x2
, &y2
))
2748 || (!press
&& mouse_released (1-but
, &x2
, &y2
)))
2753 if ((press
&& mouse_pressed (1-but
, &x2
, &y2
))
2754 || (!press
&& mouse_released (1-but
, &x2
, &y2
)))
2759 event
.kind
= MOUSE_CLICK_EVENT
;
2760 event
.code
= button_num
;
2761 event
.modifiers
= dos_get_modifiers (0)
2762 | (press
? down_modifier
: up_modifier
);
2763 event
.x
= make_number (x
);
2764 event
.y
= make_number (y
);
2765 event
.frame_or_window
= selected_frame
;
2767 event
.timestamp
= event_timestamp ();
2768 kbd_buffer_store_event (&event
);
2776 static int prev_get_char
= -1;
2778 /* Return 1 if a key is ready to be read without suspending execution. */
2782 if (prev_get_char
!= -1)
2785 return ((prev_get_char
= dos_rawgetc ()) != -1);
2788 /* Read a key. Return -1 if no key is ready. */
2792 if (prev_get_char
!= -1)
2794 int c
= prev_get_char
;
2799 return dos_rawgetc ();
2802 #ifndef HAVE_X_WINDOWS
2804 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2807 Actually, I don't know the meaning of all the parameters of the functions
2808 here -- I only know how they are called by xmenu.c. I could of course
2809 grab the nearest Xlib manual (down the hall, second-to-last door on the
2810 left), but I don't think it's worth the effort. */
2812 /* These hold text of the current and the previous menu help messages. */
2813 static const char *menu_help_message
, *prev_menu_help_message
;
2814 /* Pane number and item number of the menu item which generated the
2815 last menu help message. */
2816 static int menu_help_paneno
, menu_help_itemno
;
2819 IT_menu_create (void)
2823 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
2824 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
2828 /* Allocate some (more) memory for MENU ensuring that there is room for one
2832 IT_menu_make_room (XMenu
*menu
)
2834 if (menu
->allocated
== 0)
2836 int count
= menu
->allocated
= 10;
2837 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
2838 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
2839 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
2840 menu
->help_text
= (const char **) xmalloc (count
* sizeof (char *));
2842 else if (menu
->allocated
== menu
->count
)
2844 int count
= menu
->allocated
= menu
->allocated
+ 10;
2846 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
2848 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
2850 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
2852 = (const char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
2856 /* Search the given menu structure for a given pane number. */
2859 IT_menu_search_pane (XMenu
*menu
, int pane
)
2864 for (i
= 0; i
< menu
->count
; i
++)
2865 if (menu
->submenu
[i
])
2867 if (pane
== menu
->panenumber
[i
])
2868 return menu
->submenu
[i
];
2869 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
2875 /* Determine how much screen space a given menu needs. */
2878 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
2880 int i
, h2
, w2
, maxsubwidth
, maxheight
;
2883 maxheight
= menu
->count
;
2884 for (i
= 0; i
< menu
->count
; i
++)
2886 if (menu
->submenu
[i
])
2888 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
2889 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
2890 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
2893 *width
= menu
->width
+ maxsubwidth
;
2894 *height
= maxheight
;
2897 /* Display MENU at (X,Y) using FACES. */
2899 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
2902 (GLYPH).type = CHAR_GLYPH; \
2903 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
2904 (GLYPH).charpos = -1; \
2909 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
2911 int i
, j
, face
, width
, mx
, my
, enabled
, mousehere
, row
, col
;
2912 struct glyph
*text
, *p
;
2913 const unsigned char *q
;
2914 struct frame
*sf
= SELECTED_FRAME ();
2916 menu_help_message
= NULL
;
2918 width
= menu
->width
;
2919 /* We multiply width by 2 to account for possible control characters.
2920 FIXME: cater to non-ASCII characters in menus. */
2921 text
= (struct glyph
*) xmalloc ((width
* 2 + 2) * sizeof (struct glyph
));
2922 ScreenGetCursor (&row
, &col
);
2923 mouse_get_xy (&mx
, &my
);
2924 IT_update_begin (sf
);
2925 for (i
= 0; i
< menu
->count
; i
++)
2927 int max_width
= width
+ 2;
2929 IT_cursor_to (sf
, y
+ i
, x
);
2931 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
2932 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ max_width
);
2933 face
= faces
[enabled
+ mousehere
* 2];
2934 /* The following if clause means that we display the menu help
2935 strings even if the menu item is currently disabled. */
2936 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
2938 menu_help_message
= menu
->help_text
[i
];
2939 menu_help_paneno
= pn
- 1;
2940 menu_help_itemno
= i
;
2943 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
2945 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
2947 unsigned c
= STRING_CHAR_ADVANCE (q
);
2951 BUILD_CHAR_GLYPH (*p
, c
, face
, 0);
2954 else /* make '^x' */
2956 BUILD_CHAR_GLYPH (*p
, '^', face
, 0);
2959 BUILD_CHAR_GLYPH (*p
, c
+ 64, face
, 0);
2963 /* Don't let the menu text overflow into the next screen row. */
2964 if (x
+ max_width
> screen_size_X
)
2966 max_width
= screen_size_X
- x
;
2967 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
2969 for (; j
< max_width
- 2; j
++, p
++)
2970 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
2972 /* 16 is the character code of a character that on DOS terminal
2973 produces a nice-looking right-pointing arrow glyph. */
2974 BUILD_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
2976 IT_write_glyphs (sf
, text
, max_width
);
2979 IT_cursor_to (sf
, row
, col
);
2983 /* --------------------------- X Menu emulation ---------------------- */
2985 /* Report availability of menus. */
2988 have_menus_p (void) { return 1; }
2990 /* Create a brand new menu structure. */
2993 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2995 return IT_menu_create ();
2998 /* Create a new pane and place it on the outer-most level. It is not
2999 clear that it should be placed out there, but I don't know what else
3003 XMenuAddPane (Display
*foo
, XMenu
*menu
, const char *txt
, int enable
)
3011 IT_menu_make_room (menu
);
3012 menu
->submenu
[menu
->count
] = IT_menu_create ();
3013 menu
->text
[menu
->count
] = (char *)txt
;
3014 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
3015 menu
->help_text
[menu
->count
] = NULL
;
3018 /* Adjust length for possible control characters (which will
3019 be written as ^x). */
3020 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3024 if (len
> menu
->width
)
3027 return menu
->panecount
;
3030 /* Create a new item in a menu pane. */
3033 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
3034 int foo
, char *txt
, int enable
, char const *help_text
)
3040 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
3042 IT_menu_make_room (menu
);
3043 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
3044 menu
->text
[menu
->count
] = txt
;
3045 menu
->panenumber
[menu
->count
] = enable
;
3046 menu
->help_text
[menu
->count
] = help_text
;
3049 /* Adjust length for possible control characters (which will
3050 be written as ^x). */
3051 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3055 if (len
> menu
->width
)
3061 /* Decide where the menu would be placed if requested at (X,Y). */
3064 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3065 int *ulx
, int *uly
, int *width
, int *height
)
3067 IT_menu_calc_size (menu
, width
, height
);
3073 struct IT_menu_state
3075 void *screen_behind
;
3082 /* Display menu, wait for user's response, and return that response. */
3085 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3086 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3087 void (*help_callback
)(char const *, int, int))
3089 struct IT_menu_state
*state
;
3090 int statecount
, x
, y
, i
, b
, screensize
, leave
, result
, onepane
;
3091 int title_faces
[4]; /* face to display the menu title */
3092 int faces
[4], buffers_num_deleted
= 0;
3093 struct frame
*sf
= SELECTED_FRAME ();
3094 Lisp_Object saved_echo_area_message
, selectface
;
3096 /* Just in case we got here without a mouse present... */
3097 if (have_mouse
<= 0)
3098 return XM_IA_SELECT
;
3099 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3100 around the display. */
3106 /* We will process all the mouse events directly, so we had
3107 better prevent dos_rawgetc from stealing them from us. */
3110 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3111 screensize
= screen_size
* 2;
3113 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3114 DEFAULT_FACE_ID
, 1);
3116 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3117 DEFAULT_FACE_ID
, 1);
3118 selectface
= intern ("msdos-menu-select-face");
3119 faces
[2] = lookup_derived_face (sf
, selectface
,
3121 faces
[3] = lookup_derived_face (sf
, selectface
,
3124 /* Make sure the menu title is always displayed with
3125 `msdos-menu-active-face', no matter where the mouse pointer is. */
3126 for (i
= 0; i
< 4; i
++)
3127 title_faces
[i
] = faces
[3];
3131 /* Don't let the title for the "Buffers" popup menu include a
3132 digit (which is ugly).
3134 This is a terrible kludge, but I think the "Buffers" case is
3135 the only one where the title includes a number, so it doesn't
3136 seem to be necessary to make this more general. */
3137 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3139 menu
->text
[0][7] = '\0';
3140 buffers_num_deleted
= 1;
3143 /* We need to save the current echo area message, so that we could
3144 restore it below, before we exit. See the commentary below,
3145 before the call to message_with_string. */
3146 saved_echo_area_message
= Fcurrent_message ();
3147 state
[0].menu
= menu
;
3149 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3151 /* Turn off the cursor. Otherwise it shows through the menu
3152 panes, which is ugly. */
3153 IT_display_cursor (0);
3155 /* Display the menu title. */
3156 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3157 if (buffers_num_deleted
)
3158 menu
->text
[0][7] = ' ';
3159 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3161 menu
->width
= menu
->submenu
[0]->width
;
3162 state
[0].menu
= menu
->submenu
[0];
3166 state
[0].menu
= menu
;
3168 state
[0].x
= x0
- 1;
3170 state
[0].pane
= onepane
;
3172 mouse_last_x
= -1; /* A hack that forces display. */
3176 if (!mouse_visible
) mouse_on ();
3177 mouse_check_moved ();
3178 if (sf
->mouse_moved
)
3180 sf
->mouse_moved
= 0;
3181 result
= XM_IA_SELECT
;
3182 mouse_get_xy (&x
, &y
);
3183 for (i
= 0; i
< statecount
; i
++)
3184 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3186 int dy
= y
- state
[i
].y
;
3187 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3189 if (!state
[i
].menu
->submenu
[dy
])
3191 if (state
[i
].menu
->panenumber
[dy
])
3192 result
= XM_SUCCESS
;
3194 result
= XM_IA_SELECT
;
3196 *pane
= state
[i
].pane
- 1;
3198 /* We hit some part of a menu, so drop extra menus that
3199 have been opened. That does not include an open and
3201 if (i
!= statecount
- 2
3202 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3203 while (i
!= statecount
- 1)
3207 ScreenUpdate (state
[statecount
].screen_behind
);
3208 if (screen_virtual_segment
)
3209 dosv_refresh_virtual_screen (0, screen_size
);
3210 xfree (state
[statecount
].screen_behind
);
3212 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3214 IT_menu_display (state
[i
].menu
,
3219 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3220 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3222 ScreenRetrieve (state
[statecount
].screen_behind
3223 = xmalloc (screensize
));
3225 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3226 state
[statecount
].y
= y
;
3231 IT_menu_display (state
[statecount
- 1].menu
,
3232 state
[statecount
- 1].y
,
3233 state
[statecount
- 1].x
,
3234 state
[statecount
- 1].pane
,
3239 if ((menu_help_message
|| prev_menu_help_message
)
3240 && menu_help_message
!= prev_menu_help_message
)
3242 help_callback (menu_help_message
,
3243 menu_help_paneno
, menu_help_itemno
);
3244 IT_display_cursor (0);
3245 prev_menu_help_message
= menu_help_message
;
3247 /* We are busy-waiting for the mouse to move, so let's be nice
3248 to other Windows applications by releasing our time slice. */
3251 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3253 /* Only leave if user both pressed and released the mouse, and in
3254 that order. This avoids popping down the menu pane unless
3255 the user is really done with it. */
3256 if (mouse_pressed (b
, &x
, &y
))
3258 while (mouse_button_depressed (b
, &x
, &y
))
3262 (void) mouse_released (b
, &x
, &y
);
3267 ScreenUpdate (state
[0].screen_behind
);
3268 if (screen_virtual_segment
)
3269 dosv_refresh_virtual_screen (0, screen_size
);
3271 /* We have a situation here. ScreenUpdate has just restored the
3272 screen contents as it was before we started drawing this menu.
3273 That includes any echo area message that could have been
3274 displayed back then. (In reality, that echo area message will
3275 almost always be the ``keystroke echo'' that echoes the sequence
3276 of menu items chosen by the user.) However, if the menu had some
3277 help messages, then displaying those messages caused Emacs to
3278 forget about the original echo area message. So when
3279 ScreenUpdate restored it, it created a discrepancy between the
3280 actual screen contents and what Emacs internal data structures
3283 To avoid this conflict, we force Emacs to restore the original
3284 echo area message as we found it when we entered this function.
3285 The irony of this is that we then erase the restored message
3286 right away, so the only purpose of restoring it is so that
3287 erasing it works correctly... */
3288 if (! NILP (saved_echo_area_message
))
3289 message_with_string ("%s", saved_echo_area_message
, 0);
3291 while (statecount
--)
3292 xfree (state
[statecount
].screen_behind
);
3293 IT_display_cursor (1); /* turn cursor back on */
3294 /* Clean up any mouse events that are waiting inside Emacs event queue.
3295 These events are likely to be generated before the menu was even
3296 displayed, probably because the user pressed and released the button
3297 (which invoked the menu) too quickly. If we don't remove these events,
3298 Emacs will process them after we return and surprise the user. */
3299 discard_mouse_events ();
3300 mouse_clear_clicks ();
3301 if (!kbd_buffer_events_waiting (1))
3302 clear_input_pending ();
3303 /* Allow mouse events generation by dos_rawgetc. */
3308 /* Dispose of a menu. */
3311 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3314 if (menu
->allocated
)
3316 for (i
= 0; i
< menu
->count
; i
++)
3317 if (menu
->submenu
[i
])
3318 XMenuDestroy (foo
, menu
->submenu
[i
]);
3320 xfree (menu
->submenu
);
3321 xfree (menu
->panenumber
);
3322 xfree (menu
->help_text
);
3325 menu_help_message
= prev_menu_help_message
= NULL
;
3329 x_pixel_width (struct frame
*f
)
3331 return FRAME_COLS (f
);
3335 x_pixel_height (struct frame
*f
)
3337 return FRAME_LINES (f
);
3339 #endif /* !HAVE_X_WINDOWS */
3341 /* ----------------------- DOS / UNIX conversion --------------------- */
3343 void msdos_downcase_filename (unsigned char *);
3345 /* Destructively turn backslashes into slashes. */
3348 dostounix_filename (char *p
)
3350 msdos_downcase_filename (p
);
3360 /* Destructively turn slashes into backslashes. */
3363 unixtodos_filename (char *p
)
3365 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3379 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3382 getdefdir (int drive
, char *dst
)
3384 char in_path
[4], *p
= in_path
, e
= errno
;
3386 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3389 *p
++ = drive
+ 'A' - 1;
3396 _fixpath (in_path
, dst
);
3397 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3398 it queries the LFN support, so ignore that error. */
3399 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
3402 msdos_downcase_filename (dst
);
3409 emacs_root_dir (void)
3411 static char root_dir
[4];
3413 sprintf (root_dir
, "%c:/", 'A' + getdisk ());
3414 root_dir
[0] = tolower (root_dir
[0]);
3418 /* Remove all CR's that are followed by a LF. */
3421 crlf_to_lf (int n
, unsigned char *buf
)
3423 unsigned char *np
= buf
, *startp
= buf
, *endp
= buf
+ n
;
3427 while (buf
< endp
- 1)
3431 if (*(++buf
) != 0x0a)
3442 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
3444 doc
: /* Return non-nil if long file names are supported on MS-DOS. */)
3447 return (_USE_LFN
? Qt
: Qnil
);
3450 /* Convert alphabetic characters in a filename to lower-case. */
3453 msdos_downcase_filename (unsigned char *p
)
3455 /* Always lower-case drive letters a-z, even if the filesystem
3456 preserves case in filenames.
3457 This is so MSDOS filenames could be compared by string comparison
3458 functions that are case-sensitive. Even case-preserving filesystems
3459 do not distinguish case in drive letters. */
3460 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3466 /* Under LFN we expect to get pathnames in their true case. */
3467 if (NILP (Fmsdos_long_file_names ()))
3469 if (*p
>= 'A' && *p
<= 'Z')
3473 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
3475 doc
: /* Convert alphabetic characters in FILENAME to lower case and return that.
3476 When long filenames are supported, doesn't change FILENAME.
3477 If FILENAME is not a string, returns nil.
3478 The argument object is never altered--the value is a copy. */)
3479 (Lisp_Object filename
)
3483 if (! STRINGP (filename
))
3486 tem
= Fcopy_sequence (filename
);
3487 msdos_downcase_filename (SDATA (tem
));
3491 /* The Emacs root directory as determined by init_environment. */
3493 static char emacsroot
[MAXPATHLEN
];
3496 rootrelativepath (char *rel
)
3498 static char result
[MAXPATHLEN
+ 10];
3500 strcpy (result
, emacsroot
);
3501 strcat (result
, "/");
3502 strcat (result
, rel
);
3506 /* Define a lot of environment variables if not already defined. Don't
3507 remove anything unless you know what you're doing -- lots of code will
3508 break if one or more of these are missing. */
3511 init_environment (int argc
, char **argv
, int skip_args
)
3515 static const char * const tempdirs
[] = {
3516 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3518 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
3520 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3521 temporary files and assume "/tmp" if $TMPDIR is unset, which
3522 will break on DOS/Windows. Refuse to work if we cannot find
3523 a directory, not even "c:/", usable for that purpose. */
3524 for (i
= 0; i
< imax
; i
++)
3526 const char *tmp
= tempdirs
[i
];
3527 char buf
[FILENAME_MAX
];
3533 tmp
= getenv (tmp
+ 1);
3537 /* Some lusers set TMPDIR=e:, probably because some losing
3538 programs cannot handle multiple slashes if they use e:/.
3539 e: fails in `access' below, so we interpret e: as e:/. */
3540 tmp_len
= strlen (tmp
);
3541 if (tmp
[tmp_len
- 1] != '/' && tmp
[tmp_len
- 1] != '\\')
3544 buf
[tmp_len
++] = '/', buf
[tmp_len
] = 0;
3549 /* Note that `access' can lie to us if the directory resides on a
3550 read-only filesystem, like CD-ROM or a write-protected floppy.
3551 The only way to be really sure is to actually create a file and
3552 see if it succeeds. But I think that's too much to ask. */
3553 if (tmp
&& access (tmp
, D_OK
) == 0)
3555 setenv ("TMPDIR", tmp
, 1);
3562 Fcons (build_string ("no usable temporary directories found!!"),
3564 "While setting TMPDIR: ");
3566 /* Note the startup time, so we know not to clear the screen if we
3567 exit immediately; see IT_reset_terminal_modes.
3568 (Yes, I know `clock' returns zero the first time it's called, but
3569 I do this anyway, in case some wiseguy changes that at some point.) */
3570 startup_time
= clock ();
3572 /* Find our root from argv[0]. Assuming argv[0] is, say,
3573 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3574 root
= alloca (MAXPATHLEN
+ 20);
3575 _fixpath (argv
[0], root
);
3576 msdos_downcase_filename (root
);
3577 len
= strlen (root
);
3578 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
3582 && (strcmp (root
+ len
- 4, "/bin") == 0
3583 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
3584 root
[len
- 4] = '\0';
3586 strcpy (root
, "c:/emacs"); /* let's be defensive */
3587 len
= strlen (root
);
3588 strcpy (emacsroot
, root
);
3590 /* We default HOME to our root. */
3591 setenv ("HOME", root
, 0);
3593 /* We default EMACSPATH to root + "/bin". */
3594 strcpy (root
+ len
, "/bin");
3595 setenv ("EMACSPATH", root
, 0);
3597 /* I don't expect anybody to ever use other terminals so the internal
3598 terminal is the default. */
3599 setenv ("TERM", "internal", 0);
3601 #ifdef HAVE_X_WINDOWS
3602 /* Emacs expects DISPLAY to be set. */
3603 setenv ("DISPLAY", "unix:0.0", 0);
3606 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3607 downcase it and mirror the backslashes. */
3608 s
= getenv ("COMSPEC");
3609 if (!s
) s
= "c:/command.com";
3610 t
= alloca (strlen (s
) + 1);
3612 dostounix_filename (t
);
3613 setenv ("SHELL", t
, 0);
3615 /* PATH is also downcased and backslashes mirrored. */
3616 s
= getenv ("PATH");
3618 t
= alloca (strlen (s
) + 3);
3619 /* Current directory is always considered part of MsDos's path but it is
3620 not normally mentioned. Now it is. */
3621 strcat (strcpy (t
, ".;"), s
);
3622 dostounix_filename (t
); /* Not a single file name, but this should work. */
3623 setenv ("PATH", t
, 1);
3625 /* In some sense all dos users have root privileges, so... */
3626 setenv ("USER", "root", 0);
3627 setenv ("NAME", getenv ("USER"), 0);
3629 /* Time zone determined from country code. To make this possible, the
3630 country code may not span more than one time zone. In other words,
3631 in the USA, you lose. */
3633 switch (dos_country_code
)
3635 case 31: /* Belgium */
3636 case 32: /* The Netherlands */
3637 case 33: /* France */
3638 case 34: /* Spain */
3639 case 36: /* Hungary */
3640 case 38: /* Yugoslavia (or what's left of it?) */
3641 case 39: /* Italy */
3642 case 41: /* Switzerland */
3643 case 42: /* Tjekia */
3644 case 45: /* Denmark */
3645 case 46: /* Sweden */
3646 case 47: /* Norway */
3647 case 48: /* Poland */
3648 case 49: /* Germany */
3649 /* Daylight saving from last Sunday in March to last Sunday in
3650 September, both at 2AM. */
3651 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3653 case 44: /* United Kingdom */
3654 case 351: /* Portugal */
3655 case 354: /* Iceland */
3656 setenv ("TZ", "GMT+00", 0);
3658 case 81: /* Japan */
3659 case 82: /* Korea */
3660 setenv ("TZ", "JST-09", 0);
3662 case 90: /* Turkey */
3663 case 358: /* Finland */
3664 setenv ("TZ", "EET-02", 0);
3666 case 972: /* Israel */
3667 /* This is an approximation. (For exact rules, use the
3668 `zoneinfo/israel' file which comes with DJGPP, but you need
3669 to install it in `/usr/share/zoneinfo/' directory first.) */
3670 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3678 static int break_stat
; /* BREAK check mode status. */
3679 static int stdin_stat
; /* stdin IOCTL status. */
3681 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3682 control chars by DOS. Determine the keyboard type. */
3685 dos_ttraw (struct tty_display_info
*tty
)
3687 union REGS inregs
, outregs
;
3688 static int first_time
= 1;
3690 /* If we are called for the initial terminal, it's too early to do
3691 anything, and termscript isn't set up. */
3692 if (tty
->terminal
->type
== output_initial
)
3695 break_stat
= getcbrk ();
3701 int86 (0x15, &inregs
, &outregs
);
3702 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
3707 #ifdef HAVE_X_WINDOWS
3708 && inhibit_window_system
3712 inregs
.x
.ax
= 0x0021;
3713 int86 (0x33, &inregs
, &outregs
);
3714 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3717 /* Reportedly, the above doesn't work for some mouse drivers. There
3718 is an additional detection method that should work, but might be
3719 a little slower. Use that as an alternative. */
3720 inregs
.x
.ax
= 0x0000;
3721 int86 (0x33, &inregs
, &outregs
);
3722 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3725 mouse_button_count
= outregs
.x
.bx
;
3727 #ifndef HAVE_X_WINDOWS
3728 /* Save the cursor shape used outside Emacs. */
3729 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
3735 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
3736 return (stdin_stat
!= -1);
3739 return (setmode (fileno (stdin
), O_BINARY
) != -1);
3742 /* Restore status of standard input and Ctrl-C checking. */
3747 union REGS inregs
, outregs
;
3749 setcbrk (break_stat
);
3752 #ifndef HAVE_X_WINDOWS
3753 /* Restore the cursor shape we found on startup. */
3757 inregs
.x
.cx
= outside_cursor
;
3758 int86 (0x10, &inregs
, &outregs
);
3762 return (setmode (fileno (stdin
), stdin_stat
) != -1);
3766 /* Run command as specified by ARGV in directory DIR.
3767 The command is run with input from TEMPIN, output to
3768 file TEMPOUT and stderr to TEMPERR. */
3771 run_msdos_command (unsigned char **argv
, const char *working_dir
,
3772 int tempin
, int tempout
, int temperr
, char **envv
)
3774 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
3775 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
3776 int msshell
, result
= -1, inbak
, outbak
, errbak
, x
, y
;
3779 /* Get current directory as MSDOS cwd is not per-process. */
3782 /* If argv[0] is the shell, it might come in any lettercase.
3783 Since `Fmember' is case-sensitive, we need to downcase
3784 argv[0], even if we are on case-preserving filesystems. */
3785 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
3786 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
3789 if (*pl
>= 'A' && *pl
<= 'Z')
3794 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
3795 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
3796 && !strcmp ("-c", argv
[1]);
3799 saveargv1
= argv
[1];
3800 saveargv2
= argv
[2];
3802 /* We only need to mirror slashes if a DOS shell will be invoked
3803 not via `system' (which does the mirroring itself). Yes, that
3804 means DJGPP v1.x will lose here. */
3805 if (argv
[2] && argv
[3])
3807 char *p
= alloca (strlen (argv
[2]) + 1);
3809 strcpy (argv
[2] = p
, saveargv2
);
3810 while (*p
&& isspace (*p
))
3822 chdir (working_dir
);
3826 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3827 goto done
; /* Allocation might fail due to lack of descriptors. */
3830 mouse_get_xy (&x
, &y
);
3832 if (!noninteractive
)
3833 dos_ttcooked (); /* do it here while 0 = stdin */
3839 if (msshell
&& !argv
[3])
3841 /* MS-DOS native shells are too restrictive. For starters, they
3842 cannot grok commands longer than 126 characters. In DJGPP v2
3843 and later, `system' is much smarter, so we'll call it instead. */
3847 /* A shell gets a single argument--its full command
3848 line--whose original was saved in `saveargv2'. */
3850 /* Don't let them pass empty command lines to `system', since
3851 with some shells it will try to invoke an interactive shell,
3852 which will hang Emacs. */
3853 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
3857 extern char **environ
;
3858 char **save_env
= environ
;
3859 int save_system_flags
= __system_flags
;
3861 /* Request the most powerful version of `system'. We need
3862 all the help we can get to avoid calling stock DOS shells. */
3863 __system_flags
= (__system_redirect
3864 | __system_use_shell
3865 | __system_allow_multiple_cmds
3866 | __system_allow_long_cmds
3867 | __system_handle_null_commands
3868 | __system_emulate_chdir
);
3871 result
= system (cmnd
);
3872 __system_flags
= save_system_flags
;
3876 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
3879 result
= spawnve (P_WAIT
, argv
[0], (char **)argv
, envv
);
3884 emacs_close (inbak
);
3885 emacs_close (outbak
);
3886 emacs_close (errbak
);
3888 if (!noninteractive
)
3889 dos_ttraw (CURTTY ());
3893 mouse_moveto (x
, y
);
3896 /* Some programs might change the meaning of the highest bit of the
3897 text attribute byte, so we get blinking characters instead of the
3898 bright background colors. Restore that. */
3899 if (!noninteractive
)
3906 argv
[1] = saveargv1
;
3907 argv
[2] = saveargv2
;
3913 croak (char *badfunc
)
3915 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3916 reset_all_sys_modes ();
3921 * A few unimplemented functions that we silently ignore.
3923 int setpgrp (void) {return 0; }
3924 int setpriority (int x
, int y
, int z
) { return 0; }
3926 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 4
3928 readlink (const char *name
, char *dummy1
, size_t dummy2
)
3930 /* `access' is much faster than `stat' on MS-DOS. */
3931 if (access (name
, F_OK
) == 0)
3938 careadlinkat (int fd
, char const *filename
,
3939 char *buffer
, size_t buffer_size
,
3940 struct allocator
const *alloc
,
3941 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
3945 /* We don't support the fancy auto-allocation feature. */
3954 ssize_t len
= preadlinkat (fd
, filename
, buffer
, buffer_size
);
3956 if (len
< 0 || len
== buffer_size
)
3959 buffer
[len
+ 1] = '\0';
3965 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
3969 return readlink (filename
, buffer
, buffer_size
);
3973 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
3975 /* Augment DJGPP library POSIX signal functions. This is needed
3976 as of DJGPP v2.01, but might be in the library in later releases. */
3978 #include <libc/bss.h>
3980 /* A counter to know when to re-initialize the static sets. */
3981 static int sigprocmask_count
= -1;
3983 /* Which signals are currently blocked (initially none). */
3984 static sigset_t current_mask
;
3986 /* Which signals are pending (initially none). */
3987 static sigset_t msdos_pending_signals
;
3989 /* Previous handlers to restore when the blocked signals are unblocked. */
3990 typedef void (*sighandler_t
)(int);
3991 static sighandler_t prev_handlers
[320];
3993 /* A signal handler which just records that a signal occurred
3994 (it will be raised later, if and when the signal is unblocked). */
3996 sig_suspender (int signo
)
3998 sigaddset (&msdos_pending_signals
, signo
);
4002 sigprocmask (int how
, const sigset_t
*new_set
, sigset_t
*old_set
)
4007 /* If called for the first time, initialize. */
4008 if (sigprocmask_count
!= __bss_count
)
4010 sigprocmask_count
= __bss_count
;
4011 sigemptyset (&msdos_pending_signals
);
4012 sigemptyset (¤t_mask
);
4013 for (signo
= 0; signo
< 320; signo
++)
4014 prev_handlers
[signo
] = SIG_ERR
;
4018 *old_set
= current_mask
;
4023 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4029 sigemptyset (&new_mask
);
4031 /* DJGPP supports upto 320 signals. */
4032 for (signo
= 0; signo
< 320; signo
++)
4034 if (sigismember (¤t_mask
, signo
))
4035 sigaddset (&new_mask
, signo
);
4036 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4038 sigaddset (&new_mask
, signo
);
4040 /* SIGKILL is silently ignored, as on other platforms. */
4041 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4042 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4044 if (( how
== SIG_UNBLOCK
4045 && sigismember (&new_mask
, signo
)
4046 && sigismember (new_set
, signo
))
4047 || (how
== SIG_SETMASK
4048 && sigismember (&new_mask
, signo
)
4049 && !sigismember (new_set
, signo
)))
4051 sigdelset (&new_mask
, signo
);
4052 if (prev_handlers
[signo
] != SIG_ERR
)
4054 signal (signo
, prev_handlers
[signo
]);
4055 prev_handlers
[signo
] = SIG_ERR
;
4057 if (sigismember (&msdos_pending_signals
, signo
))
4059 sigdelset (&msdos_pending_signals
, signo
);
4064 current_mask
= new_mask
;
4068 #endif /* not __DJGPP_MINOR__ < 2 */
4071 #include "sysselect.h"
4073 #ifndef EMACS_TIME_ZERO_OR_NEG_P
4074 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
4075 ((long)(time).tv_sec < 0 \
4076 || ((time).tv_sec == 0 \
4077 && (long)(time).tv_usec <= 0))
4080 /* This yields the rest of the current time slice to the task manager.
4081 It should be called by any code which knows that it has nothing
4082 useful to do except idle.
4084 I don't use __dpmi_yield here, since versions of library before 2.02
4085 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4086 on some versions of Windows 9X. */
4089 dos_yield_time_slice (void)
4091 _go32_dpmi_registers r
;
4094 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
4095 _go32_dpmi_simulate_int (0x2f, &r
);
4100 /* Only event queue is checked. */
4101 /* We don't have to call timer_check here
4102 because wait_reading_process_output takes care of that. */
4104 sys_select (int nfds
, SELECT_TYPE
*rfds
, SELECT_TYPE
*wfds
, SELECT_TYPE
*efds
,
4105 EMACS_TIME
*timeout
)
4113 check_input
= FD_ISSET (0, rfds
);
4124 /* If we are looking only for the terminal, with no timeout,
4125 just read it and wait -- that's more efficient. */
4128 while (!detect_input_pending ())
4130 dos_yield_time_slice ();
4135 EMACS_TIME clnow
, cllast
, cldiff
;
4138 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
4140 while (!check_input
|| !detect_input_pending ())
4143 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
4144 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
4146 /* When seconds wrap around, we assume that no more than
4147 1 minute passed since last `gettime'. */
4148 if (EMACS_TIME_NEG_P (cldiff
))
4149 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
4150 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
4152 /* Stop when timeout value crosses zero. */
4153 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
4156 dos_yield_time_slice ();
4166 * Define overlaid functions:
4168 * chdir -> sys_chdir
4169 * tzset -> init_gettimeofday
4170 * abort -> dos_abort
4175 extern int chdir (const char *);
4178 sys_chdir (const char *path
)
4180 int len
= strlen (path
);
4181 char *tmp
= (char *)path
;
4183 if (*tmp
&& tmp
[1] == ':')
4185 if (getdisk () != tolower (tmp
[0]) - 'a')
4186 setdisk (tolower (tmp
[0]) - 'a');
4187 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
4191 if (len
> 1 && (tmp
[len
- 1] == '/'))
4193 char *tmp1
= (char *) alloca (len
+ 1);
4204 extern void tzset (void);
4207 init_gettimeofday (void)
4213 ltm
= gtm
= time (NULL
);
4214 ltm
= mktime (lstm
= localtime (<m
));
4215 gtm
= mktime (gmtime (>m
));
4216 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
4217 time_rec
.tm_isdst
= lstm
->tm_isdst
;
4218 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
4225 dos_abort (char *file
, int line
)
4227 char buffer1
[200], buffer2
[400];
4230 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
4231 for (i
= j
= 0; buffer1
[i
]; i
++) {
4232 buffer2
[j
++] = buffer1
[i
];
4233 buffer2
[j
++] = 0x70;
4235 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
4236 ScreenSetCursor (2, 0);
4244 ScreenSetCursor (10, 0);
4245 cputs ("\r\n\nEmacs aborted!\r\n");
4246 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4247 if (screen_virtual_segment
)
4248 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
4249 /* Generate traceback, so we could tell whodunit. */
4250 signal (SIGINT
, SIG_DFL
);
4251 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4252 #else /* __DJGPP_MINOR__ >= 2 */
4254 #endif /* __DJGPP_MINOR__ >= 2 */
4260 syms_of_msdos (void)
4262 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
4263 staticpro (&recent_doskeys
);
4265 #ifndef HAVE_X_WINDOWS
4267 /* The following two are from xfns.c: */
4268 DEFSYM (Qreverse
, "reverse");
4270 DEFVAR_LISP ("dos-unsupported-char-glyph", Vdos_unsupported_char_glyph
,
4271 doc
: /* Glyph to display instead of chars not supported by current codepage.
4272 This variable is used only by MS-DOS terminals. */);
4273 Vdos_unsupported_char_glyph
= make_number ('\177');
4277 defsubr (&Srecent_doskeys
);
4278 defsubr (&Smsdos_long_file_names
);
4279 defsubr (&Smsdos_downcase_filename
);
4280 defsubr (&Smsdos_remember_default_colors
);
4281 defsubr (&Smsdos_set_mouse_buttons
);