1 /* MS-DOS specific C utilities. -*- coding: cp850 -*-
3 Copyright (C) 1993-1997, 1999-2014 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 /* Contributed by Morten Welinder */
21 /* New display, keyboard, and mouse control by Kim F. Storm */
23 /* Note: This file MUST use a unibyte encoding, to both display the
24 keys on the non-US keyboard layout as their respective labels, and
25 provide the correct byte values for the keyboard input to inject
26 into Emacs. See 'struct dos_keyboard_map' below. As long as there
27 are only European keyboard layouts here, we are OK with DOS
28 codepage 850 encoding. */
30 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
39 #include <sys/param.h>
41 /* gettime and settime in dos.h clash with their namesakes from
42 gnulib, so we move out of our way the prototypes in dos.h. */
43 #define gettime dos_h_gettime_
44 #define settime dos_h_settime_
49 #include <sys/stat.h> /* for _fixpath */
50 #include <unistd.h> /* for chdir, dup, dup2, etc. */
51 #include <dir.h> /* for getdisk */
52 #pragma pack(0) /* dir.h does a pack(4), which isn't GCC's default */
54 #include <dirent.h> /* for opendir */
56 #include <io.h> /* for setmode */
57 #include <dpmi.h> /* for __dpmi_xxx stuff */
58 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
59 #include <libc/dosio.h> /* for _USE_LFN */
60 #include <conio.h> /* for cputs */
65 #include "termhooks.h"
67 #include "dispextern.h"
70 #include "character.h"
76 #include "blockinput.h"
78 #include "intervals.h"
82 /* #include <process.h> */
83 /* Damn that local process.h! Instead we can define P_WAIT and
86 extern int spawnve (int, const char *, char *const [], char *const []);
93 #define _dos_ds _go32_info_block.selector_for_linear_memory
97 #include "syssignal.h"
99 #include "careadlinkat.h"
100 #include "allocator.h"
102 #ifndef SYSTEM_MALLOC
106 /* If other `malloc' than ours is used, force our `sbrk' behave like
107 Unix programs expect (resize memory blocks to keep them contiguous).
108 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
109 because that's what `gmalloc' expects to get. */
113 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
114 #else /* not REL_ALLOC */
115 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
116 #endif /* not REL_ALLOC */
117 #endif /* GNU_MALLOC */
119 #endif /* not SYSTEM_MALLOC */
121 /* Return the current timestamp in milliseconds since midnight. */
123 event_timestamp (void)
132 s
+= t
.tv_nsec
* 1000000;
138 /* ------------------------ Mouse control ---------------------------
140 * Coordinates are in screen positions and zero based.
141 * Mouse buttons are numbered from left to right and also zero based.
144 /* This used to be in termhooks.h, but mainstream Emacs code no longer
145 uses it, and it was removed... */
146 #define NUM_MOUSE_BUTTONS (5)
148 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
149 static int mouse_visible
;
151 static int mouse_last_x
;
152 static int mouse_last_y
;
154 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
155 static int mouse_button_count
;
162 if (have_mouse
> 0 && !mouse_visible
)
164 struct tty_display_info
*tty
= CURTTY ();
167 fprintf (tty
->termscript
, "<M_ON>");
169 int86 (0x33, ®s
, ®s
);
179 if (have_mouse
> 0 && mouse_visible
)
181 struct tty_display_info
*tty
= CURTTY ();
184 fprintf (tty
->termscript
, "<M_OFF>");
186 int86 (0x33, ®s
, ®s
);
192 mouse_setup_buttons (int n_buttons
)
196 mouse_button_count
= 3;
197 mouse_button_translate
[0] = 0; /* Left */
198 mouse_button_translate
[1] = 2; /* Middle */
199 mouse_button_translate
[2] = 1; /* Right */
201 else /* two, what else? */
203 mouse_button_count
= 2;
204 mouse_button_translate
[0] = 0;
205 mouse_button_translate
[1] = 1;
209 DEFUN ("msdos-set-mouse-buttons", Fmsdos_set_mouse_buttons
, Smsdos_set_mouse_buttons
,
210 1, 1, "NSet number of mouse buttons to: ",
211 doc
: /* Set the number of mouse buttons to use by Emacs.
212 This is useful with mice that report the number of buttons inconsistently,
213 e.g., if the number of buttons is reported as 3, but Emacs only sees 2 of
214 them. This happens with wheeled mice on Windows 9X, for example. */)
215 (Lisp_Object nbuttons
)
219 CHECK_NUMBER (nbuttons
);
222 xsignal2 (Qargs_out_of_range
,
223 build_string ("only 2 or 3 mouse buttons are supported"),
225 mouse_setup_buttons (n
);
230 mouse_get_xy (int *x
, int *y
)
235 int86 (0x33, ®s
, ®s
);
241 mouse_moveto (int x
, int y
)
244 struct tty_display_info
*tty
= CURTTY ();
247 fprintf (tty
->termscript
, "<M_XY=%dx%d>", x
, y
);
249 mouse_last_x
= regs
.x
.cx
= x
* 8;
250 mouse_last_y
= regs
.x
.dx
= y
* 8;
251 int86 (0x33, ®s
, ®s
);
255 mouse_pressed (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_released (int b
, int *xp
, int *yp
)
274 if (b
>= mouse_button_count
)
277 regs
.x
.bx
= mouse_button_translate
[b
];
278 int86 (0x33, ®s
, ®s
);
280 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
281 return (regs
.x
.bx
!= 0);
285 mouse_button_depressed (int b
, int *xp
, int *yp
)
289 if (b
>= mouse_button_count
)
292 int86 (0x33, ®s
, ®s
);
293 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
303 mouse_get_pos (struct frame
**f
, int insist
, Lisp_Object
*bar_window
,
304 enum scroll_bar_part
*part
, Lisp_Object
*x
, Lisp_Object
*y
,
308 Lisp_Object frame
, tail
;
310 /* Clear the mouse-moved flag for every frame on this display. */
311 FOR_EACH_FRAME (tail
, frame
)
312 XFRAME (frame
)->mouse_moved
= 0;
314 *f
= SELECTED_FRAME ();
316 mouse_get_xy (&ix
, &iy
);
317 *time
= event_timestamp ();
318 *x
= make_number (mouse_last_x
= ix
);
319 *y
= make_number (mouse_last_y
= iy
);
323 mouse_check_moved (void)
327 mouse_get_xy (&x
, &y
);
328 SELECTED_FRAME ()->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
333 /* Force the mouse driver to ``forget'' about any button clicks until
336 mouse_clear_clicks (void)
340 for (b
= 0; b
< mouse_button_count
; b
++)
342 int dummy_x
, dummy_y
;
344 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
345 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
353 struct tty_display_info
*tty
= CURTTY ();
356 fprintf (tty
->termscript
, "<M_INIT>");
359 int86 (0x33, ®s
, ®s
);
361 /* Reset the mouse last press/release info. It seems that Windows
362 doesn't do that automatically when function 21h is called, which
363 causes Emacs to ``remember'' the click that switched focus to the
364 window just before Emacs was started from that window. */
365 mouse_clear_clicks ();
369 regs
.x
.dx
= 8 * (ScreenCols () - 1);
370 int86 (0x33, ®s
, ®s
);
374 regs
.x
.dx
= 8 * (ScreenRows () - 1);
375 int86 (0x33, ®s
, ®s
);
381 /* ------------------------- Screen control ----------------------
385 static int internal_terminal
= 0;
387 #ifndef HAVE_X_WINDOWS
388 extern unsigned char ScreenAttrib
;
389 static int screen_face
;
391 static int screen_size_X
;
392 static int screen_size_Y
;
393 static int screen_size
;
395 static int current_pos_X
;
396 static int current_pos_Y
;
397 static int new_pos_X
;
398 static int new_pos_Y
;
400 static void *startup_screen_buffer
;
401 static int startup_screen_size_X
;
402 static int startup_screen_size_Y
;
403 static int startup_pos_X
;
404 static int startup_pos_Y
;
405 static unsigned char startup_screen_attrib
;
407 static clock_t startup_time
;
409 static int term_setup_done
;
411 static unsigned short outside_cursor
;
413 /* The only display since MS-DOS does not support multiple ones. */
414 struct tty_display_info the_only_display_info
;
416 /* Support for DOS/V (allows Japanese characters to be displayed on
417 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
419 /* Holds the address of the text-mode screen buffer. */
420 static unsigned long screen_old_address
= 0;
421 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
422 static unsigned short screen_virtual_segment
= 0;
423 static unsigned short screen_virtual_offset
= 0;
424 extern Lisp_Object Qcursor_type
;
425 extern Lisp_Object Qbar
, Qhbar
;
427 /* The screen colors of the current frame, which serve as the default
428 colors for newly-created frames. */
429 static int initial_screen_colors
[2];
431 /* Update the screen from a part of relocated DOS/V screen buffer which
432 begins at OFFSET and includes COUNT characters. */
434 dosv_refresh_virtual_screen (int offset
, int count
)
438 if (offset
< 0 || count
< 0) /* paranoia; invalid values crash DOS/V */
441 regs
.h
.ah
= 0xff; /* update relocated screen */
442 regs
.x
.es
= screen_virtual_segment
;
443 regs
.x
.di
= screen_virtual_offset
+ offset
;
445 __dpmi_int (0x10, ®s
);
449 dos_direct_output (int y
, int x
, char *buf
, int len
)
451 int t0
= 2 * (x
+ y
* screen_size_X
);
452 int t
= t0
+ (int) ScreenPrimary
;
455 /* This is faster. */
456 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
457 _farnspokeb (t
, *buf
);
459 if (screen_virtual_segment
)
460 dosv_refresh_virtual_screen (t0
, l0
);
464 #ifndef HAVE_X_WINDOWS
466 static int blink_bit
= -1; /* the state of the blink bit at startup */
468 /* Enable bright background colors. */
474 /* Remember the original state of the blink/bright-background bit.
475 It is stored at 0040:0065h in the BIOS data area. */
477 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
481 int86 (0x10, ®s
, ®s
);
484 /* Disable bright background colors (and enable blinking) if we found
485 the video system in that state at startup. */
487 maybe_enable_blinking (void)
495 int86 (0x10, ®s
, ®s
);
499 /* Return non-zero if the system has a VGA adapter. */
506 int86 (0x10, ®s
, ®s
);
507 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
512 /* Set the screen dimensions so that it can show no less than
513 ROWS x COLS frame. */
516 dos_set_window_size (int *rows
, int *cols
)
520 Lisp_Object video_mode
;
521 int video_mode_value
, have_vga
= 0;
522 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
524 if (*rows
== current_rows
&& *cols
== current_cols
)
528 have_vga
= vga_installed ();
530 /* If the user specified a special video mode for these dimensions,
533 = Fsymbol_value (Fintern_soft (make_formatted_string
534 (video_name
, "screen-dimensions-%dx%d",
535 *rows
, *cols
), Qnil
));
537 if (INTEGERP (video_mode
)
538 && (video_mode_value
= XINT (video_mode
)) > 0)
540 regs
.x
.ax
= video_mode_value
;
541 int86 (0x10, ®s
, ®s
);
545 /* Must hardware-reset the mouse, or else it won't update
546 its notion of screen dimensions for some non-standard
547 video modes. This is *painfully* slow... */
549 int86 (0x33, ®s
, ®s
);
553 /* Find one of the dimensions supported by standard EGA/VGA
554 which gives us at least the required dimensions. */
559 } std_dimension
[] = {
569 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
571 if (std_dimension
[i
].need_vga
<= have_vga
572 && std_dimension
[i
].rows
>= *rows
)
574 if (std_dimension
[i
].rows
!= current_rows
575 || *cols
!= current_cols
)
576 _set_screen_lines (std_dimension
[i
].rows
);
590 /* Tell the caller what dimensions have been REALLY set. */
591 *rows
= ScreenRows ();
592 *cols
= ScreenCols ();
594 /* Update Emacs' notion of screen dimensions. */
595 screen_size_X
= *cols
;
596 screen_size_Y
= *rows
;
597 screen_size
= *cols
* *rows
;
599 /* If the dimensions changed, the mouse highlight info is invalid. */
600 if (current_rows
!= *rows
|| current_cols
!= *cols
)
602 struct frame
*f
= SELECTED_FRAME ();
603 Mouse_HLInfo
*hlinfo
= MOUSE_HL_INFO (f
);
604 Lisp_Object window
= hlinfo
->mouse_face_window
;
606 if (! NILP (window
) && XFRAME (XWINDOW (window
)->frame
) == f
)
607 reset_mouse_highlight (hlinfo
);
610 /* Enable bright background colors. */
613 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
614 be defensive anyway. */
615 if (screen_virtual_segment
)
616 dosv_refresh_virtual_screen (0, *cols
* *rows
);
619 /* If we write a character in the position where the mouse is,
620 the mouse cursor may need to be refreshed. */
623 mouse_off_maybe (void)
630 mouse_get_xy (&x
, &y
);
631 if (y
!= new_pos_Y
|| x
< new_pos_X
)
637 #define DEFAULT_CURSOR_START (-1)
638 #define DEFAULT_CURSOR_WIDTH (-1)
639 #define BOX_CURSOR_WIDTH (-32)
641 /* Set cursor to begin at scan line START_LINE in the character cell
642 and extend for WIDTH scan lines. Scan lines are counted from top
643 of the character cell, starting from zero. */
645 msdos_set_cursor_shape (struct frame
*f
, int start_line
, int width
)
647 unsigned desired_cursor
;
649 int max_line
, top_line
, bot_line
;
650 struct tty_display_info
*tty
= FRAME_TTY (f
);
652 /* Avoid the costly BIOS call if F isn't the currently selected
653 frame. Allow for NULL as unconditionally meaning the selected
655 if (f
&& f
!= SELECTED_FRAME ())
659 fprintf (tty
->termscript
, "\nCURSOR SHAPE=(%d,%d)", start_line
, width
);
661 /* The character cell size in scan lines is stored at 40:85 in the
663 max_line
= _farpeekw (_dos_ds
, 0x485) - 1;
666 default: /* this relies on CGA cursor emulation being ON! */
683 if (width
== BOX_CURSOR_WIDTH
)
688 else if (start_line
!= DEFAULT_CURSOR_START
)
690 top_line
= start_line
;
691 bot_line
= top_line
- width
- 1;
693 else if (width
!= DEFAULT_CURSOR_WIDTH
)
696 bot_line
= -1 - width
;
699 top_line
= bot_line
+ 1;
703 /* [31, 0] seems to DTRT for all screen sizes. */
707 else /* WIDTH is positive */
709 if (start_line
!= DEFAULT_CURSOR_START
)
710 bot_line
= start_line
;
711 top_line
= bot_line
- (width
- 1);
714 /* If the current cursor shape is already what they want, we are
716 desired_cursor
= ((top_line
& 0x1f) << 8) | (bot_line
& 0x1f);
717 if (desired_cursor
== _farpeekw (_dos_ds
, 0x460))
721 regs
.x
.cx
= desired_cursor
;
722 __dpmi_int (0x10, ®s
);
726 IT_set_cursor_type (struct frame
*f
, Lisp_Object cursor_type
)
728 if (EQ (cursor_type
, Qbar
) || EQ (cursor_type
, Qhbar
))
730 /* Just BAR means the normal EGA/VGA cursor. */
731 msdos_set_cursor_shape (f
, DEFAULT_CURSOR_START
, DEFAULT_CURSOR_WIDTH
);
733 else if (CONSP (cursor_type
)
734 && (EQ (XCAR (cursor_type
), Qbar
)
735 || EQ (XCAR (cursor_type
), Qhbar
)))
737 Lisp_Object bar_parms
= XCDR (cursor_type
);
740 if (INTEGERP (bar_parms
))
742 /* Feature: negative WIDTH means cursor at the top
743 of the character cell, zero means invisible cursor. */
744 width
= XINT (bar_parms
);
745 msdos_set_cursor_shape (f
, width
>= 0 ? DEFAULT_CURSOR_START
: 0,
748 else if (CONSP (bar_parms
)
749 && INTEGERP (XCAR (bar_parms
))
750 && INTEGERP (XCDR (bar_parms
)))
752 int start_line
= XINT (XCDR (bar_parms
));
754 width
= XINT (XCAR (bar_parms
));
755 msdos_set_cursor_shape (f
, start_line
, width
);
760 /* Treat anything unknown as "box cursor". This includes nil, so
761 that a frame which doesn't specify a cursor type gets a box,
762 which is the default in Emacs. */
763 msdos_set_cursor_shape (f
, 0, BOX_CURSOR_WIDTH
);
768 IT_ring_bell (struct frame
*f
)
777 union REGS inregs
, outregs
;
780 intdos (&inregs
, &outregs
);
784 /* Given a face id FACE, extract the face parameters to be used for
785 display until the face changes. The face parameters (actually, its
786 color) are used to construct the video attribute byte for each
787 glyph during the construction of the buffer that is then blitted to
790 IT_set_face (int face
)
792 struct frame
*sf
= SELECTED_FRAME ();
793 struct face
*fp
= FACE_FROM_ID (sf
, face
);
794 struct face
*dfp
= FACE_FROM_ID (sf
, DEFAULT_FACE_ID
);
795 unsigned long fg
, bg
, dflt_fg
, dflt_bg
;
796 struct tty_display_info
*tty
= FRAME_TTY (sf
);
801 /* The default face for the frame should always be realized and
809 dflt_fg
= dfp
->foreground
;
810 dflt_bg
= dfp
->background
;
812 /* Don't use invalid colors. In particular, FACE_TTY_DEFAULT_* colors
813 mean use the colors of the default face. Note that we assume all
814 16 colors to be available for the background, since Emacs switches
815 on this mode (and loses the blinking attribute) at startup. */
816 if (fg
== FACE_TTY_DEFAULT_COLOR
|| fg
== FACE_TTY_DEFAULT_FG_COLOR
)
817 fg
= FRAME_FOREGROUND_PIXEL (sf
);
818 else if (fg
== FACE_TTY_DEFAULT_BG_COLOR
)
819 fg
= FRAME_BACKGROUND_PIXEL (sf
);
820 if (bg
== FACE_TTY_DEFAULT_COLOR
|| bg
== FACE_TTY_DEFAULT_BG_COLOR
)
821 bg
= FRAME_BACKGROUND_PIXEL (sf
);
822 else if (bg
== FACE_TTY_DEFAULT_FG_COLOR
)
823 bg
= FRAME_FOREGROUND_PIXEL (sf
);
825 /* Make sure highlighted lines really stand out, come what may. */
826 if (fp
->tty_reverse_p
&& (fg
== dflt_fg
&& bg
== dflt_bg
))
828 unsigned long tem
= fg
;
833 /* If the user requested inverse video, obey. */
836 unsigned long tem2
= fg
;
842 fprintf (tty
->termscript
, "<FACE %d: %lu/%lu[FG:%lu/BG:%lu]>", face
,
843 fp
->foreground
, fp
->background
, fg
, bg
);
844 if (fg
>= 0 && fg
< 16)
846 ScreenAttrib
&= 0xf0;
849 if (bg
>= 0 && bg
< 16)
851 ScreenAttrib
&= 0x0f;
852 ScreenAttrib
|= ((bg
& 0x0f) << 4);
856 /* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
857 width of a DOS display in any known text mode. We multiply by 2 to
858 accommodate the screen attribute byte. */
859 #define MAX_SCREEN_BUF 160*2
861 extern unsigned char *encode_terminal_code (struct glyph
*, int,
862 struct coding_system
*);
865 IT_write_glyphs (struct frame
*f
, struct glyph
*str
, int str_len
)
867 unsigned char screen_buf
[MAX_SCREEN_BUF
], *screen_bp
, *bp
;
868 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
869 register int sl
= str_len
;
870 struct tty_display_info
*tty
= FRAME_TTY (f
);
872 unsigned char *conversion_buffer
;
874 /* If terminal_coding does any conversion, use it, otherwise use
875 safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here
876 because it always returns 1 if terminal_coding.src_multibyte is 1. */
877 struct coding_system
*coding
= FRAME_TERMINAL_CODING (f
);
879 if (!(coding
->common_flags
& CODING_REQUIRE_ENCODING_MASK
))
880 coding
= &safe_terminal_coding
;
882 if (str_len
<= 0) return;
884 sf
= SELECTED_FRAME ();
886 /* Since faces get cached and uncached behind our back, we can't
887 rely on their indices in the cache being consistent across
888 invocations. So always reset the screen face to the default
889 face of the frame, before writing glyphs, and let the glyphs
890 set the right face if it's different from the default. */
891 IT_set_face (DEFAULT_FACE_ID
);
893 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
895 coding
->mode
&= ~CODING_MODE_LAST_BLOCK
;
896 screen_bp
= &screen_buf
[0];
902 /* If the face of this glyph is different from the current
903 screen face, update the screen attribute byte. */
905 if (cf
!= screen_face
)
906 IT_set_face (cf
); /* handles invalid faces gracefully */
908 /* Identify a run of glyphs with the same face. */
909 for (n
= 1; n
< sl
; ++n
)
910 if (str
[n
].face_id
!= cf
)
914 /* This is the last glyph. */
915 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
917 conversion_buffer
= encode_terminal_code (str
, n
, coding
);
918 if (coding
->produced
> 0)
920 /* Copy the encoded bytes to the screen buffer. */
921 for (bp
= conversion_buffer
; coding
->produced
--; bp
++)
923 /* Paranoia: discard bytes that would overrun the end of
924 the screen buffer. */
925 if (screen_bp
- screen_buf
<= MAX_SCREEN_BUF
- 2)
927 *screen_bp
++ = (unsigned char)*bp
;
928 *screen_bp
++ = ScreenAttrib
;
931 fputc (*bp
, tty
->termscript
);
934 /* Update STR and its remaining length. */
939 /* Dump whatever we have in the screen buffer. */
941 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
942 if (screen_virtual_segment
)
943 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
944 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
947 /************************************************************************
948 Mouse Highlight (and friends..)
949 ************************************************************************/
951 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
954 popup_activated (void)
956 return mouse_preempted
;
959 /* Draw TEXT_AREA glyphs between START and END of glyph row ROW on
960 window W. X is relative to TEXT_AREA in W. HL is a face override
961 for drawing the glyphs. */
963 tty_draw_row_with_mouse_face (struct window
*w
, struct glyph_row
*row
,
964 int start_hpos
, int end_hpos
,
965 enum draw_glyphs_face hl
)
967 struct frame
*f
= XFRAME (WINDOW_FRAME (w
));
968 struct tty_display_info
*tty
= FRAME_TTY (f
);
969 Mouse_HLInfo
*hlinfo
= &tty
->mouse_highlight
;
971 if (hl
== DRAW_MOUSE_FACE
)
973 int vpos
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
974 int kstart
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
975 int nglyphs
= end_hpos
- start_hpos
;
976 int offset
= ScreenPrimary
+ 2*(vpos
*screen_size_X
+ kstart
) + 1;
977 int start_offset
= offset
;
980 fprintf (tty
->termscript
, "\n<MH+ %d-%d:%d>",
981 kstart
, kstart
+ nglyphs
- 1, vpos
);
984 IT_set_face (hlinfo
->mouse_face_face_id
);
985 /* Since we are going to change only the _colors_ of already
986 displayed text, there's no need to go through all the pain of
987 generating and encoding the text from the glyphs. Instead,
988 we simply poke the attribute byte of each affected position
989 in video memory with the colors computed by IT_set_face! */
990 _farsetsel (_dos_ds
);
993 _farnspokeb (offset
, ScreenAttrib
);
996 if (screen_virtual_segment
)
997 dosv_refresh_virtual_screen (start_offset
, end_hpos
- start_hpos
);
1000 else if (hl
== DRAW_NORMAL_TEXT
)
1002 /* We are removing a previously-drawn mouse highlight. The
1003 safest way to do so is to redraw the glyphs anew, since all
1004 kinds of faces and display tables could have changed behind
1006 int nglyphs
= end_hpos
- start_hpos
;
1007 int save_x
= new_pos_X
, save_y
= new_pos_Y
;
1009 if (end_hpos
>= row
->used
[TEXT_AREA
])
1010 nglyphs
= row
->used
[TEXT_AREA
] - start_hpos
;
1012 /* IT_write_glyphs writes at cursor position, so we need to
1013 temporarily move cursor coordinates to the beginning of
1014 the highlight region. */
1015 new_pos_X
= start_hpos
+ WINDOW_LEFT_EDGE_X (w
);
1016 new_pos_Y
= row
->y
+ WINDOW_TOP_EDGE_Y (w
);
1018 if (tty
->termscript
)
1019 fprintf (tty
->termscript
, "<MH- %d-%d:%d>",
1020 new_pos_X
, new_pos_X
+ nglyphs
- 1, new_pos_Y
);
1021 IT_write_glyphs (f
, row
->glyphs
[TEXT_AREA
] + start_hpos
, nglyphs
);
1022 if (tty
->termscript
)
1023 fputs ("\n", tty
->termscript
);
1030 IT_clear_end_of_line (struct frame
*f
, int first_unused
)
1033 int i
, j
, offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
1034 struct tty_display_info
*tty
= FRAME_TTY (f
);
1036 if (new_pos_X
>= first_unused
|| fatal_error_in_progress
)
1040 i
= (j
= first_unused
- new_pos_X
) * 2;
1041 if (tty
->termscript
)
1042 fprintf (tty
->termscript
, "<CLR:EOL[%d..%d)>", new_pos_X
, first_unused
);
1043 spaces
= sp
= alloca (i
);
1048 *sp
++ = ScreenAttrib
;
1052 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
1053 if (screen_virtual_segment
)
1054 dosv_refresh_virtual_screen (offset
, i
/ 2);
1056 /* clear_end_of_line_raw on term.c leaves the cursor at first_unused.
1057 Let's follow their lead, in case someone relies on this. */
1058 new_pos_X
= first_unused
;
1062 IT_clear_screen (struct frame
*f
)
1064 struct tty_display_info
*tty
= FRAME_TTY (f
);
1066 if (tty
->termscript
)
1067 fprintf (tty
->termscript
, "<CLR:SCR>");
1068 /* We are sometimes called (from clear_garbaged_frames) when a new
1069 frame is being created, but its faces are not yet realized. In
1070 such a case we cannot call IT_set_face, since it will fail to find
1071 any valid faces and will abort. Instead, use the initial screen
1072 colors; that should mimic what a Unix tty does, which simply clears
1073 the screen with whatever default colors are in use. */
1074 if (FACE_FROM_ID (SELECTED_FRAME (), DEFAULT_FACE_ID
) == NULL
)
1075 ScreenAttrib
= (initial_screen_colors
[0] << 4) | initial_screen_colors
[1];
1080 if (screen_virtual_segment
)
1081 dosv_refresh_virtual_screen (0, screen_size
);
1082 new_pos_X
= new_pos_Y
= 0;
1086 IT_clear_to_end (struct frame
*f
)
1088 struct tty_display_info
*tty
= FRAME_TTY (f
);
1090 if (tty
->termscript
)
1091 fprintf (tty
->termscript
, "<CLR:EOS>");
1093 while (new_pos_Y
< screen_size_Y
) {
1095 IT_clear_end_of_line (f
, screen_size_X
);
1101 IT_cursor_to (struct frame
*f
, int y
, int x
)
1103 struct tty_display_info
*tty
= FRAME_TTY (f
);
1105 if (tty
->termscript
)
1106 fprintf (tty
->termscript
, "\n<XY=%dx%d>", x
, y
);
1111 static int cursor_cleared
;
1114 IT_display_cursor (int on
)
1116 struct tty_display_info
*tty
= CURTTY ();
1118 if (on
&& cursor_cleared
)
1120 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1122 if (tty
->termscript
)
1123 fprintf (tty
->termscript
, "\nCURSOR ON (%dx%d)",
1124 current_pos_Y
, current_pos_X
);
1126 else if (!on
&& !cursor_cleared
)
1128 ScreenSetCursor (-1, -1);
1130 if (tty
->termscript
)
1131 fprintf (tty
->termscript
, "\nCURSOR OFF (%dx%d)",
1132 current_pos_Y
, current_pos_X
);
1136 /* Emacs calls cursor-movement functions a lot when it updates the
1137 display (probably a legacy of old terminals where you cannot
1138 update a screen line without first moving the cursor there).
1139 However, cursor movement is expensive on MSDOS (it calls a slow
1140 BIOS function and requires 2 mode switches), while actual screen
1141 updates access the video memory directly and don't depend on
1142 cursor position. To avoid slowing down the redisplay, we cheat:
1143 all functions that move the cursor only set internal variables
1144 which record the cursor position, whereas the cursor is only
1145 moved to its final position whenever screen update is complete.
1147 `IT_cmgoto' is called from the keyboard reading loop and when the
1148 frame update is complete. This means that we are ready for user
1149 input, so we update the cursor position to show where the point is,
1150 and also make the mouse pointer visible.
1152 Special treatment is required when the cursor is in the echo area,
1153 to put the cursor at the end of the text displayed there. */
1156 IT_cmgoto (struct frame
*f
)
1158 /* Only set the cursor to where it should be if the display is
1159 already in sync with the window contents. */
1160 int update_cursor_pos
= 1; /* MODIFF == unchanged_modified; */
1161 struct tty_display_info
*tty
= FRAME_TTY (f
);
1163 /* FIXME: This needs to be rewritten for the new redisplay, or
1166 static int previous_pos_X
= -1;
1168 update_cursor_pos
= 1; /* temporary!!! */
1170 /* If the display is in sync, forget any previous knowledge about
1171 cursor position. This is primarily for unexpected events like
1172 C-g in the minibuffer. */
1173 if (update_cursor_pos
&& previous_pos_X
>= 0)
1174 previous_pos_X
= -1;
1175 /* If we are in the echo area, put the cursor at the
1176 end of the echo area message. */
1177 if (!update_cursor_pos
1178 && WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f
))) <= new_pos_Y
)
1180 int tem_X
= current_pos_X
, dummy
;
1182 if (echo_area_glyphs
)
1184 tem_X
= echo_area_glyphs_length
;
1185 /* Save current cursor position, to be restored after the
1186 echo area message is erased. Only remember one level
1187 of previous cursor position. */
1188 if (previous_pos_X
== -1)
1189 ScreenGetCursor (&dummy
, &previous_pos_X
);
1191 else if (previous_pos_X
>= 0)
1193 /* We wind up here after the echo area message is erased.
1194 Restore the cursor position we remembered above. */
1195 tem_X
= previous_pos_X
;
1196 previous_pos_X
= -1;
1199 if (current_pos_X
!= tem_X
)
1202 update_cursor_pos
= 1;
1207 if (update_cursor_pos
1208 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1210 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1211 if (tty
->termscript
)
1212 fprintf (tty
->termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1215 /* Maybe cursor is invisible, so make it visible. */
1216 IT_display_cursor (1);
1218 /* Mouse pointer should be always visible if we are waiting for
1225 IT_update_begin (struct frame
*f
)
1227 struct tty_display_info
*display_info
= FRAME_DISPLAY_INFO (f
);
1228 Mouse_HLInfo
*hlinfo
= &display_info
->mouse_highlight
;
1229 struct frame
*mouse_face_frame
= hlinfo
->mouse_face_mouse_frame
;
1231 if (display_info
->termscript
)
1232 fprintf (display_info
->termscript
, "\n\n<UPDATE_BEGIN");
1236 if (f
&& f
== mouse_face_frame
)
1238 /* Don't do highlighting for mouse motion during the update. */
1239 hlinfo
->mouse_face_defer
= 1;
1241 /* If F needs to be redrawn, simply forget about any prior mouse
1243 if (FRAME_GARBAGED_P (f
))
1244 hlinfo
->mouse_face_window
= Qnil
;
1246 /* Can we tell that this update does not affect the window
1247 where the mouse highlight is? If so, no need to turn off.
1248 Likewise, don't do anything if none of the enabled rows
1249 contains glyphs highlighted in mouse face. */
1250 if (!NILP (hlinfo
->mouse_face_window
)
1251 && WINDOWP (hlinfo
->mouse_face_window
))
1253 struct window
*w
= XWINDOW (hlinfo
->mouse_face_window
);
1256 /* If the mouse highlight is in the window that was deleted
1257 (e.g., if it was popped by completion), clear highlight
1259 if (NILP (w
->contents
))
1260 hlinfo
->mouse_face_window
= Qnil
;
1263 for (i
= 0; i
< w
->desired_matrix
->nrows
; ++i
)
1264 if (MATRIX_ROW_ENABLED_P (w
->desired_matrix
, i
)
1265 && MATRIX_ROW (w
->current_matrix
, i
)->mouse_face_p
)
1269 if (NILP (w
->contents
) || i
< w
->desired_matrix
->nrows
)
1270 clear_mouse_face (hlinfo
);
1273 else if (mouse_face_frame
&& !FRAME_LIVE_P (mouse_face_frame
))
1274 /* If the frame with mouse highlight was deleted, invalidate the
1276 reset_mouse_highlight (hlinfo
);
1282 IT_update_end (struct frame
*f
)
1284 struct tty_display_info
*dpyinfo
= FRAME_DISPLAY_INFO (f
);
1286 if (dpyinfo
->termscript
)
1287 fprintf (dpyinfo
->termscript
, "\n<UPDATE_END\n");
1288 dpyinfo
->mouse_highlight
.mouse_face_defer
= 0;
1292 IT_frame_up_to_date (struct frame
*f
)
1294 Lisp_Object new_cursor
, frame_desired_cursor
;
1297 FRAME_MOUSE_UPDATE (f
);
1299 /* Set the cursor type to whatever they wanted. In a minibuffer
1300 window, we want the cursor to appear only if we are reading input
1301 from this window, and we want the cursor to be taken from the
1302 frame parameters. For the selected window, we use either its
1303 buffer-local value or the value from the frame parameters if the
1304 buffer doesn't define its local value for the cursor type. */
1305 sw
= XWINDOW (f
->selected_window
);
1306 frame_desired_cursor
= Fcdr (Fassq (Qcursor_type
, f
->param_alist
));
1307 if (cursor_in_echo_area
1308 && FRAME_HAS_MINIBUF_P (f
)
1309 && EQ (FRAME_MINIBUF_WINDOW (f
), echo_area_window
)
1310 && sw
== XWINDOW (echo_area_window
))
1311 new_cursor
= frame_desired_cursor
;
1314 struct buffer
*b
= XBUFFER (sw
->contents
);
1316 if (EQ (BVAR (b
,cursor_type
), Qt
))
1317 new_cursor
= frame_desired_cursor
;
1318 else if (NILP (BVAR (b
, cursor_type
))) /* nil means no cursor */
1319 new_cursor
= Fcons (Qbar
, make_number (0));
1321 new_cursor
= BVAR (b
, cursor_type
);
1324 IT_set_cursor_type (f
, new_cursor
);
1326 IT_cmgoto (f
); /* position cursor when update is done */
1329 /* Copy LEN glyphs displayed on a single line whose vertical position
1330 is YPOS, beginning at horizontal position XFROM to horizontal
1331 position XTO, by moving blocks in the video memory. Used by
1332 functions that insert and delete glyphs. */
1334 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1336 /* The offsets of source and destination relative to the
1337 conventional memory selector. */
1338 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1339 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1341 if (from
== to
|| len
<= 0)
1344 _farsetsel (_dos_ds
);
1346 /* The source and destination might overlap, so we need to move
1347 glyphs non-destructively. */
1350 for ( ; len
; from
+= 2, to
+= 2, len
--)
1351 _farnspokew (to
, _farnspeekw (from
));
1355 from
+= (len
- 1) * 2;
1356 to
+= (len
- 1) * 2;
1357 for ( ; len
; from
-= 2, to
-= 2, len
--)
1358 _farnspokew (to
, _farnspeekw (from
));
1360 if (screen_virtual_segment
)
1361 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1364 /* Insert and delete glyphs. */
1366 IT_insert_glyphs (struct frame
*f
, struct glyph
*start
, int len
)
1368 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1370 /* Shift right the glyphs from the nominal cursor position to the
1371 end of this line. */
1372 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
1374 /* Now write the glyphs to be inserted. */
1375 IT_write_glyphs (f
, start
, len
);
1379 IT_delete_glyphs (struct frame
*f
, int n
)
1384 /* This was copied from xfaces.c */
1386 extern Lisp_Object Qbackground_color
;
1387 extern Lisp_Object Qforeground_color
;
1388 Lisp_Object Qreverse
;
1389 extern Lisp_Object Qtitle
;
1391 /* IT_set_terminal_modes is called when emacs is started,
1392 resumed, and whenever the screen is redrawn! */
1395 IT_set_terminal_modes (struct terminal
*term
)
1397 struct tty_display_info
*tty
;
1399 /* If called with initial terminal, it's too early to do anything
1401 if (term
->type
== output_initial
)
1404 tty
= term
->display_info
.tty
;
1406 if (tty
->termscript
)
1407 fprintf (tty
->termscript
, "\n<SET_TERM>");
1409 screen_size_X
= ScreenCols ();
1410 screen_size_Y
= ScreenRows ();
1411 screen_size
= screen_size_X
* screen_size_Y
;
1413 new_pos_X
= new_pos_Y
= 0;
1414 current_pos_X
= current_pos_Y
= -1;
1416 if (term_setup_done
)
1418 term_setup_done
= 1;
1420 startup_screen_size_X
= screen_size_X
;
1421 startup_screen_size_Y
= screen_size_Y
;
1422 startup_screen_attrib
= ScreenAttrib
;
1424 /* Is DOS/V (or any other RSIS software which relocates
1425 the screen) installed? */
1427 unsigned short es_value
;
1430 regs
.h
.ah
= 0xfe; /* get relocated screen address */
1431 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
1432 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
1433 else if (screen_old_address
) /* already switched to Japanese mode once */
1434 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
1436 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
1438 es_value
= regs
.x
.es
;
1439 __dpmi_int (0x10, ®s
);
1441 if (regs
.x
.es
!= es_value
)
1443 /* screen_old_address is only set if ScreenPrimary does NOT
1444 already point to the relocated buffer address returned by
1445 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1446 ScreenPrimary to that address at startup under DOS/V. */
1447 if (regs
.x
.es
!= ((ScreenPrimary
>> 4) & 0xffff))
1448 screen_old_address
= ScreenPrimary
;
1449 screen_virtual_segment
= regs
.x
.es
;
1450 screen_virtual_offset
= regs
.x
.di
;
1451 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
1455 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
1456 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
1461 /* IT_reset_terminal_modes is called when emacs is
1462 suspended or killed. */
1465 IT_reset_terminal_modes (struct terminal
*term
)
1467 int display_row_start
= (int) ScreenPrimary
;
1468 int saved_row_len
= startup_screen_size_X
* 2;
1469 int update_row_len
= ScreenCols () * 2, current_rows
= ScreenRows ();
1470 int to_next_row
= update_row_len
;
1471 unsigned char *saved_row
= startup_screen_buffer
;
1472 int cursor_pos_X
= ScreenCols () - 1, cursor_pos_Y
= ScreenRows () - 1;
1473 struct tty_display_info
*tty
= term
->display_info
.tty
;
1475 if (tty
->termscript
)
1476 fprintf (tty
->termscript
, "\n<RESET_TERM>");
1478 if (!term_setup_done
)
1483 /* Leave the video system in the same state as we found it,
1484 as far as the blink/bright-background bit is concerned. */
1485 maybe_enable_blinking ();
1487 /* We have a situation here.
1488 We cannot just do ScreenUpdate(startup_screen_buffer) because
1489 the luser could have changed screen dimensions inside Emacs
1490 and failed (or didn't want) to restore them before killing
1491 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1492 thus will happily use memory outside what was allocated for
1493 `startup_screen_buffer'.
1494 Thus we only restore as much as the current screen dimensions
1495 can hold, and clear the rest (if the saved screen is smaller than
1496 the current) with the color attribute saved at startup. The cursor
1497 is also restored within the visible dimensions. */
1499 ScreenAttrib
= startup_screen_attrib
;
1501 /* Don't restore the screen if we are exiting less than 2 seconds
1502 after startup: we might be crashing, and the screen might show
1503 some vital clues to what's wrong. */
1504 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
1507 if (screen_virtual_segment
)
1508 dosv_refresh_virtual_screen (0, screen_size
);
1510 if (update_row_len
> saved_row_len
)
1511 update_row_len
= saved_row_len
;
1512 if (current_rows
> startup_screen_size_Y
)
1513 current_rows
= startup_screen_size_Y
;
1515 if (tty
->termscript
)
1516 fprintf (tty
->termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1517 update_row_len
/ 2, current_rows
);
1519 while (current_rows
--)
1521 dosmemput (saved_row
, update_row_len
, display_row_start
);
1522 if (screen_virtual_segment
)
1523 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
1524 update_row_len
/ 2);
1525 saved_row
+= saved_row_len
;
1526 display_row_start
+= to_next_row
;
1529 if (startup_pos_X
< cursor_pos_X
)
1530 cursor_pos_X
= startup_pos_X
;
1531 if (startup_pos_Y
< cursor_pos_Y
)
1532 cursor_pos_Y
= startup_pos_Y
;
1534 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
1535 xfree (startup_screen_buffer
);
1536 startup_screen_buffer
= NULL
;
1538 term_setup_done
= 0;
1541 /* Remember the screen colors of the current frame, to serve as the
1542 default colors for newly-created frames. */
1543 DEFUN ("msdos-remember-default-colors", Fmsdos_remember_default_colors
,
1544 Smsdos_remember_default_colors
, 1, 1, 0,
1545 doc
: /* Remember the screen colors of the current frame. */)
1550 CHECK_FRAME (frame
);
1553 /* This function is called after applying default-frame-alist to the
1554 initial frame. At that time, if reverse-colors option was
1555 specified in default-frame-alist, it was already applied, and
1556 frame colors are reversed. */
1557 initial_screen_colors
[0] = FRAME_FOREGROUND_PIXEL (f
);
1558 initial_screen_colors
[1] = FRAME_BACKGROUND_PIXEL (f
);
1564 IT_set_frame_parameters (struct frame
*f
, Lisp_Object alist
)
1567 int i
, j
, length
= XINT (Flength (alist
));
1569 = (Lisp_Object
*) alloca (length
* word_size
);
1571 = (Lisp_Object
*) alloca (length
* word_size
);
1572 /* Do we have to reverse the foreground and background colors? */
1573 int reverse
= EQ (Fcdr (Fassq (Qreverse
, f
->param_alist
)), Qt
);
1574 int redraw
= 0, fg_set
= 0, bg_set
= 0;
1575 unsigned long orig_fg
, orig_bg
;
1576 struct tty_display_info
*tty
= FRAME_TTY (f
);
1578 /* If we are creating a new frame, begin with the original screen colors
1579 used for the initial frame. */
1580 if (!f
->default_face_done_p
1581 && initial_screen_colors
[0] != -1 && initial_screen_colors
[1] != -1)
1583 FRAME_FOREGROUND_PIXEL (f
) = initial_screen_colors
[0];
1584 FRAME_BACKGROUND_PIXEL (f
) = initial_screen_colors
[1];
1585 init_frame_faces (f
);
1586 f
->default_face_done_p
= 1;
1588 orig_fg
= reverse
? FRAME_BACKGROUND_PIXEL (f
) : FRAME_FOREGROUND_PIXEL (f
);
1589 orig_bg
= reverse
? FRAME_FOREGROUND_PIXEL (f
) : FRAME_BACKGROUND_PIXEL (f
);
1591 /* Extract parm names and values into those vectors. */
1593 for (tail
= alist
; CONSP (tail
); tail
= XCDR (tail
))
1595 Lisp_Object elt
= XCAR (tail
);
1596 parms
[i
] = Fcar (elt
);
1597 CHECK_SYMBOL (parms
[i
]);
1598 values
[i
] = Fcdr (elt
);
1604 for (i
= 0; i
< j
; i
++)
1606 Lisp_Object prop
, val
;
1611 if (EQ (prop
, Qreverse
))
1612 reverse
= EQ (val
, Qt
);
1615 if (tty
->termscript
&& reverse
)
1616 fprintf (tty
->termscript
, "<INVERSE-VIDEO>\n");
1618 /* Now process the alist elements in reverse of specified order. */
1619 for (i
--; i
>= 0; i
--)
1621 Lisp_Object prop
, val
;
1626 if (EQ (prop
, Qforeground_color
))
1628 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
1629 ? LFACE_BACKGROUND_INDEX
1630 : LFACE_FOREGROUND_INDEX
);
1631 if (new_color
!= FACE_TTY_DEFAULT_COLOR
1632 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
1633 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
1637 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1638 /* Make sure the foreground of the default face for
1639 this frame is changed as well. */
1640 update_face_from_frame_parameter (f
, Qforeground_color
, val
);
1642 if (tty
->termscript
)
1643 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
1647 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1648 update_face_from_frame_parameter (f
, Qbackground_color
, val
);
1650 if (tty
->termscript
)
1651 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
1656 else if (EQ (prop
, Qbackground_color
))
1658 unsigned long new_color
= load_color (f
, NULL
, val
, reverse
1659 ? LFACE_FOREGROUND_INDEX
1660 : LFACE_BACKGROUND_INDEX
);
1661 if (new_color
!= FACE_TTY_DEFAULT_COLOR
1662 && new_color
!= FACE_TTY_DEFAULT_FG_COLOR
1663 && new_color
!= FACE_TTY_DEFAULT_BG_COLOR
)
1667 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1668 /* Make sure the background of the default face for
1669 this frame is changed as well. */
1671 update_face_from_frame_parameter (f
, Qbackground_color
, val
);
1672 if (tty
->termscript
)
1673 fprintf (tty
->termscript
, "<BGCOLOR %lu>\n", new_color
);
1677 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1679 update_face_from_frame_parameter (f
, Qforeground_color
, val
);
1680 if (tty
->termscript
)
1681 fprintf (tty
->termscript
, "<FGCOLOR %lu>\n", new_color
);
1686 else if (EQ (prop
, Qtitle
))
1688 x_set_title (f
, val
);
1689 if (tty
->termscript
)
1690 fprintf (tty
->termscript
, "<TITLE: %s>\n", SDATA (val
));
1692 else if (EQ (prop
, Qcursor_type
))
1694 IT_set_cursor_type (f
, val
);
1695 if (tty
->termscript
)
1696 fprintf (tty
->termscript
, "<CTYPE: %s>\n",
1699 || (CONSP (val
) && (EQ (XCAR (val
), Qbar
)
1700 || EQ (XCAR (val
), Qhbar
)))
1703 else if (EQ (prop
, Qtty_type
))
1705 internal_terminal_init ();
1706 if (tty
->termscript
)
1707 fprintf (tty
->termscript
, "<TERM_INIT done, TTY_TYPE: %.*s>\n",
1708 SBYTES (val
), SDATA (val
));
1710 store_frame_param (f
, prop
, val
);
1713 /* If they specified "reverse", but not the colors, we need to swap
1714 the current frame colors. */
1719 FRAME_FOREGROUND_PIXEL (f
) = orig_bg
;
1720 update_face_from_frame_parameter (f
, Qforeground_color
,
1721 tty_color_name (f
, orig_bg
));
1726 FRAME_BACKGROUND_PIXEL (f
) = orig_fg
;
1727 update_face_from_frame_parameter (f
, Qbackground_color
,
1728 tty_color_name (f
, orig_fg
));
1735 face_change_count
++; /* forces xdisp.c to recompute basic faces */
1736 if (f
== SELECTED_FRAME ())
1741 extern void init_frame_faces (struct frame
*);
1743 #endif /* !HAVE_X_WINDOWS */
1746 /* Do we need the internal terminal? */
1749 internal_terminal_init (void)
1751 static int init_needed
= 1;
1752 char *term
= getenv ("TERM"), *colors
;
1753 struct frame
*sf
= SELECTED_FRAME ();
1754 struct tty_display_info
*tty
;
1756 #ifdef HAVE_X_WINDOWS
1757 if (!inhibit_window_system
)
1761 /* If this is the initial terminal, we are done here. */
1762 if (sf
->output_method
== output_initial
)
1766 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1768 #ifndef HAVE_X_WINDOWS
1769 if (!internal_terminal
|| inhibit_window_system
)
1771 sf
->output_method
= output_termcap
;
1775 tty
= FRAME_TTY (sf
);
1776 kset_window_system (current_kboard
, Qpc
);
1777 sf
->output_method
= output_msdos_raw
;
1780 if (!tty
->termscript
&& getenv ("EMACSTEST"))
1781 tty
->termscript
= fopen (getenv ("EMACSTEST"), "wt");
1782 if (tty
->termscript
)
1784 time_t now
= time (NULL
);
1785 struct tm
*tnow
= localtime (&now
);
1788 strftime (tbuf
, sizeof (tbuf
) - 1, "%a %b %e %Y %H:%M:%S %Z", tnow
);
1789 fprintf (tty
->termscript
, "\nEmacs session started at %s\n", tbuf
);
1790 fprintf (tty
->termscript
, "=====================\n\n");
1793 Vinitial_window_system
= Qpc
;
1794 Vwindow_system_version
= make_number (24); /* RE Emacs version */
1795 tty
->terminal
->type
= output_msdos_raw
;
1797 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
1799 screen_old_address
= 0;
1801 /* Forget the stale screen colors as well. */
1802 initial_screen_colors
[0] = initial_screen_colors
[1] = -1;
1804 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = 7; /* White */
1805 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = 0; /* Black */
1807 colors
= getenv ("EMACSCOLORS");
1808 if (colors
&& strlen (colors
) >= 2)
1810 /* The colors use 4 bits each (we enable bright background). */
1811 if (isdigit (colors
[0]))
1813 else if (isxdigit (colors
[0]))
1814 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1815 if (colors
[0] >= 0 && colors
[0] < 16)
1816 FRAME_FOREGROUND_PIXEL (SELECTED_FRAME ()) = colors
[0];
1817 if (isdigit (colors
[1]))
1819 else if (isxdigit (colors
[1]))
1820 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1821 if (colors
[1] >= 0 && colors
[1] < 16)
1822 FRAME_BACKGROUND_PIXEL (SELECTED_FRAME ()) = colors
[1];
1825 reset_mouse_highlight (&the_only_display_info
.mouse_highlight
);
1827 if (have_mouse
) /* detected in dos_ttraw, which see */
1829 have_mouse
= 1; /* enable mouse */
1831 mouse_setup_buttons (mouse_button_count
);
1832 tty
->terminal
->mouse_position_hook
= &mouse_get_pos
;
1836 if (tty
->termscript
&& screen_size
)
1837 fprintf (tty
->termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1838 screen_size_X
, screen_size_Y
);
1840 init_frame_faces (sf
);
1847 initialize_msdos_display (struct terminal
*term
)
1849 term
->rif
= 0; /* we don't support window-based display */
1850 term
->cursor_to_hook
= term
->raw_cursor_to_hook
= IT_cursor_to
;
1851 term
->clear_to_end_hook
= IT_clear_to_end
;
1852 term
->clear_frame_hook
= IT_clear_screen
;
1853 term
->clear_end_of_line_hook
= IT_clear_end_of_line
;
1854 term
->ins_del_lines_hook
= 0;
1855 term
->insert_glyphs_hook
= IT_insert_glyphs
;
1856 term
->write_glyphs_hook
= IT_write_glyphs
;
1857 term
->delete_glyphs_hook
= IT_delete_glyphs
;
1858 term
->ring_bell_hook
= IT_ring_bell
;
1859 term
->reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1860 term
->set_terminal_modes_hook
= IT_set_terminal_modes
;
1861 term
->set_terminal_window_hook
= NULL
;
1862 term
->update_begin_hook
= IT_update_begin
;
1863 term
->update_end_hook
= IT_update_end
;
1864 term
->frame_up_to_date_hook
= IT_frame_up_to_date
;
1865 term
->mouse_position_hook
= 0; /* set later by dos_ttraw */
1866 term
->frame_rehighlight_hook
= 0;
1867 term
->frame_raise_lower_hook
= 0;
1868 term
->set_vertical_scroll_bar_hook
= 0;
1869 term
->condemn_scroll_bars_hook
= 0;
1870 term
->redeem_scroll_bar_hook
= 0;
1871 term
->judge_scroll_bars_hook
= 0;
1872 term
->read_socket_hook
= &tty_read_avail_input
; /* from keyboard.c */
1876 dos_get_saved_screen (char **screen
, int *rows
, int *cols
)
1878 #ifndef HAVE_X_WINDOWS
1879 *screen
= startup_screen_buffer
;
1880 *cols
= startup_screen_size_X
;
1881 *rows
= startup_screen_size_Y
;
1882 return *screen
!= (char *)0;
1889 /* ----------------------- Keyboard control ----------------------
1891 * Keymaps reflect the following keyboard layout:
1893 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1894 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1895 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1896 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1900 #define Ignore 0x0000
1901 #define Normal 0x0000 /* normal key - alt changes scan-code */
1902 #define FctKey 0x1000 /* func key if c == 0, else c */
1903 #define Special 0x2000 /* func key even if c != 0 */
1904 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1905 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1906 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1907 #define Grey 0x6000 /* Grey keypad key */
1909 #define Alt 0x0100 /* alt scan-code */
1910 #define Ctrl 0x0200 /* ctrl scan-code */
1911 #define Shift 0x0400 /* shift scan-code */
1913 static int extended_kbd
; /* 101 (102) keyboard present. */
1915 struct kbd_translate
{
1918 unsigned short code
;
1921 struct dos_keyboard_map
1926 struct kbd_translate
*translate_table
;
1930 static struct dos_keyboard_map us_keyboard
= {
1932 /* 01234567890123456789012345678901234567890 123 45678901234 */
1933 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ \\zxcvbnm,./ ",
1934 /* 0123456789012345678901234567890123456789 012345678901234 */
1935 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| |ZXCVBNM<>? ",
1936 0, /* no Alt-Gr key */
1937 0 /* no translate table */
1940 static struct dos_keyboard_map fr_keyboard
= {
1942 /* 012 3456789012345678901234567890123456789012345678901234 */
1943 "ý&‚\"'(-Š_€…)= azertyuiop^$ qsdfghjklm—* <wxcvbn,;:! ",
1944 /* 0123456789012345678901234567890123456789012345678901234 */
1945 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ >WXCVBN?./õ ",
1946 /* 01234567 89012345678901234567890123456789012345678901234 */
1948 0 /* no translate table */
1952 * Italian keyboard support, country code 39.
1955 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1956 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1959 static struct kbd_translate it_kbd_translate_table
[] = {
1960 { 0x56, 0x3c, Normal
| 13 },
1961 { 0x56, 0x3e, Normal
| 27 },
1964 static struct dos_keyboard_map it_keyboard
= {
1966 /* 0 123456789012345678901234567890123456789012345678901234 */
1967 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— <zxcvbnm,.- ",
1968 /* 01 23456789012345678901234567890123456789012345678901234 */
1969 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ >ZXCVBNM;:_ ",
1970 /* 0123456789012345678901234567890123456789012345678901234 */
1972 it_kbd_translate_table
1975 static struct dos_keyboard_map dk_keyboard
= {
1977 /* 0123456789012345678901234567890123456789012345678901234 */
1978 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' <zxcvbnm,.- ",
1979 /* 01 23456789012345678901234567890123456789012345678901234 */
1980 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* >ZXCVBNM;:_ ",
1981 /* 0123456789012345678901234567890123456789012345678901234 */
1983 0 /* no translate table */
1986 static struct kbd_translate jp_kbd_translate_table
[] = {
1987 { 0x73, 0x5c, Normal
| 0 },
1988 { 0x73, 0x5f, Normal
| 0 },
1989 { 0x73, 0x1c, Map
| 0 },
1990 { 0x7d, 0x5c, Normal
| 13 },
1991 { 0x7d, 0x7c, Normal
| 13 },
1992 { 0x7d, 0x1c, Map
| 13 },
1995 static struct dos_keyboard_map jp_keyboard
= {
1997 /* 0123456789012 345678901234567890123456789012345678901234 */
1998 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
1999 /* 01 23456789012345678901234567890123456789012345678901234 */
2000 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
2001 0, /* no Alt-Gr key */
2002 jp_kbd_translate_table
2005 static struct keyboard_layout_list
2008 struct dos_keyboard_map
*keyboard_map
;
2009 } keyboard_layout_list
[] =
2011 { 1, &us_keyboard
},
2012 { 33, &fr_keyboard
},
2013 { 39, &it_keyboard
},
2014 { 45, &dk_keyboard
},
2015 { 81, &jp_keyboard
}
2018 static struct dos_keyboard_map
*keyboard
;
2019 static int keyboard_map_all
;
2020 static int international_keyboard
;
2023 dos_set_keyboard (int code
, int always
)
2026 _go32_dpmi_registers regs
;
2028 /* See if Keyb.Com is installed (for international keyboard support).
2029 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
2030 of Windows 9X! So don't do that! */
2032 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
2033 _go32_dpmi_simulate_int (0x2f, ®s
);
2034 if (regs
.h
.al
== 0xff)
2035 international_keyboard
= 1;
2037 /* Initialize to US settings, for countries that don't have their own. */
2038 keyboard
= keyboard_layout_list
[0].keyboard_map
;
2039 keyboard_map_all
= always
;
2040 dos_keyboard_layout
= 1;
2042 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
2043 if (code
== keyboard_layout_list
[i
].country_code
)
2045 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
2046 keyboard_map_all
= always
;
2047 dos_keyboard_layout
= code
;
2055 unsigned char char_code
; /* normal code */
2056 unsigned char meta_code
; /* M- code */
2057 unsigned char keypad_code
; /* keypad code */
2058 unsigned char editkey_code
; /* edit key */
2059 } keypad_translate_map
[] = {
2060 { '0', '0', 0xb0, /* kp-0 */ 0x63 /* insert */ },
2061 { '1', '1', 0xb1, /* kp-1 */ 0x57 /* end */ },
2062 { '2', '2', 0xb2, /* kp-2 */ 0x54 /* down */ },
2063 { '3', '3', 0xb3, /* kp-3 */ 0x56 /* next */ },
2064 { '4', '4', 0xb4, /* kp-4 */ 0x51 /* left */ },
2065 { '5', '5', 0xb5, /* kp-5 */ 0xb5 /* kp-5 */ },
2066 { '6', '6', 0xb6, /* kp-6 */ 0x53 /* right */ },
2067 { '7', '7', 0xb7, /* kp-7 */ 0x50 /* home */ },
2068 { '8', '8', 0xb8, /* kp-8 */ 0x52 /* up */ },
2069 { '9', '9', 0xb9, /* kp-9 */ 0x55 /* prior */ },
2070 { '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */}
2075 unsigned char char_code
; /* normal code */
2076 unsigned char keypad_code
; /* keypad code */
2077 } grey_key_translate_map
[] = {
2078 { '/', 0xaf /* kp-decimal */ },
2079 { '*', 0xaa /* kp-multiply */ },
2080 { '-', 0xad /* kp-subtract */ },
2081 { '+', 0xab /* kp-add */ },
2082 { '\r', 0x8d /* kp-enter */ }
2085 static unsigned short
2086 ibmpc_translate_map
[] =
2088 /* --------------- 00 to 0f --------------- */
2089 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
2090 Alt
| ModFct
| 0x1b, /* Escape */
2091 Normal
| 1, /* '1' */
2092 Normal
| 2, /* '2' */
2093 Normal
| 3, /* '3' */
2094 Normal
| 4, /* '4' */
2095 Normal
| 5, /* '5' */
2096 Normal
| 6, /* '6' */
2097 Normal
| 7, /* '7' */
2098 Normal
| 8, /* '8' */
2099 Normal
| 9, /* '9' */
2100 Normal
| 10, /* '0' */
2101 Normal
| 11, /* '-' */
2102 Normal
| 12, /* '=' */
2103 Special
| 0x08, /* Backspace */
2104 ModFct
| 0x74, /* Tab/Backtab */
2106 /* --------------- 10 to 1f --------------- */
2119 ModFct
| 0x0d, /* Return */
2124 /* --------------- 20 to 2f --------------- */
2133 Map
| 40, /* '\'' */
2135 Ignore
, /* Left shift */
2136 Map
| 41, /* '\\' */
2142 /* --------------- 30 to 3f --------------- */
2149 Ignore
, /* Right shift */
2150 Grey
| 1, /* Grey * */
2152 Normal
| 55, /* ' ' */
2153 Ignore
, /* Caps Lock */
2154 FctKey
| 0xbe, /* F1 */
2155 FctKey
| 0xbf, /* F2 */
2156 FctKey
| 0xc0, /* F3 */
2157 FctKey
| 0xc1, /* F4 */
2158 FctKey
| 0xc2, /* F5 */
2160 /* --------------- 40 to 4f --------------- */
2161 FctKey
| 0xc3, /* F6 */
2162 FctKey
| 0xc4, /* F7 */
2163 FctKey
| 0xc5, /* F8 */
2164 FctKey
| 0xc6, /* F9 */
2165 FctKey
| 0xc7, /* F10 */
2166 Ignore
, /* Num Lock */
2167 Ignore
, /* Scroll Lock */
2168 KeyPad
| 7, /* Home */
2169 KeyPad
| 8, /* Up */
2170 KeyPad
| 9, /* Page Up */
2171 Grey
| 2, /* Grey - */
2172 KeyPad
| 4, /* Left */
2173 KeyPad
| 5, /* Keypad 5 */
2174 KeyPad
| 6, /* Right */
2175 Grey
| 3, /* Grey + */
2176 KeyPad
| 1, /* End */
2178 /* --------------- 50 to 5f --------------- */
2179 KeyPad
| 2, /* Down */
2180 KeyPad
| 3, /* Page Down */
2181 KeyPad
| 0, /* Insert */
2182 KeyPad
| 10, /* Delete */
2183 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
2184 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
2185 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
2186 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
2187 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
2188 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
2189 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
2190 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
2191 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
2192 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
2193 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
2194 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
2196 /* --------------- 60 to 6f --------------- */
2197 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
2198 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
2199 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
2200 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
2201 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
2202 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
2203 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
2204 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
2205 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
2206 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
2207 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
2208 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
2209 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
2210 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
2211 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
2212 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
2214 /* --------------- 70 to 7f --------------- */
2215 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
2216 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
2217 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
2218 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
2219 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
2220 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
2221 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
2222 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
2223 Alt
| Map
| 1, /* '1' */
2224 Alt
| Map
| 2, /* '2' */
2225 Alt
| Map
| 3, /* '3' */
2226 Alt
| Map
| 4, /* '4' */
2227 Alt
| Map
| 5, /* '5' */
2228 Alt
| Map
| 6, /* '6' */
2229 Alt
| Map
| 7, /* '7' */
2230 Alt
| Map
| 8, /* '8' */
2232 /* --------------- 80 to 8f --------------- */
2233 Alt
| Map
| 9, /* '9' */
2234 Alt
| Map
| 10, /* '0' */
2235 Alt
| Map
| 11, /* '-' */
2236 Alt
| Map
| 12, /* '=' */
2237 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
2238 FctKey
| 0xc8, /* F11 */
2239 FctKey
| 0xc9, /* F12 */
2240 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
2241 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
2242 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
2243 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
2244 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
2245 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
2246 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
2247 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
2248 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
2250 /* --------------- 90 to 9f --------------- */
2251 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
2252 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
2253 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
2254 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
2255 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
2256 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
2257 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
2258 Alt
| FctKey
| 0x50, /* (Alt) Home */
2259 Alt
| FctKey
| 0x52, /* (Alt) Up */
2260 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
2261 Ignore
, /* NO KEY */
2262 Alt
| FctKey
| 0x51, /* (Alt) Left */
2263 Ignore
, /* NO KEY */
2264 Alt
| FctKey
| 0x53, /* (Alt) Right */
2265 Ignore
, /* NO KEY */
2266 Alt
| FctKey
| 0x57, /* (Alt) End */
2268 /* --------------- a0 to af --------------- */
2269 Alt
| KeyPad
| 2, /* (Alt) Down */
2270 Alt
| KeyPad
| 3, /* (Alt) Page Down */
2271 Alt
| KeyPad
| 0, /* (Alt) Insert */
2272 Alt
| KeyPad
| 10, /* (Alt) Delete */
2273 Alt
| Grey
| 0, /* (Alt) Grey / */
2274 Alt
| FctKey
| 0x09, /* (Alt) Tab */
2275 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
2278 /* These bit-positions corresponds to values returned by BIOS */
2279 #define SHIFT_P 0x0003 /* two bits! */
2280 #define CTRL_P 0x0004
2281 #define ALT_P 0x0008
2282 #define SCRLOCK_P 0x0010
2283 #define NUMLOCK_P 0x0020
2284 #define CAPSLOCK_P 0x0040
2285 #define ALT_GR_P 0x0800
2286 #define SUPER_P 0x4000 /* pseudo */
2287 #define HYPER_P 0x8000 /* pseudo */
2290 dos_get_modifiers (int *keymask
)
2293 int mask
, modifiers
= 0;
2295 /* Calculate modifier bits */
2296 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
2297 int86 (0x16, ®s
, ®s
);
2301 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
2302 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2306 mask
= regs
.h
.al
& (SHIFT_P
|
2307 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
2309 /* Do not break international keyboard support. */
2310 /* When Keyb.Com is loaded, the right Alt key is */
2311 /* used for accessing characters like { and } */
2312 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
2315 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
2318 if (dos_hyper_key
== 1)
2321 modifiers
|= hyper_modifier
;
2323 else if (dos_super_key
== 1)
2326 modifiers
|= super_modifier
;
2328 else if (!international_keyboard
)
2330 /* If Keyb.Com is NOT installed, let Right Alt behave
2331 like the Left Alt. */
2337 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2340 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2342 if (dos_hyper_key
== 2)
2345 modifiers
|= hyper_modifier
;
2347 else if (dos_super_key
== 2)
2350 modifiers
|= super_modifier
;
2358 modifiers
|= shift_modifier
;
2360 modifiers
|= ctrl_modifier
;
2362 modifiers
|= meta_modifier
;
2369 #define NUM_RECENT_DOSKEYS (100)
2370 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2371 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
2372 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
2374 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
2375 doc
: /* Return vector of last 100 keyboard input values seen in dos_rawgetc.
2376 Each input key receives two values in this vector: first the ASCII code,
2377 and then the scan code. */)
2380 Lisp_Object val
, *keys
= XVECTOR (recent_doskeys
)->contents
;
2382 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
2383 return Fvector (total_doskeys
, keys
);
2386 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
2387 vcopy (val
, 0, keys
+ recent_doskeys_index
,
2388 NUM_RECENT_DOSKEYS
- recent_doskeys_index
);
2389 vcopy (val
, NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
2390 keys
, recent_doskeys_index
);
2395 /* Get a char from keyboard. Function keys are put into the event queue. */
2399 struct input_event event
;
2401 Mouse_HLInfo
*hlinfo
= MOUSE_HL_INFO (SELECTED_FRAME ());
2404 #ifndef HAVE_X_WINDOWS
2405 /* Maybe put the cursor where it should be. */
2406 IT_cmgoto (SELECTED_FRAME ());
2409 /* The following condition is equivalent to `kbhit ()', except that
2410 it uses the bios to do its job. This pleases DESQview/X. */
2411 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
2412 int86 (0x16, ®s
, ®s
),
2413 (regs
.x
.flags
& 0x40) == 0)
2416 register unsigned char c
;
2417 int modifiers
, sc
, code
= -1, mask
, kp_mode
;
2419 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
2420 int86 (0x16, ®s
, ®s
);
2425 ASET (recent_doskeys
, recent_doskeys_index
, make_number (c
));
2426 recent_doskeys_index
++;
2427 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2428 recent_doskeys_index
= 0;
2429 ASET (recent_doskeys
, recent_doskeys_index
, make_number (sc
));
2430 recent_doskeys_index
++;
2431 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2432 recent_doskeys_index
= 0;
2434 modifiers
= dos_get_modifiers (&mask
);
2436 #ifndef HAVE_X_WINDOWS
2437 if (!NILP (Vdos_display_scancodes
))
2440 sprintf (buf
, "%02x:%02x*%04x",
2441 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
2442 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
2450 case 10: /* Ctrl Grey Enter */
2451 code
= Ctrl
| Grey
| 4;
2453 case 13: /* Grey Enter */
2456 case '/': /* Grey / */
2466 /* Try the keyboard-private translation table first. */
2467 if (keyboard
->translate_table
)
2469 struct kbd_translate
*p
= keyboard
->translate_table
;
2473 if (p
->sc
== sc
&& p
->ch
== c
)
2481 /* If the private table didn't translate it, use the general
2485 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
2487 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
2494 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2495 Emacs is ready to read a key. Therefore, if they press
2496 `Alt-x' when Emacs is busy, by the time we get to
2497 `dos_get_modifiers', they might have already released the
2498 Alt key, and Emacs gets just `x', which is BAD.
2499 However, for keys with the `Map' property set, the ASCII
2500 code returns zero only if Alt is pressed. So, when we DON'T
2501 have to support international_keyboard, we don't have to
2502 distinguish between the left and right Alt keys, and we
2503 can set the META modifier for any keys with the `Map'
2504 property if they return zero ASCII code (c = 0). */
2506 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
2507 modifiers
|= meta_modifier
;
2509 modifiers
|= ctrl_modifier
;
2511 modifiers
|= shift_modifier
;
2514 switch (code
& 0xf000)
2517 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
2519 c
= 0; /* Special */
2532 if (c
== 0) /* ctrl-break */
2534 return c
; /* ALT-nnn */
2536 if (!keyboard_map_all
)
2545 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
2546 if (!keyboard_map_all
)
2550 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
2551 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
2555 code
= keyboard
->shifted
[code
];
2557 modifiers
&= ~shift_modifier
;
2560 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
2561 code
= keyboard
->alt_gr
[code
];
2563 code
= keyboard
->unshifted
[code
];
2568 if (c
== 0xe0) /* edit key */
2571 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
2572 kp_mode
= dos_keypad_mode
& 0x03;
2574 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
2579 if (code
== 10 && dos_decimal_point
)
2580 return dos_decimal_point
;
2581 return keypad_translate_map
[code
].char_code
;
2584 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
2588 code
= keypad_translate_map
[code
].meta_code
;
2589 modifiers
= meta_modifier
;
2593 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
2600 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
2601 if (dos_keypad_mode
& kp_mode
)
2602 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
2604 code
= grey_key_translate_map
[code
].char_code
;
2611 if (!hlinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
))
2613 clear_mouse_face (hlinfo
);
2614 hlinfo
->mouse_face_hidden
= 1;
2618 event
.kind
= NON_ASCII_KEYSTROKE_EVENT
;
2620 event
.kind
= ASCII_KEYSTROKE_EVENT
;
2622 event
.modifiers
= modifiers
;
2623 event
.frame_or_window
= selected_frame
;
2625 event
.timestamp
= event_timestamp ();
2626 kbd_buffer_store_event (&event
);
2629 if (have_mouse
> 0 && !mouse_preempted
)
2631 int but
, press
, x
, y
, ok
;
2632 int mouse_prev_x
= mouse_last_x
, mouse_prev_y
= mouse_last_y
;
2633 Lisp_Object mouse_window
= Qnil
;
2635 /* Check for mouse movement *before* buttons. */
2636 mouse_check_moved ();
2638 /* If the mouse moved from the spot of its last sighting, we
2639 might need to update mouse highlight. */
2640 if (mouse_last_x
!= mouse_prev_x
|| mouse_last_y
!= mouse_prev_y
)
2642 if (hlinfo
->mouse_face_hidden
)
2644 hlinfo
->mouse_face_hidden
= 0;
2645 clear_mouse_face (hlinfo
);
2648 /* Generate SELECT_WINDOW_EVENTs when needed. */
2649 if (!NILP (Vmouse_autoselect_window
))
2651 static Lisp_Object last_mouse_window
;
2653 mouse_window
= window_from_coordinates
2654 (SELECTED_FRAME (), mouse_last_x
, mouse_last_y
, 0, 0);
2655 /* A window will be selected only when it is not
2656 selected now, and the last mouse movement event was
2657 not in it. A minibuffer window will be selected iff
2659 if (WINDOWP (mouse_window
)
2660 && !EQ (mouse_window
, last_mouse_window
)
2661 && !EQ (mouse_window
, selected_window
))
2663 event
.kind
= SELECT_WINDOW_EVENT
;
2664 event
.frame_or_window
= mouse_window
;
2666 event
.timestamp
= event_timestamp ();
2667 kbd_buffer_store_event (&event
);
2669 /* Remember the last window where we saw the mouse. */
2670 last_mouse_window
= mouse_window
;
2673 previous_help_echo_string
= help_echo_string
;
2674 help_echo_string
= help_echo_object
= help_echo_window
= Qnil
;
2676 note_mouse_highlight (SELECTED_FRAME (), mouse_last_x
, mouse_last_y
);
2677 /* If the contents of the global variable help_echo has
2678 changed, generate a HELP_EVENT. */
2679 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
2680 gen_help_event (help_echo_string
, selected_frame
, help_echo_window
,
2681 help_echo_object
, help_echo_pos
);
2684 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
2685 for (press
= 0; press
< 2; press
++)
2687 int button_num
= but
;
2690 ok
= mouse_pressed (but
, &x
, &y
);
2692 ok
= mouse_released (but
, &x
, &y
);
2695 /* Allow a simultaneous press/release of Mouse-1 and
2696 Mouse-2 to simulate Mouse-3 on two-button mice. */
2697 if (mouse_button_count
== 2 && but
< 2)
2699 int x2
, y2
; /* don't clobber original coordinates */
2701 /* If only one button is pressed, wait 100 msec and
2702 check again. This way, Speedy Gonzales isn't
2703 punished, while the slow get their chance. */
2704 if ((press
&& mouse_pressed (1-but
, &x2
, &y2
))
2705 || (!press
&& mouse_released (1-but
, &x2
, &y2
)))
2710 if ((press
&& mouse_pressed (1-but
, &x2
, &y2
))
2711 || (!press
&& mouse_released (1-but
, &x2
, &y2
)))
2716 event
.kind
= MOUSE_CLICK_EVENT
;
2717 event
.code
= button_num
;
2718 event
.modifiers
= dos_get_modifiers (0)
2719 | (press
? down_modifier
: up_modifier
);
2720 event
.x
= make_number (x
);
2721 event
.y
= make_number (y
);
2722 event
.frame_or_window
= selected_frame
;
2724 event
.timestamp
= event_timestamp ();
2725 kbd_buffer_store_event (&event
);
2733 static int prev_get_char
= -1;
2735 /* Return 1 if a key is ready to be read without suspending execution. */
2739 if (prev_get_char
!= -1)
2742 return ((prev_get_char
= dos_rawgetc ()) != -1);
2745 /* Read a key. Return -1 if no key is ready. */
2749 if (prev_get_char
!= -1)
2751 int c
= prev_get_char
;
2756 return dos_rawgetc ();
2759 #ifndef HAVE_X_WINDOWS
2761 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2764 Actually, I don't know the meaning of all the parameters of the functions
2765 here -- I only know how they are called by xmenu.c. I could of course
2766 grab the nearest Xlib manual (down the hall, second-to-last door on the
2767 left), but I don't think it's worth the effort. */
2769 /* These hold text of the current and the previous menu help messages. */
2770 static const char *menu_help_message
, *prev_menu_help_message
;
2771 /* Pane number and item number of the menu item which generated the
2772 last menu help message. */
2773 static int menu_help_paneno
, menu_help_itemno
;
2776 IT_menu_create (void)
2780 menu
= xmalloc (sizeof (XMenu
));
2781 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
2785 /* Allocate some (more) memory for MENU ensuring that there is room for one
2789 IT_menu_make_room (XMenu
*menu
)
2791 if (menu
->allocated
== 0)
2793 int count
= menu
->allocated
= 10;
2794 menu
->text
= xmalloc (count
* sizeof (char *));
2795 menu
->submenu
= xmalloc (count
* sizeof (XMenu
*));
2796 menu
->panenumber
= xmalloc (count
* sizeof (int));
2797 menu
->help_text
= xmalloc (count
* sizeof (char *));
2799 else if (menu
->allocated
== menu
->count
)
2801 int count
= menu
->allocated
= menu
->allocated
+ 10;
2803 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
2805 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
2807 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
2809 = (const char **) xrealloc (menu
->help_text
, count
* sizeof (char *));
2813 /* Search the given menu structure for a given pane number. */
2816 IT_menu_search_pane (XMenu
*menu
, int pane
)
2821 for (i
= 0; i
< menu
->count
; i
++)
2822 if (menu
->submenu
[i
])
2824 if (pane
== menu
->panenumber
[i
])
2825 return menu
->submenu
[i
];
2826 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
2832 /* Determine how much screen space a given menu needs. */
2835 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
2837 int i
, h2
, w2
, maxsubwidth
, maxheight
;
2840 maxheight
= menu
->count
;
2841 for (i
= 0; i
< menu
->count
; i
++)
2843 if (menu
->submenu
[i
])
2845 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
2846 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
2847 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
2850 *width
= menu
->width
+ maxsubwidth
;
2851 *height
= maxheight
;
2854 /* Display MENU at (X,Y) using FACES. */
2856 #define BUILD_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \
2859 (GLYPH).type = CHAR_GLYPH; \
2860 SET_CHAR_GLYPH ((GLYPH), CODE, FACE_ID, PADDING_P); \
2861 (GLYPH).charpos = -1; \
2866 IT_menu_display (XMenu
*menu
, int y
, int x
, int pn
, int *faces
, int disp_help
)
2868 int i
, j
, face
, width
, mx
, my
, enabled
, mousehere
, row
, col
;
2869 struct glyph
*text
, *p
;
2870 const unsigned char *q
;
2871 struct frame
*sf
= SELECTED_FRAME ();
2873 menu_help_message
= NULL
;
2875 width
= menu
->width
;
2876 /* We multiply width by 2 to account for possible control characters.
2877 FIXME: cater to non-ASCII characters in menus. */
2878 text
= xmalloc ((width
* 2 + 2) * sizeof (struct glyph
));
2879 ScreenGetCursor (&row
, &col
);
2880 mouse_get_xy (&mx
, &my
);
2881 IT_update_begin (sf
);
2882 for (i
= 0; i
< menu
->count
; i
++)
2884 int max_width
= width
+ 2;
2886 IT_cursor_to (sf
, y
+ i
, x
);
2888 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
2889 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ max_width
);
2890 face
= faces
[enabled
+ mousehere
* 2];
2891 /* The following if clause means that we display the menu help
2892 strings even if the menu item is currently disabled. */
2893 if (disp_help
&& enabled
+ mousehere
* 2 >= 2)
2895 menu_help_message
= menu
->help_text
[i
];
2896 menu_help_paneno
= pn
- 1;
2897 menu_help_itemno
= i
;
2900 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
2902 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
2904 unsigned c
= STRING_CHAR_ADVANCE (q
);
2908 BUILD_CHAR_GLYPH (*p
, c
, face
, 0);
2911 else /* make '^x' */
2913 BUILD_CHAR_GLYPH (*p
, '^', face
, 0);
2916 BUILD_CHAR_GLYPH (*p
, c
+ 64, face
, 0);
2920 /* Don't let the menu text overflow into the next screen row. */
2921 if (x
+ max_width
> screen_size_X
)
2923 max_width
= screen_size_X
- x
;
2924 text
[max_width
- 1].u
.ch
= '$'; /* indicate it's truncated */
2926 for (; j
< max_width
- 2; j
++, p
++)
2927 BUILD_CHAR_GLYPH (*p
, ' ', face
, 0);
2929 /* 16 is the character code of a character that on DOS terminal
2930 produces a nice-looking right-pointing arrow glyph. */
2931 BUILD_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
2933 IT_write_glyphs (sf
, text
, max_width
);
2936 IT_cursor_to (sf
, row
, col
);
2940 /* --------------------------- X Menu emulation ---------------------- */
2942 /* Create a brand new menu structure. */
2945 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2947 return IT_menu_create ();
2950 /* Create a new pane and place it on the outer-most level. It is not
2951 clear that it should be placed out there, but I don't know what else
2955 XMenuAddPane (Display
*foo
, XMenu
*menu
, const char *txt
, int enable
)
2963 IT_menu_make_room (menu
);
2964 menu
->submenu
[menu
->count
] = IT_menu_create ();
2965 menu
->text
[menu
->count
] = (char *)txt
;
2966 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
2967 menu
->help_text
[menu
->count
] = NULL
;
2970 /* Adjust length for possible control characters (which will
2971 be written as ^x). */
2972 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2976 if (len
> menu
->width
)
2979 return menu
->panecount
;
2982 /* Create a new item in a menu pane. */
2985 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
2986 int foo
, char *txt
, int enable
, char const *help_text
)
2992 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
2994 IT_menu_make_room (menu
);
2995 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
2996 menu
->text
[menu
->count
] = txt
;
2997 menu
->panenumber
[menu
->count
] = enable
;
2998 menu
->help_text
[menu
->count
] = help_text
;
3001 /* Adjust length for possible control characters (which will
3002 be written as ^x). */
3003 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
3007 if (len
> menu
->width
)
3013 /* Decide where the menu would be placed if requested at (X,Y). */
3016 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
3017 int *ulx
, int *uly
, int *width
, int *height
)
3019 IT_menu_calc_size (menu
, width
, height
);
3025 struct IT_menu_state
3027 void *screen_behind
;
3034 /* Display menu, wait for user's response, and return that response. */
3037 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
3038 int x0
, int y0
, unsigned ButtonMask
, char **txt
,
3039 void (*help_callback
)(char const *, int, int))
3041 struct IT_menu_state
*state
;
3042 int statecount
, x
, y
, i
, b
, screensize
, leave
, result
, onepane
;
3043 int title_faces
[4]; /* face to display the menu title */
3044 int faces
[4], buffers_num_deleted
= 0;
3045 struct frame
*sf
= SELECTED_FRAME ();
3046 Lisp_Object saved_echo_area_message
, selectface
;
3048 /* Just in case we got here without a mouse present... */
3049 if (have_mouse
<= 0)
3050 return XM_IA_SELECT
;
3051 /* Don't allow non-positive x0 and y0, lest the menu will wrap
3052 around the display. */
3058 /* We will process all the mouse events directly, so we had
3059 better prevent dos_rawgetc from stealing them from us. */
3062 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
3063 screensize
= screen_size
* 2;
3065 = lookup_derived_face (sf
, intern ("msdos-menu-passive-face"),
3066 DEFAULT_FACE_ID
, 1);
3068 = lookup_derived_face (sf
, intern ("msdos-menu-active-face"),
3069 DEFAULT_FACE_ID
, 1);
3070 selectface
= intern ("msdos-menu-select-face");
3071 faces
[2] = lookup_derived_face (sf
, selectface
,
3073 faces
[3] = lookup_derived_face (sf
, selectface
,
3076 /* Make sure the menu title is always displayed with
3077 `msdos-menu-active-face', no matter where the mouse pointer is. */
3078 for (i
= 0; i
< 4; i
++)
3079 title_faces
[i
] = faces
[3];
3083 /* Don't let the title for the "Buffers" popup menu include a
3084 digit (which is ugly).
3086 This is a terrible kludge, but I think the "Buffers" case is
3087 the only one where the title includes a number, so it doesn't
3088 seem to be necessary to make this more general. */
3089 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
3091 menu
->text
[0][7] = '\0';
3092 buffers_num_deleted
= 1;
3095 /* We need to save the current echo area message, so that we could
3096 restore it below, before we exit. See the commentary below,
3097 before the call to message_with_string. */
3098 saved_echo_area_message
= Fcurrent_message ();
3099 state
[0].menu
= menu
;
3101 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
3103 /* Turn off the cursor. Otherwise it shows through the menu
3104 panes, which is ugly. */
3105 IT_display_cursor (0);
3107 /* Display the menu title. */
3108 IT_menu_display (menu
, y0
- 1, x0
- 1, 1, title_faces
, 0);
3109 if (buffers_num_deleted
)
3110 menu
->text
[0][7] = ' ';
3111 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
3113 menu
->width
= menu
->submenu
[0]->width
;
3114 state
[0].menu
= menu
->submenu
[0];
3118 state
[0].menu
= menu
;
3120 state
[0].x
= x0
- 1;
3122 state
[0].pane
= onepane
;
3124 mouse_last_x
= -1; /* A hack that forces display. */
3128 if (!mouse_visible
) mouse_on ();
3129 mouse_check_moved ();
3130 if (sf
->mouse_moved
)
3132 sf
->mouse_moved
= 0;
3133 result
= XM_IA_SELECT
;
3134 mouse_get_xy (&x
, &y
);
3135 for (i
= 0; i
< statecount
; i
++)
3136 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
3138 int dy
= y
- state
[i
].y
;
3139 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
3141 if (!state
[i
].menu
->submenu
[dy
])
3143 if (state
[i
].menu
->panenumber
[dy
])
3144 result
= XM_SUCCESS
;
3146 result
= XM_IA_SELECT
;
3148 *pane
= state
[i
].pane
- 1;
3150 /* We hit some part of a menu, so drop extra menus that
3151 have been opened. That does not include an open and
3153 if (i
!= statecount
- 2
3154 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
3155 while (i
!= statecount
- 1)
3159 ScreenUpdate (state
[statecount
].screen_behind
);
3160 if (screen_virtual_segment
)
3161 dosv_refresh_virtual_screen (0, screen_size
);
3162 xfree (state
[statecount
].screen_behind
);
3164 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
3166 IT_menu_display (state
[i
].menu
,
3171 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
3172 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
3174 ScreenRetrieve (state
[statecount
].screen_behind
3175 = xmalloc (screensize
));
3177 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
3178 state
[statecount
].y
= y
;
3183 IT_menu_display (state
[statecount
- 1].menu
,
3184 state
[statecount
- 1].y
,
3185 state
[statecount
- 1].x
,
3186 state
[statecount
- 1].pane
,
3191 if ((menu_help_message
|| prev_menu_help_message
)
3192 && menu_help_message
!= prev_menu_help_message
)
3194 help_callback (menu_help_message
,
3195 menu_help_paneno
, menu_help_itemno
);
3196 IT_display_cursor (0);
3197 prev_menu_help_message
= menu_help_message
;
3199 /* We are busy-waiting for the mouse to move, so let's be nice
3200 to other Windows applications by releasing our time slice. */
3203 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
3205 /* Only leave if user both pressed and released the mouse, and in
3206 that order. This avoids popping down the menu pane unless
3207 the user is really done with it. */
3208 if (mouse_pressed (b
, &x
, &y
))
3210 while (mouse_button_depressed (b
, &x
, &y
))
3214 (void) mouse_released (b
, &x
, &y
);
3219 ScreenUpdate (state
[0].screen_behind
);
3220 if (screen_virtual_segment
)
3221 dosv_refresh_virtual_screen (0, screen_size
);
3223 /* We have a situation here. ScreenUpdate has just restored the
3224 screen contents as it was before we started drawing this menu.
3225 That includes any echo area message that could have been
3226 displayed back then. (In reality, that echo area message will
3227 almost always be the ``keystroke echo'' that echoes the sequence
3228 of menu items chosen by the user.) However, if the menu had some
3229 help messages, then displaying those messages caused Emacs to
3230 forget about the original echo area message. So when
3231 ScreenUpdate restored it, it created a discrepancy between the
3232 actual screen contents and what Emacs internal data structures
3235 To avoid this conflict, we force Emacs to restore the original
3236 echo area message as we found it when we entered this function.
3237 The irony of this is that we then erase the restored message
3238 right away, so the only purpose of restoring it is so that
3239 erasing it works correctly... */
3240 if (! NILP (saved_echo_area_message
))
3241 message_with_string ("%s", saved_echo_area_message
, 0);
3243 while (statecount
--)
3244 xfree (state
[statecount
].screen_behind
);
3245 IT_display_cursor (1); /* Turn cursor back on. */
3246 /* Clean up any mouse events that are waiting inside Emacs event queue.
3247 These events are likely to be generated before the menu was even
3248 displayed, probably because the user pressed and released the button
3249 (which invoked the menu) too quickly. If we don't remove these events,
3250 Emacs will process them after we return and surprise the user. */
3251 discard_mouse_events ();
3252 mouse_clear_clicks ();
3253 if (!kbd_buffer_events_waiting ())
3254 clear_input_pending ();
3255 /* Allow mouse events generation by dos_rawgetc. */
3260 /* Dispose of a menu. */
3263 XMenuDestroy (Display
*foo
, XMenu
*menu
)
3266 if (menu
->allocated
)
3268 for (i
= 0; i
< menu
->count
; i
++)
3269 if (menu
->submenu
[i
])
3270 XMenuDestroy (foo
, menu
->submenu
[i
]);
3272 xfree (menu
->submenu
);
3273 xfree (menu
->panenumber
);
3274 xfree (menu
->help_text
);
3277 menu_help_message
= prev_menu_help_message
= NULL
;
3279 #endif /* !HAVE_X_WINDOWS */
3281 /* ----------------------- DOS / UNIX conversion --------------------- */
3283 void msdos_downcase_filename (unsigned char *);
3285 /* Destructively turn backslashes into slashes. */
3288 dostounix_filename (char *p
)
3290 msdos_downcase_filename (p
);
3300 /* Destructively turn slashes into backslashes. */
3303 unixtodos_filename (char *p
)
3305 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3319 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
3322 getdefdir (int drive
, char *dst
)
3324 char in_path
[4], *p
= in_path
, e
= errno
;
3326 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
3329 *p
++ = drive
+ 'A' - 1;
3336 _fixpath (in_path
, dst
);
3337 /* _fixpath can set errno to ENOSYS on non-LFN systems because
3338 it queries the LFN support, so ignore that error. */
3339 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
3342 msdos_downcase_filename (dst
);
3349 emacs_root_dir (void)
3351 static char root_dir
[4];
3353 sprintf (root_dir
, "%c:/", 'A' + getdisk ());
3354 root_dir
[0] = tolower (root_dir
[0]);
3358 /* Remove all CR's that are followed by a LF. */
3361 crlf_to_lf (int n
, unsigned char *buf
)
3363 unsigned char *np
= buf
, *startp
= buf
, *endp
= buf
+ n
;
3367 while (buf
< endp
- 1)
3371 if (*(++buf
) != 0x0a)
3382 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
3384 doc
: /* Return non-nil if long file names are supported on MS-DOS. */)
3387 return (_USE_LFN
? Qt
: Qnil
);
3390 /* Convert alphabetic characters in a filename to lower-case. */
3393 msdos_downcase_filename (unsigned char *p
)
3395 /* Always lower-case drive letters a-z, even if the filesystem
3396 preserves case in filenames.
3397 This is so MSDOS filenames could be compared by string comparison
3398 functions that are case-sensitive. Even case-preserving filesystems
3399 do not distinguish case in drive letters. */
3400 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3406 /* Under LFN we expect to get pathnames in their true case. */
3407 if (NILP (Fmsdos_long_file_names ()))
3409 if (*p
>= 'A' && *p
<= 'Z')
3413 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
3415 doc
: /* Convert alphabetic characters in FILENAME to lower case and return that.
3416 When long filenames are supported, doesn't change FILENAME.
3417 If FILENAME is not a string, returns nil.
3418 The argument object is never altered--the value is a copy. */)
3419 (Lisp_Object filename
)
3423 if (! STRINGP (filename
))
3426 tem
= Fcopy_sequence (filename
);
3427 msdos_downcase_filename (SDATA (tem
));
3431 /* The Emacs root directory as determined by init_environment. */
3433 static char emacsroot
[MAXPATHLEN
];
3436 rootrelativepath (char *rel
)
3438 static char result
[MAXPATHLEN
+ 10];
3440 strcpy (result
, emacsroot
);
3441 strcat (result
, "/");
3442 strcat (result
, rel
);
3446 /* Define a lot of environment variables if not already defined. Don't
3447 remove anything unless you know what you're doing -- lots of code will
3448 break if one or more of these are missing. */
3451 init_environment (int argc
, char **argv
, int skip_args
)
3455 static const char * const tempdirs
[] = {
3456 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3458 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
3460 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3461 temporary files and assume "/tmp" if $TMPDIR is unset, which
3462 will break on DOS/Windows. Refuse to work if we cannot find
3463 a directory, not even "c:/", usable for that purpose. */
3464 for (i
= 0; i
< imax
; i
++)
3466 const char *tmp
= tempdirs
[i
];
3467 char buf
[FILENAME_MAX
];
3473 tmp
= getenv (tmp
+ 1);
3477 /* Some lusers set TMPDIR=e:, probably because some losing
3478 programs cannot handle multiple slashes if they use e:/.
3479 e: fails in `access' below, so we interpret e: as e:/. */
3480 tmp_len
= strlen (tmp
);
3481 if (tmp
[tmp_len
- 1] != '/' && tmp
[tmp_len
- 1] != '\\')
3484 buf
[tmp_len
++] = '/', buf
[tmp_len
] = 0;
3489 /* Note that `access' can lie to us if the directory resides on a
3490 read-only filesystem, like CD-ROM or a write-protected floppy.
3491 The only way to be really sure is to actually create a file and
3492 see if it succeeds. But I think that's too much to ask. */
3493 if (tmp
&& access (tmp
, D_OK
) == 0)
3495 setenv ("TMPDIR", tmp
, 1);
3502 Fcons (build_string ("no usable temporary directories found!!"),
3504 "While setting TMPDIR: ");
3506 /* Note the startup time, so we know not to clear the screen if we
3507 exit immediately; see IT_reset_terminal_modes.
3508 (Yes, I know `clock' returns zero the first time it's called, but
3509 I do this anyway, in case some wiseguy changes that at some point.) */
3510 startup_time
= clock ();
3512 /* Find our root from argv[0]. Assuming argv[0] is, say,
3513 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3514 root
= alloca (MAXPATHLEN
+ 20);
3515 _fixpath (argv
[0], root
);
3516 msdos_downcase_filename (root
);
3517 len
= strlen (root
);
3518 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
3522 && (strcmp (root
+ len
- 4, "/bin") == 0
3523 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
3524 root
[len
- 4] = '\0';
3526 strcpy (root
, "c:/emacs"); /* let's be defensive */
3527 len
= strlen (root
);
3528 strcpy (emacsroot
, root
);
3530 /* We default HOME to our root. */
3531 setenv ("HOME", root
, 0);
3533 /* We default EMACSPATH to root + "/bin". */
3534 strcpy (root
+ len
, "/bin");
3535 setenv ("EMACSPATH", root
, 0);
3537 /* I don't expect anybody to ever use other terminals so the internal
3538 terminal is the default. */
3539 setenv ("TERM", "internal", 0);
3541 #ifdef HAVE_X_WINDOWS
3542 /* Emacs expects DISPLAY to be set. */
3543 setenv ("DISPLAY", "unix:0.0", 0);
3546 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3547 downcase it and mirror the backslashes. */
3548 s
= getenv ("COMSPEC");
3549 if (!s
) s
= "c:/command.com";
3550 t
= alloca (strlen (s
) + 1);
3552 dostounix_filename (t
);
3553 setenv ("SHELL", t
, 0);
3555 /* PATH is also downcased and backslashes mirrored. */
3556 s
= getenv ("PATH");
3558 t
= alloca (strlen (s
) + 3);
3559 /* Current directory is always considered part of MsDos's path but it is
3560 not normally mentioned. Now it is. */
3561 strcat (strcpy (t
, ".;"), s
);
3562 dostounix_filename (t
); /* Not a single file name, but this should work. */
3563 setenv ("PATH", t
, 1);
3565 /* In some sense all dos users have root privileges, so... */
3566 setenv ("USER", "root", 0);
3567 setenv ("NAME", getenv ("USER"), 0);
3569 /* Time zone determined from country code. To make this possible, the
3570 country code may not span more than one time zone. In other words,
3571 in the USA, you lose. */
3573 switch (dos_country_code
)
3575 case 31: /* Belgium */
3576 case 32: /* The Netherlands */
3577 case 33: /* France */
3578 case 34: /* Spain */
3579 case 36: /* Hungary */
3580 case 38: /* Yugoslavia (or what's left of it?) */
3581 case 39: /* Italy */
3582 case 41: /* Switzerland */
3583 case 42: /* Tjekia */
3584 case 45: /* Denmark */
3585 case 46: /* Sweden */
3586 case 47: /* Norway */
3587 case 48: /* Poland */
3588 case 49: /* Germany */
3589 /* Daylight saving from last Sunday in March to last Sunday in
3590 September, both at 2AM. */
3591 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3593 case 44: /* United Kingdom */
3594 case 351: /* Portugal */
3595 case 354: /* Iceland */
3596 setenv ("TZ", "GMT+00", 0);
3598 case 81: /* Japan */
3599 case 82: /* Korea */
3600 setenv ("TZ", "JST-09", 0);
3602 case 90: /* Turkey */
3603 case 358: /* Finland */
3604 setenv ("TZ", "EET-02", 0);
3606 case 972: /* Israel */
3607 /* This is an approximation. (For exact rules, use the
3608 `zoneinfo/israel' file which comes with DJGPP, but you need
3609 to install it in `/usr/share/zoneinfo/' directory first.) */
3610 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3618 static int break_stat
; /* BREAK check mode status. */
3619 static int stdin_stat
; /* stdin IOCTL status. */
3621 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3622 control chars by DOS. Determine the keyboard type. */
3625 dos_ttraw (struct tty_display_info
*tty
)
3627 union REGS inregs
, outregs
;
3628 static int first_time
= 1;
3630 /* If we are called for the initial terminal, it's too early to do
3631 anything, and termscript isn't set up. */
3632 if (tty
->terminal
->type
== output_initial
)
3635 break_stat
= getcbrk ();
3641 int86 (0x15, &inregs
, &outregs
);
3642 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
3647 #ifdef HAVE_X_WINDOWS
3648 && inhibit_window_system
3652 inregs
.x
.ax
= 0x0021;
3653 int86 (0x33, &inregs
, &outregs
);
3654 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3657 /* Reportedly, the above doesn't work for some mouse drivers. There
3658 is an additional detection method that should work, but might be
3659 a little slower. Use that as an alternative. */
3660 inregs
.x
.ax
= 0x0000;
3661 int86 (0x33, &inregs
, &outregs
);
3662 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3665 mouse_button_count
= outregs
.x
.bx
;
3667 #ifndef HAVE_X_WINDOWS
3668 /* Save the cursor shape used outside Emacs. */
3669 outside_cursor
= _farpeekw (_dos_ds
, 0x460);
3675 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
3676 return (stdin_stat
!= -1);
3679 return (setmode (fileno (stdin
), O_BINARY
) != -1);
3682 /* Restore status of standard input and Ctrl-C checking. */
3687 union REGS inregs
, outregs
;
3689 setcbrk (break_stat
);
3692 #ifndef HAVE_X_WINDOWS
3693 /* Restore the cursor shape we found on startup. */
3697 inregs
.x
.cx
= outside_cursor
;
3698 int86 (0x10, &inregs
, &outregs
);
3702 return (setmode (fileno (stdin
), stdin_stat
) != -1);
3706 /* Run command as specified by ARGV in directory DIR.
3707 The command is run with input from TEMPIN, output to
3708 file TEMPOUT and stderr to TEMPERR. */
3711 run_msdos_command (unsigned char **argv
, const char *working_dir
,
3712 int tempin
, int tempout
, int temperr
, char **envv
)
3714 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
3715 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
3716 int msshell
, result
= -1, inbak
, outbak
, errbak
, x
, y
;
3719 /* Get current directory as MSDOS cwd is not per-process. */
3722 /* If argv[0] is the shell, it might come in any lettercase.
3723 Since `Fmember' is case-sensitive, we need to downcase
3724 argv[0], even if we are on case-preserving filesystems. */
3725 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
3726 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
3729 if (*pl
>= 'A' && *pl
<= 'Z')
3734 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
3735 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
3736 && !strcmp ("-c", argv
[1]);
3739 saveargv1
= argv
[1];
3740 saveargv2
= argv
[2];
3742 /* We only need to mirror slashes if a DOS shell will be invoked
3743 not via `system' (which does the mirroring itself). Yes, that
3744 means DJGPP v1.x will lose here. */
3745 if (argv
[2] && argv
[3])
3747 char *p
= alloca (strlen (argv
[2]) + 1);
3749 strcpy (argv
[2] = p
, saveargv2
);
3750 while (*p
&& isspace (*p
))
3762 chdir (working_dir
);
3766 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3767 goto done
; /* Allocation might fail due to lack of descriptors. */
3770 mouse_get_xy (&x
, &y
);
3772 if (!noninteractive
)
3773 dos_ttcooked (); /* do it here while 0 = stdin */
3779 if (msshell
&& !argv
[3])
3781 /* MS-DOS native shells are too restrictive. For starters, they
3782 cannot grok commands longer than 126 characters. In DJGPP v2
3783 and later, `system' is much smarter, so we'll call it instead. */
3787 /* A shell gets a single argument--its full command
3788 line--whose original was saved in `saveargv2'. */
3790 /* Don't let them pass empty command lines to `system', since
3791 with some shells it will try to invoke an interactive shell,
3792 which will hang Emacs. */
3793 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
3797 extern char **environ
;
3798 char **save_env
= environ
;
3799 int save_system_flags
= __system_flags
;
3801 /* Request the most powerful version of `system'. We need
3802 all the help we can get to avoid calling stock DOS shells. */
3803 __system_flags
= (__system_redirect
3804 | __system_use_shell
3805 | __system_allow_multiple_cmds
3806 | __system_allow_long_cmds
3807 | __system_handle_null_commands
3808 | __system_emulate_chdir
);
3811 result
= system (cmnd
);
3812 __system_flags
= save_system_flags
;
3816 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
3819 result
= spawnve (P_WAIT
, argv
[0], (char **)argv
, envv
);
3824 emacs_close (inbak
);
3825 emacs_close (outbak
);
3826 emacs_close (errbak
);
3828 if (!noninteractive
)
3829 dos_ttraw (CURTTY ());
3833 mouse_moveto (x
, y
);
3836 /* Some programs might change the meaning of the highest bit of the
3837 text attribute byte, so we get blinking characters instead of the
3838 bright background colors. Restore that. */
3839 if (!noninteractive
)
3846 argv
[1] = saveargv1
;
3847 argv
[2] = saveargv2
;
3853 croak (char *badfunc
)
3855 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3856 reset_all_sys_modes ();
3861 * A few unimplemented functions that we silently ignore.
3863 pid_t
tcgetpgrp (int fd
) { return 0; }
3864 int setpgid (int pid
, int pgid
) { return 0; }
3865 int setpriority (int x
, int y
, int z
) { return 0; }
3866 pid_t
setsid (void) { return 0; }
3869 /* Gnulib support and emulation. */
3871 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 4
3873 readlink (const char *name
, char *dummy1
, size_t dummy2
)
3875 /* `access' is much faster than `stat' on MS-DOS. */
3876 if (access (name
, F_OK
) == 0)
3882 /* dir_pathname is set by sys_opendir and used in readlinkat and in
3883 fstatat, when they get a special FD of zero, which means use the
3884 last directory opened by opendir. */
3885 static char dir_pathname
[MAXPATHLEN
];
3887 sys_opendir (const char *dirname
)
3889 _fixpath (dirname
, dir_pathname
);
3890 return opendir (dirname
);
3894 readlinkat (int fd
, char const *name
, char *buffer
, size_t buffer_size
)
3896 /* Rely on a hack: an open directory is modeled as file descriptor 0,
3897 as in fstatat. FIXME: Add proper support for readlinkat. */
3898 char fullname
[MAXPATHLEN
];
3902 if (strlen (dir_pathname
) + strlen (name
) + 1 >= MAXPATHLEN
)
3904 errno
= ENAMETOOLONG
;
3907 sprintf (fullname
, "%s/%s", dir_pathname
, name
);
3911 return readlink (name
, buffer
, buffer_size
);
3915 careadlinkat (int fd
, char const *filename
,
3916 char *buffer
, size_t buffer_size
,
3917 struct allocator
const *alloc
,
3918 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
3922 /* We don't support the fancy auto-allocation feature. */
3931 ssize_t len
= preadlinkat (fd
, filename
, buffer
, buffer_size
);
3933 if (len
< 0 || len
== buffer_size
)
3936 buffer
[len
+ 1] = '\0';
3941 /* Emulate faccessat(2). */
3943 faccessat (int dirfd
, const char * path
, int mode
, int flags
)
3945 /* We silently ignore FLAGS. */
3948 if (dirfd
!= AT_FDCWD
3949 && !(IS_DIRECTORY_SEP (path
[0])
3950 || IS_DEVICE_SEP (path
[1])))
3956 return access (path
, mode
);
3959 /* Emulate fstatat. */
3961 fstatat (int fd
, char const *name
, struct stat
*st
, int flags
)
3963 /* Rely on a hack: an open directory is modeled as file descriptor 0.
3964 This is good enough for the current usage in Emacs, but is fragile.
3966 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
3967 Gnulib does this and can serve as a model. */
3968 char fullname
[MAXPATHLEN
];
3974 char lastc
= dir_pathname
[strlen (dir_pathname
) - 1];
3976 if (strlen (dir_pathname
) + strlen (name
) + IS_DIRECTORY_SEP (lastc
)
3979 errno
= ENAMETOOLONG
;
3983 sprintf (fullname
, "%s%s%s",
3984 dir_pathname
, IS_DIRECTORY_SEP (lastc
) ? "" : "/", name
);
3988 #if __DJGPP__ > 2 || __DJGPP_MINOR__ > 3
3989 return (flags
& AT_SYMLINK_NOFOLLOW
) ? lstat (name
, st
) : stat (name
, st
);
3991 return stat (name
, st
);
3995 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 4
3996 /* Emulate the Posix unsetenv. DJGPP v2.04 has this in the library. */
3998 unsetenv (const char *name
)
4004 if (name
== NULL
|| *name
== '\0' || strchr (name
, '=') != NULL
)
4010 /* DJGPP's 'putenv' deletes the entry if it doesn't include '='. */
4018 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4020 /* Augment DJGPP library POSIX signal functions. This is needed
4021 as of DJGPP v2.01, but might be in the library in later releases. */
4023 #include <libc/bss.h>
4025 /* A counter to know when to re-initialize the static sets. */
4026 static int sigprocmask_count
= -1;
4028 /* Which signals are currently blocked (initially none). */
4029 static sigset_t current_mask
;
4031 /* Which signals are pending (initially none). */
4032 static sigset_t msdos_pending_signals
;
4034 /* Previous handlers to restore when the blocked signals are unblocked. */
4035 typedef void (*sighandler_t
)(int);
4036 static sighandler_t prev_handlers
[320];
4038 /* A signal handler which just records that a signal occurred
4039 (it will be raised later, if and when the signal is unblocked). */
4041 sig_suspender (int signo
)
4043 sigaddset (&msdos_pending_signals
, signo
);
4047 sigprocmask (int how
, const sigset_t
*new_set
, sigset_t
*old_set
)
4052 /* If called for the first time, initialize. */
4053 if (sigprocmask_count
!= __bss_count
)
4055 sigprocmask_count
= __bss_count
;
4056 sigemptyset (&msdos_pending_signals
);
4057 sigemptyset (¤t_mask
);
4058 for (signo
= 0; signo
< 320; signo
++)
4059 prev_handlers
[signo
] = SIG_ERR
;
4063 *old_set
= current_mask
;
4068 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
4074 sigemptyset (&new_mask
);
4076 /* DJGPP supports upto 320 signals. */
4077 for (signo
= 0; signo
< 320; signo
++)
4079 if (sigismember (¤t_mask
, signo
))
4080 sigaddset (&new_mask
, signo
);
4081 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
4083 sigaddset (&new_mask
, signo
);
4085 /* SIGKILL is silently ignored, as on other platforms. */
4086 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
4087 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
4089 if (( how
== SIG_UNBLOCK
4090 && sigismember (&new_mask
, signo
)
4091 && sigismember (new_set
, signo
))
4092 || (how
== SIG_SETMASK
4093 && sigismember (&new_mask
, signo
)
4094 && !sigismember (new_set
, signo
)))
4096 sigdelset (&new_mask
, signo
);
4097 if (prev_handlers
[signo
] != SIG_ERR
)
4099 signal (signo
, prev_handlers
[signo
]);
4100 prev_handlers
[signo
] = SIG_ERR
;
4102 if (sigismember (&msdos_pending_signals
, signo
))
4104 sigdelset (&msdos_pending_signals
, signo
);
4109 current_mask
= new_mask
;
4113 #endif /* not __DJGPP_MINOR__ < 2 */
4116 #include "sysselect.h"
4118 /* This yields the rest of the current time slice to the task manager.
4119 It should be called by any code which knows that it has nothing
4120 useful to do except idle.
4122 I don't use __dpmi_yield here, since versions of library before 2.02
4123 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
4124 on some versions of Windows 9X. */
4127 dos_yield_time_slice (void)
4129 _go32_dpmi_registers r
;
4132 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
4133 _go32_dpmi_simulate_int (0x2f, &r
);
4138 /* Only event queue is checked. */
4139 /* We don't have to call timer_check here
4140 because wait_reading_process_output takes care of that. */
4142 sys_select (int nfds
, fd_set
*rfds
, fd_set
*wfds
, fd_set
*efds
,
4143 struct timespec
*timeout
, void *ignored
)
4151 check_input
= FD_ISSET (0, rfds
);
4162 /* If we are looking only for the terminal, with no timeout,
4163 just read it and wait -- that's more efficient. */
4166 while (!detect_input_pending ())
4168 dos_yield_time_slice ();
4173 struct timespec clnow
, cllast
, cldiff
;
4176 cllast
= make_timespec (t
.tv_sec
, t
.tv_nsec
);
4178 while (!check_input
|| !detect_input_pending ())
4181 clnow
= make_timespec (t
.tv_sec
, t
.tv_nsec
);
4182 cldiff
= timespec_sub (clnow
, cllast
);
4183 *timeout
= timespec_sub (*timeout
, cldiff
);
4185 /* Stop when timeout value crosses zero. */
4186 if (timespec_sign (*timeout
) <= 0)
4189 dos_yield_time_slice ();
4199 * Define overlaid functions:
4201 * chdir -> sys_chdir
4202 * tzset -> init_gettimeofday
4203 * abort -> dos_abort
4208 extern int chdir (const char *);
4211 sys_chdir (const char *path
)
4213 int len
= strlen (path
);
4214 char *tmp
= (char *)path
;
4216 if (*tmp
&& tmp
[1] == ':')
4218 if (getdisk () != tolower (tmp
[0]) - 'a')
4219 setdisk (tolower (tmp
[0]) - 'a');
4220 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
4224 if (len
> 1 && (tmp
[len
- 1] == '/'))
4226 char *tmp1
= (char *) alloca (len
+ 1);
4237 extern void tzset (void);
4240 init_gettimeofday (void)
4246 ltm
= gtm
= time (NULL
);
4247 ltm
= mktime (lstm
= localtime (<m
));
4248 gtm
= mktime (gmtime (>m
));
4249 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
4250 time_rec
.tm_isdst
= lstm
->tm_isdst
;
4251 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
4259 ScreenSetCursor (10, 0);
4260 cputs ("\r\n\nEmacs aborted!\r\n");
4261 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4262 if (screen_virtual_segment
)
4263 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
4264 /* Generate traceback, so we could tell whodunit. */
4265 signal (SIGINT
, SIG_DFL
);
4266 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4267 #else /* __DJGPP_MINOR__ >= 2 */
4269 #endif /* __DJGPP_MINOR__ >= 2 */
4274 msdos_fatal_signal (int sig
)
4283 syms_of_msdos (void)
4285 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
4286 staticpro (&recent_doskeys
);
4288 #ifndef HAVE_X_WINDOWS
4290 /* The following two are from xfns.c: */
4291 DEFSYM (Qreverse
, "reverse");
4293 DEFVAR_LISP ("dos-unsupported-char-glyph", Vdos_unsupported_char_glyph
,
4294 doc
: /* Glyph to display instead of chars not supported by current codepage.
4295 This variable is used only by MS-DOS terminals. */);
4296 Vdos_unsupported_char_glyph
= make_number ('\177');
4300 defsubr (&Srecent_doskeys
);
4301 defsubr (&Smsdos_long_file_names
);
4302 defsubr (&Smsdos_downcase_filename
);
4303 defsubr (&Smsdos_remember_default_colors
);
4304 defsubr (&Smsdos_set_mouse_buttons
);