1 /* MS-DOS specific C utilities. -*- coding: raw-text -*-
2 Copyright (C) 1993, 1994, 1995, 1996, 1997 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 */
52 #include "termhooks.h"
54 #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;
360 /* Update the screen from a part of relocated DOS/V screen buffer which
361 begins at OFFSET and includes COUNT characters. */
363 dosv_refresh_virtual_screen (int offset
, int count
)
367 if (offset
< 0 || count
< 0) /* paranoia; illegal values crash DOS/V */
370 regs
.h
.ah
= 0xff; /* update relocated screen */
371 regs
.x
.es
= screen_virtual_segment
;
372 regs
.x
.di
= screen_virtual_offset
+ offset
;
374 __dpmi_int (0x10, ®s
);
379 dos_direct_output (y
, x
, buf
, len
)
385 int t0
= 2 * (x
+ y
* screen_size_X
);
386 int t
= t0
+ (int) ScreenPrimary
;
391 dosmemput (buf
++, 1, t
);
395 /* This is faster. */
396 for (_farsetsel (_dos_ds
); --len
>= 0; t
+= 2, buf
++)
397 _farnspokeb (t
, *buf
);
399 if (screen_virtual_segment
)
400 dosv_refresh_virtual_screen (t0
, l0
);
405 /* Flash the screen as a substitute for BEEPs. */
409 do_visible_bell (xorattr
)
410 unsigned char xorattr
;
415 movl _ScreenPrimary,%%eax
422 xorb %%al,%%gs:(%%ebx)
438 : "m" (xorattr
), "g" (screen_size
)
439 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
443 ScreenVisualBell (void)
445 /* This creates an xor-mask that will swap the default fore- and
446 background colors. */
447 do_visible_bell (((the_only_x_display
.foreground_pixel
448 ^ the_only_x_display
.background_pixel
)
453 #ifndef HAVE_X_WINDOWS
455 static int blink_bit
= -1; /* the state of the blink bit at startup */
457 /* Enable bright background colors. */
463 /* Remember the original state of the blink/bright-background bit.
464 It is stored at 0040:0065h in the BIOS data area. */
466 blink_bit
= (_farpeekb (_dos_ds
, 0x465) & 0x20) == 0x20;
470 int86 (0x10, ®s
, ®s
);
473 /* Disable bright background colors (and enable blinking) if we found
474 the video system in that state at startup. */
476 maybe_enable_blinking (void)
484 int86 (0x10, ®s
, ®s
);
488 /* Set the screen dimensions so that it can show no less than
489 ROWS x COLS frame. */
492 dos_set_window_size (rows
, cols
)
496 Lisp_Object video_mode
;
497 int video_mode_value
;
500 int current_rows
= ScreenRows (), current_cols
= ScreenCols ();
502 if (*rows
== current_rows
&& *cols
== current_cols
)
505 /* Do we have a VGA? */
507 int86 (0x10, ®s
, ®s
);
508 if (regs
.h
.al
== 0x1a && regs
.h
.bl
> 5 && regs
.h
.bl
< 13)
513 /* If the user specified a special video mode for these dimensions,
515 sprintf (video_name
, "screen-dimensions-%dx%d", *rows
, *cols
);
516 video_mode
= XSYMBOL (Fintern_soft (build_string (video_name
),
519 if (INTEGERP (video_mode
)
520 && (video_mode_value
= XINT (video_mode
)) > 0)
522 regs
.x
.ax
= video_mode_value
;
523 int86 (0x10, ®s
, ®s
);
527 /* Must hardware-reset the mouse, or else it won't update
528 its notion of screen dimensions for some non-standard
529 video modes. This is *painfully* slow... */
531 int86 (0x33, ®s
, ®s
);
535 /* Find one of the dimensions supported by standard EGA/VGA
536 which gives us at least the required dimensions. */
545 } std_dimension
[] = {
555 while (i
< sizeof (std_dimension
) / sizeof (std_dimension
[0]))
557 if (std_dimension
[i
].need_vga
<= have_vga
558 && std_dimension
[i
].rows
>= *rows
)
560 if (std_dimension
[i
].rows
!= current_rows
561 || *cols
!= current_cols
)
562 _set_screen_lines (std_dimension
[i
].rows
);
569 #else /* not __DJGPP__ > 1 */
571 else if (*rows
<= 25)
573 if (current_rows
!= 25 || current_cols
!= 80)
576 int86 (0x10, ®s
, ®s
);
579 int86 (0x10, ®s
, ®s
);
582 int86 (0x10, ®s
, ®s
);
584 int86 (0x10, ®s
, ®s
);
587 else if (*rows
<= 50)
588 if (have_vga
&& (current_rows
!= 50 || current_cols
!= 80)
589 || *rows
<= 43 && (current_rows
!= 43 || current_cols
!= 80))
592 int86 (0x10, ®s
, ®s
);
595 int86 (0x10, ®s
, ®s
);
598 int86 (0x10, ®s
, ®s
);
601 int86 (0x10, ®s
, ®s
);
603 #endif /* not __DJGPP__ > 1 */
611 /* Tell the caller what dimensions have been REALLY set. */
612 *rows
= ScreenRows ();
613 *cols
= ScreenCols ();
615 /* Enable bright background colors. */
618 /* FIXME: I'm not sure the above will run at all on DOS/V. But let's
619 be defensive anyway. */
620 if (screen_virtual_segment
)
621 dosv_refresh_virtual_screen (0, *cols
* *rows
);
624 /* If we write a character in the position where the mouse is,
625 the mouse cursor may need to be refreshed. */
635 mouse_get_xy (&x
, &y
);
636 if (y
!= new_pos_Y
|| x
< new_pos_X
)
652 union REGS inregs
, outregs
;
655 intdos (&inregs
, &outregs
);
660 IT_set_face (int face
)
663 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
665 if (face
== 1 || (face
== 0 && highlight
))
666 fp
= FRAME_MODE_LINE_FACE (foo
);
667 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
668 fp
= FRAME_DEFAULT_FACE (foo
);
670 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
672 fprintf (termscript
, "<FACE %d: %d/%d>",
673 face
, FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
675 ScreenAttrib
= (FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
);
678 Lisp_Object Vdos_unsupported_char_glyph
;
681 IT_write_glyphs (GLYPH
*str
, int str_len
)
683 unsigned char *screen_buf
, *screen_bp
, *screen_buf_end
, *bp
;
684 int unsupported_face
= FAST_GLYPH_FACE (Vdos_unsupported_char_glyph
);
685 unsigned unsupported_char
= FAST_GLYPH_CHAR (Vdos_unsupported_char_glyph
);
686 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
687 register int sl
= str_len
;
688 register int tlen
= GLYPH_TABLE_LENGTH
;
689 register Lisp_Object
*tbase
= GLYPH_TABLE_BASE
;
691 struct coding_system
*coding
= (CODING_REQUIRE_ENCODING (&terminal_coding
)
693 : &safe_terminal_coding
);
695 /* Do we need to consider conversion of unibyte characters to
697 int convert_unibyte_characters
698 = (NILP (current_buffer
->enable_multibyte_characters
)
699 && unibyte_display_via_language_environment
);
701 if (str_len
== 0) return;
703 screen_buf
= screen_bp
= alloca (str_len
* 2);
704 screen_buf_end
= screen_buf
+ str_len
* 2;
706 /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
708 terminal_coding
.mode
&= ~CODING_MODE_LAST_BLOCK
;
711 int cf
, ch
, chlen
, enclen
;
712 unsigned char workbuf
[4], *buf
;
713 register GLYPH g
= *str
;
715 /* Find the actual glyph to display by traversing the entire
716 aliases chain for this glyph. */
717 GLYPH_FOLLOW_ALIASES (tbase
, tlen
, g
);
719 /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
720 only for the redisplay code to know how many columns does
721 this character occupy on the screen. Skip padding glyphs. */
722 if ((g
& GLYPH_MASK_PADDING
))
729 /* Convert the character code to multibyte, if they
730 requested display via language environment. */
731 ch
= FAST_GLYPH_CHAR (g
);
732 /* We only want to convert unibyte characters to multibyte
733 in unibyte buffers! Otherwise, the 8-bit code might come
734 from the display table set up to display foreign characters. */
735 if (SINGLE_BYTE_CHAR_P (ch
) && convert_unibyte_characters
737 || (ch
>= 0200 && !NILP (Vnonascii_translation_table
))))
738 ch
= unibyte_char_to_multibyte (ch
);
740 /* Invalid characters are displayed with a special glyph. */
743 g
= !NILP (Vdos_unsupported_char_glyph
)
744 ? Vdos_unsupported_char_glyph
745 : MAKE_GLYPH (selected_frame
, '\177',
746 GLYPH_FACE (selected_frame
, g
));
747 ch
= FAST_GLYPH_CHAR (g
);
749 if (COMPOSITE_CHAR_P (ch
))
751 /* If CH is a composite character, we can display
752 only the first component. */
753 g
= cmpchar_table
[COMPOSITE_CHAR_ID (ch
)]->glyph
[0],
754 ch
= GLYPH_CHAR (selected_frame
, g
);
755 cf
= FAST_GLYPH_FACE (g
);
758 /* If the face of this glyph is different from the current
759 screen face, update the screen attribute byte. */
760 cf
= FAST_GLYPH_FACE (g
);
761 if (cf
!= screen_face
)
762 IT_set_face (cf
); /* handles invalid faces gracefully */
764 if (GLYPH_SIMPLE_P (tbase
, tlen
, g
))
765 /* We generate the multi-byte form of CH in BUF. */
766 chlen
= CHAR_STRING (ch
, workbuf
, buf
);
769 /* We have a string in Vglyph_table. */
770 chlen
= GLYPH_LENGTH (tbase
, g
);
771 buf
= GLYPH_STRING (tbase
, g
);
774 /* If the character is not multibyte, don't bother converting it.
775 FIXME: what about "emacs --unibyte" */
778 *conversion_buffer
= (unsigned char)ch
;
784 encode_coding (coding
, buf
, conversion_buffer
, chlen
,
785 conversion_buffer_size
);
786 chlen
-= coding
->consumed
;
787 enclen
= coding
->produced
;
789 /* Replace glyph codes that cannot be converted by
790 terminal_coding with Vdos_unsupported_char_glyph. */
791 if (*conversion_buffer
== '?')
793 char *cbp
= conversion_buffer
;
795 while (cbp
< conversion_buffer
+ enclen
&& *cbp
== '?')
796 *cbp
++ = unsupported_char
;
797 if (unsupported_face
!= screen_face
)
798 IT_set_face (unsupported_face
);
802 if (enclen
+ chlen
> screen_buf_end
- screen_bp
)
804 /* The allocated buffer for screen writes is too small.
805 Flush it and loop again without incrementing STR, so
806 that the next loop will begin with the same glyph. */
807 int nbytes
= screen_bp
- screen_buf
;
810 dosmemput (screen_buf
, nbytes
, (int)ScreenPrimary
+ offset
);
811 if (screen_virtual_segment
)
812 dosv_refresh_virtual_screen (offset
, nbytes
/ 2);
813 new_pos_X
+= nbytes
/ 2;
816 /* Prepare to reuse the same buffer again. */
817 screen_bp
= screen_buf
;
821 /* There's enough place in the allocated buffer to add
822 the encoding of this glyph. */
824 /* First, copy the encoded bytes. */
825 for (bp
= conversion_buffer
; enclen
--; bp
++)
827 *screen_bp
++ = (unsigned char)*bp
;
828 *screen_bp
++ = ScreenAttrib
;
830 fputc (*bp
, termscript
);
833 /* Now copy the bytes not consumed by the encoding. */
836 buf
+= coding
->consumed
;
840 fputc (*buf
, termscript
);
841 *screen_bp
++ = (unsigned char)*buf
++;
842 *screen_bp
++ = ScreenAttrib
;
846 /* Update STR and its remaining length. */
853 /* Dump whatever is left in the screen buffer. */
855 dosmemput (screen_buf
, screen_bp
- screen_buf
, (int)ScreenPrimary
+ offset
);
856 if (screen_virtual_segment
)
857 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
858 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
860 /* We may have to output some codes to terminate the writing. */
861 if (CODING_REQUIRE_FLUSHING (coding
))
863 coding
->mode
|= CODING_MODE_LAST_BLOCK
;
864 encode_coding (coding
, "", conversion_buffer
, 0, conversion_buffer_size
);
865 if (coding
->produced
> 0)
867 for (screen_bp
= screen_buf
, bp
= conversion_buffer
;
868 coding
->produced
--; bp
++)
870 *screen_bp
++ = (unsigned char)*bp
;
871 *screen_bp
++ = ScreenAttrib
;
873 fputc (*bp
, termscript
);
875 offset
+= screen_bp
- screen_buf
;
877 dosmemput (screen_buf
, screen_bp
- screen_buf
,
878 (int)ScreenPrimary
+ offset
);
879 if (screen_virtual_segment
)
880 dosv_refresh_virtual_screen (offset
, (screen_bp
- screen_buf
) / 2);
881 new_pos_X
+= (screen_bp
- screen_buf
) / 2;
887 IT_clear_end_of_line (int first_unused
)
891 int offset
= 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
);
892 extern int fatal_error_in_progress
;
894 if (fatal_error_in_progress
)
899 fprintf (termscript
, "<CLR:EOL>");
900 i
= (j
= screen_size_X
- new_pos_X
) * 2;
901 spaces
= sp
= alloca (i
);
906 *sp
++ = ScreenAttrib
;
910 dosmemput (spaces
, i
, (int)ScreenPrimary
+ offset
);
911 if (screen_virtual_segment
)
912 dosv_refresh_virtual_screen (offset
, i
/ 2);
916 IT_clear_screen (void)
919 fprintf (termscript
, "<CLR:SCR>");
923 if (screen_virtual_segment
)
924 dosv_refresh_virtual_screen (0, screen_size
);
925 new_pos_X
= new_pos_Y
= 0;
929 IT_clear_to_end (void)
932 fprintf (termscript
, "<CLR:EOS>");
934 while (new_pos_Y
< screen_size_Y
) {
936 IT_clear_end_of_line (0);
942 IT_cursor_to (int y
, int x
)
945 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
950 static int cursor_cleared
;
953 IT_display_cursor (int on
)
955 if (on
&& cursor_cleared
)
957 ScreenSetCursor (current_pos_Y
, current_pos_X
);
960 else if (!on
&& !cursor_cleared
)
962 ScreenSetCursor (-1, -1);
967 /* Emacs calls cursor-movement functions a lot when it updates the
968 display (probably a legacy of old terminals where you cannot
969 update a screen line without first moving the cursor there).
970 However, cursor movement is expensive on MSDOS (it calls a slow
971 BIOS function and requires 2 mode switches), while actual screen
972 updates access the video memory directly and don't depend on
973 cursor position. To avoid slowing down the redisplay, we cheat:
974 all functions that move the cursor only set internal variables
975 which record the cursor position, whereas the cursor is only
976 moved to its final position whenever screen update is complete.
978 `IT_cmgoto' is called from the keyboard reading loop and when the
979 frame update is complete. This means that we are ready for user
980 input, so we update the cursor position to show where the point is,
981 and also make the mouse pointer visible.
983 Special treatment is required when the cursor is in the echo area,
984 to put the cursor at the end of the text displayed there. */
987 IT_cmgoto (FRAME_PTR f
)
989 /* Only set the cursor to where it should be if the display is
990 already in sync with the window contents. */
991 int update_cursor_pos
= MODIFF
== unchanged_modified
;
992 static int previous_pos_X
= -1;
994 /* If the display is in sync, forget any previous knowledge about
995 cursor position. This is primarily for unexpected events like
996 C-g in the minibuffer. */
997 if (update_cursor_pos
&& previous_pos_X
>= 0)
999 /* If we are in the echo area, put the cursor at the
1000 end of the echo area message. */
1001 if (!update_cursor_pos
1002 && XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f
))->top
) <= new_pos_Y
)
1004 int tem_X
= current_pos_X
, dummy
;
1006 if (echo_area_glyphs
)
1008 tem_X
= echo_area_glyphs_length
;
1009 /* Save current cursor position, to be restored after the
1010 echo area message is erased. Only remember one level
1011 of previous cursor position. */
1012 if (previous_pos_X
== -1)
1013 ScreenGetCursor (&dummy
, &previous_pos_X
);
1015 else if (previous_pos_X
>= 0)
1017 /* We wind up here after the echo area message is erased.
1018 Restore the cursor position we remembered above. */
1019 tem_X
= previous_pos_X
;
1020 previous_pos_X
= -1;
1023 if (current_pos_X
!= tem_X
)
1026 update_cursor_pos
= 1;
1030 if (update_cursor_pos
1031 && (current_pos_X
!= new_pos_X
|| current_pos_Y
!= new_pos_Y
))
1033 ScreenSetCursor (current_pos_Y
= new_pos_Y
, current_pos_X
= new_pos_X
);
1035 fprintf (termscript
, "\n<CURSOR:%dx%d>", current_pos_X
, current_pos_Y
);
1038 /* Maybe cursor is invisible, so make it visible. */
1039 IT_display_cursor (1);
1041 /* Mouse pointer should be always visible if we are waiting for
1048 IT_reassert_line_highlight (int new, int vpos
)
1051 IT_set_face (0); /* To possibly clear the highlighting. */
1055 IT_change_line_highlight (int new_highlight
, int vpos
, int first_unused_hpos
)
1057 highlight
= new_highlight
;
1058 IT_set_face (0); /* To possibly clear the highlighting. */
1059 IT_cursor_to (vpos
, 0);
1060 IT_clear_end_of_line (first_unused_hpos
);
1064 IT_update_begin (struct frame
*foo
)
1067 IT_set_face (0); /* To possibly clear the highlighting. */
1072 IT_update_end (struct frame
*foo
)
1076 /* Insert and delete characters. These are not supposed to be used
1077 because we are supposed to turn off the feature of using them by
1078 setting char_ins_del_ok to zero (see internal_terminal_init). */
1080 IT_insert_glyphs (start
, len
)
1081 register char *start
;
1088 IT_delete_glyphs (n
)
1094 /* set-window-configuration on window.c needs this. */
1096 x_set_menu_bar_lines (f
, value
, oldval
)
1098 Lisp_Object value
, oldval
;
1100 set_menu_bar_lines (f
, value
, oldval
);
1103 /* This was copied from xfns.c */
1105 Lisp_Object Qbackground_color
;
1106 Lisp_Object Qforeground_color
;
1107 extern Lisp_Object Qtitle
;
1109 /* IT_set_terminal_modes is called when emacs is started,
1110 resumed, and whenever the screen is redrawn! */
1113 IT_set_terminal_modes (void)
1116 fprintf (termscript
, "\n<SET_TERM>");
1119 screen_size_X
= ScreenCols ();
1120 screen_size_Y
= ScreenRows ();
1121 screen_size
= screen_size_X
* screen_size_Y
;
1123 new_pos_X
= new_pos_Y
= 0;
1124 current_pos_X
= current_pos_Y
= -1;
1126 if (term_setup_done
)
1128 term_setup_done
= 1;
1130 startup_screen_size_X
= screen_size_X
;
1131 startup_screen_size_Y
= screen_size_Y
;
1132 startup_screen_attrib
= ScreenAttrib
;
1135 /* Is DOS/V (or any other RSIS software which relocates
1136 the screen) installed? */
1138 unsigned short es_value
;
1141 regs
.h
.ah
= 0xfe; /* get relocated screen address */
1142 if (ScreenPrimary
== 0xb0000UL
|| ScreenPrimary
== 0xb8000UL
)
1143 regs
.x
.es
= (ScreenPrimary
>> 4) & 0xffff;
1144 else if (screen_old_address
) /* already switched to Japanese mode once */
1145 regs
.x
.es
= (screen_old_address
>> 4) & 0xffff;
1147 regs
.x
.es
= ScreenMode () == 7 ? 0xb000 : 0xb800;
1149 es_value
= regs
.x
.es
;
1150 __dpmi_int (0x10, ®s
);
1152 if (regs
.x
.es
!= es_value
)
1154 /* screen_old_address is only set if ScreenPrimary does NOT
1155 already point to the relocated buffer address returned by
1156 the Int 10h/AX=FEh call above. DJGPP v2.02 and later sets
1157 ScreenPrimary to that address at startup under DOS/V. */
1158 if (regs
.x
.es
!= (ScreenPrimary
>> 4) & 0xffff)
1159 screen_old_address
= ScreenPrimary
;
1160 screen_virtual_segment
= regs
.x
.es
;
1161 screen_virtual_offset
= regs
.x
.di
;
1162 ScreenPrimary
= (screen_virtual_segment
<< 4) + screen_virtual_offset
;
1165 #endif /* __DJGPP__ > 1 */
1167 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
1168 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
1171 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
1172 screen_size_X
, screen_size_Y
);
1177 /* IT_reset_terminal_modes is called when emacs is
1178 suspended or killed. */
1181 IT_reset_terminal_modes (void)
1183 int display_row_start
= (int) ScreenPrimary
;
1184 int saved_row_len
= startup_screen_size_X
* 2;
1185 int update_row_len
= ScreenCols () * 2;
1186 int current_rows
= ScreenRows ();
1187 int to_next_row
= update_row_len
;
1188 unsigned char *saved_row
= startup_screen_buffer
;
1189 int cursor_pos_X
= ScreenCols () - 1;
1190 int cursor_pos_Y
= ScreenRows () - 1;
1193 fprintf (termscript
, "\n<RESET_TERM>");
1197 if (!term_setup_done
)
1202 /* Leave the video system in the same state as we found it,
1203 as far as the blink/bright-background bit is concerned. */
1204 maybe_enable_blinking ();
1206 /* We have a situation here.
1207 We cannot just do ScreenUpdate(startup_screen_buffer) because
1208 the luser could have changed screen dimensions inside Emacs
1209 and failed (or didn't want) to restore them before killing
1210 Emacs. ScreenUpdate() uses the *current* screen dimensions and
1211 thus will happily use memory outside what was allocated for
1212 `startup_screen_buffer'.
1213 Thus we only restore as much as the current screen dimensions
1214 can hold, and clear the rest (if the saved screen is smaller than
1215 the current) with the color attribute saved at startup. The cursor
1216 is also restored within the visible dimensions. */
1218 ScreenAttrib
= startup_screen_attrib
;
1220 /* Don't restore the screen if we are exiting less than 2 seconds
1221 after startup: we might be crashing, and the screen might show
1222 some vital clues to what's wrong. */
1223 if (clock () - startup_time
>= 2*CLOCKS_PER_SEC
)
1226 if (screen_virtual_segment
)
1227 dosv_refresh_virtual_screen (0, screen_size
);
1229 if (update_row_len
> saved_row_len
)
1230 update_row_len
= saved_row_len
;
1231 if (current_rows
> startup_screen_size_Y
)
1232 current_rows
= startup_screen_size_Y
;
1235 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
1236 update_row_len
/ 2, current_rows
);
1238 while (current_rows
--)
1240 dosmemput (saved_row
, update_row_len
, display_row_start
);
1241 if (screen_virtual_segment
)
1242 dosv_refresh_virtual_screen (display_row_start
- ScreenPrimary
,
1243 update_row_len
/ 2);
1244 saved_row
+= saved_row_len
;
1245 display_row_start
+= to_next_row
;
1248 if (startup_pos_X
< cursor_pos_X
)
1249 cursor_pos_X
= startup_pos_X
;
1250 if (startup_pos_Y
< cursor_pos_Y
)
1251 cursor_pos_Y
= startup_pos_Y
;
1253 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
1254 xfree (startup_screen_buffer
);
1256 term_setup_done
= 0;
1260 IT_set_terminal_window (int foo
)
1265 IT_set_frame_parameters (f
, alist
)
1270 int length
= XINT (Flength (alist
));
1273 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1275 = (Lisp_Object
*) alloca (length
* sizeof (Lisp_Object
));
1277 extern unsigned long load_color ();
1281 /* Extract parm names and values into those vectors. */
1283 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
1288 parms
[i
] = Fcar (elt
);
1289 CHECK_SYMBOL (parms
[i
], 1);
1290 values
[i
] = Fcdr (elt
);
1295 /* Now process them in reverse of specified order. */
1296 for (i
--; i
>= 0; i
--)
1298 Lisp_Object prop
= parms
[i
];
1299 Lisp_Object val
= values
[i
];
1301 if (EQ (prop
, Qforeground_color
))
1303 unsigned long new_color
= load_color (f
, val
);
1304 if (new_color
!= ~0)
1306 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
1309 fprintf (termscript
, "<FGCOLOR %lu>\n", new_color
);
1312 else if (EQ (prop
, Qbackground_color
))
1314 unsigned long new_color
= load_color (f
, val
);
1315 if (new_color
!= ~0)
1317 FRAME_BACKGROUND_PIXEL (f
) = new_color
;
1320 fprintf (termscript
, "<BGCOLOR %lu>\n", new_color
);
1323 else if (EQ (prop
, Qtitle
))
1325 x_set_title (f
, val
);
1327 fprintf (termscript
, "<TITLE: %s>\n", XSTRING (val
)->data
);
1329 else if (EQ (prop
, intern ("reverse")) && EQ (val
, Qt
))
1331 unsigned long fg
= FRAME_FOREGROUND_PIXEL (f
);
1333 FRAME_FOREGROUND_PIXEL (f
) = FRAME_BACKGROUND_PIXEL (f
);
1334 FRAME_BACKGROUND_PIXEL (f
) = fg
;
1336 fprintf (termscript
, "<INVERSE-VIDEO>\n");
1338 store_frame_param (f
, prop
, val
);
1344 extern void recompute_basic_faces (FRAME_PTR
);
1345 extern void redraw_frame (FRAME_PTR
);
1347 recompute_basic_faces (f
);
1348 if (f
== selected_frame
)
1353 extern void init_frame_faces (FRAME_PTR
);
1355 #endif /* !HAVE_X_WINDOWS */
1358 /* Do we need the internal terminal? */
1361 internal_terminal_init ()
1363 char *term
= getenv ("TERM");
1366 #ifdef HAVE_X_WINDOWS
1367 if (!inhibit_window_system
)
1372 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
1374 if (getenv ("EMACSTEST"))
1375 termscript
= fopen (getenv ("EMACSTEST"), "wt");
1377 #ifndef HAVE_X_WINDOWS
1378 if (!internal_terminal
|| inhibit_window_system
)
1380 selected_frame
->output_method
= output_termcap
;
1384 Vwindow_system
= intern ("pc");
1385 Vwindow_system_version
= make_number (1);
1387 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM address. */
1388 screen_old_address
= 0;
1390 bzero (&the_only_x_display
, sizeof the_only_x_display
);
1391 the_only_x_display
.background_pixel
= 7; /* White */
1392 the_only_x_display
.foreground_pixel
= 0; /* Black */
1394 colors
= getenv ("EMACSCOLORS");
1395 if (colors
&& strlen (colors
) >= 2)
1397 /* The colors use 4 bits each (we enable bright background). */
1398 if (isdigit (colors
[0]))
1400 else if (isxdigit (colors
[0]))
1401 colors
[0] -= (isupper (colors
[0]) ? 'A' : 'a') - 10;
1402 if (colors
[0] >= 0 && colors
[0] < 16)
1403 the_only_x_display
.foreground_pixel
= colors
[0];
1404 if (isdigit (colors
[1]))
1406 else if (isxdigit (colors
[1]))
1407 colors
[1] -= (isupper (colors
[1]) ? 'A' : 'a') - 10;
1408 if (colors
[1] >= 0 && colors
[1] < 16)
1409 the_only_x_display
.background_pixel
= colors
[1];
1411 the_only_x_display
.line_height
= 1;
1412 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
1414 init_frame_faces (selected_frame
);
1416 ring_bell_hook
= IT_ring_bell
;
1417 insert_glyphs_hook
= IT_insert_glyphs
;
1418 delete_glyphs_hook
= IT_delete_glyphs
;
1419 write_glyphs_hook
= IT_write_glyphs
;
1420 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
1421 clear_to_end_hook
= IT_clear_to_end
;
1422 clear_end_of_line_hook
= IT_clear_end_of_line
;
1423 clear_frame_hook
= IT_clear_screen
;
1424 change_line_highlight_hook
= IT_change_line_highlight
;
1425 update_begin_hook
= IT_update_begin
;
1426 update_end_hook
= IT_update_end
;
1427 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
1428 frame_up_to_date_hook
= IT_cmgoto
; /* position cursor when update is done */
1430 /* These hooks are called by term.c without being checked. */
1431 set_terminal_modes_hook
= IT_set_terminal_modes
;
1432 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
1433 set_terminal_window_hook
= IT_set_terminal_window
;
1435 char_ins_del_ok
= 0; /* just as fast to write the line */
1439 dos_get_saved_screen (screen
, rows
, cols
)
1444 #ifndef HAVE_X_WINDOWS
1445 *screen
= startup_screen_buffer
;
1446 *cols
= startup_screen_size_X
;
1447 *rows
= startup_screen_size_Y
;
1448 return *screen
!= (char *)0;
1454 #ifndef HAVE_X_WINDOWS
1456 /* We are not X, but we can emulate it well enough for our needs... */
1460 if (! FRAME_MSDOS_P (selected_frame
))
1461 error ("Not running under a windows system");
1467 /* ----------------------- Keyboard control ----------------------
1469 * Keymaps reflect the following keyboard layout:
1471 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
1472 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
1473 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
1474 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
1478 #define Ignore 0x0000
1479 #define Normal 0x0000 /* normal key - alt changes scan-code */
1480 #define FctKey 0x1000 /* func key if c == 0, else c */
1481 #define Special 0x2000 /* func key even if c != 0 */
1482 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1483 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1484 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1485 #define Grey 0x6000 /* Grey keypad key */
1487 #define Alt 0x0100 /* alt scan-code */
1488 #define Ctrl 0x0200 /* ctrl scan-code */
1489 #define Shift 0x0400 /* shift scan-code */
1491 static int extended_kbd
; /* 101 (102) keyboard present. */
1493 struct kbd_translate
{
1496 unsigned short code
;
1499 struct dos_keyboard_map
1504 struct kbd_translate
*translate_table
;
1508 static struct dos_keyboard_map us_keyboard
= {
1510 /* 01234567890123456789012345678901234567890 12345678901234 */
1511 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
1512 /* 0123456789012345678901234567890123456789 012345678901234 */
1513 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
1514 0, /* no Alt-Gr key */
1515 0 /* no translate table */
1518 static struct dos_keyboard_map fr_keyboard
= {
1520 /* 012 3456789012345678901234567890123456789012345678901234 */
1521 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
1522 /* 0123456789012345678901234567890123456789012345678901234 */
1523 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
1524 /* 01234567 89012345678901234567890123456789012345678901234 */
1526 0 /* no translate table */
1530 * Italian keyboard support, country code 39.
1533 * added also {,},` as, respectively, AltGr-8, AltGr-9, AltGr-'
1534 * Donated by Stefano Brozzi <brozzis@mag00.cedi.unipr.it>
1537 static struct kbd_translate it_kbd_translate_table
[] = {
1538 { 0x56, 0x3c, Normal
| 13 },
1539 { 0x56, 0x3e, Normal
| 27 },
1542 static struct dos_keyboard_map it_keyboard
= {
1544 /* 0 123456789012345678901234567890123456789012345678901234 */
1545 "\\1234567890'\8d< qwertyuiop\8a+> asdfghjkl\95\85\97 zxcvbnm,.- ",
1546 /* 01 23456789012345678901234567890123456789012345678901234 */
1547 "|!\"\9c$%&/()=?^> QWERTYUIOP\82* ASDFGHJKL\87øõ ZXCVBNM;:_ ",
1548 /* 0123456789012345678901234567890123456789012345678901234 */
1550 it_kbd_translate_table
1553 static struct dos_keyboard_map dk_keyboard
= {
1555 /* 0123456789012345678901234567890123456789012345678901234 */
1556 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
1557 /* 01 23456789012345678901234567890123456789012345678901234 */
1558 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
1559 /* 0123456789012345678901234567890123456789012345678901234 */
1561 0 /* no translate table */
1564 static struct kbd_translate jp_kbd_translate_table
[] = {
1565 { 0x73, 0x5c, Normal
| 0 },
1566 { 0x73, 0x5f, Normal
| 0 },
1567 { 0x73, 0x1c, Map
| 0 },
1568 { 0x7d, 0x5c, Normal
| 13 },
1569 { 0x7d, 0x7c, Normal
| 13 },
1570 { 0x7d, 0x1c, Map
| 13 },
1573 static struct dos_keyboard_map jp_keyboard
= {
1575 /* 0123456789012 345678901234567890123456789012345678901234 */
1576 "\\1234567890-^\\ qwertyuiop@[ asdfghjkl;:] zxcvbnm,./ ",
1577 /* 01 23456789012345678901234567890123456789012345678901234 */
1578 "_!\"#$%&'()~=~| QWERTYUIOP`{ ASDFGHJKL+*} ZXCVBNM<>? ",
1579 0, /* no Alt-Gr key */
1580 jp_kbd_translate_table
1583 static struct keyboard_layout_list
1586 struct dos_keyboard_map
*keyboard_map
;
1587 } keyboard_layout_list
[] =
1596 static struct dos_keyboard_map
*keyboard
;
1597 static int keyboard_map_all
;
1598 static int international_keyboard
;
1601 dos_set_keyboard (code
, always
)
1606 _go32_dpmi_registers regs
;
1608 /* See if Keyb.Com is installed (for international keyboard support).
1609 Note: calling Int 2Fh via int86 wedges the DOS box on some versions
1610 of Windows 9X! So don't do that! */
1612 regs
.x
.ss
= regs
.x
.sp
= regs
.x
.flags
= 0;
1613 _go32_dpmi_simulate_int (0x2f, ®s
);
1614 if (regs
.h
.al
== 0xff)
1615 international_keyboard
= 1;
1617 /* Initialize to US settings, for countries that don't have their own. */
1618 keyboard
= keyboard_layout_list
[0].keyboard_map
;
1619 keyboard_map_all
= always
;
1620 dos_keyboard_layout
= 1;
1622 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
1623 if (code
== keyboard_layout_list
[i
].country_code
)
1625 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
1626 keyboard_map_all
= always
;
1627 dos_keyboard_layout
= code
;
1635 unsigned char char_code
; /* normal code */
1636 unsigned char meta_code
; /* M- code */
1637 unsigned char keypad_code
; /* keypad code */
1638 unsigned char editkey_code
; /* edit key */
1639 } keypad_translate_map
[] = {
1640 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1641 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1642 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1643 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1644 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1645 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1646 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1647 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1648 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1649 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1650 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1655 unsigned char char_code
; /* normal code */
1656 unsigned char keypad_code
; /* keypad code */
1657 } grey_key_translate_map
[] = {
1658 '/', 0xaf, /* kp-decimal */
1659 '*', 0xaa, /* kp-multiply */
1660 '-', 0xad, /* kp-subtract */
1661 '+', 0xab, /* kp-add */
1662 '\r', 0x8d /* kp-enter */
1665 static unsigned short
1666 ibmpc_translate_map
[] =
1668 /* --------------- 00 to 0f --------------- */
1669 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
1670 Alt
| ModFct
| 0x1b, /* Escape */
1671 Normal
| 1, /* '1' */
1672 Normal
| 2, /* '2' */
1673 Normal
| 3, /* '3' */
1674 Normal
| 4, /* '4' */
1675 Normal
| 5, /* '5' */
1676 Normal
| 6, /* '6' */
1677 Normal
| 7, /* '7' */
1678 Normal
| 8, /* '8' */
1679 Normal
| 9, /* '9' */
1680 Normal
| 10, /* '0' */
1681 Normal
| 11, /* '-' */
1682 Normal
| 12, /* '=' */
1683 Special
| 0x08, /* Backspace */
1684 ModFct
| 0x74, /* Tab/Backtab */
1686 /* --------------- 10 to 1f --------------- */
1699 ModFct
| 0x0d, /* Return */
1704 /* --------------- 20 to 2f --------------- */
1713 Map
| 40, /* '\'' */
1715 Ignore
, /* Left shift */
1716 Map
| 41, /* '\\' */
1722 /* --------------- 30 to 3f --------------- */
1729 Ignore
, /* Right shift */
1730 Grey
| 1, /* Grey * */
1732 Normal
| 55, /* ' ' */
1733 Ignore
, /* Caps Lock */
1734 FctKey
| 0xbe, /* F1 */
1735 FctKey
| 0xbf, /* F2 */
1736 FctKey
| 0xc0, /* F3 */
1737 FctKey
| 0xc1, /* F4 */
1738 FctKey
| 0xc2, /* F5 */
1740 /* --------------- 40 to 4f --------------- */
1741 FctKey
| 0xc3, /* F6 */
1742 FctKey
| 0xc4, /* F7 */
1743 FctKey
| 0xc5, /* F8 */
1744 FctKey
| 0xc6, /* F9 */
1745 FctKey
| 0xc7, /* F10 */
1746 Ignore
, /* Num Lock */
1747 Ignore
, /* Scroll Lock */
1748 KeyPad
| 7, /* Home */
1749 KeyPad
| 8, /* Up */
1750 KeyPad
| 9, /* Page Up */
1751 Grey
| 2, /* Grey - */
1752 KeyPad
| 4, /* Left */
1753 KeyPad
| 5, /* Keypad 5 */
1754 KeyPad
| 6, /* Right */
1755 Grey
| 3, /* Grey + */
1756 KeyPad
| 1, /* End */
1758 /* --------------- 50 to 5f --------------- */
1759 KeyPad
| 2, /* Down */
1760 KeyPad
| 3, /* Page Down */
1761 KeyPad
| 0, /* Insert */
1762 KeyPad
| 10, /* Delete */
1763 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1764 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1765 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1766 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1767 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1768 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1769 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1770 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1771 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1772 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1773 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1774 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1776 /* --------------- 60 to 6f --------------- */
1777 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1778 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1779 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1780 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1781 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1782 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1783 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1784 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1785 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1786 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1787 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1788 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1789 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1790 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1791 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1792 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1794 /* --------------- 70 to 7f --------------- */
1795 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1796 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1797 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1798 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1799 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1800 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1801 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1802 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1803 Alt
| Map
| 1, /* '1' */
1804 Alt
| Map
| 2, /* '2' */
1805 Alt
| Map
| 3, /* '3' */
1806 Alt
| Map
| 4, /* '4' */
1807 Alt
| Map
| 5, /* '5' */
1808 Alt
| Map
| 6, /* '6' */
1809 Alt
| Map
| 7, /* '7' */
1810 Alt
| Map
| 8, /* '8' */
1812 /* --------------- 80 to 8f --------------- */
1813 Alt
| Map
| 9, /* '9' */
1814 Alt
| Map
| 10, /* '0' */
1815 Alt
| Map
| 11, /* '-' */
1816 Alt
| Map
| 12, /* '=' */
1817 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1818 FctKey
| 0xc8, /* F11 */
1819 FctKey
| 0xc9, /* F12 */
1820 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1821 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1822 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1823 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1824 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1825 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1826 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1827 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1828 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1830 /* --------------- 90 to 9f --------------- */
1831 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1832 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1833 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1834 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1835 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1836 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1837 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1838 Alt
| FctKey
| 0x50, /* (Alt) Home */
1839 Alt
| FctKey
| 0x52, /* (Alt) Up */
1840 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1841 Ignore
, /* NO KEY */
1842 Alt
| FctKey
| 0x51, /* (Alt) Left */
1843 Ignore
, /* NO KEY */
1844 Alt
| FctKey
| 0x53, /* (Alt) Right */
1845 Ignore
, /* NO KEY */
1846 Alt
| FctKey
| 0x57, /* (Alt) End */
1848 /* --------------- a0 to af --------------- */
1849 Alt
| KeyPad
| 2, /* (Alt) Down */
1850 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1851 Alt
| KeyPad
| 0, /* (Alt) Insert */
1852 Alt
| KeyPad
| 10, /* (Alt) Delete */
1853 Alt
| Grey
| 0, /* (Alt) Grey / */
1854 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1855 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1858 /* These bit-positions corresponds to values returned by BIOS */
1859 #define SHIFT_P 0x0003 /* two bits! */
1860 #define CTRL_P 0x0004
1861 #define ALT_P 0x0008
1862 #define SCRLOCK_P 0x0010
1863 #define NUMLOCK_P 0x0020
1864 #define CAPSLOCK_P 0x0040
1865 #define ALT_GR_P 0x0800
1866 #define SUPER_P 0x4000 /* pseudo */
1867 #define HYPER_P 0x8000 /* pseudo */
1870 dos_get_modifiers (keymask
)
1877 /* Calculate modifier bits */
1878 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1879 int86 (0x16, ®s
, ®s
);
1883 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1884 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1888 mask
= regs
.h
.al
& (SHIFT_P
|
1889 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1891 /* Do not break international keyboard support. */
1892 /* When Keyb.Com is loaded, the right Alt key is */
1893 /* used for accessing characters like { and } */
1894 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1897 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1900 if (dos_hyper_key
== 1)
1903 modifiers
|= hyper_modifier
;
1905 else if (dos_super_key
== 1)
1908 modifiers
|= super_modifier
;
1910 else if (!international_keyboard
)
1912 /* If Keyb.Com is NOT installed, let Right Alt behave
1913 like the Left Alt. */
1919 if (regs
.h
.ah
& 1) /* Left CTRL pressed ? */
1922 if (regs
.h
.ah
& 4) /* Right CTRL pressed ? */
1924 if (dos_hyper_key
== 2)
1927 modifiers
|= hyper_modifier
;
1929 else if (dos_super_key
== 2)
1932 modifiers
|= super_modifier
;
1940 modifiers
|= shift_modifier
;
1942 modifiers
|= ctrl_modifier
;
1944 modifiers
|= meta_modifier
;
1951 #define NUM_RECENT_DOSKEYS (100)
1952 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1953 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1954 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1956 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1957 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1958 Each input key receives two values in this vector: first the ASCII code,\n\
1959 and then the scan code.")
1962 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1965 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1966 return Fvector (total_doskeys
, keys
);
1969 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1970 bcopy (keys
+ recent_doskeys_index
,
1971 XVECTOR (val
)->contents
,
1972 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1974 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1975 recent_doskeys_index
* sizeof (Lisp_Object
));
1980 /* Get a char from keyboard. Function keys are put into the event queue. */
1982 extern void kbd_buffer_store_event (struct input_event
*);
1983 static int mouse_preempted
= 0; /* non-zero when XMenu gobbles mouse events */
1988 struct input_event event
;
1991 #ifndef HAVE_X_WINDOWS
1992 /* Maybe put the cursor where it should be. */
1993 IT_cmgoto (selected_frame
);
1996 /* The following condition is equivalent to `kbhit ()', except that
1997 it uses the bios to do its job. This pleases DESQview/X. */
1998 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1999 int86 (0x16, ®s
, ®s
),
2000 (regs
.x
.flags
& 0x40) == 0)
2003 register unsigned char c
;
2004 int sc
, code
= -1, mask
, kp_mode
;
2007 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
2008 int86 (0x16, ®s
, ®s
);
2013 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2015 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2016 recent_doskeys_index
= 0;
2017 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
2019 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
2020 recent_doskeys_index
= 0;
2022 modifiers
= dos_get_modifiers (&mask
);
2024 #ifndef HAVE_X_WINDOWS
2025 if (!NILP (Vdos_display_scancodes
))
2028 sprintf (buf
, "%02x:%02x*%04x",
2029 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
2030 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
2038 case 10: /* Ctrl Grey Enter */
2039 code
= Ctrl
| Grey
| 4;
2041 case 13: /* Grey Enter */
2044 case '/': /* Grey / */
2054 /* Try the keyboard-private translation table first. */
2055 if (keyboard
->translate_table
)
2057 struct kbd_translate
*p
= keyboard
->translate_table
;
2061 if (p
->sc
== sc
&& p
->ch
== c
)
2069 /* If the private table didn't translate it, use the general
2073 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
2075 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
2082 /* We only look at the keyboard Ctrl/Shift/Alt keys when
2083 Emacs is ready to read a key. Therefore, if they press
2084 `Alt-x' when Emacs is busy, by the time we get to
2085 `dos_get_modifiers', they might have already released the
2086 Alt key, and Emacs gets just `x', which is BAD.
2087 However, for keys with the `Map' property set, the ASCII
2088 code returns zero iff Alt is pressed. So, when we DON'T
2089 have to support international_keyboard, we don't have to
2090 distinguish between the left and right Alt keys, and we
2091 can set the META modifier for any keys with the `Map'
2092 property if they return zero ASCII code (c = 0). */
2094 || ( (code
& 0xf000) == Map
&& !international_keyboard
))
2095 modifiers
|= meta_modifier
;
2097 modifiers
|= ctrl_modifier
;
2099 modifiers
|= shift_modifier
;
2102 switch (code
& 0xf000)
2105 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
2107 c
= 0; /* Special */
2120 if (c
== 0) /* ctrl-break */
2122 return c
; /* ALT-nnn */
2124 if (!keyboard_map_all
)
2133 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
2134 if (!keyboard_map_all
)
2138 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
2139 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
2143 code
= keyboard
->shifted
[code
];
2145 modifiers
&= ~shift_modifier
;
2148 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
2149 code
= keyboard
->alt_gr
[code
];
2151 code
= keyboard
->unshifted
[code
];
2156 if (c
== 0xe0) /* edit key */
2159 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
2160 kp_mode
= dos_keypad_mode
& 0x03;
2162 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
2167 if (code
== 10 && dos_decimal_point
)
2168 return dos_decimal_point
;
2169 return keypad_translate_map
[code
].char_code
;
2172 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
2176 code
= keypad_translate_map
[code
].meta_code
;
2177 modifiers
= meta_modifier
;
2181 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
2188 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
2189 if (dos_keypad_mode
& kp_mode
)
2190 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
2192 code
= grey_key_translate_map
[code
].char_code
;
2201 event
.kind
= non_ascii_keystroke
;
2203 event
.kind
= ascii_keystroke
;
2205 event
.modifiers
= modifiers
;
2206 XSETFRAME (event
.frame_or_window
, selected_frame
);
2207 event
.timestamp
= event_timestamp ();
2208 kbd_buffer_store_event (&event
);
2211 if (have_mouse
> 0 && !mouse_preempted
)
2213 int but
, press
, x
, y
, ok
;
2215 /* Check for mouse movement *before* buttons. */
2216 mouse_check_moved ();
2218 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
2219 for (press
= 0; press
< 2; press
++)
2221 int button_num
= but
;
2224 ok
= mouse_pressed (but
, &x
, &y
);
2226 ok
= mouse_released (but
, &x
, &y
);
2229 /* Allow a simultaneous press/release of Mouse-1 and
2230 Mouse-2 to simulate Mouse-3 on two-button mice. */
2231 if (mouse_button_count
== 2 && but
< 2)
2233 int x2
, y2
; /* don't clobber original coordinates */
2235 /* If only one button is pressed, wait 100 msec and
2236 check again. This way, Speedy Gonzales isn't
2237 punished, while the slow get their chance. */
2238 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
2239 || !press
&& mouse_released (1-but
, &x2
, &y2
))
2244 if (press
&& mouse_pressed (1-but
, &x2
, &y2
)
2245 || !press
&& mouse_released (1-but
, &x2
, &y2
))
2250 event
.kind
= mouse_click
;
2251 event
.code
= button_num
;
2252 event
.modifiers
= dos_get_modifiers (0)
2253 | (press
? down_modifier
: up_modifier
);
2256 XSETFRAME (event
.frame_or_window
, selected_frame
);
2257 event
.timestamp
= event_timestamp ();
2258 kbd_buffer_store_event (&event
);
2266 static int prev_get_char
= -1;
2268 /* Return 1 if a key is ready to be read without suspending execution. */
2272 if (prev_get_char
!= -1)
2275 return ((prev_get_char
= dos_rawgetc ()) != -1);
2278 /* Read a key. Return -1 if no key is ready. */
2282 if (prev_get_char
!= -1)
2284 int c
= prev_get_char
;
2289 return dos_rawgetc ();
2292 #ifndef HAVE_X_WINDOWS
2293 /* See xterm.c for more info. */
2295 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
2297 register int pix_x
, pix_y
;
2298 register int *x
, *y
;
2302 if (bounds
) abort ();
2304 /* Ignore clipping. */
2311 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
2314 register int *pix_x
, *pix_y
;
2320 /* Simulation of X's menus. Nothing too fancy here -- just make it work
2323 Actually, I don't know the meaning of all the parameters of the functions
2324 here -- I only know how they are called by xmenu.c. I could of course
2325 grab the nearest Xlib manual (down the hall, second-to-last door on the
2326 left), but I don't think it's worth the effort. */
2333 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
2334 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
2338 /* Allocate some (more) memory for MENU ensuring that there is room for one
2342 IT_menu_make_room (XMenu
*menu
)
2344 if (menu
->allocated
== 0)
2346 int count
= menu
->allocated
= 10;
2347 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
2348 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
2349 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
2351 else if (menu
->allocated
== menu
->count
)
2353 int count
= menu
->allocated
= menu
->allocated
+ 10;
2355 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
2357 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
2359 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
2363 /* Search the given menu structure for a given pane number. */
2366 IT_menu_search_pane (XMenu
*menu
, int pane
)
2371 for (i
= 0; i
< menu
->count
; i
++)
2372 if (menu
->submenu
[i
])
2374 if (pane
== menu
->panenumber
[i
])
2375 return menu
->submenu
[i
];
2376 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
2382 /* Determine how much screen space a given menu needs. */
2385 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
2387 int i
, h2
, w2
, maxsubwidth
, maxheight
;
2390 maxheight
= menu
->count
;
2391 for (i
= 0; i
< menu
->count
; i
++)
2393 if (menu
->submenu
[i
])
2395 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
2396 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
2397 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
2400 *width
= menu
->width
+ maxsubwidth
;
2401 *height
= maxheight
;
2404 /* Display MENU at (X,Y) using FACES. */
2407 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
2409 int i
, j
, face
, width
;
2413 int enabled
, mousehere
;
2416 width
= menu
->width
;
2417 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
2418 ScreenGetCursor (&row
, &col
);
2419 mouse_get_xy (&mx
, &my
);
2420 IT_update_begin (selected_frame
);
2421 for (i
= 0; i
< menu
->count
; i
++)
2423 IT_cursor_to (y
+ i
, x
);
2425 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
2426 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
2427 face
= faces
[enabled
+ mousehere
* 2];
2429 *p
++ = FAST_MAKE_GLYPH (' ', face
);
2430 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
2433 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
2434 else /* make '^x' */
2436 *p
++ = FAST_MAKE_GLYPH ('^', face
);
2438 *p
++ = FAST_MAKE_GLYPH (*q
++ + 64, face
);
2442 for (; j
< width
; j
++)
2443 *p
++ = FAST_MAKE_GLYPH (' ', face
);
2444 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
2445 IT_write_glyphs (text
, width
+ 2);
2447 IT_update_end (selected_frame
);
2448 IT_cursor_to (row
, col
);
2452 /* --------------------------- X Menu emulation ---------------------- */
2454 /* Report availability of menus. */
2462 /* Create a brand new menu structure. */
2465 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
2467 return IT_menu_create ();
2470 /* Create a new pane and place it on the outer-most level. It is not
2471 clear that it should be placed out there, but I don't know what else
2475 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
2483 IT_menu_make_room (menu
);
2484 menu
->submenu
[menu
->count
] = IT_menu_create ();
2485 menu
->text
[menu
->count
] = txt
;
2486 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
2489 /* Adjust length for possible control characters (which will
2490 be written as ^x). */
2491 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2495 if (len
> menu
->width
)
2498 return menu
->panecount
;
2501 /* Create a new item in a menu pane. */
2504 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
2505 int foo
, char *txt
, int enable
)
2511 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
2513 IT_menu_make_room (menu
);
2514 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
2515 menu
->text
[menu
->count
] = txt
;
2516 menu
->panenumber
[menu
->count
] = enable
;
2519 /* Adjust length for possible control characters (which will
2520 be written as ^x). */
2521 for (len
= strlen (txt
), p
= txt
; *p
; p
++)
2525 if (len
> menu
->width
)
2531 /* Decide where the menu would be placed if requested at (X,Y). */
2534 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
2535 int *ulx
, int *uly
, int *width
, int *height
)
2537 IT_menu_calc_size (menu
, width
, height
);
2543 struct IT_menu_state
2545 void *screen_behind
;
2552 /* Display menu, wait for user's response, and return that response. */
2555 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
2556 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
2558 struct IT_menu_state
*state
;
2562 int faces
[4], selectface
;
2563 int leave
, result
, onepane
;
2564 int title_faces
[4]; /* face to display the menu title */
2565 int buffers_num_deleted
= 0;
2567 /* Just in case we got here without a mouse present... */
2568 if (have_mouse
<= 0)
2569 return XM_IA_SELECT
;
2570 /* Don't allow non-positive x0 and y0, lest the menu will wrap
2571 around the display. */
2577 /* We will process all the mouse events directly, so we had
2578 better prevented dos_rawgetc from stealing them from us. */
2581 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
2582 screensize
= screen_size
* 2;
2584 = compute_glyph_face (selected_frame
,
2587 intern ("msdos-menu-passive-face")),
2590 = compute_glyph_face (selected_frame
,
2593 intern ("msdos-menu-active-face")),
2596 = face_name_id_number (selected_frame
, intern ("msdos-menu-select-face"));
2597 faces
[2] = compute_glyph_face (selected_frame
, selectface
, faces
[0]);
2598 faces
[3] = compute_glyph_face (selected_frame
, selectface
, faces
[1]);
2600 /* Make sure the menu title is always displayed with
2601 `msdos-menu-active-face', no matter where the mouse pointer is. */
2602 for (i
= 0; i
< 4; i
++)
2603 title_faces
[i
] = faces
[3];
2607 /* Don't let the title for the "Buffers" popup menu include a
2608 digit (which is ugly).
2610 This is a terrible kludge, but I think the "Buffers" case is
2611 the only one where the title includes a number, so it doesn't
2612 seem to be necessary to make this more general. */
2613 if (strncmp (menu
->text
[0], "Buffers 1", 9) == 0)
2615 menu
->text
[0][7] = '\0';
2616 buffers_num_deleted
= 1;
2618 state
[0].menu
= menu
;
2620 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
2622 /* Turn off the cursor. Otherwise it shows through the menu
2623 panes, which is ugly. */
2624 IT_display_cursor (0);
2626 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
2627 if (buffers_num_deleted
)
2628 menu
->text
[0][7] = ' ';
2629 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
2631 menu
->width
= menu
->submenu
[0]->width
;
2632 state
[0].menu
= menu
->submenu
[0];
2636 state
[0].menu
= menu
;
2638 state
[0].x
= x0
- 1;
2640 state
[0].pane
= onepane
;
2642 mouse_last_x
= -1; /* A hack that forces display. */
2646 if (!mouse_visible
) mouse_on ();
2647 mouse_check_moved ();
2648 if (selected_frame
->mouse_moved
)
2650 selected_frame
->mouse_moved
= 0;
2651 result
= XM_IA_SELECT
;
2652 mouse_get_xy (&x
, &y
);
2653 for (i
= 0; i
< statecount
; i
++)
2654 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
2656 int dy
= y
- state
[i
].y
;
2657 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
2659 if (!state
[i
].menu
->submenu
[dy
])
2660 if (state
[i
].menu
->panenumber
[dy
])
2661 result
= XM_SUCCESS
;
2663 result
= XM_IA_SELECT
;
2664 *pane
= state
[i
].pane
- 1;
2666 /* We hit some part of a menu, so drop extra menus that
2667 have been opened. That does not include an open and
2669 if (i
!= statecount
- 2
2670 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
2671 while (i
!= statecount
- 1)
2675 ScreenUpdate (state
[statecount
].screen_behind
);
2676 if (screen_virtual_segment
)
2677 dosv_refresh_virtual_screen (0, screen_size
);
2678 xfree (state
[statecount
].screen_behind
);
2680 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
2682 IT_menu_display (state
[i
].menu
,
2686 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
2687 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
2689 ScreenRetrieve (state
[statecount
].screen_behind
2690 = xmalloc (screensize
));
2692 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
2693 state
[statecount
].y
= y
;
2698 IT_menu_display (state
[statecount
- 1].menu
,
2699 state
[statecount
- 1].y
,
2700 state
[statecount
- 1].x
,
2704 /* We are busy-waiting for the mouse to move, so let's be nice
2705 to other Windows applications by releasing our time slice. */
2707 for (b
= 0; b
< mouse_button_count
&& !leave
; b
++)
2709 /* Only leave if user both pressed and released the mouse, and in
2710 that order. This avoids popping down the menu pane unless
2711 the user is really done with it. */
2712 if (mouse_pressed (b
, &x
, &y
))
2714 while (mouse_button_depressed (b
, &x
, &y
))
2718 (void) mouse_released (b
, &x
, &y
);
2723 ScreenUpdate (state
[0].screen_behind
);
2724 if (screen_virtual_segment
)
2725 dosv_refresh_virtual_screen (0, screen_size
);
2726 while (statecount
--)
2727 xfree (state
[statecount
].screen_behind
);
2728 IT_display_cursor (1); /* turn cursor back on */
2729 /* Clean up any mouse events that are waiting inside Emacs event queue.
2730 These events are likely to be generated before the menu was even
2731 displayed, probably because the user pressed and released the button
2732 (which invoked the menu) too quickly. If we don't remove these events,
2733 Emacs will process them after we return and surprise the user. */
2734 discard_mouse_events ();
2735 /* Allow mouse events generation by dos_rawgetc. */
2740 /* Dispose of a menu. */
2743 XMenuDestroy (Display
*foo
, XMenu
*menu
)
2746 if (menu
->allocated
)
2748 for (i
= 0; i
< menu
->count
; i
++)
2749 if (menu
->submenu
[i
])
2750 XMenuDestroy (foo
, menu
->submenu
[i
]);
2752 xfree (menu
->submenu
);
2753 xfree (menu
->panenumber
);
2759 x_pixel_width (struct frame
*f
)
2761 return FRAME_WIDTH (f
);
2765 x_pixel_height (struct frame
*f
)
2767 return FRAME_HEIGHT (f
);
2769 #endif /* !HAVE_X_WINDOWS */
2771 /* ----------------------- DOS / UNIX conversion --------------------- */
2773 void msdos_downcase_filename (unsigned char *);
2775 /* Destructively turn backslashes into slashes. */
2778 dostounix_filename (p
)
2781 msdos_downcase_filename (p
);
2791 /* Destructively turn slashes into backslashes. */
2794 unixtodos_filename (p
)
2797 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
2811 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2814 getdefdir (drive
, dst
)
2818 char in_path
[4], *p
= in_path
;
2821 /* Generate "X:." (when drive is X) or "." (when drive is 0). */
2824 *p
++ = drive
+ 'A' - 1;
2831 _fixpath (in_path
, dst
);
2835 msdos_downcase_filename (dst
);
2841 /* Remove all CR's that are followed by a LF. */
2846 register unsigned char *buf
;
2848 unsigned char *np
= buf
;
2849 unsigned char *startp
= buf
;
2850 unsigned char *endp
= buf
+ n
;
2854 while (buf
< endp
- 1)
2858 if (*(++buf
) != 0x0a)
2869 #if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 0
2871 /* In DJGPP v2.0, library `write' can call `malloc', which might
2872 cause relocation of the buffer whose address we get in ADDR.
2873 Here is a version of `write' that avoids calling `malloc',
2874 to serve us until such time as the library is fixed.
2875 Actually, what we define here is called `__write', because
2876 `write' is a stub that just jmp's to `__write' (to be
2877 POSIXLY-correct with respect to the global name-space). */
2879 #include <io.h> /* for _write */
2880 #include <libc/dosio.h> /* for __file_handle_modes[] */
2882 static char xbuf
[64 * 1024]; /* DOS cannot write more in one chunk */
2884 #define XBUF_END (xbuf + sizeof (xbuf) - 1)
2887 __write (int handle
, const void *buffer
, size_t count
)
2892 if(__file_handle_modes
[handle
] & O_BINARY
)
2893 return _write (handle
, buffer
, count
);
2897 const char *bp
= buffer
;
2898 int total_written
= 0;
2899 int nmoved
= 0, ncr
= 0;
2903 /* The next test makes sure there's space for at least 2 more
2904 characters in xbuf[], so both CR and LF can be put there. */
2916 if (xbp
>= XBUF_END
|| !count
)
2918 size_t to_write
= nmoved
+ ncr
;
2919 int written
= _write (handle
, xbuf
, to_write
);
2924 total_written
+= nmoved
; /* CRs aren't counted in ret value */
2926 /* If some, but not all were written (disk full?), return
2927 an estimate of the total written bytes not counting CRs. */
2928 if (written
< to_write
)
2929 return total_written
- (to_write
- written
) * nmoved
/to_write
;
2936 return total_written
;
2940 /* A low-level file-renaming function which works around Windows 95 bug.
2941 This is pulled directly out of DJGPP v2.01 library sources, and only
2942 used when you compile with DJGPP v2.0. */
2946 int _rename(const char *old
, const char *new)
2949 int olen
= strlen(old
) + 1;
2951 int use_lfn
= _USE_LFN
;
2952 char tempfile
[FILENAME_MAX
];
2953 const char *orig
= old
;
2956 r
.x
.dx
= __tb_offset
;
2957 r
.x
.di
= __tb_offset
+ olen
;
2958 r
.x
.ds
= r
.x
.es
= __tb_segment
;
2962 /* Windows 95 bug: for some filenames, when you rename
2963 file -> file~ (as in Emacs, to leave a backup), the
2964 short 8+3 alias doesn't change, which effectively
2965 makes OLD and NEW the same file. We must rename
2966 through a temporary file to work around this. */
2968 char *pbase
= 0, *p
;
2969 static char try_char
[] = "abcdefghijklmnopqrstuvwxyz012345789";
2970 int idx
= sizeof(try_char
) - 1;
2972 /* Generate a temporary name. Can't use `tmpnam', since $TMPDIR
2973 might point to another drive, which will fail the DOS call. */
2974 strcpy(tempfile
, old
);
2975 for (p
= tempfile
; *p
; p
++) /* ensure temporary is on the same drive */
2976 if (*p
== '/' || *p
== '\\' || *p
== ':')
2982 strcpy(pbase
, "X$$djren$$.$$temp$$");
2988 *pbase
= try_char
[--idx
];
2989 } while (_chmod(tempfile
, 0) != -1);
2992 _put_path2(tempfile
, olen
);
2994 __dpmi_int(0x21, &r
);
2997 errno
= __doserr_to_errno(r
.x
.ax
);
3001 /* Now create a file with the original name. This will
3002 ensure that NEW will always have a 8+3 alias
3003 different from that of OLD. (Seems to be required
3004 when NameNumericTail in the Registry is set to 0.) */
3005 lfn_fd
= _creat(old
, 0);
3007 olen
= strlen(tempfile
) + 1;
3009 r
.x
.di
= __tb_offset
+ olen
;
3018 _put_path2(new, olen
);
3020 __dpmi_int(0x21, &r
);
3023 if (r
.x
.ax
== 5 && i
== 0) /* access denied */
3024 remove(new); /* and try again */
3027 errno
= __doserr_to_errno(r
.x
.ax
);
3029 /* Restore to original name if we renamed it to temporary. */
3037 _put_path2(orig
, olen
);
3038 _put_path(tempfile
);
3040 __dpmi_int(0x21, &r
);
3049 /* Success. Delete the file possibly created to work
3050 around the Windows 95 bug. */
3052 return (_close (lfn_fd
) == 0) ? remove (orig
) : -1;
3056 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
3058 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names
, Smsdos_long_file_names
,
3060 "Return non-nil if long file names are supported on MSDOS.")
3063 return (_USE_LFN
? Qt
: Qnil
);
3066 /* Convert alphabetic characters in a filename to lower-case. */
3069 msdos_downcase_filename (p
)
3070 register unsigned char *p
;
3072 /* Always lower-case drive letters a-z, even if the filesystem
3073 preserves case in filenames.
3074 This is so MSDOS filenames could be compared by string comparison
3075 functions that are case-sensitive. Even case-preserving filesystems
3076 do not distinguish case in drive letters. */
3077 if (p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
3083 /* Under LFN we expect to get pathnames in their true case. */
3084 if (NILP (Fmsdos_long_file_names ()))
3086 if (*p
>= 'A' && *p
<= 'Z')
3090 DEFUN ("msdos-downcase-filename", Fmsdos_downcase_filename
, Smsdos_downcase_filename
,
3092 "Convert alphabetic characters in FILENAME to lower case and return that.\n\
3093 When long filenames are supported, doesn't change FILENAME.\n\
3094 If FILENAME is not a string, returns nil.\n\
3095 The argument object is never altered--the value is a copy.")
3097 Lisp_Object filename
;
3101 if (! STRINGP (filename
))
3104 tem
= Fcopy_sequence (filename
);
3105 msdos_downcase_filename (XSTRING (tem
)->data
);
3109 /* The Emacs root directory as determined by init_environment. */
3111 static char emacsroot
[MAXPATHLEN
];
3114 rootrelativepath (rel
)
3117 static char result
[MAXPATHLEN
+ 10];
3119 strcpy (result
, emacsroot
);
3120 strcat (result
, "/");
3121 strcat (result
, rel
);
3125 /* Define a lot of environment variables if not already defined. Don't
3126 remove anything unless you know what you're doing -- lots of code will
3127 break if one or more of these are missing. */
3130 init_environment (argc
, argv
, skip_args
)
3137 static const char * const tempdirs
[] = {
3138 "$TMPDIR", "$TEMP", "$TMP", "c:/"
3141 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
3143 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
3144 temporary files and assume "/tmp" if $TMPDIR is unset, which
3145 will break on DOS/Windows. Refuse to work if we cannot find
3146 a directory, not even "c:/", usable for that purpose. */
3147 for (i
= 0; i
< imax
; i
++)
3149 const char *tmp
= tempdirs
[i
];
3152 tmp
= getenv (tmp
+ 1);
3153 /* Note that `access' can lie to us if the directory resides on a
3154 read-only filesystem, like CD-ROM or a write-protected floppy.
3155 The only way to be really sure is to actually create a file and
3156 see if it succeeds. But I think that's too much to ask. */
3157 if (tmp
&& access (tmp
, D_OK
) == 0)
3159 setenv ("TMPDIR", tmp
, 1);
3166 Fcons (build_string ("no usable temporary directories found!!"),
3168 "While setting TMPDIR: ");
3170 /* Note the startup time, so we know not to clear the screen if we
3171 exit immediately; see IT_reset_terminal_modes.
3172 (Yes, I know `clock' returns zero the first time it's called, but
3173 I do this anyway, in case some wiseguy changes that at some point.) */
3174 startup_time
= clock ();
3176 /* Find our root from argv[0]. Assuming argv[0] is, say,
3177 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
3178 root
= alloca (MAXPATHLEN
+ 20);
3179 _fixpath (argv
[0], root
);
3180 msdos_downcase_filename (root
);
3181 len
= strlen (root
);
3182 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
3186 && (strcmp (root
+ len
- 4, "/bin") == 0
3187 || strcmp (root
+ len
- 4, "/src") == 0)) /* under a debugger */
3188 root
[len
- 4] = '\0';
3190 strcpy (root
, "c:/emacs"); /* let's be defensive */
3191 len
= strlen (root
);
3192 strcpy (emacsroot
, root
);
3194 /* We default HOME to our root. */
3195 setenv ("HOME", root
, 0);
3197 /* We default EMACSPATH to root + "/bin". */
3198 strcpy (root
+ len
, "/bin");
3199 setenv ("EMACSPATH", root
, 0);
3201 /* I don't expect anybody to ever use other terminals so the internal
3202 terminal is the default. */
3203 setenv ("TERM", "internal", 0);
3205 #ifdef HAVE_X_WINDOWS
3206 /* Emacs expects DISPLAY to be set. */
3207 setenv ("DISPLAY", "unix:0.0", 0);
3210 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
3211 downcase it and mirror the backslashes. */
3212 s
= getenv ("COMSPEC");
3213 if (!s
) s
= "c:/command.com";
3214 t
= alloca (strlen (s
) + 1);
3216 dostounix_filename (t
);
3217 setenv ("SHELL", t
, 0);
3219 /* PATH is also downcased and backslashes mirrored. */
3220 s
= getenv ("PATH");
3222 t
= alloca (strlen (s
) + 3);
3223 /* Current directory is always considered part of MsDos's path but it is
3224 not normally mentioned. Now it is. */
3225 strcat (strcpy (t
, ".;"), s
);
3226 dostounix_filename (t
); /* Not a single file name, but this should work. */
3227 setenv ("PATH", t
, 1);
3229 /* In some sense all dos users have root privileges, so... */
3230 setenv ("USER", "root", 0);
3231 setenv ("NAME", getenv ("USER"), 0);
3233 /* Time zone determined from country code. To make this possible, the
3234 country code may not span more than one time zone. In other words,
3235 in the USA, you lose. */
3237 switch (dos_country_code
)
3239 case 31: /* Belgium */
3240 case 32: /* The Netherlands */
3241 case 33: /* France */
3242 case 34: /* Spain */
3243 case 36: /* Hungary */
3244 case 38: /* Yugoslavia (or what's left of it?) */
3245 case 39: /* Italy */
3246 case 41: /* Switzerland */
3247 case 42: /* Tjekia */
3248 case 45: /* Denmark */
3249 case 46: /* Sweden */
3250 case 47: /* Norway */
3251 case 48: /* Poland */
3252 case 49: /* Germany */
3253 /* Daylight saving from last Sunday in March to last Sunday in
3254 September, both at 2AM. */
3255 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
3257 case 44: /* United Kingdom */
3258 case 351: /* Portugal */
3259 case 354: /* Iceland */
3260 setenv ("TZ", "GMT+00", 0);
3262 case 81: /* Japan */
3263 case 82: /* Korea */
3264 setenv ("TZ", "JST-09", 0);
3266 case 90: /* Turkey */
3267 case 358: /* Finland */
3268 setenv ("TZ", "EET-02", 0);
3270 case 972: /* Israel */
3271 /* This is an approximation. (For exact rules, use the
3272 `zoneinfo/israel' file which comes with DJGPP, but you need
3273 to install it in `/usr/share/zoneinfo/' directory first.) */
3274 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
3282 static int break_stat
; /* BREAK check mode status. */
3283 static int stdin_stat
; /* stdin IOCTL status. */
3287 /* These must be global. */
3288 static _go32_dpmi_seginfo ctrl_break_vector
;
3289 static _go32_dpmi_registers ctrl_break_regs
;
3290 static int ctrlbreakinstalled
= 0;
3292 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
3295 ctrl_break_func (regs
)
3296 _go32_dpmi_registers
*regs
;
3302 install_ctrl_break_check ()
3304 if (!ctrlbreakinstalled
)
3306 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
3307 was compiler with Djgpp 1.11 maintenance level 5 or later! */
3308 ctrlbreakinstalled
= 1;
3309 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
3310 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
3312 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
3316 #endif /* __DJGPP__ < 2 */
3318 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
3319 control chars by DOS. Determine the keyboard type. */
3324 union REGS inregs
, outregs
;
3325 static int first_time
= 1;
3327 break_stat
= getcbrk ();
3330 install_ctrl_break_check ();
3336 int86 (0x15, &inregs
, &outregs
);
3337 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
3341 if (internal_terminal
3342 #ifdef HAVE_X_WINDOWS
3343 && inhibit_window_system
3347 inregs
.x
.ax
= 0x0021;
3348 int86 (0x33, &inregs
, &outregs
);
3349 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3352 /* Reportedly, the above doesn't work for some mouse drivers. There
3353 is an additional detection method that should work, but might be
3354 a little slower. Use that as an alternative. */
3355 inregs
.x
.ax
= 0x0000;
3356 int86 (0x33, &inregs
, &outregs
);
3357 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
3362 have_mouse
= 1; /* enable mouse */
3365 if (outregs
.x
.bx
== 3)
3367 mouse_button_count
= 3;
3368 mouse_button_translate
[0] = 0; /* Left */
3369 mouse_button_translate
[1] = 2; /* Middle */
3370 mouse_button_translate
[2] = 1; /* Right */
3374 mouse_button_count
= 2;
3375 mouse_button_translate
[0] = 0;
3376 mouse_button_translate
[1] = 1;
3378 mouse_position_hook
= &mouse_get_pos
;
3387 stdin_stat
= setmode (fileno (stdin
), O_BINARY
);
3388 return (stdin_stat
!= -1);
3391 return (setmode (fileno (stdin
), O_BINARY
) != -1);
3393 #else /* __DJGPP__ < 2 */
3397 /* I think it is wrong to overwrite `stdin_stat' every time
3398 but the first one this function is called, but I don't
3399 want to change the way it used to work in v1.x.--EZ */
3401 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
3402 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
3403 intdos (&inregs
, &outregs
);
3404 stdin_stat
= outregs
.h
.dl
;
3406 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
3407 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
3408 intdos (&inregs
, &outregs
);
3409 return !outregs
.x
.cflag
;
3411 #endif /* __DJGPP__ < 2 */
3414 /* Restore status of standard input and Ctrl-C checking. */
3419 union REGS inregs
, outregs
;
3421 setcbrk (break_stat
);
3426 return (setmode (fileno (stdin
), stdin_stat
) != -1);
3428 #else /* not __DJGPP__ >= 2 */
3430 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
3431 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
3432 inregs
.x
.dx
= stdin_stat
;
3433 intdos (&inregs
, &outregs
);
3434 return !outregs
.x
.cflag
;
3436 #endif /* not __DJGPP__ >= 2 */
3440 /* Run command as specified by ARGV in directory DIR.
3441 The command is run with input from TEMPIN, output to
3442 file TEMPOUT and stderr to TEMPERR. */
3445 run_msdos_command (argv
, working_dir
, tempin
, tempout
, temperr
, envv
)
3446 unsigned char **argv
;
3447 const char *working_dir
;
3448 int tempin
, tempout
, temperr
;
3451 char *saveargv1
, *saveargv2
, *lowcase_argv0
, *pa
, *pl
;
3452 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
3453 int msshell
, result
= -1;
3454 int inbak
, outbak
, errbak
;
3458 /* Get current directory as MSDOS cwd is not per-process. */
3461 /* If argv[0] is the shell, it might come in any lettercase.
3462 Since `Fmember' is case-sensitive, we need to downcase
3463 argv[0], even if we are on case-preserving filesystems. */
3464 lowcase_argv0
= alloca (strlen (argv
[0]) + 1);
3465 for (pa
= argv
[0], pl
= lowcase_argv0
; *pa
; pl
++)
3468 if (*pl
>= 'A' && *pl
<= 'Z')
3473 cmd
= Ffile_name_nondirectory (build_string (lowcase_argv0
));
3474 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
3475 && !strcmp ("-c", argv
[1]);
3478 saveargv1
= argv
[1];
3479 saveargv2
= argv
[2];
3483 char *p
= alloca (strlen (argv
[2]) + 1);
3485 strcpy (argv
[2] = p
, saveargv2
);
3486 while (*p
&& isspace (*p
))
3488 while (*p
&& !isspace (*p
))
3496 chdir (working_dir
);
3500 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
3501 goto done
; /* Allocation might fail due to lack of descriptors. */
3504 mouse_get_xy (&x
, &y
);
3506 dos_ttcooked (); /* do it here while 0 = stdin */
3514 if (msshell
&& !argv
[3])
3516 /* MS-DOS native shells are too restrictive. For starters, they
3517 cannot grok commands longer than 126 characters. In DJGPP v2
3518 and later, `system' is much smarter, so we'll call it instead. */
3522 /* A shell gets a single argument--its full command
3523 line--whose original was saved in `saveargv2'. */
3525 /* Don't let them pass empty command lines to `system', since
3526 with some shells it will try to invoke an interactive shell,
3527 which will hang Emacs. */
3528 for (cmnd
= saveargv2
; *cmnd
&& isspace (*cmnd
); cmnd
++)
3532 extern char **environ
;
3533 int save_system_flags
= __system_flags
;
3535 /* Request the most powerful version of `system'. We need
3536 all the help we can get to avoid calling stock DOS shells. */
3537 __system_flags
= (__system_redirect
3538 | __system_use_shell
3539 | __system_allow_multiple_cmds
3540 | __system_allow_long_cmds
3541 | __system_handle_null_commands
3542 | __system_emulate_chdir
);
3545 result
= system (cmnd
);
3546 __system_flags
= save_system_flags
;
3549 result
= 0; /* emulate Unixy shell behavior with empty cmd line */
3553 #endif /* __DJGPP__ > 1 */
3555 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
3568 mouse_moveto (x
, y
);
3571 /* Some programs might change the meaning of the highest bit of the
3572 text attribute byte, so we get blinking characters instead of the
3573 bright background colors. Restore that. */
3580 argv
[1] = saveargv1
;
3581 argv
[2] = saveargv2
;
3589 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
3596 /* ------------------------- Compatibility functions -------------------
3601 /* Hostnames for a pc are not really funny,
3602 but they are used in change log so we emulate the best we can. */
3604 gethostname (p
, size
)
3608 char *q
= egetenv ("HOSTNAME");
3615 /* When time zones are set from Ms-Dos too many C-libraries are playing
3616 tricks with time values. We solve this by defining our own version
3617 of `gettimeofday' bypassing GO32. Our version needs to be initialized
3618 once and after each call to `tzset' with TZ changed. That is
3619 accomplished by aliasing tzset to init_gettimeofday. */
3621 static struct tm time_rec
;
3624 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
3632 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
3636 time_rec
.tm_year
= d
.da_year
- 1900;
3637 time_rec
.tm_mon
= d
.da_mon
- 1;
3638 time_rec
.tm_mday
= d
.da_day
;
3641 time_rec
.tm_hour
= t
.ti_hour
;
3642 time_rec
.tm_min
= t
.ti_min
;
3643 time_rec
.tm_sec
= t
.ti_sec
;
3646 tm
.tm_gmtoff
= dos_timezone_offset
;
3648 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
3649 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
3651 /* Ignore tzp; it's obsolescent. */
3655 #endif /* __DJGPP__ < 2 */
3658 * A list of unimplemented functions that we silently ignore.
3662 unsigned alarm (s
) unsigned s
; {}
3663 fork () { return 0; }
3664 int kill (x
, y
) int x
, y
; { return -1; }
3666 void volatile pause () {}
3667 sigsetmask (x
) int x
; { return 0; }
3668 sigblock (mask
) int mask
; { return 0; }
3671 void request_sigio (void) {}
3672 setpgrp () {return 0; }
3673 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
3674 void unrequest_sigio (void) {}
3678 #ifdef POSIX_SIGNALS
3680 /* Augment DJGPP library POSIX signal functions. This is needed
3681 as of DJGPP v2.01, but might be in the library in later releases. */
3683 #include <libc/bss.h>
3685 /* A counter to know when to re-initialize the static sets. */
3686 static int sigprocmask_count
= -1;
3688 /* Which signals are currently blocked (initially none). */
3689 static sigset_t current_mask
;
3691 /* Which signals are pending (initially none). */
3692 static sigset_t pending_signals
;
3694 /* Previous handlers to restore when the blocked signals are unblocked. */
3695 typedef void (*sighandler_t
)(int);
3696 static sighandler_t prev_handlers
[320];
3698 /* A signal handler which just records that a signal occured
3699 (it will be raised later, if and when the signal is unblocked). */
3701 sig_suspender (signo
)
3704 sigaddset (&pending_signals
, signo
);
3708 sigprocmask (how
, new_set
, old_set
)
3710 const sigset_t
*new_set
;
3716 /* If called for the first time, initialize. */
3717 if (sigprocmask_count
!= __bss_count
)
3719 sigprocmask_count
= __bss_count
;
3720 sigemptyset (&pending_signals
);
3721 sigemptyset (¤t_mask
);
3722 for (signo
= 0; signo
< 320; signo
++)
3723 prev_handlers
[signo
] = SIG_ERR
;
3727 *old_set
= current_mask
;
3732 if (how
!= SIG_BLOCK
&& how
!= SIG_UNBLOCK
&& how
!= SIG_SETMASK
)
3738 sigemptyset (&new_mask
);
3740 /* DJGPP supports upto 320 signals. */
3741 for (signo
= 0; signo
< 320; signo
++)
3743 if (sigismember (¤t_mask
, signo
))
3744 sigaddset (&new_mask
, signo
);
3745 else if (sigismember (new_set
, signo
) && how
!= SIG_UNBLOCK
)
3747 sigaddset (&new_mask
, signo
);
3749 /* SIGKILL is silently ignored, as on other platforms. */
3750 if (signo
!= SIGKILL
&& prev_handlers
[signo
] == SIG_ERR
)
3751 prev_handlers
[signo
] = signal (signo
, sig_suspender
);
3753 if (( how
== SIG_UNBLOCK
3754 && sigismember (&new_mask
, signo
)
3755 && sigismember (new_set
, signo
))
3756 || (how
== SIG_SETMASK
3757 && sigismember (&new_mask
, signo
)
3758 && !sigismember (new_set
, signo
)))
3760 sigdelset (&new_mask
, signo
);
3761 if (prev_handlers
[signo
] != SIG_ERR
)
3763 signal (signo
, prev_handlers
[signo
]);
3764 prev_handlers
[signo
] = SIG_ERR
;
3766 if (sigismember (&pending_signals
, signo
))
3768 sigdelset (&pending_signals
, signo
);
3773 current_mask
= new_mask
;
3777 #else /* not POSIX_SIGNALS */
3779 sigsetmask (x
) int x
; { return 0; }
3780 sigblock (mask
) int mask
; { return 0; }
3782 #endif /* not POSIX_SIGNALS */
3783 #endif /* __DJGPP__ > 1 */
3786 #include "sysselect.h"
3788 #ifndef EMACS_TIME_ZERO_OR_NEG_P
3789 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
3790 ((long)(time).tv_sec < 0 \
3791 || ((time).tv_sec == 0 \
3792 && (long)(time).tv_usec <= 0))
3795 /* This yields the rest of the current time slice to the task manager.
3796 It should be called by any code which knows that it has nothing
3797 useful to do except idle.
3799 I don't use __dpmi_yield here, since versions of library before 2.02
3800 called Int 2Fh/AX=1680h there in a way that would wedge the DOS box
3801 on some versions of Windows 9X. */
3804 dos_yield_time_slice (void)
3806 _go32_dpmi_registers r
;
3809 r
.x
.ss
= r
.x
.sp
= r
.x
.flags
= 0;
3810 _go32_dpmi_simulate_int (0x2f, &r
);
3815 /* Only event queue is checked. */
3816 /* We don't have to call timer_check here
3817 because wait_reading_process_input takes care of that. */
3819 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
3821 SELECT_TYPE
*rfds
, *wfds
, *efds
;
3822 EMACS_TIME
*timeout
;
3830 check_input
= FD_ISSET (0, rfds
);
3841 /* If we are looking only for the terminal, with no timeout,
3842 just read it and wait -- that's more efficient. */
3845 while (!detect_input_pending ())
3847 dos_yield_time_slice ();
3852 EMACS_TIME clnow
, cllast
, cldiff
;
3855 EMACS_SET_SECS_USECS (cllast
, t
.ti_sec
, t
.ti_hund
* 10000L);
3857 while (!check_input
|| !detect_input_pending ())
3860 EMACS_SET_SECS_USECS (clnow
, t
.ti_sec
, t
.ti_hund
* 10000L);
3861 EMACS_SUB_TIME (cldiff
, clnow
, cllast
);
3863 /* When seconds wrap around, we assume that no more than
3864 1 minute passed since last `gettime'. */
3865 if (EMACS_TIME_NEG_P (cldiff
))
3866 EMACS_SET_SECS (cldiff
, EMACS_SECS (cldiff
) + 60);
3867 EMACS_SUB_TIME (*timeout
, *timeout
, cldiff
);
3869 /* Stop when timeout value crosses zero. */
3870 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout
))
3873 dos_yield_time_slice ();
3883 * Define overlaid functions:
3885 * chdir -> sys_chdir
3886 * tzset -> init_gettimeofday
3887 * abort -> dos_abort
3892 extern int chdir ();
3898 int len
= strlen (path
);
3899 char *tmp
= (char *)path
;
3901 if (*tmp
&& tmp
[1] == ':')
3903 if (getdisk () != tolower (tmp
[0]) - 'a')
3904 setdisk (tolower (tmp
[0]) - 'a');
3905 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
3909 if (len
> 1 && (tmp
[len
- 1] == '/'))
3911 char *tmp1
= (char *) alloca (len
+ 1);
3922 extern void tzset (void);
3925 init_gettimeofday ()
3931 ltm
= gtm
= time (NULL
);
3932 ltm
= mktime (lstm
= localtime (<m
));
3933 gtm
= mktime (gmtime (>m
));
3934 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
3935 time_rec
.tm_isdst
= lstm
->tm_isdst
;
3936 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
3943 dos_abort (file
, line
)
3947 char buffer1
[200], buffer2
[400];
3950 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
3951 for (i
= j
= 0; buffer1
[i
]; i
++) {
3952 buffer2
[j
++] = buffer1
[i
];
3953 buffer2
[j
++] = 0x70;
3955 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
3956 ScreenSetCursor (2, 0);
3964 ScreenSetCursor (10, 0);
3965 cputs ("\r\n\nEmacs aborted!\r\n");
3967 #if __DJGPP__ == 2 && __DJGPP_MINOR__ < 2
3968 if (screen_virtual_segment
)
3969 dosv_refresh_virtual_screen (2 * 10 * screen_size_X
, 4 * screen_size_X
);
3970 /* Generate traceback, so we could tell whodunit. */
3971 signal (SIGINT
, SIG_DFL
);
3972 __asm__
__volatile__ ("movb $0x1b,%al;call ___djgpp_hw_exception");
3973 #else /* __DJGPP_MINOR__ >= 2 */
3975 #endif /* __DJGPP_MINOR__ >= 2 */
3981 /* The following two are required so that customization feature
3982 won't complain about unbound variables. */
3983 #ifndef HAVE_X_WINDOWS
3984 /* Search path for bitmap files (xfns.c). */
3985 Lisp_Object Vx_bitmap_file_path
;
3987 #ifndef subprocesses
3988 /* Nonzero means delete a process right away if it exits (process.c). */
3989 static int delete_exited_processes
;
3994 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
3995 staticpro (&recent_doskeys
);
3996 #ifndef HAVE_X_WINDOWS
3997 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path
,
3998 "List of directories to search for bitmap files for X.");
3999 Vx_bitmap_file_path
= decode_env_path ((char *) 0, ".");
4001 /* The following three are from xfns.c: */
4002 Qbackground_color
= intern ("background-color");
4003 staticpro (&Qbackground_color
);
4004 Qforeground_color
= intern ("foreground-color");
4005 staticpro (&Qforeground_color
);
4007 DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph
,
4008 "*Glyph to display instead of chars not supported by current codepage.\n\
4010 This variable is used only by MSDOS terminals.");
4011 Vdos_unsupported_char_glyph
= '\177';
4013 #ifndef subprocesses
4014 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes
,
4015 "*Non-nil means delete processes immediately when they exit.\n\
4016 nil means don't delete them until `list-processes' is run.");
4017 delete_exited_processes
= 0;
4020 defsubr (&Srecent_doskeys
);
4021 defsubr (&Smsdos_long_file_names
);
4022 defsubr (&Smsdos_downcase_filename
);