1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 94, 95, 96, 97, 1999 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
33 #include <sys/param.h>
37 #include <string.h> /* for bzero and string functions */
38 #include <sys/stat.h> /* for _fixpath */
39 #include <unistd.h> /* for chdir, dup, dup2, etc. */
42 #include <io.h> /* for setmode */
43 #include <dpmi.h> /* for __dpmi_xxx stuff */
44 #include <sys/farptr.h> /* for _farsetsel, _farnspokeb */
45 #include <libc/dosio.h> /* for _USE_LFN */
46 #include <conio.h> /* for cputs */
51 #include "termhooks.h"
53 #include "dispextern.h"
66 /* #include <process.h> */
67 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
75 #define _dos_ds _go32_info_block.selector_for_linear_memory
81 #include "syssignal.h"
87 /* If other `malloc' than ours is used, force our `sbrk' behave like
88 Unix programs expect (resize memory blocks to keep them contiguous).
89 If `sbrk' from `ralloc.c' is NOT used, also zero-out sbrk'ed memory,
90 because that's what `gmalloc' expects to get. */
94 int _crt0_startup_flags
= _CRT0_FLAG_UNIX_SBRK
;
95 #else /* not REL_ALLOC */
96 int _crt0_startup_flags
= (_CRT0_FLAG_UNIX_SBRK
| _CRT0_FLAG_FILL_SBRK_MEMORY
);
97 #endif /* not REL_ALLOC */
98 #endif /* GNU_MALLOC */
100 #endif /* not SYSTEM_MALLOC */
101 #endif /* __DJGPP__ > 1 */
120 /* ------------------------ Mouse control ---------------------------
122 * Coordinates are in screen positions and zero based.
123 * Mouse buttons are numbered from left to right and also zero based.
126 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
127 static int mouse_visible
;
129 static int mouse_last_x
;
130 static int mouse_last_y
;
132 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
133 static int mouse_button_count
;
140 if (have_mouse
> 0 && !mouse_visible
)
143 fprintf (termscript
, "<M_ON>");
145 int86 (0x33, ®s
, ®s
);
155 if (have_mouse
> 0 && mouse_visible
)
158 fprintf (termscript
, "<M_OFF>");
160 int86 (0x33, ®s
, ®s
);
166 mouse_get_xy (int *x
, int *y
)
171 int86 (0x33, ®s
, ®s
);
183 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
185 mouse_last_x
= regs
.x
.cx
= x
* 8;
186 mouse_last_y
= regs
.x
.dx
= y
* 8;
187 int86 (0x33, ®s
, ®s
);
191 mouse_pressed (b
, xp
, yp
)
196 if (b
>= mouse_button_count
)
199 regs
.x
.bx
= mouse_button_translate
[b
];
200 int86 (0x33, ®s
, ®s
);
202 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
203 return (regs
.x
.bx
!= 0);
207 mouse_released (b
, xp
, yp
)
212 if (b
>= mouse_button_count
)
215 regs
.x
.bx
= mouse_button_translate
[b
];
216 int86 (0x33, ®s
, ®s
);
218 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
219 return (regs
.x
.bx
!= 0);
223 mouse_button_depressed (b
, xp
, yp
)
228 if (b
>= mouse_button_count
)
231 int86 (0x33, ®s
, ®s
);
232 if ((regs
.x
.bx
& (1 << mouse_button_translate
[b
])) != 0)
242 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
245 Lisp_Object
*bar_window
, *x
, *y
;
246 enum scroll_bar_part
*part
;
250 Lisp_Object frame
, tail
;
252 /* Clear the mouse-moved flag for every frame on this display. */
253 FOR_EACH_FRAME (tail
, frame
)
254 XFRAME (frame
)->mouse_moved
= 0;
258 mouse_get_xy (&ix
, &iy
);
259 *time
= event_timestamp ();
260 *x
= make_number (mouse_last_x
= ix
);
261 *y
= make_number (mouse_last_y
= iy
);
269 mouse_get_xy (&x
, &y
);
270 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
282 fprintf (termscript
, "<M_INIT>");
285 int86 (0x33, ®s
, ®s
);
287 /* Reset the mouse last press/release info. It seems that Windows
288 doesn't do that automatically when function 21h is called, which
289 causes Emacs to ``remember'' the click that switched focus to the
290 window just before Emacs was started from that window. */
291 for (b
= 0; b
< mouse_button_count
; b
++)
293 int dummy_x
, dummy_y
;
295 (void) mouse_pressed (b
, &dummy_x
, &dummy_y
);
296 (void) mouse_released (b
, &dummy_x
, &dummy_y
);
301 regs
.x
.dx
= 8 * (ScreenCols () - 1);
302 int86 (0x33, ®s
, ®s
);
306 regs
.x
.dx
= 8 * (ScreenRows () - 1);
307 int86 (0x33, ®s
, ®s
);
313 /* ------------------------- Screen control ----------------------
317 static int internal_terminal
= 0;
319 #ifndef HAVE_X_WINDOWS
320 extern unsigned char ScreenAttrib
;
321 static int screen_face
;
322 static int highlight
;
324 static int screen_size_X
;
325 static int screen_size_Y
;
326 static int screen_size
;
328 static int current_pos_X
;
329 static int current_pos_Y
;
330 static int new_pos_X
;
331 static int new_pos_Y
;
333 static void *startup_screen_buffer
;
334 static int startup_screen_size_X
;
335 static int startup_screen_size_Y
;
336 static int startup_pos_X
;
337 static int startup_pos_Y
;
338 static unsigned char startup_screen_attrib
;
340 static clock_t startup_time
;
342 static int term_setup_done
;
344 /* Similar to the_only_frame. */
345 struct x_output the_only_x_display
;
347 /* This is never dereferenced. */
348 Display
*x_current_display
;
350 /* Support for DOS/V (allows Japanese characters to be displayed on
351 standard, non-Japanese, ATs). Only supported for DJGPP v2 and later. */
353 /* Holds the address of the text-mode screen buffer. */
354 static unsigned long screen_old_address
= 0;
355 /* Segment and offset of the virtual screen. If 0, DOS/V is NOT loaded. */
356 static unsigned short screen_virtual_segment
= 0;
357 static unsigned short screen_virtual_offset
= 0;
358 /* A flag to control how to display unibyte 8-bit characters. */
359 extern int unibyte_display_via_language_environment
;
362 /* Update the screen from a part of relocated DOS/V screen buffer which
363 begins at OFFSET and includes COUNT characters. */
365 dosv_refresh_virtual_screen (int offset
, int count
)
369 if (offset
< 0 || count
< 0) /* paranoia; illegal values crash DOS/V */
372 regs
.h
.ah
= 0xff; /* update relocated screen */
373 regs
.x
.es
= screen_virtual_segment
;
374 regs
.x
.di
= screen_virtual_offset
+ offset
;
376 __dpmi_int (0x10, ®s
);
381 dos_direct_output (y
, x
, buf
, len
)
387 int t0
= 2 * (x
+ y
* screen_size_X
);
388 int t
= t0
+ (int) ScreenPrimary
;
393 dosmemput (buf
++, 1, t
);
397 /* This is faster. */
398 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
399 _farnspokeb (t
, *buf
);
401 if (screen_virtual_segment
)
402 dosv_refresh_virtual_screen (t0
, l0
);
407 /* Flash the screen as a substitute for BEEPs. */
411 do_visible_bell (xorattr
)
412 unsigned char xorattr
;
417 movl _ScreenPrimary,%%eax
424 xorb %%al,%%gs:(%%ebx)
440 : "m" (xorattr
), "g" (screen_size
)
441 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
445 ScreenVisualBell (void)
447 /* This creates an xor-mask that will swap the default fore- and
448 background colors. */
449 do_visible_bell (((the_only_x_display
.foreground_pixel
450 ^ the_only_x_display
.background_pixel
)
455 #ifndef HAVE_X_WINDOWS
457 static int blink_bit
= -1; /* the state of the blink bit at startup */
459 /* Enable bright background colors. */
465 /* Remember the original state of the blink/bright-background bit.
466 It is stored at 0040:0065h in the BIOS data area. */
468 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
472 int86 (0x10, ®s
, ®s
);
475 /* Disable bright background colors (and enable blinking) if we found
476 the video system in that state at startup. */
478 maybe_enable_blinking (void)
486 int86 (0x10, ®s
, ®s
);
490 /* Set the screen dimensions so that it can show no less than
491 ROWS x COLS frame. */
494 dos_set_window_size (rows
, cols
)
498 Lisp_Object video_mode
;
499 int video_mode_value
;
502 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
504 if (*rows
== current_rows
&& *cols
== current_cols
)
507 /* Do we have a VGA? */
509 int86 (0x10, ®s
, ®s
);
510 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
515 /* If the user specified a special video mode for these dimensions,
517 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
518 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
521 if (INTEGERP (video_mode
)
522 && (video_mode_value
= XINT (video_mode
)) > 0)
524 regs
.x
.ax
= video_mode_value
;
525 int86 (0x10, ®s
, ®s
);
529 /* Must hardware-reset the mouse, or else it won't update
530 its notion of screen dimensions for some non-standard
531 video modes. This is *painfully* slow... */
533 int86 (0x33, ®s
, ®s
);
537 /* Find one of the dimensions supported by standard EGA/VGA
538 which gives us at least the required dimensions. */
547 } std_dimension
[] = {
557 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
559 if (std_dimension
[i
].need_vga
<= have_vga
560 && std_dimension
[i
].rows
>= *rows
)
562 if (std_dimension
[i
].rows
!= current_rows
563 || *cols
!= current_cols
)
564 _set_screen_lines (std_dimension
[i
].rows
);
571 #else /* not __DJGPP__ > 1 */
573 else if (*rows
<= 25)
575 if (current_rows
!= 25 || current_cols
!= 80)
578 int86 (0x10, ®s
, ®s
);
581 int86 (0x10, ®s
, ®s
);
584 int86 (0x10, ®s
, ®s
);
586 int86 (0x10, ®s
, ®s
);
589 else if (*rows
<= 50)
590 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
591 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
594 int86 (0x10, ®s
, ®s
);
597 int86 (0x10, ®s
, ®s
);
600 int86 (0x10, ®s
, ®s
);
603 int86 (0x10, ®s
, ®s
);
605 #endif /* not __DJGPP__ > 1 */
613 /* Tell the caller what dimensions have been REALLY set. */
614 *rows
= ScreenRows ();
615 *cols
= ScreenCols ();
617 /* Enable bright background colors. */
620 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
621 be defensive anyway. */
622 if (screen_virtual_segment
)
623 dosv_refresh_virtual_screen (0, *cols
* *rows
);
626 /* If we write a character in the position where the mouse is,
627 the mouse cursor may need to be refreshed. */
637 mouse_get_xy (&x
, &y
);
638 if (y
!= new_pos_Y
|| x
< new_pos_X
)
654 union REGS inregs
, outregs
;
657 intdos (&inregs
, &outregs
);
661 /* Given a face id FACE, extract the face parameters to be used for
662 display until the face changes. The face parameters (actually, its
663 color) are used to construct the video attribute byte for each
664 glyph during the construction of the buffer that is then blitted to
667 IT_set_face (int face
)
669 struct face
*fp
= FACE_FROM_ID (selected_frame
, face
);
670 unsigned long fg
, bg
;
674 fp
= FACE_FROM_ID (selected_frame
, DEFAULT_FACE_ID
);
675 /* The default face for the frame should always be realized and
684 /* Don't use invalid colors. In particular, a color of -1 means use
685 the colors of the default face, except that if highlight is on,
686 invert the foreground and the background. Note that we assume
687 all 16 colors to be available for the background, since Emacs
688 switches on this mode (and loses the blinking attribute) at
690 if (fg
== (unsigned long)-1)
691 fg
= highlight
? FRAME_BACKGROUND_PIXEL (selected_frame
)
692 : FRAME_FOREGROUND_PIXEL (selected_frame
);
693 if (bg
== (unsigned long)-1)
694 bg
= highlight
? FRAME_FOREGROUND_PIXEL (selected_frame
)
695 : FRAME_BACKGROUND_PIXEL (selected_frame
);
697 fprintf (termscript
, "<FACE %d%s: %d/%d>",
698 face
, highlight
? "H" : "", fp
->foreground
, fp
->background
);
699 if (fg
>= 0 && fg
< 16)
701 ScreenAttrib
&= 0xf0;
704 if (bg
>= 0 && bg
< 16)
706 ScreenAttrib
&= 0x0f;
707 ScreenAttrib
|= ((bg
& 0x0f) << 4);
711 Lisp_Object Vdos_unsupported_char_glyph
;
714 IT_write_glyphs (struct glyph
*str
, int str_len
)
716 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
717 int unsupported_face
= FAST_GLYPH_FACE (Vdos_unsupported_char_glyph
);
718 unsigned unsupported_char
= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph
);
719 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
720 register int sl
= str_len
;
721 register int tlen
= GLYPH_TABLE_LENGTH
;
722 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
724 struct coding_system
*coding
= (CODING_REQUIRE_ENCODING (&terminal_coding
)
726 : &safe_terminal_coding
);
728 /* Do we need to consider conversion of unibyte characters to
730 int convert_unibyte_characters
731 = (NILP (current_buffer
->enable_multibyte_characters
)
732 && unibyte_display_via_language_environment
);
734 if (str_len
== 0) return;
736 screen_buf
= screen_bp
= alloca (str_len
* 2);
737 screen_buf_end
= screen_buf
+ str_len
* 2;
739 /* Since faces get cached and uncached behind our back, we can't
740 rely on their indices in the cache being consistent across
741 invocations. So always reset the screen face to the default
742 face of the frame, before writing glyphs, and let the glyphs
743 set the right face if it's different from the default. */
744 IT_set_face (DEFAULT_FACE_ID
);
746 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
748 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
751 int cf
, chlen
, enclen
;
752 unsigned char workbuf
[4], *buf
;
754 register GLYPH g
= GLYPH_FROM_CHAR_GLYPH (*str
);
756 /* Find the actual glyph to display by traversing the entire
757 aliases chain for this glyph. */
758 GLYPH_FOLLOW_ALIASES (tbase
, tlen
, g
);
760 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
761 only for the redisplay code to know how many columns does
762 this character occupy on the screen. Skip padding glyphs. */
763 if (CHAR_GLYPH_PADDING_P (*str
))
770 /* Convert the character code to multibyte, if they
771 requested display via language environment. */
772 ch
= FAST_GLYPH_CHAR (g
);
773 /* We only want to convert unibyte characters to multibyte
774 in unibyte buffers! Otherwise, the 8-bit code might come
775 from the display table set up to display foreign characters. */
776 if (SINGLE_BYTE_CHAR_P (ch
) && convert_unibyte_characters
778 || (ch
>= 0200 && !NILP (Vnonascii_translation_table
))))
779 ch
= unibyte_char_to_multibyte (ch
);
781 /* Invalid characters are displayed with a special glyph. */
782 if (! GLYPH_CHAR_VALID_P (ch
))
784 g
= !NILP (Vdos_unsupported_char_glyph
)
785 ? Vdos_unsupported_char_glyph
786 : MAKE_GLYPH (selected_frame
, '\177',
787 GLYPH_FACE (selected_frame
, g
));
788 ch
= FAST_GLYPH_CHAR (g
);
790 if (COMPOSITE_CHAR_P (ch
))
792 /* If CH is a composite character, we can display
793 only the first component. */
794 g
= cmpchar_table
[COMPOSITE_CHAR_ID (ch
)]->glyph
[0],
795 ch
= GLYPH_CHAR (selected_frame
, g
);
796 cf
= FAST_GLYPH_FACE (g
);
799 /* If the face of this glyph is different from the current
800 screen face, update the screen attribute byte. */
801 cf
= FAST_GLYPH_FACE (g
);
802 if (cf
!= screen_face
)
803 IT_set_face (cf
); /* handles invalid faces gracefully */
805 if (GLYPH_SIMPLE_P (tbase
, tlen
, g
))
806 /* We generate the multi-byte form of CH in BUF. */
807 chlen
= CHAR_STRING (ch
, workbuf
, buf
);
810 /* We have a string in Vglyph_table. */
811 chlen
= GLYPH_LENGTH (tbase
, g
);
812 buf
= GLYPH_STRING (tbase
, g
);
815 /* If the character is not multibyte, don't bother converting it. */
818 *conversion_buffer
= (unsigned char)ch
;
824 encode_coding (coding
, buf
, conversion_buffer
, chlen
,
825 conversion_buffer_size
);
826 chlen
-= coding
->consumed
;
827 enclen
= coding
->produced
;
829 /* Replace glyph codes that cannot be converted by
830 terminal_coding with Vdos_unsupported_char_glyph. */
831 if (*conversion_buffer
== '?')
833 char *cbp
= conversion_buffer
;
835 while (cbp
< conversion_buffer
+ enclen
&& *cbp
== '?')
836 *cbp
++ = unsupported_char
;
837 if (unsupported_face
!= screen_face
)
838 IT_set_face (unsupported_face
);
842 if (enclen
+ chlen
> screen_buf_end
- screen_bp
)
844 /* The allocated buffer for screen writes is too small.
845 Flush it and loop again without incrementing STR, so
846 that the next loop will begin with the same glyph. */
847 int nbytes
= screen_bp
- screen_buf
;
850 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
851 if (screen_virtual_segment
)
852 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
853 new_pos_X
+= nbytes
/ 2;
856 /* Prepare to reuse the same buffer again. */
857 screen_bp
= screen_buf
;
861 /* There's enough place in the allocated buffer to add
862 the encoding of this glyph. */
864 /* First, copy the encoded bytes. */
865 for (bp
= conversion_buffer
; enclen
--; bp
++)
867 *screen_bp
++ = (unsigned char)*bp
;
868 *screen_bp
++ = ScreenAttrib
;
870 fputc (*bp
, termscript
);
873 /* Now copy the bytes not consumed by the encoding. */
876 buf
+= coding
->consumed
;
880 fputc (*buf
, termscript
);
881 *screen_bp
++ = (unsigned char)*buf
++;
882 *screen_bp
++ = ScreenAttrib
;
886 /* Update STR and its remaining length. */
893 /* Dump whatever is left in the screen buffer. */
895 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
896 if (screen_virtual_segment
)
897 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
898 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
900 /* We may have to output some codes to terminate the writing. */
901 if (CODING_REQUIRE_FLUSHING (coding
))
903 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
904 encode_coding (coding
, "", conversion_buffer
, 0, conversion_buffer_size
);
905 if (coding
->produced
> 0)
907 for (screen_bp
= screen_buf
, bp
= conversion_buffer
;
908 coding
->produced
--; bp
++)
910 *screen_bp
++ = (unsigned char)*bp
;
911 *screen_bp
++ = ScreenAttrib
;
913 fputc (*bp
, termscript
);
915 offset
+= screen_bp
- screen_buf
;
917 dosmemput (screen_buf
, screen_bp
- screen_buf
,
918 (int)ScreenPrimary
+ offset
);
919 if (screen_virtual_segment
)
920 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
921 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
927 IT_clear_end_of_line (int first_unused
)
931 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
932 extern int fatal_error_in_progress
;
934 if (fatal_error_in_progress
)
939 fprintf (termscript
, "<CLR:EOL>");
940 i
= (j
= screen_size_X
- new_pos_X
) * 2;
941 spaces
= sp
= alloca (i
);
946 *sp
++ = ScreenAttrib
;
950 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
951 if (screen_virtual_segment
)
952 dosv_refresh_virtual_screen (offset
, i
/ 2);
956 IT_clear_screen (void)
959 fprintf (termscript
, "<CLR:SCR>");
963 if (screen_virtual_segment
)
964 dosv_refresh_virtual_screen (0, screen_size
);
965 new_pos_X
= new_pos_Y
= 0;
969 IT_clear_to_end (void)
972 fprintf (termscript
, "<CLR:EOS>");
974 while (new_pos_Y
< screen_size_Y
) {
976 IT_clear_end_of_line (0);
982 IT_cursor_to (int y
, int x
)
985 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
990 static int cursor_cleared
;
993 IT_display_cursor (int on
)
995 if (on
&& cursor_cleared
)
997 ScreenSetCursor (current_pos_Y
, current_pos_X
);
1000 else if (!on
&& !cursor_cleared
)
1002 ScreenSetCursor (-1, -1);
1007 /* Emacs calls cursor-movement functions a lot when it updates the
1008 display (probably a legacy of old terminals where you cannot
1009 update a screen line without first moving the cursor there).
1010 However, cursor movement is expensive on MSDOS (it calls a slow
1011 BIOS function and requires 2 mode switches), while actual screen
1012 updates access the video memory directly and don't depend on
1013 cursor position. To avoid slowing down the redisplay, we cheat:
1014 all functions that move the cursor only set internal variables
1015 which record the cursor position, whereas the cursor is only
1016 moved to its final position whenever screen update is complete.
1018 `IT_cmgoto' is called from the keyboard reading loop and when the
1019 frame update is complete. This means that we are ready for user
1020 input, so we update the cursor position to show where the point is,
1021 and also make the mouse pointer visible.
1023 Special treatment is required when the cursor is in the echo area,
1024 to put the cursor at the end of the text displayed there. */
1027 IT_cmgoto (FRAME_PTR f
)
1029 /* Only set the cursor to where it should be if the display is
1030 already in sync with the window contents. */
1031 int update_cursor_pos
= MODIFF
== unchanged_modified
;
1032 static int previous_pos_X
= -1;
1034 /* If the display is in sync, forget any previous knowledge about
1035 cursor position. This is primarily for unexpected events like
1036 C-g in the minibuffer. */
1037 if (update_cursor_pos
&& previous_pos_X
>= 0)
1038 previous_pos_X
= -1;
1039 /* If we are in the echo area, put the cursor at the
1040 end of the echo area message. */
1041 if (!update_cursor_pos
1042 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1044 int tem_X
= current_pos_X
, dummy
;
1046 if (echo_area_glyphs
)
1048 tem_X
= echo_area_glyphs_length
;
1049 /* Save current cursor position, to be restored after the
1050 echo area message is erased. Only remember one level
1051 of previous cursor position. */
1052 if (previous_pos_X
== -1)
1053 ScreenGetCursor (&dummy
, &previous_pos_X
);
1055 else if (previous_pos_X
>= 0)
1057 /* We wind up here after the echo area message is erased.
1058 Restore the cursor position we remembered above. */
1059 tem_X
= previous_pos_X
;
1060 previous_pos_X
= -1;
1063 if (current_pos_X
!= tem_X
)
1066 update_cursor_pos
= 1;
1070 if (update_cursor_pos
1071 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1073 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1075 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1078 /* Maybe cursor is invisible, so make it visible. */
1079 IT_display_cursor (1);
1081 /* Mouse pointer should be always visible if we are waiting for
1088 IT_reassert_line_highlight (int new, int vpos
)
1091 IT_set_face (0); /* To possibly clear the highlighting. */
1095 IT_change_line_highlight (int new_highlight
, int y
, int vpos
, int first_unused_hpos
)
1097 highlight
= new_highlight
;
1098 IT_set_face (0); /* To possibly clear the highlighting. */
1099 IT_cursor_to (vpos
, 0);
1100 IT_clear_end_of_line (first_unused_hpos
);
1104 IT_update_begin (struct frame
*foo
)
1107 IT_set_face (0); /* To possibly clear the highlighting. */
1112 IT_update_end (struct frame
*foo
)
1116 /* Copy LEN glyphs displayed on a single line whose vertical position
1117 is YPOS, beginning at horizontal position XFROM to horizontal
1118 position XTO, by moving blocks in the video memory. Used by
1119 functions that insert and delete glyphs. */
1121 IT_copy_glyphs (int xfrom
, int xto
, size_t len
, int ypos
)
1123 /* The offsets of source and destination relative to the
1124 conventional memorty selector. */
1125 int from
= 2 * (xfrom
+ screen_size_X
* ypos
) + ScreenPrimary
;
1126 int to
= 2 * (xto
+ screen_size_X
* ypos
) + ScreenPrimary
;
1128 if (from
== to
|| len
<= 0)
1131 _farsetsel (_dos_ds
);
1133 /* The source and destination might overlap, so we need to move
1134 glyphs non-destructively. */
1137 for ( ; len
; from
+= 2, to
+= 2, len
--)
1138 _farnspokew (to
, _farnspeekw (from
));
1142 from
+= (len
- 1) * 2;
1143 to
+= (len
- 1) * 2;
1144 for ( ; len
; from
-= 2, to
-= 2, len
--)
1145 _farnspokew (to
, _farnspeekw (from
));
1147 if (screen_virtual_segment
)
1148 dosv_refresh_virtual_screen (ypos
* screen_size_X
* 2, screen_size_X
);
1151 /* Insert and delete glyphs. */
1153 IT_insert_glyphs (start
, len
)
1154 register struct glyph
*start
;
1157 int shift_by_width
= screen_size_X
- (new_pos_X
+ len
);
1159 /* Shift right the glyphs from the nominal cursor position to the
1160 end of this line. */
1161 IT_copy_glyphs (new_pos_X
, new_pos_X
+ len
, shift_by_width
, new_pos_Y
);
1163 /* Now write the glyphs to be inserted. */
1164 IT_write_glyphs (start
, len
);
1168 IT_delete_glyphs (n
)
1174 /* set-window-configuration on window.c needs this. */
1176 x_set_menu_bar_lines (f
, value
, oldval
)
1178 Lisp_Object value
, oldval
;
1180 set_menu_bar_lines (f
, value
, oldval
);
1183 /* This was copied from xfns.c */
1185 Lisp_Object Qbackground_color
;
1186 Lisp_Object Qforeground_color
;
1187 extern Lisp_Object Qtitle
;
1189 /* IT_set_terminal_modes is called when emacs is started,
1190 resumed, and whenever the screen is redrawn! */
1193 IT_set_terminal_modes (void)
1196 fprintf (termscript
, "\n<SET_TERM>");
1199 screen_size_X
= ScreenCols ();
1200 screen_size_Y
= ScreenRows ();
1201 screen_size
= screen_size_X
* screen_size_Y
;
1203 new_pos_X
= new_pos_Y
= 0;
1204 current_pos_X
= current_pos_Y
= -1;
1206 if (term_setup_done
)
1208 term_setup_done
= 1;
1210 startup_screen_size_X
= screen_size_X
;
1211 startup_screen_size_Y
= screen_size_Y
;
1212 startup_screen_attrib
= ScreenAttrib
;
1215 /* Is DOS/V (or any other RSIS software which relocates
1216 the screen) installed? */
1218 unsigned short es_value
;
1221 regs
.h
.ah
= 0xfe; /* get relocated screen address */
1222 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
1223 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
1224 else if (screen_old_address
) /* already switched to Japanese mode once */
1225 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
1227 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
1229 es_value
= regs
.x
.es
;
1230 __dpmi_int (0x10, ®s
);
1232 if (regs
.x
.es
!= es_value
)
1234 /* screen_old_address is only set if ScreenPrimary does NOT
1235 already point to the relocated buffer address returned by
1236 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1237 ScreenPrimary to that address at startup under DOS/V. */
1238 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
1239 screen_old_address
= ScreenPrimary
;
1240 screen_virtual_segment
= regs
.x
.es
;
1241 screen_virtual_offset
= regs
.x
.di
;
1242 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
1245 #endif /* __DJGPP__ > 1 */
1247 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
1248 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
1251 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1252 screen_size_X
, screen_size_Y
);
1257 /* IT_reset_terminal_modes is called when emacs is
1258 suspended or killed. */
1261 IT_reset_terminal_modes (void)
1263 int display_row_start
= (int) ScreenPrimary
;
1264 int saved_row_len
= startup_screen_size_X
* 2;
1265 int update_row_len
= ScreenCols () * 2;
1266 int current_rows
= ScreenRows ();
1267 int to_next_row
= update_row_len
;
1268 unsigned char *saved_row
= startup_screen_buffer
;
1269 int cursor_pos_X
= ScreenCols () - 1;
1270 int cursor_pos_Y
= ScreenRows () - 1;
1273 fprintf (termscript
, "\n<RESET_TERM>");
1277 if (!term_setup_done
)
1282 /* Leave the video system in the same state as we found it,
1283 as far as the blink/bright-background bit is concerned. */
1284 maybe_enable_blinking ();
1286 /* We have a situation here.
1287 We cannot just do ScreenUpdate(startup_screen_buffer) because
1288 the luser could have changed screen dimensions inside Emacs
1289 and failed (or didn't want) to restore them before killing
1290 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1291 thus will happily use memory outside what was allocated for
1292 `startup_screen_buffer'.
1293 Thus we only restore as much as the current screen dimensions
1294 can hold, and clear the rest (if the saved screen is smaller than
1295 the current) with the color attribute saved at startup. The cursor
1296 is also restored within the visible dimensions. */
1298 ScreenAttrib
= startup_screen_attrib
;
1300 /* Don't restore the screen if we are exiting less than 2 seconds
1301 after startup: we might be crashing, and the screen might show
1302 some vital clues to what's wrong. */
1303 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
1306 if (screen_virtual_segment
)
1307 dosv_refresh_virtual_screen (0, screen_size
);
1309 if (update_row_len
> saved_row_len
)
1310 update_row_len
= saved_row_len
;
1311 if (current_rows
> startup_screen_size_Y
)
1312 current_rows
= startup_screen_size_Y
;
1315 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1316 update_row_len
/ 2, current_rows
);
1318 while (current_rows
--)
1320 dosmemput (saved_row
, update_row_len
, display_row_start
);
1321 if (screen_virtual_segment
)
1322 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
1323 update_row_len
/ 2);
1324 saved_row
+= saved_row_len
;
1325 display_row_start
+= to_next_row
;
1328 if (startup_pos_X
< cursor_pos_X
)
1329 cursor_pos_X
= startup_pos_X
;
1330 if (startup_pos_Y
< cursor_pos_Y
)
1331 cursor_pos_Y
= startup_pos_Y
;
1333 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
1334 xfree (startup_screen_buffer
);
1336 term_setup_done
= 0;
1340 IT_set_terminal_window (int foo
)
1345 IT_set_frame_parameters (f
, alist
)
1350 int length
= XINT (Flength (alist
));
1353 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1355 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1357 struct face
*dflt
= NULL
;
1359 if (FRAME_FACE_CACHE (f
))
1360 dflt
= FACE_FROM_ID (f
, DEFAULT_FACE_ID
);
1364 /* Extract parm names and values into those vectors. */
1366 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
1371 parms
[i
] = Fcar (elt
);
1372 CHECK_SYMBOL (parms
[i
], 1);
1373 values
[i
] = Fcdr (elt
);
1378 /* Now process them in reverse of specified order. */
1379 for (i
--; i
>= 0; i
--)
1381 Lisp_Object prop
= parms
[i
];
1382 Lisp_Object val
= values
[i
];
1384 if (EQ (prop
, Qforeground_color
))
1386 unsigned long new_color
= load_color (f
, NULL
, val
,
1387 LFACE_FOREGROUND_INDEX
);
1388 if (new_color
!= ~0)
1392 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1393 dflt
->foreground
= new_color
;
1396 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
1399 else if (EQ (prop
, Qbackground_color
))
1401 unsigned long new_color
= load_color (f
, NULL
, val
,
1402 LFACE_BACKGROUND_INDEX
);
1403 if (new_color
!= ~0)
1407 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1408 dflt
->background
= new_color
;
1411 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
1414 else if (EQ (prop
, Qtitle
))
1416 x_set_title (f
, val
);
1418 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
1420 else if (EQ (prop
, intern ("reverse")) && EQ (val
, Qt
))
1422 unsigned long fg
= FRAME_FOREGROUND_PIXEL (f
);
1426 FRAME_FOREGROUND_PIXEL (f
) = FRAME_BACKGROUND_PIXEL (f
); /* FIXME! */
1427 FRAME_BACKGROUND_PIXEL (f
) = fg
;
1428 dflt
->foreground
= FRAME_FOREGROUND_PIXEL (f
);
1429 dflt
->foreground
= fg
;
1431 fprintf (termscript
, "<INVERSE-VIDEO>\n");
1433 store_frame_param (f
, prop
, val
);
1439 recompute_basic_faces (f
);
1440 if (f
== selected_frame
)
1445 extern void init_frame_faces (FRAME_PTR
);
1447 #endif /* !HAVE_X_WINDOWS */
1450 /* Do we need the internal terminal? */
1453 internal_terminal_init ()
1455 char *term
= getenv ("TERM");
1458 #ifdef HAVE_X_WINDOWS
1459 if (!inhibit_window_system
)
1464 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1466 if (getenv ("EMACSTEST"))
1467 termscript
= fopen (getenv ("EMACSTEST"), "wt");
1469 #ifndef HAVE_X_WINDOWS
1470 if (!internal_terminal
|| inhibit_window_system
)
1472 selected_frame
->output_method
= output_termcap
;
1476 Vwindow_system
= intern ("pc");
1477 Vwindow_system_version
= make_number (1);
1479 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1480 screen_old_address
= 0;
1482 bzero (&the_only_x_display
, sizeof the_only_x_display
);
1483 the_only_x_display
.background_pixel
= 7; /* White */
1484 the_only_x_display
.foreground_pixel
= 0; /* Black */
1486 colors
= getenv ("EMACSCOLORS");
1487 if (colors
&& strlen (colors
) >= 2)
1489 /* The colors use 4 bits each (we enable bright background). */
1490 if (isdigit (colors
[0]))
1492 else if (isxdigit (colors
[0]))
1493 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1494 if (colors
[0] >= 0 && colors
[0] < 16)
1495 the_only_x_display
.foreground_pixel
= colors
[0];
1496 if (isdigit (colors
[1]))
1498 else if (isxdigit (colors
[1]))
1499 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1500 if (colors
[1] >= 0 && colors
[1] < 16)
1501 the_only_x_display
.background_pixel
= colors
[1];
1503 the_only_x_display
.line_height
= 1;
1504 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
1506 init_frame_faces (selected_frame
);
1508 ring_bell_hook
= IT_ring_bell
;
1509 insert_glyphs_hook
= IT_insert_glyphs
;
1510 delete_glyphs_hook
= IT_delete_glyphs
;
1511 write_glyphs_hook
= IT_write_glyphs
;
1512 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
1513 clear_to_end_hook
= IT_clear_to_end
;
1514 clear_end_of_line_hook
= IT_clear_end_of_line
;
1515 clear_frame_hook
= IT_clear_screen
;
1516 change_line_highlight_hook
= IT_change_line_highlight
;
1517 update_begin_hook
= IT_update_begin
;
1518 update_end_hook
= IT_update_end
;
1519 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
1520 frame_up_to_date_hook
= IT_cmgoto
; /* position cursor when update is done */
1522 /* These hooks are called by term.c without being checked. */
1523 set_terminal_modes_hook
= IT_set_terminal_modes
;
1524 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1525 set_terminal_window_hook
= IT_set_terminal_window
;
1526 char_ins_del_ok
= 0;
1530 dos_get_saved_screen (screen
, rows
, cols
)
1535 #ifndef HAVE_X_WINDOWS
1536 *screen
= startup_screen_buffer
;
1537 *cols
= startup_screen_size_X
;
1538 *rows
= startup_screen_size_Y
;
1539 return *screen
!= (char *)0;
1545 #ifndef HAVE_X_WINDOWS
1547 /* We are not X, but we can emulate it well enough for our needs... */
1551 if (! FRAME_MSDOS_P (selected_frame
))
1552 error ("Not running under a windows system");
1558 /* ----------------------- Keyboard control ----------------------
1560 * Keymaps reflect the following keyboard layout:
1562 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1563 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1564 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1565 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1569 #define Ignore 0x0000
1570 #define Normal 0x0000 /* normal key - alt changes scan-code */
1571 #define FctKey 0x1000 /* func key if c == 0, else c */
1572 #define Special 0x2000 /* func key even if c != 0 */
1573 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1574 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1575 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1576 #define Grey 0x6000 /* Grey keypad key */
1578 #define Alt 0x0100 /* alt scan-code */
1579 #define Ctrl 0x0200 /* ctrl scan-code */
1580 #define Shift 0x0400 /* shift scan-code */
1582 static int extended_kbd
; /* 101 (102) keyboard present. */
1584 struct kbd_translate
{
1587 unsigned short code
;
1590 struct dos_keyboard_map
1595 struct kbd_translate
*translate_table
;
1599 static struct dos_keyboard_map us_keyboard
= {
1601 /* 01234567890123456789012345678901234567890 12345678901234 */
1602 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1603 /* 0123456789012345678901234567890123456789 012345678901234 */
1604 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1605 0, /* no Alt-Gr key */
1606 0 /* no translate table */
1609 static struct dos_keyboard_map fr_keyboard
= {
1611 /* 012 3456789012345678901234567890123456789012345678901234 */
1612 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
1613 /* 0123456789012345678901234567890123456789012345678901234 */
1614 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
1615 /* 01234567 89012345678901234567890123456789012345678901234 */
1617 0 /* no translate table */
1621 * Italian keyboard support, country code 39.
1624 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1625 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1628 static struct kbd_translate it_kbd_translate_table
[] = {
1629 { 0x56, 0x3c, Normal
| 13 },
1630 { 0x56, 0x3e, Normal
| 27 },
1633 static struct dos_keyboard_map it_keyboard
= {
1635 /* 0 123456789012345678901234567890123456789012345678901234 */
1636 "\\1234567890'�< qwertyuiopŠ+> asdfghjkl•…— zxcvbnm,.- ",
1637 /* 01 23456789012345678901234567890123456789012345678901234 */
1638 "|!\"œ$%&/()=?^> QWERTYUIOP‚* ASDFGHJKL‡øõ ZXCVBNM;:_ ",
1639 /* 0123456789012345678901234567890123456789012345678901234 */
1641 it_kbd_translate_table
1644 static struct dos_keyboard_map dk_keyboard
= {
1646 /* 0123456789012345678901234567890123456789012345678901234 */
1647 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
1648 /* 01 23456789012345678901234567890123456789012345678901234 */
1649 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
1650 /* 0123456789012345678901234567890123456789012345678901234 */
1652 0 /* no translate table */
1655 static struct kbd_translate jp_kbd_translate_table
[] = {
1656 { 0x73, 0x5c, Normal
| 0 },
1657 { 0x73, 0x5f, Normal
| 0 },
1658 { 0x73, 0x1c, Map
| 0 },
1659 { 0x7d, 0x5c, Normal
| 13 },
1660 { 0x7d, 0x7c, Normal
| 13 },
1661 { 0x7d, 0x1c, Map
| 13 },
1664 static struct dos_keyboard_map jp_keyboard
= {
1666 /* 0123456789012 345678901234567890123456789012345678901234 */
1667 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
1668 /* 01 23456789012345678901234567890123456789012345678901234 */
1669 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
1670 0, /* no Alt-Gr key */
1671 jp_kbd_translate_table
1674 static struct keyboard_layout_list
1677 struct dos_keyboard_map
*keyboard_map
;
1678 } keyboard_layout_list
[] =
1687 static struct dos_keyboard_map
*keyboard
;
1688 static int keyboard_map_all
;
1689 static int international_keyboard
;
1692 dos_set_keyboard (code
, always
)
1697 _go32_dpmi_registers regs
;
1699 /* See if Keyb.Com is installed (for international keyboard support).
1700 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
1701 of Windows 9X! So don't do that! */
1703 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
1704 _go32_dpmi_simulate_int (0x2f, ®s
);
1705 if (regs
.h
.al
== 0xff)
1706 international_keyboard
= 1;
1708 /* Initialize to US settings, for countries that don't have their own. */
1709 keyboard
= keyboard_layout_list
[0].keyboard_map
;
1710 keyboard_map_all
= always
;
1711 dos_keyboard_layout
= 1;
1713 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
1714 if (code
== keyboard_layout_list
[i
].country_code
)
1716 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
1717 keyboard_map_all
= always
;
1718 dos_keyboard_layout
= code
;
1726 unsigned char char_code
; /* normal code */
1727 unsigned char meta_code
; /* M- code */
1728 unsigned char keypad_code
; /* keypad code */
1729 unsigned char editkey_code
; /* edit key */
1730 } keypad_translate_map
[] = {
1731 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1732 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1733 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1734 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1735 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1736 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1737 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1738 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1739 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1740 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1741 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1746 unsigned char char_code
; /* normal code */
1747 unsigned char keypad_code
; /* keypad code */
1748 } grey_key_translate_map
[] = {
1749 '/', 0xaf, /* kp-decimal */
1750 '*', 0xaa, /* kp-multiply */
1751 '-', 0xad, /* kp-subtract */
1752 '+', 0xab, /* kp-add */
1753 '\r', 0x8d /* kp-enter */
1756 static unsigned short
1757 ibmpc_translate_map
[] =
1759 /* --------------- 00 to 0f --------------- */
1760 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
1761 Alt
| ModFct
| 0x1b, /* Escape */
1762 Normal
| 1, /* '1' */
1763 Normal
| 2, /* '2' */
1764 Normal
| 3, /* '3' */
1765 Normal
| 4, /* '4' */
1766 Normal
| 5, /* '5' */
1767 Normal
| 6, /* '6' */
1768 Normal
| 7, /* '7' */
1769 Normal
| 8, /* '8' */
1770 Normal
| 9, /* '9' */
1771 Normal
| 10, /* '0' */
1772 Normal
| 11, /* '-' */
1773 Normal
| 12, /* '=' */
1774 Special
| 0x08, /* Backspace */
1775 ModFct
| 0x74, /* Tab/Backtab */
1777 /* --------------- 10 to 1f --------------- */
1790 ModFct
| 0x0d, /* Return */
1795 /* --------------- 20 to 2f --------------- */
1804 Map
| 40, /* '\'' */
1806 Ignore
, /* Left shift */
1807 Map
| 41, /* '\\' */
1813 /* --------------- 30 to 3f --------------- */
1820 Ignore
, /* Right shift */
1821 Grey
| 1, /* Grey * */
1823 Normal
| 55, /* ' ' */
1824 Ignore
, /* Caps Lock */
1825 FctKey
| 0xbe, /* F1 */
1826 FctKey
| 0xbf, /* F2 */
1827 FctKey
| 0xc0, /* F3 */
1828 FctKey
| 0xc1, /* F4 */
1829 FctKey
| 0xc2, /* F5 */
1831 /* --------------- 40 to 4f --------------- */
1832 FctKey
| 0xc3, /* F6 */
1833 FctKey
| 0xc4, /* F7 */
1834 FctKey
| 0xc5, /* F8 */
1835 FctKey
| 0xc6, /* F9 */
1836 FctKey
| 0xc7, /* F10 */
1837 Ignore
, /* Num Lock */
1838 Ignore
, /* Scroll Lock */
1839 KeyPad
| 7, /* Home */
1840 KeyPad
| 8, /* Up */
1841 KeyPad
| 9, /* Page Up */
1842 Grey
| 2, /* Grey - */
1843 KeyPad
| 4, /* Left */
1844 KeyPad
| 5, /* Keypad 5 */
1845 KeyPad
| 6, /* Right */
1846 Grey
| 3, /* Grey + */
1847 KeyPad
| 1, /* End */
1849 /* --------------- 50 to 5f --------------- */
1850 KeyPad
| 2, /* Down */
1851 KeyPad
| 3, /* Page Down */
1852 KeyPad
| 0, /* Insert */
1853 KeyPad
| 10, /* Delete */
1854 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1855 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1856 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1857 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1858 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1859 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1860 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1861 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1862 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1863 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1864 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1865 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1867 /* --------------- 60 to 6f --------------- */
1868 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1869 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1870 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1871 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1872 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1873 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1874 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1875 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1876 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1877 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1878 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1879 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1880 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1881 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1882 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1883 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1885 /* --------------- 70 to 7f --------------- */
1886 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1887 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1888 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1889 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1890 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1891 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1892 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1893 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1894 Alt
| Map
| 1, /* '1' */
1895 Alt
| Map
| 2, /* '2' */
1896 Alt
| Map
| 3, /* '3' */
1897 Alt
| Map
| 4, /* '4' */
1898 Alt
| Map
| 5, /* '5' */
1899 Alt
| Map
| 6, /* '6' */
1900 Alt
| Map
| 7, /* '7' */
1901 Alt
| Map
| 8, /* '8' */
1903 /* --------------- 80 to 8f --------------- */
1904 Alt
| Map
| 9, /* '9' */
1905 Alt
| Map
| 10, /* '0' */
1906 Alt
| Map
| 11, /* '-' */
1907 Alt
| Map
| 12, /* '=' */
1908 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1909 FctKey
| 0xc8, /* F11 */
1910 FctKey
| 0xc9, /* F12 */
1911 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1912 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1913 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1914 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1915 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1916 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1917 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1918 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1919 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1921 /* --------------- 90 to 9f --------------- */
1922 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1923 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1924 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1925 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1926 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1927 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1928 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1929 Alt
| FctKey
| 0x50, /* (Alt) Home */
1930 Alt
| FctKey
| 0x52, /* (Alt) Up */
1931 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1932 Ignore
, /* NO KEY */
1933 Alt
| FctKey
| 0x51, /* (Alt) Left */
1934 Ignore
, /* NO KEY */
1935 Alt
| FctKey
| 0x53, /* (Alt) Right */
1936 Ignore
, /* NO KEY */
1937 Alt
| FctKey
| 0x57, /* (Alt) End */
1939 /* --------------- a0 to af --------------- */
1940 Alt
| KeyPad
| 2, /* (Alt) Down */
1941 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1942 Alt
| KeyPad
| 0, /* (Alt) Insert */
1943 Alt
| KeyPad
| 10, /* (Alt) Delete */
1944 Alt
| Grey
| 0, /* (Alt) Grey / */
1945 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1946 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1949 /* These bit-positions corresponds to values returned by BIOS */
1950 #define SHIFT_P 0x0003 /* two bits! */
1951 #define CTRL_P 0x0004
1952 #define ALT_P 0x0008
1953 #define SCRLOCK_P 0x0010
1954 #define NUMLOCK_P 0x0020
1955 #define CAPSLOCK_P 0x0040
1956 #define ALT_GR_P 0x0800
1957 #define SUPER_P 0x4000 /* pseudo */
1958 #define HYPER_P 0x8000 /* pseudo */
1961 dos_get_modifiers (keymask
)
1968 /* Calculate modifier bits */
1969 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1970 int86 (0x16, ®s
, ®s
);
1974 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1975 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1979 mask
= regs
.h
.al
& (SHIFT_P
|
1980 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1982 /* Do not break international keyboard support. */
1983 /* When Keyb.Com is loaded, the right Alt key is */
1984 /* used for accessing characters like { and } */
1985 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1988 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1991 if (dos_hyper_key
== 1)
1994 modifiers
|= hyper_modifier
;
1996 else if (dos_super_key
== 1)
1999 modifiers
|= super_modifier
;
2001 else if (!international_keyboard
)
2003 /* If Keyb.Com is NOT installed, let Right Alt behave
2004 like the Left Alt. */
2010 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
2013 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
2015 if (dos_hyper_key
== 2)
2018 modifiers
|= hyper_modifier
;
2020 else if (dos_super_key
== 2)
2023 modifiers
|= super_modifier
;
2031 modifiers
|= shift_modifier
;
2033 modifiers
|= ctrl_modifier
;
2035 modifiers
|= meta_modifier
;
2042 #define NUM_RECENT_DOSKEYS (100)
2043 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
2044 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
2045 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
2047 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
2048 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
2049 Each input key receives two values in this vector: first the ASCII code,\n\
2050 and then the scan code.")
2053 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
2056 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
2057 return Fvector (total_doskeys
, keys
);
2060 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
2061 bcopy (keys
+ recent_doskeys_index
,
2062 XVECTOR (val
)->contents
,
2063 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
2065 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
2066 recent_doskeys_index
* sizeof (Lisp_Object
));
2071 /* Get a char from keyboard. Function keys are put into the event queue. */
2073 extern void kbd_buffer_store_event (struct input_event
*);
2074 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
2079 struct input_event event
;
2082 #ifndef HAVE_X_WINDOWS
2083 /* Maybe put the cursor where it should be. */
2084 IT_cmgoto (selected_frame
);
2087 /* The following condition is equivalent to `kbhit ()', except that
2088 it uses the bios to do its job. This pleases DESQview/X. */
2089 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
2090 int86 (0x16, ®s
, ®s
),
2091 (regs
.x
.flags
& 0x40) == 0)
2094 register unsigned char c
;
2095 int sc
, code
= -1, mask
, kp_mode
;
2098 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
2099 int86 (0x16, ®s
, ®s
);
2104 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2106 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2107 recent_doskeys_index
= 0;
2108 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2110 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2111 recent_doskeys_index
= 0;
2113 modifiers
= dos_get_modifiers (&mask
);
2115 #ifndef HAVE_X_WINDOWS
2116 if (!NILP (Vdos_display_scancodes
))
2119 sprintf (buf
, "%02x:%02x*%04x",
2120 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
2121 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
2129 case 10: /* Ctrl Grey Enter */
2130 code
= Ctrl
| Grey
| 4;
2132 case 13: /* Grey Enter */
2135 case '/': /* Grey / */
2145 /* Try the keyboard-private translation table first. */
2146 if (keyboard
->translate_table
)
2148 struct kbd_translate
*p
= keyboard
->translate_table
;
2152 if (p
->sc
== sc
&& p
->ch
== c
)
2160 /* If the private table didn't translate it, use the general
2164 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
2166 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
2173 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2174 Emacs is ready to read a key. Therefore, if they press
2175 `Alt-x' when Emacs is busy, by the time we get to
2176 `dos_get_modifiers', they might have already released the
2177 Alt key, and Emacs gets just `x', which is BAD.
2178 However, for keys with the `Map' property set, the ASCII
2179 code returns zero iff Alt is pressed. So, when we DON'T
2180 have to support international_keyboard, we don't have to
2181 distinguish between the left and right Alt keys, and we
2182 can set the META modifier for any keys with the `Map'
2183 property if they return zero ASCII code (c = 0). */
2185 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
2186 modifiers
|= meta_modifier
;
2188 modifiers
|= ctrl_modifier
;
2190 modifiers
|= shift_modifier
;
2193 switch (code
& 0xf000)
2196 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
2198 c
= 0; /* Special */
2211 if (c
== 0) /* ctrl-break */
2213 return c
; /* ALT-nnn */
2215 if (!keyboard_map_all
)
2224 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
2225 if (!keyboard_map_all
)
2229 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
2230 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
2234 code
= keyboard
->shifted
[code
];
2236 modifiers
&= ~shift_modifier
;
2239 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
2240 code
= keyboard
->alt_gr
[code
];
2242 code
= keyboard
->unshifted
[code
];
2247 if (c
== 0xe0) /* edit key */
2250 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
2251 kp_mode
= dos_keypad_mode
& 0x03;
2253 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
2258 if (code
== 10 && dos_decimal_point
)
2259 return dos_decimal_point
;
2260 return keypad_translate_map
[code
].char_code
;
2263 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
2267 code
= keypad_translate_map
[code
].meta_code
;
2268 modifiers
= meta_modifier
;
2272 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
2279 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
2280 if (dos_keypad_mode
& kp_mode
)
2281 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
2283 code
= grey_key_translate_map
[code
].char_code
;
2292 event
.kind
= non_ascii_keystroke
;
2294 event
.kind
= ascii_keystroke
;
2296 event
.modifiers
= modifiers
;
2297 XSETFRAME (event
.frame_or_window
, selected_frame
);
2298 event
.timestamp
= event_timestamp ();
2299 kbd_buffer_store_event (&event
);
2302 if (have_mouse
> 0 && !mouse_preempted
)
2304 int but
, press
, x
, y
, ok
;
2306 /* Check for mouse movement *before* buttons. */
2307 mouse_check_moved ();
2309 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
2310 for (press
= 0; press
< 2; press
++)
2312 int button_num
= but
;
2315 ok
= mouse_pressed (but
, &x
, &y
);
2317 ok
= mouse_released (but
, &x
, &y
);
2320 /* Allow a simultaneous press/release of Mouse-1 and
2321 Mouse-2 to simulate Mouse-3 on two-button mice. */
2322 if (mouse_button_count
== 2 && but
< 2)
2324 int x2
, y2
; /* don't clobber original coordinates */
2326 /* If only one button is pressed, wait 100 msec and
2327 check again. This way, Speedy Gonzales isn't
2328 punished, while the slow get their chance. */
2329 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
2330 || !press
&& mouse_released (1-but
, &x2
, &y2
))
2335 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
2336 || !press
&& mouse_released (1-but
, &x2
, &y2
))
2341 event
.kind
= mouse_click
;
2342 event
.code
= button_num
;
2343 event
.modifiers
= dos_get_modifiers (0)
2344 | (press
? down_modifier
: up_modifier
);
2347 XSETFRAME (event
.frame_or_window
, selected_frame
);
2348 event
.timestamp
= event_timestamp ();
2349 kbd_buffer_store_event (&event
);
2357 static int prev_get_char
= -1;
2359 /* Return 1 if a key is ready to be read without suspending execution. */
2363 if (prev_get_char
!= -1)
2366 return ((prev_get_char
= dos_rawgetc ()) != -1);
2369 /* Read a key. Return -1 if no key is ready. */
2373 if (prev_get_char
!= -1)
2375 int c
= prev_get_char
;
2380 return dos_rawgetc ();
2383 #ifndef HAVE_X_WINDOWS
2384 /* See xterm.c for more info. */
2386 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
2388 register int pix_x
, pix_y
;
2389 register int *x
, *y
;
2393 if (bounds
) abort ();
2395 /* Ignore clipping. */
2402 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
2405 register int *pix_x
, *pix_y
;
2411 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2414 Actually, I don't know the meaning of all the parameters of the functions
2415 here -- I only know how they are called by xmenu.c. I could of course
2416 grab the nearest Xlib manual (down the hall, second-to-last door on the
2417 left), but I don't think it's worth the effort. */
2424 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
2425 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
2429 /* Allocate some (more) memory for MENU ensuring that there is room for one
2433 IT_menu_make_room (XMenu
*menu
)
2435 if (menu
->allocated
== 0)
2437 int count
= menu
->allocated
= 10;
2438 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
2439 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
2440 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
2442 else if (menu
->allocated
== menu
->count
)
2444 int count
= menu
->allocated
= menu
->allocated
+ 10;
2446 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
2448 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
2450 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
2454 /* Search the given menu structure for a given pane number. */
2457 IT_menu_search_pane (XMenu
*menu
, int pane
)
2462 for (i
= 0; i
< menu
->count
; i
++)
2463 if (menu
->submenu
[i
])
2465 if (pane
== menu
->panenumber
[i
])
2466 return menu
->submenu
[i
];
2467 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
2473 /* Determine how much screen space a given menu needs. */
2476 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
2478 int i
, h2
, w2
, maxsubwidth
, maxheight
;
2481 maxheight
= menu
->count
;
2482 for (i
= 0; i
< menu
->count
; i
++)
2484 if (menu
->submenu
[i
])
2486 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
2487 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
2488 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
2491 *width
= menu
->width
+ maxsubwidth
;
2492 *height
= maxheight
;
2495 /* Display MENU at (X,Y) using FACES. */
2498 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
2500 int i
, j
, face
, width
;
2501 struct glyph
*text
, *p
;
2504 int enabled
, mousehere
;
2507 width
= menu
->width
;
2508 text
= (struct glyph
*) xmalloc ((width
+ 2) * sizeof (struct glyph
));
2509 ScreenGetCursor (&row
, &col
);
2510 mouse_get_xy (&mx
, &my
);
2511 IT_update_begin (selected_frame
);
2512 for (i
= 0; i
< menu
->count
; i
++)
2514 IT_cursor_to (y
+ i
, x
);
2516 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
2517 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
2518 face
= faces
[enabled
+ mousehere
* 2];
2520 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
2522 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
2526 SET_CHAR_GLYPH (*p
, *q
++, face
, 0);
2529 else /* make '^x' */
2531 SET_CHAR_GLYPH (*p
, '^', face
, 0);
2534 SET_CHAR_GLYPH (*p
, *q
++ + 64, face
, 0);
2539 for (; j
< width
; j
++, p
++)
2540 SET_CHAR_GLYPH (*p
, ' ', face
, 0);
2542 SET_CHAR_GLYPH (*p
, menu
->submenu
[i
] ? 16 : ' ', face
, 0);
2544 IT_write_glyphs (text
, width
+ 2);
2546 IT_update_end (selected_frame
);
2547 IT_cursor_to (row
, col
);
2551 /* --------------------------- X Menu emulation ---------------------- */
2553 /* Report availability of menus. */
2561 /* Create a brand new menu structure. */
2564 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2566 return IT_menu_create ();
2569 /* Create a new pane and place it on the outer-most level. It is not
2570 clear that it should be placed out there, but I don't know what else
2574 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
2582 IT_menu_make_room (menu
);
2583 menu
->submenu
[menu
->count
] = IT_menu_create ();
2584 menu
->text
[menu
->count
] = txt
;
2585 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
2588 /* Adjust length for possible control characters (which will
2589 be written as ^x). */
2590 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2594 if (len
> menu
->width
)
2597 return menu
->panecount
;
2600 /* Create a new item in a menu pane. */
2603 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
2604 int foo
, char *txt
, int enable
)
2610 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
2612 IT_menu_make_room (menu
);
2613 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
2614 menu
->text
[menu
->count
] = txt
;
2615 menu
->panenumber
[menu
->count
] = enable
;
2618 /* Adjust length for possible control characters (which will
2619 be written as ^x). */
2620 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2624 if (len
> menu
->width
)
2630 /* Decide where the menu would be placed if requested at (X,Y). */
2633 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
2634 int *ulx
, int *uly
, int *width
, int *height
)
2636 IT_menu_calc_size (menu
, width
, height
);
2642 struct IT_menu_state
2644 void *screen_behind
;
2651 /* Display menu, wait for user's response, and return that response. */
2654 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
2655 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
2657 struct IT_menu_state
*state
;
2662 Lisp_Object selectface
;
2663 int leave
, result
, onepane
;
2664 int title_faces
[4]; /* face to display the menu title */
2665 int buffers_num_deleted
= 0;
2667 /* Just in case we got here without a mouse present... */
2668 if (have_mouse
<= 0)
2669 return XM_IA_SELECT
;
2670 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2671 around the display. */
2677 /* We will process all the mouse events directly, so we had
2678 better prevented dos_rawgetc from stealing them from us. */
2681 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
2682 screensize
= screen_size
* 2;
2684 = lookup_derived_face (selected_frame
, intern ("msdos-menu-passive-face"),
2685 CHARSET_ASCII
, DEFAULT_FACE_ID
);
2687 = lookup_derived_face (selected_frame
, intern ("msdos-menu-active-face"),
2688 CHARSET_ASCII
, DEFAULT_FACE_ID
);
2689 selectface
= intern ("msdos-menu-select-face");
2690 faces
[2] = lookup_derived_face (selected_frame
, selectface
,
2691 CHARSET_ASCII
, faces
[0]);
2692 faces
[3] = lookup_derived_face (selected_frame
, selectface
,
2693 CHARSET_ASCII
, faces
[1]);
2695 /* Make sure the menu title is always displayed with
2696 `msdos-menu-active-face', no matter where the mouse pointer is. */
2697 for (i
= 0; i
< 4; i
++)
2698 title_faces
[i
] = faces
[3];
2702 /* Don't let the title for the "Buffers" popup menu include a
2703 digit (which is ugly).
2705 This is a terrible kludge, but I think the "Buffers" case is
2706 the only one where the title includes a number, so it doesn't
2707 seem to be necessary to make this more general. */
2708 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
2710 menu
->text
[0][7] = '\0';
2711 buffers_num_deleted
= 1;
2713 state
[0].menu
= menu
;
2715 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
2717 /* Turn off the cursor. Otherwise it shows through the menu
2718 panes, which is ugly. */
2719 IT_display_cursor (0);
2721 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
2722 if (buffers_num_deleted
)
2723 menu
->text
[0][7] = ' ';
2724 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
2726 menu
->width
= menu
->submenu
[0]->width
;
2727 state
[0].menu
= menu
->submenu
[0];
2731 state
[0].menu
= menu
;
2733 state
[0].x
= x0
- 1;
2735 state
[0].pane
= onepane
;
2737 mouse_last_x
= -1; /* A hack that forces display. */
2741 if (!mouse_visible
) mouse_on ();
2742 mouse_check_moved ();
2743 if (selected_frame
->mouse_moved
)
2745 selected_frame
->mouse_moved
= 0;
2746 result
= XM_IA_SELECT
;
2747 mouse_get_xy (&x
, &y
);
2748 for (i
= 0; i
< statecount
; i
++)
2749 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
2751 int dy
= y
- state
[i
].y
;
2752 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
2754 if (!state
[i
].menu
->submenu
[dy
])
2755 if (state
[i
].menu
->panenumber
[dy
])
2756 result
= XM_SUCCESS
;
2758 result
= XM_IA_SELECT
;
2759 *pane
= state
[i
].pane
- 1;
2761 /* We hit some part of a menu, so drop extra menus that
2762 have been opened. That does not include an open and
2764 if (i
!= statecount
- 2
2765 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
2766 while (i
!= statecount
- 1)
2770 ScreenUpdate (state
[statecount
].screen_behind
);
2771 if (screen_virtual_segment
)
2772 dosv_refresh_virtual_screen (0, screen_size
);
2773 xfree (state
[statecount
].screen_behind
);
2775 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2777 IT_menu_display (state
[i
].menu
,
2781 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2782 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2784 ScreenRetrieve (state
[statecount
].screen_behind
2785 = xmalloc (screensize
));
2787 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2788 state
[statecount
].y
= y
;
2793 IT_menu_display (state
[statecount
- 1].menu
,
2794 state
[statecount
- 1].y
,
2795 state
[statecount
- 1].x
,
2799 /* We are busy-waiting for the mouse to move, so let's be nice
2800 to other Windows applications by releasing our time slice. */
2802 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
2804 /* Only leave if user both pressed and released the mouse, and in
2805 that order. This avoids popping down the menu pane unless
2806 the user is really done with it. */
2807 if (mouse_pressed (b
, &x
, &y
))
2809 while (mouse_button_depressed (b
, &x
, &y
))
2813 (void) mouse_released (b
, &x
, &y
);
2818 ScreenUpdate (state
[0].screen_behind
);
2819 if (screen_virtual_segment
)
2820 dosv_refresh_virtual_screen (0, screen_size
);
2821 while (statecount
--)
2822 xfree (state
[statecount
].screen_behind
);
2823 IT_display_cursor (1); /* turn cursor back on */
2824 /* Clean up any mouse events that are waiting inside Emacs event queue.
2825 These events are likely to be generated before the menu was even
2826 displayed, probably because the user pressed and released the button
2827 (which invoked the menu) too quickly. If we don't remove these events,
2828 Emacs will process them after we return and surprise the user. */
2829 discard_mouse_events ();
2830 /* Allow mouse events generation by dos_rawgetc. */
2835 /* Dispose of a menu. */
2838 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2841 if (menu
->allocated
)
2843 for (i
= 0; i
< menu
->count
; i
++)
2844 if (menu
->submenu
[i
])
2845 XMenuDestroy (foo
, menu
->submenu
[i
]);
2847 xfree (menu
->submenu
);
2848 xfree (menu
->panenumber
);
2854 x_pixel_width (struct frame
*f
)
2856 return FRAME_WIDTH (f
);
2860 x_pixel_height (struct frame
*f
)
2862 return FRAME_HEIGHT (f
);
2864 #endif /* !HAVE_X_WINDOWS */
2866 /* ----------------------- DOS / UNIX conversion --------------------- */
2868 void msdos_downcase_filename (unsigned char *);
2870 /* Destructively turn backslashes into slashes. */
2873 dostounix_filename (p
)
2876 msdos_downcase_filename (p
);
2886 /* Destructively turn slashes into backslashes. */
2889 unixtodos_filename (p
)
2892 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2906 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2909 getdefdir (drive
, dst
)
2913 char in_path
[4], *p
= in_path
;
2916 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2919 *p
++ = drive
+ 'A' - 1;
2926 _fixpath (in_path
, dst
);
2927 /* _fixpath can set errno to ENOSYS on non-LFN systems because
2928 it queries the LFN support, so ignore that error. */
2929 if ((errno
&& errno
!= ENOSYS
) || *dst
== '\0')
2932 msdos_downcase_filename (dst
);
2938 /* Remove all CR's that are followed by a LF. */
2943 register unsigned char *buf
;
2945 unsigned char *np
= buf
;
2946 unsigned char *startp
= buf
;
2947 unsigned char *endp
= buf
+ n
;
2951 while (buf
< endp
- 1)
2955 if (*(++buf
) != 0x0a)
2966 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2968 /* In DJGPP v2.0, library `write' can call `malloc', which might
2969 cause relocation of the buffer whose address we get in ADDR.
2970 Here is a version of `write' that avoids calling `malloc',
2971 to serve us until such time as the library is fixed.
2972 Actually, what we define here is called `__write', because
2973 `write' is a stub that just jmp's to `__write' (to be
2974 POSIXLY-correct with respect to the global name-space). */
2976 #include <io.h> /* for _write */
2977 #include <libc/dosio.h> /* for __file_handle_modes[] */
2979 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
2981 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2984 __write (int handle
, const void *buffer
, size_t count
)
2989 if(__file_handle_modes
[handle
] & O_BINARY
)
2990 return _write (handle
, buffer
, count
);
2994 const char *bp
= buffer
;
2995 int total_written
= 0;
2996 int nmoved
= 0, ncr
= 0;
3000 /* The next test makes sure there's space for at least 2 more
3001 characters in xbuf[], so both CR and LF can be put there. */
3013 if (xbp
>= XBUF_END
|| !count
)
3015 size_t to_write
= nmoved
+ ncr
;
3016 int written
= _write (handle
, xbuf
, to_write
);
3021 total_written
+= nmoved
; /* CRs aren't counted in ret value */
3023 /* If some, but not all were written (disk full?), return
3024 an estimate of the total written bytes not counting CRs. */
3025 if (written
< to_write
)
3026 return total_written
- (to_write
- written
) * nmoved
/to_write
;
3033 return total_written
;
3037 /* A low-level file-renaming function which works around Windows 95 bug.
3038 This is pulled directly out of DJGPP v2.01 library sources, and only
3039 used when you compile with DJGPP v2.0. */
3043 int _rename(const char *old
, const char *new)
3046 int olen
= strlen(old
) + 1;
3048 int use_lfn
= _USE_LFN
;
3049 char tempfile
[FILENAME_MAX
];
3050 const char *orig
= old
;
3053 r
.x
.dx
= __tb_offset
;
3054 r
.x
.di
= __tb_offset
+ olen
;
3055 r
.x
.ds
= r
.x
.es
= __tb_segment
;
3059 /* Windows 95 bug: for some filenames, when you rename
3060 file -> file~ (as in Emacs, to leave a backup), the
3061 short 8+3 alias doesn't change, which effectively
3062 makes OLD and NEW the same file. We must rename
3063 through a temporary file to work around this. */
3065 char *pbase
= 0, *p
;
3066 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
3067 int idx
= sizeof(try_char
) - 1;
3069 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
3070 might point to another drive, which will fail the DOS call. */
3071 strcpy(tempfile
, old
);
3072 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
3073 if (*p
== '/' || *p
== '\\' || *p
== ':')
3079 strcpy(pbase
, "X$$djren$$.$$temp$$");
3085 *pbase
= try_char
[--idx
];
3086 } while (_chmod(tempfile
, 0) != -1);
3089 _put_path2(tempfile
, olen
);
3091 __dpmi_int(0x21, &r
);
3094 errno
= __doserr_to_errno(r
.x
.ax
);
3098 /* Now create a file with the original name. This will
3099 ensure that NEW will always have a 8+3 alias
3100 different from that of OLD. (Seems to be required
3101 when NameNumericTail in the Registry is set to 0.) */
3102 lfn_fd
= _creat(old
, 0);
3104 olen
= strlen(tempfile
) + 1;
3106 r
.x
.di
= __tb_offset
+ olen
;
3115 _put_path2(new, olen
);
3117 __dpmi_int(0x21, &r
);
3120 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
3121 remove(new); /* and try again */
3124 errno
= __doserr_to_errno(r
.x
.ax
);
3126 /* Restore to original name if we renamed it to temporary. */
3134 _put_path2(orig
, olen
);
3135 _put_path(tempfile
);
3137 __dpmi_int(0x21, &r
);
3146 /* Success. Delete the file possibly created to work
3147 around the Windows 95 bug. */
3149 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
3153 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
3155 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
3157 "Return non-nil if long file names are supported on MSDOS.")
3160 return (_USE_LFN
? Qt
: Qnil
);
3163 /* Convert alphabetic characters in a filename to lower-case. */
3166 msdos_downcase_filename (p
)
3167 register unsigned char *p
;
3169 /* Always lower-case drive letters a-z, even if the filesystem
3170 preserves case in filenames.
3171 This is so MSDOS filenames could be compared by string comparison
3172 functions that are case-sensitive. Even case-preserving filesystems
3173 do not distinguish case in drive letters. */
3174 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3180 /* Under LFN we expect to get pathnames in their true case. */
3181 if (NILP (Fmsdos_long_file_names ()))
3183 if (*p
>= 'A' && *p
<= 'Z')
3187 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
3189 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
3190 When long filenames are supported, doesn't change FILENAME.\n\
3191 If FILENAME is not a string, returns nil.\n\
3192 The argument object is never altered--the value is a copy.")
3194 Lisp_Object filename
;
3198 if (! STRINGP (filename
))
3201 tem
= Fcopy_sequence (filename
);
3202 msdos_downcase_filename (XSTRING (tem
)->data
);
3206 /* The Emacs root directory as determined by init_environment. */
3208 static char emacsroot
[MAXPATHLEN
];
3211 rootrelativepath (rel
)
3214 static char result
[MAXPATHLEN
+ 10];
3216 strcpy (result
, emacsroot
);
3217 strcat (result
, "/");
3218 strcat (result
, rel
);
3222 /* Define a lot of environment variables if not already defined. Don't
3223 remove anything unless you know what you're doing -- lots of code will
3224 break if one or more of these are missing. */
3227 init_environment (argc
, argv
, skip_args
)
3234 static const char * const tempdirs
[] = {
3235 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3238 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
3240 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3241 temporary files and assume "/tmp" if $TMPDIR is unset, which
3242 will break on DOS/Windows. Refuse to work if we cannot find
3243 a directory, not even "c:/", usable for that purpose. */
3244 for (i
= 0; i
< imax
; i
++)
3246 const char *tmp
= tempdirs
[i
];
3249 tmp
= getenv (tmp
+ 1);
3250 /* Note that `access' can lie to us if the directory resides on a
3251 read-only filesystem, like CD-ROM or a write-protected floppy.
3252 The only way to be really sure is to actually create a file and
3253 see if it succeeds. But I think that's too much to ask. */
3254 if (tmp
&& access (tmp
, D_OK
) == 0)
3256 setenv ("TMPDIR", tmp
, 1);
3263 Fcons (build_string ("no usable temporary directories found!!"),
3265 "While setting TMPDIR: ");
3267 /* Note the startup time, so we know not to clear the screen if we
3268 exit immediately; see IT_reset_terminal_modes.
3269 (Yes, I know `clock' returns zero the first time it's called, but
3270 I do this anyway, in case some wiseguy changes that at some point.) */
3271 startup_time
= clock ();
3273 /* Find our root from argv[0]. Assuming argv[0] is, say,
3274 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3275 root
= alloca (MAXPATHLEN
+ 20);
3276 _fixpath (argv
[0], root
);
3277 msdos_downcase_filename (root
);
3278 len
= strlen (root
);
3279 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
3283 && (strcmp (root
+ len
- 4, "/bin") == 0
3284 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
3285 root
[len
- 4] = '\0';
3287 strcpy (root
, "c:/emacs"); /* let's be defensive */
3288 len
= strlen (root
);
3289 strcpy (emacsroot
, root
);
3291 /* We default HOME to our root. */
3292 setenv ("HOME", root
, 0);
3294 /* We default EMACSPATH to root + "/bin". */
3295 strcpy (root
+ len
, "/bin");
3296 setenv ("EMACSPATH", root
, 0);
3298 /* I don't expect anybody to ever use other terminals so the internal
3299 terminal is the default. */
3300 setenv ("TERM", "internal", 0);
3302 #ifdef HAVE_X_WINDOWS
3303 /* Emacs expects DISPLAY to be set. */
3304 setenv ("DISPLAY", "unix:0.0", 0);
3307 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3308 downcase it and mirror the backslashes. */
3309 s
= getenv ("COMSPEC");
3310 if (!s
) s
= "c:/command.com";
3311 t
= alloca (strlen (s
) + 1);
3313 dostounix_filename (t
);
3314 setenv ("SHELL", t
, 0);
3316 /* PATH is also downcased and backslashes mirrored. */
3317 s
= getenv ("PATH");
3319 t
= alloca (strlen (s
) + 3);
3320 /* Current directory is always considered part of MsDos's path but it is
3321 not normally mentioned. Now it is. */
3322 strcat (strcpy (t
, ".;"), s
);
3323 dostounix_filename (t
); /* Not a single file name, but this should work. */
3324 setenv ("PATH", t
, 1);
3326 /* In some sense all dos users have root privileges, so... */
3327 setenv ("USER", "root", 0);
3328 setenv ("NAME", getenv ("USER"), 0);
3330 /* Time zone determined from country code. To make this possible, the
3331 country code may not span more than one time zone. In other words,
3332 in the USA, you lose. */
3334 switch (dos_country_code
)
3336 case 31: /* Belgium */
3337 case 32: /* The Netherlands */
3338 case 33: /* France */
3339 case 34: /* Spain */
3340 case 36: /* Hungary */
3341 case 38: /* Yugoslavia (or what's left of it?) */
3342 case 39: /* Italy */
3343 case 41: /* Switzerland */
3344 case 42: /* Tjekia */
3345 case 45: /* Denmark */
3346 case 46: /* Sweden */
3347 case 47: /* Norway */
3348 case 48: /* Poland */
3349 case 49: /* Germany */
3350 /* Daylight saving from last Sunday in March to last Sunday in
3351 September, both at 2AM. */
3352 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3354 case 44: /* United Kingdom */
3355 case 351: /* Portugal */
3356 case 354: /* Iceland */
3357 setenv ("TZ", "GMT+00", 0);
3359 case 81: /* Japan */
3360 case 82: /* Korea */
3361 setenv ("TZ", "JST-09", 0);
3363 case 90: /* Turkey */
3364 case 358: /* Finland */
3365 setenv ("TZ", "EET-02", 0);
3367 case 972: /* Israel */
3368 /* This is an approximation. (For exact rules, use the
3369 `zoneinfo/israel' file which comes with DJGPP, but you need
3370 to install it in `/usr/share/zoneinfo/' directory first.) */
3371 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3379 static int break_stat
; /* BREAK check mode status. */
3380 static int stdin_stat
; /* stdin IOCTL status. */
3384 /* These must be global. */
3385 static _go32_dpmi_seginfo ctrl_break_vector
;
3386 static _go32_dpmi_registers ctrl_break_regs
;
3387 static int ctrlbreakinstalled
= 0;
3389 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
3392 ctrl_break_func (regs
)
3393 _go32_dpmi_registers
*regs
;
3399 install_ctrl_break_check ()
3401 if (!ctrlbreakinstalled
)
3403 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
3404 was compiler with Djgpp 1.11 maintenance level 5 or later! */
3405 ctrlbreakinstalled
= 1;
3406 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
3407 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
3409 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
3413 #endif /* __DJGPP__ < 2 */
3415 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3416 control chars by DOS. Determine the keyboard type. */
3421 union REGS inregs
, outregs
;
3422 static int first_time
= 1;
3424 break_stat
= getcbrk ();
3427 install_ctrl_break_check ();
3433 int86 (0x15, &inregs
, &outregs
);
3434 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
3438 if (internal_terminal
3439 #ifdef HAVE_X_WINDOWS
3440 && inhibit_window_system
3444 inregs
.x
.ax
= 0x0021;
3445 int86 (0x33, &inregs
, &outregs
);
3446 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3449 /* Reportedly, the above doesn't work for some mouse drivers. There
3450 is an additional detection method that should work, but might be
3451 a little slower. Use that as an alternative. */
3452 inregs
.x
.ax
= 0x0000;
3453 int86 (0x33, &inregs
, &outregs
);
3454 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3459 have_mouse
= 1; /* enable mouse */
3462 if (outregs
.x
.bx
== 3)
3464 mouse_button_count
= 3;
3465 mouse_button_translate
[0] = 0; /* Left */
3466 mouse_button_translate
[1] = 2; /* Middle */
3467 mouse_button_translate
[2] = 1; /* Right */
3471 mouse_button_count
= 2;
3472 mouse_button_translate
[0] = 0;
3473 mouse_button_translate
[1] = 1;
3475 mouse_position_hook
= &mouse_get_pos
;
3484 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
3485 return (stdin_stat
!= -1);
3488 return (setmode (fileno (stdin
), O_BINARY
) != -1);
3490 #else /* __DJGPP__ < 2 */
3494 /* I think it is wrong to overwrite `stdin_stat' every time
3495 but the first one this function is called, but I don't
3496 want to change the way it used to work in v1.x.--EZ */
3498 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
3499 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
3500 intdos (&inregs
, &outregs
);
3501 stdin_stat
= outregs
.h
.dl
;
3503 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
3504 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
3505 intdos (&inregs
, &outregs
);
3506 return !outregs
.x
.cflag
;
3508 #endif /* __DJGPP__ < 2 */
3511 /* Restore status of standard input and Ctrl-C checking. */
3516 union REGS inregs
, outregs
;
3518 setcbrk (break_stat
);
3523 return (setmode (fileno (stdin
), stdin_stat
) != -1);
3525 #else /* not __DJGPP__ >= 2 */
3527 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
3528 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
3529 inregs
.x
.dx
= stdin_stat
;
3530 intdos (&inregs
, &outregs
);
3531 return !outregs
.x
.cflag
;
3533 #endif /* not __DJGPP__ >= 2 */
3537 /* Run command as specified by ARGV in directory DIR.
3538 The command is run with input from TEMPIN, output to
3539 file TEMPOUT and stderr to TEMPERR. */
3542 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
3543 unsigned char **argv
;
3544 const char *working_dir
;
3545 int tempin
, tempout
, temperr
;
3548 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
3549 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
3550 int msshell
, result
= -1;
3551 int inbak
, outbak
, errbak
;
3555 /* Get current directory as MSDOS cwd is not per-process. */
3558 /* If argv[0] is the shell, it might come in any lettercase.
3559 Since `Fmember' is case-sensitive, we need to downcase
3560 argv[0], even if we are on case-preserving filesystems. */
3561 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
3562 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
3565 if (*pl
>= 'A' && *pl
<= 'Z')
3570 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
3571 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
3572 && !strcmp ("-c", argv
[1]);
3575 saveargv1
= argv
[1];
3576 saveargv2
= argv
[2];
3580 char *p
= alloca (strlen (argv
[2]) + 1);
3582 strcpy (argv
[2] = p
, saveargv2
);
3583 while (*p
&& isspace (*p
))
3585 while (*p
&& !isspace (*p
))
3593 chdir (working_dir
);
3597 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3598 goto done
; /* Allocation might fail due to lack of descriptors. */
3601 mouse_get_xy (&x
, &y
);
3603 dos_ttcooked (); /* do it here while 0 = stdin */
3611 if (msshell
&& !argv
[3])
3613 /* MS-DOS native shells are too restrictive. For starters, they
3614 cannot grok commands longer than 126 characters. In DJGPP v2
3615 and later, `system' is much smarter, so we'll call it instead. */
3619 /* A shell gets a single argument--its full command
3620 line--whose original was saved in `saveargv2'. */
3622 /* Don't let them pass empty command lines to `system', since
3623 with some shells it will try to invoke an interactive shell,
3624 which will hang Emacs. */
3625 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
3629 extern char **environ
;
3630 int save_system_flags
= __system_flags
;
3632 /* Request the most powerful version of `system'. We need
3633 all the help we can get to avoid calling stock DOS shells. */
3634 __system_flags
= (__system_redirect
3635 | __system_use_shell
3636 | __system_allow_multiple_cmds
3637 | __system_allow_long_cmds
3638 | __system_handle_null_commands
3639 | __system_emulate_chdir
);
3642 result
= system (cmnd
);
3643 __system_flags
= save_system_flags
;
3646 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
3650 #endif /* __DJGPP__ > 1 */
3652 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
3657 emacs_close (inbak
);
3658 emacs_close (outbak
);
3659 emacs_close (errbak
);
3665 mouse_moveto (x
, y
);
3668 /* Some programs might change the meaning of the highest bit of the
3669 text attribute byte, so we get blinking characters instead of the
3670 bright background colors. Restore that. */
3677 argv
[1] = saveargv1
;
3678 argv
[2] = saveargv2
;
3686 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3693 /* ------------------------- Compatibility functions -------------------
3698 /* Hostnames for a pc are not really funny,
3699 but they are used in change log so we emulate the best we can. */
3701 gethostname (p
, size
)
3705 char *q
= egetenv ("HOSTNAME");
3712 /* When time zones are set from Ms-Dos too many C-libraries are playing
3713 tricks with time values. We solve this by defining our own version
3714 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3715 once and after each call to `tzset' with TZ changed. That is
3716 accomplished by aliasing tzset to init_gettimeofday. */
3718 static struct tm time_rec
;
3721 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
3729 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
3733 time_rec
.tm_year
= d
.da_year
- 1900;
3734 time_rec
.tm_mon
= d
.da_mon
- 1;
3735 time_rec
.tm_mday
= d
.da_day
;
3738 time_rec
.tm_hour
= t
.ti_hour
;
3739 time_rec
.tm_min
= t
.ti_min
;
3740 time_rec
.tm_sec
= t
.ti_sec
;
3743 tm
.tm_gmtoff
= dos_timezone_offset
;
3745 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
3746 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
3748 /* Ignore tzp; it's obsolescent. */
3752 #endif /* __DJGPP__ < 2 */
3755 * A list of unimplemented functions that we silently ignore.
3759 unsigned alarm (s
) unsigned s
; {}
3760 fork () { return 0; }
3761 int kill (x
, y
) int x
, y
; { return -1; }
3763 void volatile pause () {}
3764 sigsetmask (x
) int x
; { return 0; }
3765 sigblock (mask
) int mask
; { return 0; }
3768 void request_sigio (void) {}
3769 setpgrp () {return 0; }
3770 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
3771 void unrequest_sigio (void) {}
3775 #ifdef POSIX_SIGNALS
3777 /* Augment DJGPP library POSIX signal functions. This is needed
3778 as of DJGPP v2.01, but might be in the library in later releases. */
3780 #include <libc/bss.h>
3782 /* A counter to know when to re-initialize the static sets. */
3783 static int sigprocmask_count
= -1;
3785 /* Which signals are currently blocked (initially none). */
3786 static sigset_t current_mask
;
3788 /* Which signals are pending (initially none). */
3789 static sigset_t pending_signals
;
3791 /* Previous handlers to restore when the blocked signals are unblocked. */
3792 typedef void (*sighandler_t
)(int);
3793 static sighandler_t prev_handlers
[320];
3795 /* A signal handler which just records that a signal occured
3796 (it will be raised later, if and when the signal is unblocked). */
3798 sig_suspender (signo
)
3801 sigaddset (&pending_signals
, signo
);
3805 sigprocmask (how
, new_set
, old_set
)
3807 const sigset_t
*new_set
;
3813 /* If called for the first time, initialize. */
3814 if (sigprocmask_count
!= __bss_count
)
3816 sigprocmask_count
= __bss_count
;
3817 sigemptyset (&pending_signals
);
3818 sigemptyset (¤t_mask
);
3819 for (signo
= 0; signo
< 320; signo
++)
3820 prev_handlers
[signo
] = SIG_ERR
;
3824 *old_set
= current_mask
;
3829 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
3835 sigemptyset (&new_mask
);
3837 /* DJGPP supports upto 320 signals. */
3838 for (signo
= 0; signo
< 320; signo
++)
3840 if (sigismember (¤t_mask
, signo
))
3841 sigaddset (&new_mask
, signo
);
3842 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
3844 sigaddset (&new_mask
, signo
);
3846 /* SIGKILL is silently ignored, as on other platforms. */
3847 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
3848 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
3850 if (( how
== SIG_UNBLOCK
3851 && sigismember (&new_mask
, signo
)
3852 && sigismember (new_set
, signo
))
3853 || (how
== SIG_SETMASK
3854 && sigismember (&new_mask
, signo
)
3855 && !sigismember (new_set
, signo
)))
3857 sigdelset (&new_mask
, signo
);
3858 if (prev_handlers
[signo
] != SIG_ERR
)
3860 signal (signo
, prev_handlers
[signo
]);
3861 prev_handlers
[signo
] = SIG_ERR
;
3863 if (sigismember (&pending_signals
, signo
))
3865 sigdelset (&pending_signals
, signo
);
3870 current_mask
= new_mask
;
3874 #else /* not POSIX_SIGNALS */
3876 sigsetmask (x
) int x
; { return 0; }
3877 sigblock (mask
) int mask
; { return 0; }
3879 #endif /* not POSIX_SIGNALS */
3880 #endif /* __DJGPP__ > 1 */
3883 #include "sysselect.h"
3885 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3886 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3887 ((long)(time).tv_sec < 0 \
3888 || ((time).tv_sec == 0 \
3889 && (long)(time).tv_usec <= 0))
3892 /* This yields the rest of the current time slice to the task manager.
3893 It should be called by any code which knows that it has nothing
3894 useful to do except idle.
3896 I don't use __dpmi_yield here, since versions of library before 2.02
3897 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
3898 on some versions of Windows 9X. */
3901 dos_yield_time_slice (void)
3903 _go32_dpmi_registers r
;
3906 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
3907 _go32_dpmi_simulate_int (0x2f, &r
);
3912 /* Only event queue is checked. */
3913 /* We don't have to call timer_check here
3914 because wait_reading_process_input takes care of that. */
3916 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
3918 SELECT_TYPE
*rfds
, *wfds
, *efds
;
3919 EMACS_TIME
*timeout
;
3927 check_input
= FD_ISSET (0, rfds
);
3938 /* If we are looking only for the terminal, with no timeout,
3939 just read it and wait -- that's more efficient. */
3942 while (!detect_input_pending ())
3944 dos_yield_time_slice ();
3949 EMACS_TIME clnow
, cllast
, cldiff
;
3952 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
3954 while (!check_input
|| !detect_input_pending ())
3957 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
3958 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
3960 /* When seconds wrap around, we assume that no more than
3961 1 minute passed since last `gettime'. */
3962 if (EMACS_TIME_NEG_P (cldiff
))
3963 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
3964 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
3966 /* Stop when timeout value crosses zero. */
3967 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
3970 dos_yield_time_slice ();
3980 * Define overlaid functions:
3982 * chdir -> sys_chdir
3983 * tzset -> init_gettimeofday
3984 * abort -> dos_abort
3989 extern int chdir ();
3995 int len
= strlen (path
);
3996 char *tmp
= (char *)path
;
3998 if (*tmp
&& tmp
[1] == ':')
4000 if (getdisk () != tolower (tmp
[0]) - 'a')
4001 setdisk (tolower (tmp
[0]) - 'a');
4002 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
4006 if (len
> 1 && (tmp
[len
- 1] == '/'))
4008 char *tmp1
= (char *) alloca (len
+ 1);
4019 extern void tzset (void);
4022 init_gettimeofday ()
4028 ltm
= gtm
= time (NULL
);
4029 ltm
= mktime (lstm
= localtime (<m
));
4030 gtm
= mktime (gmtime (>m
));
4031 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
4032 time_rec
.tm_isdst
= lstm
->tm_isdst
;
4033 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
4040 dos_abort (file
, line
)
4044 char buffer1
[200], buffer2
[400];
4047 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
4048 for (i
= j
= 0; buffer1
[i
]; i
++) {
4049 buffer2
[j
++] = buffer1
[i
];
4050 buffer2
[j
++] = 0x70;
4052 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
4053 ScreenSetCursor (2, 0);
4061 ScreenSetCursor (10, 0);
4062 cputs ("\r\n\nEmacs aborted!\r\n");
4064 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
4065 if (screen_virtual_segment
)
4066 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
4067 /* Generate traceback, so we could tell whodunit. */
4068 signal (SIGINT
, SIG_DFL
);
4069 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
4070 #else /* __DJGPP_MINOR__ >= 2 */
4072 #endif /* __DJGPP_MINOR__ >= 2 */
4078 /* The following two are required so that customization feature
4079 won't complain about unbound variables. */
4080 #ifndef HAVE_X_WINDOWS
4081 /* Search path for bitmap files (xfns.c). */
4082 Lisp_Object Vx_bitmap_file_path
;
4084 #ifndef subprocesses
4085 /* Nonzero means delete a process right away if it exits (process.c). */
4086 static int delete_exited_processes
;
4091 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
4092 staticpro (&recent_doskeys
);
4093 #ifndef HAVE_X_WINDOWS
4094 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
4095 "List of directories to search for bitmap files for X.");
4096 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
4098 /* The following three are from xfns.c: */
4099 Qbackground_color
= intern ("background-color");
4100 staticpro (&Qbackground_color
);
4101 Qforeground_color
= intern ("foreground-color");
4102 staticpro (&Qforeground_color
);
4104 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
4105 "*Glyph to display instead of chars not supported by current codepage.\n\
4107 This variable is used only by MSDOS terminals.");
4108 Vdos_unsupported_char_glyph
= '\177';
4110 #ifndef subprocesses
4111 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
4112 "*Non-nil means delete processes immediately when they exit.\n\
4113 nil means don't delete them until `list-processes' is run.");
4114 delete_exited_processes
= 0;
4117 defsubr (&Srecent_doskeys
);
4118 defsubr (&Smsdos_long_file_names
);
4119 defsubr (&Smsdos_downcase_filename
);